Unencrypted Password Authentication

JESPERSEN,IAN (HP-Unitedkingdom,ex1) ian_jespersen at hp.com
Wed Jun 13 11:23:10 GMT 2001


Hi All,

Using Samba 2.06 or 2.07, when a client connects to the Samba server running
as a Member server to a NT 4.0 server using unencrypted passwords the DC
Server rejects the authentication request.

The clients used by our customer who reported the issue are WfW clients, but
I could not reproduce this issue using this client - but I could using a
pre-encryption version of smbclient.  My WfW client always sent out
encrypted passwords, but I have traces showing the customer's WfW client
sending unencrypted passwords.

Relevant section of the smb.conf file is

#Global parameters
[global]
workgroup = HAKILLER
netbios name = HPPINE37
server string = Samba Server
security = DOMAIN
encrypt passwords =yes
password server = hppine95
log level = 10
syslog = 0

So the setup is

Client          HPPINE37	     HPPINE95
  |        Samba 'member' server   NT4 PDC for HAKILLER domain
  |               |                   |  
  +---------------+-------------------+

What appears to happen is the Samba server encrypts the plain text password
supplied by the client, using a locally generated challenge, and passes this
on to the DC for authentication, but the DC rejects the request with bad
password.

This setup works for a client passing encrypted passwords - just the plain
text one fails.

I've created a fix, more of a workaround, for this issue - but I am not
really happy with it. My fix sends the plain text password onto the DC,
which gets accepted, and the client is authenticated.  If the password from
the client is already encrypted then there is no change to the functionally.

But I think the current implementation is cleaner where the password is
encrypted, but I didn't understand why the encryption does not work.  Also I
am relying on a call to the superseded function 'cli_nt_login_interactive'.

The fact the password goes over the wire unencrypted is not too much of a
problem since it has already passed on the wire in its plain text version.

I have samba and network (netmon) traces of this happening, which I can
supply if required.

I've not done any testing of this on the 2.2.0 build.

Many thanks in advance for any feedback - hopefully with a real fix to the
encypytion issue.

Best Regards,
Ian.

Here is the code from the file I've marked my changes with '/* IJ */, and
this is from smbd\password.c
 
/***********************************************************************
 Do the same as security=server, but using NT Domain calls and a session
 key from the machine password.
************************************************************************/
 
BOOL domain_client_validate( char *user, char *domain, 
                             char *smb_apasswd, int smb_apasslen, 
                             char *smb_ntpasswd, int smb_ntpasslen,
                             BOOL *user_exists)
{
  unsigned char local_challenge[8];
  unsigned char local_lm_response[24];
  unsigned char local_nt_reponse[24];
  unsigned char trust_passwd[16];
  fstring remote_machine;
  char *p;
  NET_ID_INFO_CTR ctr;
  NET_USER_INFO_3 info3;
  struct cli_state cli;
  uint32 smb_uid_low;
  BOOL connected_ok = False;  
  BOOL loggedon_ok = False;      /* IJ */
  BOOL passwd_encrypted = False; /* IJ */
 
  if(user_exists != NULL)
    *user_exists = True; /* Only set false on a very specific error. */
 
  /* 
   * Check that the requested domain is not our own machine name.
   * If it is, we should never check the PDC here, we use our own local
   * password file.
   */
 
  if(strequal( domain, global_myname)) {
    DEBUG(3,("domain_client_validate: Requested domain was for this
machine.\n"));
    return False;
  }
 
  /*
   * Next, check that the passwords given were encrypted.
   */
 
  if(((smb_apasslen != 24) && (smb_apasslen != 0)) || 
     ((smb_ntpasslen != 24) && (smb_ntpasslen != 0))) {
 
    /*
     * Not encrypted - do so.
     */
    /* IJ */ 
    DEBUG(3,("domain_client_validate: User passwords not in encrypted
format.\n"));
    DEBUG(5,("domain_client_validate:
smb_apasslen=%d,smb_ntpasslen=%d.\n",smb_apasslen, smb_ntpasslen));
    passwd_encrypted = False;
    
  } else {
 
    /*
     * Encrypted - get the challenge we sent for these
     * responses.
     */
    passwd_encrypted = True;   /* IJ */
 
    if (!last_challenge(local_challenge)) {
      DEBUG(0,("domain_client_validate: no challenge done - password
failed\n"));
      return False;
    }
  }
 
  /*
   * Get the machine account password.
   */
  if (!trust_get_passwd( trust_passwd, global_myworkgroup, global_myname))
  {
    return False;
  }
 
  /*
   * At this point, smb_apasswd points to the lanman response to
   * the challenge in local_challenge, and smb_ntpasswd points to
   * the NT response to the challenge in local_challenge. Ship
   * these over the secure channel to a domain controller and
   * see if they were valid.
   */
 
  ZERO_STRUCT(cli);
 
  /*
   * Treat each name in the 'password server =' line as a potential
   * PDC/BDC. Contact each in turn and try and authenticate.
   */
 
  p = lp_passwordserver();
  while(!connected_ok && p &&
        next_token(&p,remote_machine,LIST_SEP,sizeof(remote_machine))) {
    if(strequal(remote_machine, "*")) {
 
      /*
       * We have been asked to dynamcially determine the IP addresses of
       * the PDC and BDC's for this DOMAIN, and query them in turn.
       */
 
      struct in_addr *ip_list = NULL;
      int count = 0;
      int i;
 
      if(!get_dc_list(lp_workgroup(), &ip_list, &count))
        continue;
 
      /*
       * Firstly try and contact a PDC/BDC who has the same
       * network address as any of our interfaces.
       */
 
      for(i = 0; i < count; i++) {
        if(!is_local_net(ip_list[i]))
          continue;
 
        if((connected_ok = attempt_connect_to_dc(&cli, &ip_list[i])))
          break;
 
        ip_list[i] = ipzero; /* Tried and failed. */
      }
 
      /*
       * Secondly try and contact a random PDC/BDC.
       */
 
      if(!connected_ok) {
        i = (sys_random() % count);
 
        if(!(connected_ok = attempt_connect_to_dc(&cli, &ip_list[i])))
          ip_list[i] = ipzero; /* Tried and failed. */
      }
 
      /*
       * Finally go through the IP list in turn, ignoring any addresses
       * we have already tried.
       */
 
      if(!connected_ok) {
 
        /*
         * Try and connect to any of the other IP addresses in the PDC/BDC
list.
         */
 
        for(i = 0; i < count; i++) {
          if((connected_ok = attempt_connect_to_dc(&cli, &ip_list[i])))
            break;
        }
      }
 
      if(ip_list != NULL)
        free((char *)ip_list);
 
    } else {
      connected_ok = connect_to_domain_password_server(&cli,
remote_machine);
    }
  }
 
  if (!connected_ok) {
    DEBUG(0,("domain_client_validate: Domain password server not
available.\n"));
    cli_shutdown(&cli);
    return False;
  }
 
  /*
   * Ok - we have an anonymous connection to the IPC$ share.
   * Now start the NT Domain stuff :-).
   */
 
  if(cli_nt_session_open(&cli, PIPE_NETLOGON) == False) {
    DEBUG(0,("domain_client_validate: unable to open the domain client
session to \
machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
    cli_nt_session_close(&cli);
    cli_ulogoff(&cli);
    cli_shutdown(&cli);
    return False; 
  }
 
  if(cli_nt_setup_creds(&cli, trust_passwd) == False) {
    DEBUG(0,("domain_client_validate: unable to setup the PDC credentials to
machine \
%s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
    cli_nt_session_close(&cli);
    cli_ulogoff(&cli);
    cli_shutdown(&cli);
    return False;
  }
 
  /* We really don't care what LUID we give the user. */
  generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
  
  if (passwd_encrypted) {  /* IJ */
    loggedon_ok=cli_nt_login_network(&cli, domain, user, smb_uid_low, (char
*)local_challenge,
                          ((smb_apasslen != 0) ? smb_apasswd : NULL),
                          ((smb_ntpasslen != 0) ? smb_ntpasswd : NULL),
                          &ctr, &info3) ;
  }
  else {
    loggedon_ok=	(&cli, domain, user, smb_uid_low,
                          ((smb_apasslen != 0) ? smb_apasswd : NULL),
                          &ctr, &info3);
  }
  
  if (loggedon_ok == False) {
    uint32 nt_rpc_err;
 
    cli_error(&cli, NULL, NULL, &nt_rpc_err);
    DEBUG(0,("domain_client_validate: unable to validate password for user
%s in domain \
%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine,
cli_errstr(&cli)));
    cli_nt_session_close(&cli);
    cli_ulogoff(&cli);
    cli_shutdown(&cli);
 
    if((nt_rpc_err == NT_STATUS_NO_SUCH_USER) && (user_exists != NULL))
      *user_exists = False;
 
    return False;
  }
 
  /*
   * Here, if we really want it, we have lots of info about the user in
info3.
   */
 
#if 0
  /* 
   * We don't actually need to do this - plus it fails currently with
   * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
   * send here. JRA.
   */
 
  if(cli_nt_logoff(&cli, &ctr) == False) {
    DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
%s to Domain controller %s. Error was %s.\n", user, domain, remote_machine,
cli_errstr(&cli)));        
    cli_nt_session_close(&cli);
    cli_ulogoff(&cli);
    cli_shutdown(&cli);
    return False;
  }
#endif /* 0 */
 
  cli_nt_session_close(&cli);
  cli_ulogoff(&cli);
  cli_shutdown(&cli);
  return True;
}
 

Ian Jespersen
Network Operating Systems (NOS) 
Worldwide Technology Expert Centre (WTEC) 
Hewlett Packard, Pinewood UK 




More information about the samba-technical mailing list