2 Unix SMB/Netbios implementation.
4 Password and authentication handling
5 Copyright (C) Andrew Tridgell 1992-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #if (defined(NETGROUP) && defined (AUTOMOUNT))
25 #include "rpcsvc/ypclnt.h"
28 extern int DEBUGLEVEL;
31 /* users from session setup */
32 static pstring session_users="";
34 extern pstring global_myname;
35 extern fstring global_myworkgroup;
37 /* these are kept here to keep the string_combinations function simple */
38 static char this_user[100]="";
39 static char this_salt[100]="";
40 static char this_crypted[100]="";
42 /* Data to do lanman1/2 password challenge. */
43 static unsigned char saved_challenge[8];
44 static BOOL challenge_sent=False;
46 /*******************************************************************
47 Get the next challenge value - no repeats.
48 ********************************************************************/
49 void generate_next_challenge(char *challenge)
53 * Leave this ifdef'd out while we test
54 * the new crypto random number generator.
57 unsigned char buf[16];
58 static int counter = 0;
62 /* get a sort-of random number */
64 v1 = (counter++) + getpid() + tval.tv_sec;
65 v2 = (counter++) * getpid() + tval.tv_usec;
66 SIVAL(challenge,0,v1);
67 SIVAL(challenge,4,v2);
69 /* mash it up with md4 */
70 mdfour(buf, (unsigned char *)challenge, 8);
74 generate_random_buffer(buf,8,False);
76 memcpy(saved_challenge, buf, 8);
77 memcpy(challenge,buf,8);
78 challenge_sent = True;
81 /*******************************************************************
82 set the last challenge sent, usually from a password server
83 ********************************************************************/
84 BOOL set_challenge(char *challenge)
86 memcpy(saved_challenge,challenge,8);
87 challenge_sent = True;
91 /*******************************************************************
92 get the last challenge sent
93 ********************************************************************/
94 BOOL last_challenge(unsigned char *challenge)
96 if (!challenge_sent) return(False);
97 memcpy(challenge,saved_challenge,8);
101 /* this holds info on user ids that are already validated for this VC */
102 static user_struct *validated_users = NULL;
103 static int num_validated_users = 0;
105 /****************************************************************************
106 check if a uid has been validated, and return an pointer to the user_struct
107 if it has. NULL if not. vuid is biased by an offset. This allows us to
108 tell random client vuid's (normally zero) from valid vuids.
109 ****************************************************************************/
110 user_struct *get_valid_user_struct(uint16 vuid)
112 if (vuid == UID_FIELD_INVALID)
115 if ((vuid >= (uint16)num_validated_users) ||
116 (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1))
118 return &validated_users[vuid];
121 /****************************************************************************
123 ****************************************************************************/
124 void invalidate_vuid(uint16 vuid)
126 user_struct *vuser = get_valid_user_struct(vuid);
128 if (vuser == NULL) return;
135 /* same number of igroups as groups as attrs */
138 if (vuser->groups && (vuser->groups != (gid_t *)vuser->igroups))
141 if (vuser->igroups) free(vuser->igroups);
142 if (vuser->attrs ) free(vuser->attrs);
143 if (vuser->sids ) free(vuser->sids);
147 vuser->igroups = NULL;
148 vuser->groups = NULL;
152 /****************************************************************************
153 return a validated username
154 ****************************************************************************/
155 char *validated_username(uint16 vuid)
157 user_struct *vuser = get_valid_user_struct(vuid);
164 /****************************************************************************
165 Setup the groups a user belongs to.
166 ****************************************************************************/
167 int setup_groups(char *user, int uid, int gid, int *p_ngroups,
168 int **p_igroups, gid_t **p_groups,
171 if (-1 == initgroups(user,gid))
175 DEBUG(0,("Unable to initgroups!\n"));
176 if (gid < 0 || gid > 16000 || uid < 0 || uid > 16000)
177 DEBUG(0,("This is probably a problem with the account %s\n",user));
186 ngroups = getgroups(0,&grp);
189 igroups = (int *)malloc(sizeof(int)*ngroups);
190 attrs = (int *)malloc(sizeof(int)*ngroups);
191 for (i=0;i<ngroups;i++)
193 attrs [i] = 0x7; /* XXXX don't know what NT user attributes are yet! */
194 igroups[i] = 0x42424242;
196 ngroups = getgroups(ngroups,(gid_t *)igroups);
198 if (igroups[0] == 0x42424242)
201 *p_ngroups = ngroups;
204 /* The following bit of code is very strange. It is due to the
205 fact that some OSes use int* and some use gid_t* for
206 getgroups, and some (like SunOS) use both, one in prototypes,
207 and one in man pages and the actual code. Thus we detect it
208 dynamically using some very ugly code */
211 /* does getgroups return ints or gid_t ?? */
212 static BOOL groups_use_ints = True;
214 if (groups_use_ints &&
216 SVAL(igroups,2) == 0x4242)
217 groups_use_ints = False;
219 for (i=0;groups_use_ints && i<ngroups;i++)
220 if (igroups[i] == 0x42424242)
221 groups_use_ints = False;
225 *p_igroups = igroups;
226 *p_groups = (gid_t *)igroups;
230 gid_t *groups = (gid_t *)igroups;
231 igroups = (int *)malloc(sizeof(int)*ngroups);
232 for (i=0;i<ngroups;i++)
234 igroups[i] = groups[i];
236 *p_igroups = igroups;
237 *p_groups = (gid_t *)groups;
240 DEBUG(3,("%s is in %d groups\n",user,ngroups));
241 for (i=0;i<ngroups;i++)
242 DEBUG(3,("%d ",igroups[i]));
249 /****************************************************************************
250 register a uid/name pair as being valid and that a valid password
251 has been given. vuid is biased by an offset. This allows us to
252 tell random client vuid's (normally zero) from valid vuids.
253 ****************************************************************************/
254 uint16 register_vuid(int uid,int gid, char *unix_name, char *requested_name, BOOL guest)
257 struct passwd *pwfile; /* for getting real name from passwd file */
259 /* Ensure no vuid gets registered in share level security. */
260 if(lp_security() == SEC_SHARE)
261 return UID_FIELD_INVALID;
265 * After observing MS-Exchange services writing to a Samba share
266 * I belive this code is incorrect. Each service does its own
267 * sessionsetup_and_X for the same user, and as each service shuts
268 * down, it does a user_logoff_and_X. As we are consolidating multiple
269 * sessionsetup_and_X's onto the same vuid here, when the first service
270 * shuts down, it invalidates all the open files for the other services.
271 * Hence I am removing this code and forcing each sessionsetup_and_X
273 * Jeremy Allison. (jallison@whistle.com).
277 for(i = 0; i < num_validated_users; i++) {
278 vuser = &validated_users[i];
279 if ( vuser->uid == uid )
280 return (uint16)(i + VUID_OFFSET); /* User already validated */
284 validated_users = (user_struct *)Realloc(validated_users,
286 (num_validated_users+1));
288 if (!validated_users)
290 DEBUG(0,("Failed to realloc users struct!\n"));
291 num_validated_users = 0;
292 return UID_FIELD_INVALID;
295 vuser = &validated_users[num_validated_users];
296 num_validated_users++;
300 vuser->guest = guest;
301 fstrcpy(vuser->name,unix_name);
302 fstrcpy(vuser->requested_name,requested_name);
308 vuser->groups = NULL;
309 vuser->igroups = NULL;
312 /* Find all the groups this uid is in and store them.
313 Used by become_user() */
314 setup_groups(unix_name,uid,gid,
320 DEBUG(3,("uid %d registered to name %s\n",uid,unix_name));
322 DEBUG(3, ("Clearing default real name\n"));
323 fstrcpy(vuser->real_name, "<Full Name>\0");
324 if (lp_unix_realname()) {
325 if ((pwfile=getpwnam(vuser->name))!= NULL)
327 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
328 fstrcpy(vuser->real_name, pwfile->pw_gecos);
332 return (uint16)((num_validated_users - 1) + VUID_OFFSET);
336 /****************************************************************************
337 add a name to the session users list
338 ****************************************************************************/
339 void add_session_user(char *user)
342 StrnCpy(suser,user,sizeof(suser)-1);
344 if (!Get_Pwnam(suser,True)) return;
346 if (suser && *suser && !in_list(suser,session_users,False))
348 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
349 DEBUG(1,("Too many session users??\n"));
352 pstrcat(session_users," ");
353 pstrcat(session_users,suser);
360 /* a fake shadow password routine which just fills a fake spwd struct
361 * with the sp_pwdp field. (sreiz@aie.nl)
363 static struct spwd *getspnam(char *username) /* fake shadow password routine */
368 static struct spwd static_spwd;
370 static_spwd.sp_pwdp=0;
371 if (!(f=fopen("/etc/master.passwd", "r")))
373 while (fgets(line, 1024, f)) {
374 if (!strncmp(line, username, strlen(username)) &&
375 line[strlen(username)]==':') { /* found entry */
378 p=line+strlen(username)+1;
379 if ((q=strchr(p, ':'))) {
384 static_spwd.sp_pwdp=pw;
390 if (static_spwd.sp_pwdp)
398 /****************************************************************************
399 an enhanced crypt for OSF1
400 ****************************************************************************/
401 static char *osf1_bigcrypt(char *password,char *salt1)
403 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
408 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
409 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
412 StrnCpy(salt,salt1,2);
413 StrnCpy(result,salt1,2);
415 for (i=0; i<parts;i++)
418 strncat(result,p1+2,AUTH_MAX_PASSWD_LENGTH-strlen(p1+2)-1);
419 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
420 p2 += AUTH_CLEARTEXT_SEG_CHARS;
427 /****************************************************************************
428 update the encrypted smbpasswd file from the plaintext username and password
429 *****************************************************************************/
430 BOOL update_smbpassword_file( char *user, fstring password)
432 struct smb_passwd *smbpw;
436 smbpw = getsmbpwnam(user);
441 DEBUG(0,("update_smbpassword_file: getsmbpwnam returned NULL\n"));
445 /* Here, the flag is one, because we want to ignore the XXXXXXX'd out password */
446 ret = change_oem_password( smbpw, password, True);
448 DEBUG(3,("update_smbpasswd_file: change_oem_password returned False\n"));
453 /****************************************************************************
454 update the enhanced security database. Only relevant for OSF1 at the moment.
455 ****************************************************************************/
456 static void update_protected_database( char *user, BOOL result)
459 struct pr_passwd *mypasswd;
462 mypasswd = getprpwnam (user);
463 starttime = time (NULL);
467 mypasswd->ufld.fd_slogin = starttime;
468 mypasswd->ufld.fd_nlogins = 0;
470 putprpwnam(user,mypasswd);
472 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
476 mypasswd->ufld.fd_ulogin = starttime;
477 mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
478 if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
480 mypasswd->uflg.fg_lock = 0;
481 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
483 putprpwnam ( user , mypasswd );
484 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
487 DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
493 /*******************************************************************
494 check on PAM authentication
495 ********************************************************************/
497 /* We first need some helper functions */
498 #include <security/pam_appl.h>
499 /* Static variables used to communicate between the conversation function
500 * and the server_login function
502 static char *PAM_username;
503 static char *PAM_password;
505 /* PAM conversation function
506 * Here we assume (for now, at least) that echo on means login name, and
507 * echo off means password.
509 static int PAM_conv (int num_msg,
510 const struct pam_message **msg,
511 struct pam_response **resp,
514 struct pam_response *reply = NULL;
516 #define COPY_STRING(s) (s) ? strdup(s) : NULL
518 reply = malloc(sizeof(struct pam_response) * num_msg);
519 if (!reply) return PAM_CONV_ERR;
521 for (replies = 0; replies < num_msg; replies++) {
522 switch (msg[replies]->msg_style) {
523 case PAM_PROMPT_ECHO_ON:
524 reply[replies].resp_retcode = PAM_SUCCESS;
525 reply[replies].resp = COPY_STRING(PAM_username);
528 case PAM_PROMPT_ECHO_OFF:
529 reply[replies].resp_retcode = PAM_SUCCESS;
530 reply[replies].resp = COPY_STRING(PAM_password);
537 reply[replies].resp_retcode = PAM_SUCCESS;
538 reply[replies].resp = NULL;
541 /* Must be an error of some sort... */
546 if (reply) *resp = reply;
549 static struct pam_conv PAM_conversation = {
555 static BOOL pam_auth(char *this_user,char *password)
560 /* Now use PAM to do authentication. For now, we won't worry about
561 * session logging, only authentication. Bail out if there are any
562 * errors. Since this is a limited protocol, and an even more limited
563 * function within a server speaking this protocol, we can't be as
564 * verbose as would otherwise make sense.
565 * Query: should we be using PAM_SILENT to shut PAM up?
567 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
568 pam_end(pamh, 0); return False; \
570 PAM_password = password;
571 PAM_username = this_user;
572 pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
574 /* Setting PAM_SILENT stops generation of error messages to syslog
575 * to enable debugging on Red Hat Linux set:
577 * auth required /lib/security/pam_pwdb.so nullok shadow audit
578 * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
580 pam_error = pam_authenticate(pamh, PAM_SILENT);
582 /* It is not clear to me that account management is the right thing
583 * to do, but it is not clear that it isn't, either. This can be
584 * removed if no account management should be done. Alternately,
585 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
586 pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
588 pam_end(pamh, PAM_SUCCESS);
589 /* If this point is reached, the user has been authenticated. */
596 /*******************************************************************
597 check on AFS authentication
598 ********************************************************************/
599 static BOOL afs_auth(char *this_user,char *password)
601 long password_expires = 0;
604 /* For versions of AFS prior to 3.3, this routine has few arguments, */
605 /* but since I can't find the old documentation... :-) */
607 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
609 (char *) 0, /* instance */
610 (char *) 0, /* cell */
612 0, /* lifetime, default */
613 &password_expires, /*days 'til it expires */
624 sec_login_handle_t my_dce_sec_context;
625 int dcelogin_atmost_once = 0;
627 /*******************************************************************
628 check on a DCE/DFS authentication
629 ********************************************************************/
630 static BOOL dfs_auth(char *this_user,char *password)
635 boolean32 password_reset;
636 sec_passwd_rec_t my_dce_password;
637 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
638 unsigned char dce_errstr[dce_c_error_string_len];
641 * We only go for a DCE login context if the given password
642 * matches that stored in the local password file..
643 * Assumes local passwd file is kept in sync w/ DCE RGY!
646 /* Fix for original (broken) code from Brett Wooldridge <brettw@austin.ibm.com> */
647 if (dcelogin_atmost_once)
649 /* This can be ifdefed as the DCE check below is stricter... */
651 if ( strcmp((char *)crypt(password,this_salt),this_crypted) )
655 if (sec_login_setup_identity(
656 (unsigned char *)this_user,
661 dce_error_inq_text(err, dce_errstr, &err2);
662 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
663 this_user,dce_errstr));
667 my_dce_password.version_number = sec_passwd_c_version_none;
668 my_dce_password.pepper = NULL;
669 my_dce_password.key.key_type = sec_passwd_plain;
670 my_dce_password.key.tagged_union.plain = (idl_char *)password;
672 if (sec_login_valid_and_cert_ident(my_dce_sec_context,
678 dce_error_inq_text(err, dce_errstr, &err2);
679 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
680 this_user,dce_errstr));
685 sec_login_set_context(my_dce_sec_context, &err);
686 if (err != error_status_ok )
688 dce_error_inq_text(err, dce_errstr, &err2);
689 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
690 this_user,dce_errstr));
691 sec_login_purge_context(my_dce_sec_context, &err);
696 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
697 this_user, getpid()));
700 dcelogin_atmost_once = 1;
704 void dfs_unlogin(void)
708 unsigned char dce_errstr[dce_c_error_string_len];
710 sec_login_purge_context(my_dce_sec_context, &err);
711 if (err != error_status_ok )
713 dce_error_inq_text(err, dce_errstr, &err2);
714 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
715 getpid(), dce_errstr));
722 /*******************************************************************
723 check on Kerberos authentication
724 ********************************************************************/
725 static BOOL krb5_auth(char *this_user,char *password)
727 krb5_data tgtname = {
732 krb5_context kcontext;
733 krb5_principal kprinc;
734 krb5_principal server;
737 krb5_address **addrs = (krb5_address **)0;
738 krb5_preauthtype *preauth = NULL;
739 krb5_keytab keytab = NULL;
741 krb5_ccache ccache = NULL;
745 if ( retval=krb5_init_context(&kcontext))
750 if ( retval = krb5_timeofday(kcontext, &now) )
755 if ( retval = krb5_cc_default(kcontext, &ccache) )
760 if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
765 memset((char *)&kcreds, 0, sizeof(kcreds));
767 kcreds.client = kprinc;
769 if ((retval = krb5_build_principal_ext(kcontext, &server,
770 krb5_princ_realm(kcontext, kprinc)->length,
771 krb5_princ_realm(kcontext, kprinc)->data,
774 krb5_princ_realm(kcontext, kprinc)->length,
775 krb5_princ_realm(kcontext, kprinc)->data,
781 kcreds.server = server;
783 retval = krb5_get_in_tkt_with_password(kcontext,
800 #endif /* KRB5_AUTH */
803 /*******************************************************************
804 check on Kerberos authentication
805 ********************************************************************/
806 static BOOL krb4_auth(char *this_user,char *password)
808 char realm[REALM_SZ];
809 char tkfile[MAXPATHLEN];
811 if (krb_get_lrealm(realm, 1) != KSUCCESS)
812 (void) safe_strcpy(realm, KRB_REALM, sizeof (realm) - 1);
814 (void) slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d", getpid());
816 krb_set_tkt_string(tkfile);
817 if (krb_verify_user(this_user, "", realm,
819 "rmcd") == KSUCCESS) {
826 #endif /* KRB4_AUTH */
828 #ifdef LINUX_BIGCRYPT
829 /****************************************************************************
830 an enhanced crypt for Linux to handle password longer than 8 characters
831 ****************************************************************************/
832 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
834 #define LINUX_PASSWORD_SEG_CHARS 8
838 StrnCpy(salt,salt1,2);
841 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
842 char * p = crypt(password,salt) + 2;
843 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
845 password += LINUX_PASSWORD_SEG_CHARS;
846 crypted += strlen(p);
854 /****************************************************************************
855 apply a function to upper/lower case combinations
856 of a string and return true if one of them returns true.
857 try all combinations with N uppercase letters.
858 offset is the first char to try and change (start with 0)
859 it assumes the string starts lowercased
860 ****************************************************************************/
861 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(char *),int N)
866 #ifdef PASSWORD_LENGTH
867 len = MIN(len,PASSWORD_LENGTH);
870 if (N <= 0 || offset >= len)
873 for (i=offset;i<(len-(N-1));i++)
876 if (!islower(c)) continue;
878 if (string_combinations2(s,i+1,fn,N-1))
885 /****************************************************************************
886 apply a function to upper/lower case combinations
887 of a string and return true if one of them returns true.
888 try all combinations with up to N uppercase letters.
889 offset is the first char to try and change (start with 0)
890 it assumes the string starts lowercased
891 ****************************************************************************/
892 static BOOL string_combinations(char *s,BOOL (*fn)(char *),int N)
896 if (string_combinations2(s,0,fn,n)) return(True);
902 /****************************************************************************
903 core of password checking routine
904 ****************************************************************************/
905 BOOL password_check(char *password)
909 /* This falls through if the password check fails
910 - if NO_CRYPT is defined this causes an error msg
911 saying Warning - no crypt available
912 - if NO_CRYPT is NOT defined this is a potential security hole
913 as it may authenticate via the crypt call when PAM
914 settings say it should fail.
915 if (pam_auth(this_user,password)) return(True);
916 Hence we make a direct return to avoid a second chance!!!
918 return (pam_auth(this_user,password));
922 if (afs_auth(this_user,password)) return(True);
926 if (dfs_auth(this_user,password)) return(True);
930 if (krb5_auth(this_user,password)) return(True);
934 if (krb4_auth(this_user,password)) return(True);
938 if (pwdauth(this_user,password) == 0)
944 BOOL ret = (strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
946 DEBUG(2,("password_check: OSF1_ENH_SEC failed. Trying normal crypt.\n"));
947 ret = (strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
954 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
957 #ifdef LINUX_BIGCRYPT
958 return(linux_bigcrypt(password,this_salt,this_crypted));
961 #ifdef HPUX_10_TRUSTED
962 return(bigcrypt(password,this_salt,this_crypted));
966 DEBUG(1,("Warning - no crypt available\n"));
969 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
973 /****************************************************************************
974 core of smb password checking routine.
975 ****************************************************************************/
976 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
978 /* Finish the encryption of part_passwd. */
979 unsigned char p21[21];
980 unsigned char p24[24];
982 if (part_passwd == NULL)
983 DEBUG(10,("No password set - allowing access\n"));
984 /* No password set - always true ! */
985 if (part_passwd == NULL)
989 memcpy(p21,part_passwd,16);
994 DEBUG(100,("Part password (P16) was |"));
995 for(i = 0; i < 16; i++)
996 DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
998 DEBUG(100,("Password from client was |"));
999 for(i = 0; i < 24; i++)
1000 DEBUG(100,("%X ", (unsigned char)password[i]));
1002 DEBUG(100,("Given challenge was |"));
1003 for(i = 0; i < 8; i++)
1004 DEBUG(100,("%X ", (unsigned char)c8[i]));
1006 DEBUG(100,("Value from encryption was |"));
1007 for(i = 0; i < 24; i++)
1008 DEBUG(100,("%X ", (unsigned char)p24[i]));
1012 return (memcmp(p24, password, 24) == 0);
1015 /****************************************************************************
1016 Do a specific test for an smb password being correct, given a smb_password and
1017 the lanman and NT responses.
1018 ****************************************************************************/
1020 BOOL smb_password_ok(struct smb_passwd *smb_pass,
1021 uchar lm_pass[24], uchar nt_pass[24])
1025 if (!lm_pass || !smb_pass) return(False);
1027 if(smb_pass->acct_ctrl & ACB_DISABLED)
1029 DEBUG(3,("smb_password_ok: account for user %s was disabled.\n", smb_pass->smb_name));
1033 if (!last_challenge(challenge))
1035 DEBUG(1,("smb_password_ok: no challenge done - password failed\n"));
1039 DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n", smb_pass->smb_name));
1041 if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL))
1043 /* We have the NT MD4 hash challenge available - see if we can
1044 use it (ie. does it exist in the smbpasswd file).
1046 DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
1047 if (smb_password_check((char *)nt_pass, (uchar *)smb_pass->smb_nt_passwd, challenge))
1049 DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n"));
1052 DEBUG(4,("smb_password_ok: NT MD4 password check failed\n"));
1055 /* Try against the lanman password. smb_pass->smb_passwd == NULL means
1056 no password, allow access. */
1058 DEBUG(4,("Checking LM MD4 password\n"));
1060 if((smb_pass->smb_passwd == NULL) && (smb_pass->acct_ctrl & ACB_PWNOTREQ))
1062 DEBUG(4,("smb_password_ok: no password required for user %s\n", smb_pass->smb_name));
1066 if((smb_pass->smb_passwd != NULL) && smb_password_check((char *)lm_pass, (uchar *)smb_pass->smb_passwd, challenge))
1068 DEBUG(4,("smb_password_ok: LM MD4 password check succeeded\n"));
1072 DEBUG(4,("smb_password_ok: LM MD4 password check failed\n"));
1077 /****************************************************************************
1078 check if a username/password is OK
1079 ****************************************************************************/
1080 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
1083 int level = lp_passwordlevel();
1084 struct passwd *pass;
1086 struct smb_passwd *smb_pass;
1087 BOOL update_encrypted = lp_update_encrypted();
1088 BOOL challenge_done = False;
1090 if (password) password[pwlen] = 0;
1093 challenge_done = last_challenge(challenge);
1099 DEBUG(100,("checking user=[%s] pass=[",user));
1100 for( i = 0; i < 24; i++)
1101 DEBUG(100,("%0x ", (unsigned char)password[i]));
1104 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
1111 if (((!*password) || (!pwlen)) && !lp_null_passwords())
1116 pass = (struct passwd *) pwd;
1117 user = pass->pw_name;
1120 pass = Get_Pwnam(user,True);
1122 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
1124 if ((pwlen == 24) && challenge_done)
1126 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
1130 DEBUG(3,("Couldn't find user %s\n",user));
1134 smb_pass = getsmbpwnam(user);
1138 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
1142 /* Quit if the account was disabled. */
1143 if(smb_pass->acct_ctrl & ACB_DISABLED)
1145 DEBUG(3,("password_ok: account for user %s was disabled.\n", user));
1149 /* Ensure the uid's match */
1150 if (smb_pass->smb_userid != pass->pw_uid)
1152 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
1156 if(smb_password_ok( smb_pass, (unsigned char *)password,(uchar *)password))
1158 update_protected_database(user,True);
1162 DEBUG(3,("Error smb_password_check failed\n"));
1165 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
1169 DEBUG(3,("Couldn't find user %s\n",user));
1177 /* many shadow systems require you to be root to get the password,
1178 in most cases this should already be the case when this
1179 function is called, except perhaps for IPC password changing
1182 spass = getspnam(pass->pw_name);
1183 if (spass && spass->sp_pwdp)
1184 pass->pw_passwd = spass->sp_pwdp;
1186 #elif defined(IA_UINFO)
1188 /* Need to get password with SVR4.2's ia_ functions instead of
1189 get{sp,pw}ent functions. Required by UnixWare 2.x, tested on
1190 version 2.1. (tangent@cyberport.com) */
1192 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
1193 ia_get_logpwd(uinfo, &(pass->pw_passwd));
1199 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1200 if (pr_pw && pr_pw->ufld.fd_encrypt)
1201 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1205 #ifdef HPUX_10_TRUSTED
1207 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1208 if (pr_pw && pr_pw->ufld.fd_encrypt)
1209 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1215 struct pr_passwd *mypasswd;
1216 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
1217 mypasswd = getprpwnam (user);
1220 fstrcpy(pass->pw_name,mypasswd->ufld.fd_name);
1221 fstrcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
1225 DEBUG(5,("No entry for user %s in protected database !\n",user));
1233 AUTHORIZATION *ap = getauthuid( pass->pw_uid );
1236 fstrcpy( pass->pw_passwd, ap->a_password );
1242 /* extract relevant info */
1243 fstrcpy(this_user,pass->pw_name);
1244 fstrcpy(this_salt,pass->pw_passwd);
1246 /* The crypt on HPUX won't work with more than 2 salt characters. */
1249 fstrcpy(this_crypted,pass->pw_passwd);
1251 if (!*this_crypted) {
1252 if (!lp_null_passwords()) {
1253 DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
1258 DEBUG(3,("Allowing access to %s with null password\n",this_user));
1264 /* try it as it came to us */
1265 if (password_check(password))
1267 update_protected_database(user,True);
1268 if (update_encrypted)
1269 update_smbpassword_file(user,password);
1273 /* if the password was given to us with mixed case then we don't
1274 need to proceed as we know it hasn't been case modified by the
1276 if (strhasupper(password) && strhaslower(password))
1279 /* make a copy of it */
1280 StrnCpy(pass2,password,sizeof(pstring)-1);
1282 /* try all lowercase */
1284 if (password_check(password))
1286 update_protected_database(user,True);
1287 if (update_encrypted)
1288 update_smbpassword_file(user,password);
1295 update_protected_database(user,False);
1298 fstrcpy(password,pass2);
1303 /* last chance - all combinations of up to level chars upper! */
1306 if (string_combinations(password,password_check,level))
1308 update_protected_database(user,True);
1309 if (update_encrypted)
1310 update_smbpassword_file(user,password);
1314 update_protected_database(user,False);
1317 fstrcpy(password,pass2);
1324 /****************************************************************************
1325 check if a username is valid
1326 ****************************************************************************/
1327 BOOL user_ok(char *user,int snum)
1329 pstring valid, invalid;
1332 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
1333 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
1335 string_sub(valid,"%S",lp_servicename(snum));
1336 string_sub(invalid,"%S",lp_servicename(snum));
1338 ret = !user_in_list(user,invalid);
1340 if (ret && valid && *valid)
1341 ret = user_in_list(user,valid);
1343 if (ret && lp_onlyuser(snum)) {
1344 char *user_list = lp_username(snum);
1345 string_sub(user_list,"%S",lp_servicename(snum));
1346 ret = user_in_list(user,user_list);
1355 /****************************************************************************
1356 validate a group username entry. Return the username or NULL
1357 ****************************************************************************/
1358 static char *validate_group(char *group,char *password,int pwlen,int snum)
1362 char *host, *user, *domain;
1364 while (getnetgrent(&host, &user, &domain)) {
1366 if (user_ok(user, snum) &&
1367 password_ok(user,password,pwlen,NULL)) {
1379 struct group *gptr = (struct group *)getgrnam(group);
1383 member = gptr->gr_mem;
1384 while (member && *member)
1386 static fstring name;
1387 fstrcpy(name,*member);
1388 if (user_ok(name,snum) &&
1389 password_ok(name,password,pwlen,NULL))
1393 #ifdef GROUP_CHECK_PWENT
1399 while (pwd = getpwent ()) {
1400 if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
1401 /* This Entry have PASSWORD and same GID then check pwd */
1402 if (password_ok(NULL, password, pwlen, pwd)) {
1403 fstrcpy(tm, pwd->pw_name);
1411 #endif /* GROUP_CHECK_PWENT */
1420 /****************************************************************************
1421 check for authority to login to a service with a given username/password
1422 ****************************************************************************/
1423 BOOL authorise_login(int snum,char *user,char *password, int pwlen,
1424 BOOL *guest,BOOL *force,uint16 vuid)
1431 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1434 /* there are several possibilities:
1435 1) login as the given user with given password
1436 2) login as a previously registered username with the given password
1437 3) login as a session list username with the given password
1438 4) login as a previously validated user/password pair
1439 5) login as the "user =" user with given password
1440 6) login as the "user =" user with no password (guest connection)
1441 7) login as guest user with no password
1443 if the service is guest_only then steps 1 to 5 are skipped
1446 if (GUEST_ONLY(snum)) *force = True;
1448 if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1451 user_struct *vuser = get_valid_user_struct(vuid);
1453 /* check the given username and password */
1454 if (!ok && (*user) && user_ok(user,snum)) {
1455 ok = password_ok(user,password, pwlen, NULL);
1456 if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
1459 /* check for a previously registered guest username */
1460 if (!ok && (vuser != 0) && vuser->guest) {
1461 if (user_ok(vuser->name,snum) &&
1462 password_ok(vuser->name, password, pwlen, NULL)) {
1463 fstrcpy(user, vuser->name);
1464 vuser->guest = False;
1465 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
1471 /* now check the list of session users */
1475 char *user_list = strdup(session_users);
1476 if (!user_list) return(False);
1478 for (auser=strtok(user_list,LIST_SEP);
1480 auser = strtok(NULL,LIST_SEP))
1483 fstrcpy(user2,auser);
1484 if (!user_ok(user2,snum)) continue;
1486 if (password_ok(user2,password, pwlen, NULL)) {
1488 fstrcpy(user,user2);
1489 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1495 /* check for a previously validated username/password pair */
1496 if (!ok && (!lp_revalidate(snum) || lp_security() > SEC_SHARE) &&
1497 (vuser != 0) && !vuser->guest &&
1498 user_ok(vuser->name,snum)) {
1499 fstrcpy(user,vuser->name);
1501 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1505 /* check for a rhosts entry */
1506 if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1508 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1511 /* check the user= fields and the given password */
1512 if (!ok && lp_username(snum)) {
1515 StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1517 string_sub(user_list,"%S",lp_servicename(snum));
1519 for (auser=strtok(user_list,LIST_SEP);
1521 auser = strtok(NULL,LIST_SEP))
1525 auser = validate_group(auser+1,password,pwlen,snum);
1529 fstrcpy(user,auser);
1530 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1536 fstrcpy(user2,auser);
1537 if (user_ok(user2,snum) &&
1538 password_ok(user2,password,pwlen,NULL))
1541 fstrcpy(user,user2);
1542 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1547 } /* not guest only */
1549 /* check for a normal guest connection */
1550 if (!ok && GUEST_OK(snum))
1553 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1554 if (Get_Pwnam(guestname,True))
1556 fstrcpy(user,guestname);
1558 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1561 DEBUG(0,("Invalid guest account %s??\n",guestname));
1566 if (ok && !user_ok(user,snum))
1568 DEBUG(0,("rejected invalid user %s\n",user));
1576 /****************************************************************************
1577 read the a hosts.equiv or .rhosts file and check if it
1578 allows this user from this machine
1579 ****************************************************************************/
1580 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1583 int plus_allowed = 1;
1586 FILE *fp = fopen(equiv_file, "r");
1587 DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1588 if (! fp) return False;
1589 while(fgets(buf, sizeof(buf), fp))
1591 trim_string(buf," "," ");
1593 if (buf[0] != '#' && buf[0] != '\n')
1595 BOOL is_group = False;
1598 if (strcmp(buf, "NO_PLUS\n") == 0)
1600 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1607 if (*bp == '\n' && plus_allowed)
1609 /* a bare plus means everbody allowed */
1610 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1615 else if (buf[0] == '-')
1625 file_host = strtok(bp, " \t\n");
1626 file_user = strtok(NULL, " \t\n");
1627 DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)",
1628 file_user ? file_user : "(null)" ));
1629 if (file_host && *file_host)
1631 BOOL host_ok = False;
1636 static char *mydomain = NULL;
1638 yp_get_default_domain(&mydomain);
1639 if (mydomain && innetgr(file_host,remote,user,mydomain))
1645 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1650 /* is it this host */
1651 /* the fact that remote has come from a call of gethostbyaddr
1652 * means that it may have the fully qualified domain name
1653 * so we could look up the file version to get it into
1654 * a canonical form, but I would rather just type it
1655 * in full in the equiv file
1657 if (!host_ok && !is_group && strequal(remote, file_host))
1663 /* is it this user */
1664 if (file_user == 0 || strequal(user, file_user))
1667 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1668 (plus ? "+" : "-"), file_host,
1669 (file_user ? file_user : "")));
1670 return (plus ? True : False);
1681 /****************************************************************************
1682 check for a possible hosts equiv or rhosts entry for the user
1683 ****************************************************************************/
1684 BOOL check_hosts_equiv(char *user)
1688 struct passwd *pass = Get_Pwnam(user,True);
1693 fname = lp_hosts_equiv();
1695 /* note: don't allow hosts.equiv on root */
1696 if (fname && *fname && (pass->pw_uid != 0)) {
1698 if (check_user_equiv(user,client_name(Client),fname))
1702 if (lp_use_rhosts())
1704 char *home = get_home_dir(user);
1707 slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
1708 if (check_user_equiv(user,client_name(Client),rhostsfile))
1717 static struct cli_state pw_cli;
1719 /****************************************************************************
1720 return the client state structure
1721 ****************************************************************************/
1722 struct cli_state *server_client(void)
1727 /****************************************************************************
1728 support for server level security
1729 ****************************************************************************/
1730 struct cli_state *server_cryptkey(void)
1733 struct in_addr dest_ip;
1734 extern fstring local_machine;
1736 BOOL connected_ok = False;
1738 if (!cli_initialise(&pw_cli))
1741 p = lp_passwordserver();
1742 while(p && next_token( &p, desthost, LIST_SEP)) {
1743 standard_sub_basic(desthost);
1746 if(!resolve_name( desthost, &dest_ip)) {
1747 DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
1751 if (ismyip(dest_ip)) {
1752 DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
1756 if (cli_connect(&pw_cli, desthost, &dest_ip)) {
1757 DEBUG(3,("connected to password server %s\n",desthost));
1758 connected_ok = True;
1763 if (!connected_ok) {
1764 DEBUG(0,("password server not available\n"));
1765 cli_shutdown(&pw_cli);
1769 if (!cli_session_request(&pw_cli, desthost, 0x20, local_machine)) {
1770 DEBUG(1,("%s rejected the session\n",desthost));
1771 cli_shutdown(&pw_cli);
1775 DEBUG(3,("got session\n"));
1777 if (!cli_negprot(&pw_cli)) {
1778 DEBUG(1,("%s rejected the negprot\n",desthost));
1779 cli_shutdown(&pw_cli);
1783 if (pw_cli.protocol < PROTOCOL_LANMAN2 ||
1784 !(pw_cli.sec_mode & 1)) {
1785 DEBUG(1,("%s isn't in user level security mode\n",desthost));
1786 cli_shutdown(&pw_cli);
1790 DEBUG(3,("password server OK\n"));
1795 /****************************************************************************
1796 validate a password with the password server
1797 ****************************************************************************/
1798 BOOL server_validate(char *user, char *domain,
1799 char *pass, int passlen,
1800 char *ntpass, int ntpasslen)
1802 extern fstring local_machine;
1803 static unsigned char badpass[24];
1805 if (!pw_cli.initialised) {
1806 DEBUG(1,("password server %s is not connected\n", pw_cli.desthost));
1810 if(badpass[0] == 0) {
1811 memset(badpass, 0x1f, sizeof(badpass));
1814 if((passlen == sizeof(badpass)) && !memcmp(badpass, pass, passlen)) {
1815 /* Very unlikely, our random bad password is the same as the users
1817 memset(badpass, badpass[0]+1, sizeof(badpass));
1821 * Attempt a session setup with a totally incorrect password.
1822 * If this succeeds with the guest bit *NOT* set then the password
1823 * server is broken and is not correctly setting the guest bit. We
1824 * need to detect this as some versions of NT4.x are broken. JRA.
1827 if (cli_session_setup(&pw_cli, user, (char *)badpass, sizeof(badpass),
1828 (char *)badpass, sizeof(badpass), domain)) {
1829 if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) == 0) {
1830 DEBUG(0,("server_validate: password server %s allows users as non-guest \
1831 with a bad password.\n", pw_cli.desthost));
1832 DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
1833 use this machine as the password server.\n"));
1834 cli_ulogoff(&pw_cli);
1837 cli_ulogoff(&pw_cli);
1841 * Now we know the password server will correctly set the guest bit, or is
1842 * not guest enabled, we can try with the real password.
1845 if (!cli_session_setup(&pw_cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
1846 DEBUG(1,("password server %s rejected the password\n", pw_cli.desthost));
1850 /* if logged in as guest then reject */
1851 if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) != 0) {
1852 DEBUG(1,("password server %s gave us guest only\n", pw_cli.desthost));
1853 cli_ulogoff(&pw_cli);
1858 * This patch from Rob Nielsen <ran@adc.com> makes doing
1859 * the NetWksaUserLogon a dynamic, rather than compile-time
1860 * parameter, defaulting to on. This is somewhat dangerous
1861 * as it allows people to turn off this neccessary check,
1862 * but so many people have had problems with this that I
1863 * think it is a neccessary change. JRA.
1866 if (lp_net_wksta_user_logon()) {
1867 DEBUG(3,("trying NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
1869 if (!cli_send_tconX(&pw_cli, "IPC$", "IPC", "", 1)) {
1870 DEBUG(0,("password server %s refused IPC$ connect\n", pw_cli.desthost));
1871 cli_ulogoff(&pw_cli);
1875 if (!cli_NetWkstaUserLogon(&pw_cli,user,local_machine)) {
1876 DEBUG(0,("password server %s failed NetWkstaUserLogon\n", pw_cli.desthost));
1878 cli_ulogoff(&pw_cli);
1882 if (pw_cli.privilages == 0) {
1883 DEBUG(0,("password server %s gave guest privilages\n", pw_cli.desthost));
1885 cli_ulogoff(&pw_cli);
1889 if (!strequal(pw_cli.eff_name, user)) {
1890 DEBUG(0,("password server %s gave different username %s\n",
1894 cli_ulogoff(&pw_cli);
1900 DEBUG(3,("skipping NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
1903 DEBUG(3,("password server %s accepted the password\n", pw_cli.desthost));
1905 cli_ulogoff(&pw_cli);
1910 /***********************************************************************
1911 Do the same as security=server, but using NT Domain calls and a session
1912 key from the machine password.
1913 ************************************************************************/
1915 BOOL domain_client_validate( char *user, char *domain,
1916 char *smb_apasswd, int smb_apasslen,
1917 char *smb_ntpasswd, int smb_ntpasslen)
1919 unsigned char local_challenge[8];
1920 unsigned char local_lm_response[24];
1921 unsigned char local_nt_reponse[24];
1922 unsigned char trust_passwd[16];
1924 fstring remote_machine;
1926 struct in_addr dest_ip;
1927 NET_ID_INFO_CTR ctr;
1928 NET_USER_INFO_3 info3;
1929 struct cli_state cli;
1931 BOOL connected_ok = False;
1934 * Check that the requested domain is not our own machine name.
1935 * If it is, we should never check the PDC here, we use our own local
1939 if(strequal( domain, global_myname)) {
1940 DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
1945 * Next, check that the passwords given were encrypted.
1948 if(smb_apasslen != 24 || smb_ntpasslen != 24) {
1951 * Not encrypted - do so.
1954 DEBUG(3,("domain_client_validate: User passwords not in encrypted format.\n"));
1955 generate_random_buffer( local_challenge, 8, False);
1956 SMBencrypt( (uchar *)smb_apasswd, local_challenge, local_lm_response);
1957 SMBNTencrypt((uchar *)smb_ntpasswd, local_challenge, local_nt_reponse);
1960 smb_apasswd = (char *)local_lm_response;
1961 smb_ntpasswd = (char *)local_nt_reponse;
1965 * Encrypted - get the challenge we sent for these
1969 if (!last_challenge(local_challenge)) {
1970 DEBUG(0,("domain_client_validate: no challenge done - password failed\n"));
1978 * Get the machine account password.
1980 if(!trust_password_lock( global_myworkgroup, global_myname, False)) {
1981 DEBUG(0,("domain_client_validate: unable to open the machine account password file for \
1982 machine %s in domain %s.\n", global_myname, global_myworkgroup ));
1986 if(get_trust_account_password( trust_passwd, &lct) == False) {
1987 DEBUG(0,("domain_client_validate: unable to read the machine account password for \
1988 machine %s in domain %s.\n", global_myname, global_myworkgroup ));
1989 trust_password_unlock();
1993 trust_password_unlock();
1995 unbecome_root(False);
1998 * Here we should check the last change time to see if the machine
1999 * password needs changing..... TODO... JRA.
2003 * At this point, smb_apasswd points to the lanman response to
2004 * the challenge in local_challenge, and smb_ntpasswd points to
2005 * the NT response to the challenge in local_challenge. Ship
2006 * these over the secure channel to a domain controller and
2007 * see if they were valid.
2010 memset(&cli, '\0', sizeof(struct cli_state));
2011 if(cli_initialise(&cli) == False) {
2012 DEBUG(0,("domain_client_validate: unable to initialize client connection.\n"));
2017 * Treat each name in the 'password server =' line as a potential
2018 * PDC/BDC. Contact each in turn and try and authenticate.
2021 p = lp_passwordserver();
2022 while(p && next_token( &p, remote_machine, LIST_SEP)) {
2024 standard_sub_basic(remote_machine);
2025 strupper(remote_machine);
2027 if(!resolve_name( remote_machine, &dest_ip)) {
2028 DEBUG(1,("domain_client_validate: Can't resolve address for %s\n", remote_machine));
2032 if (ismyip(dest_ip)) {
2033 DEBUG(1,("domain_client_validate: Password server loop - not using password server %s\n",remote_machine));
2037 if (!cli_connect(&cli, remote_machine, &dest_ip)) {
2038 DEBUG(0,("domain_client_validate: unable to connect to SMB server on \
2039 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2043 if (!cli_session_request(&cli, remote_machine, 0x20, global_myname)) {
2044 DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
2045 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2050 cli.protocol = PROTOCOL_NT1;
2052 if (!cli_negprot(&cli)) {
2053 DEBUG(0,("domain_client_validate: machine %s rejected the negotiate protocol. \
2054 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2059 if (cli.protocol != PROTOCOL_NT1) {
2060 DEBUG(0,("domain_client_validate: machine %s didn't negotiate NT protocol.\n",
2067 * Do an anonymous session setup.
2070 if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
2071 DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
2072 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2077 if (!(cli.sec_mode & 1)) {
2078 DEBUG(1,("domain_client_validate: machine %s isn't in user level security mode\n",
2084 if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
2085 DEBUG(0,("domain_client_validate: machine %s rejected the tconX on the IPC$ share. \
2086 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2092 * We have an anonymous connection to IPC$.
2094 connected_ok = True;
2098 if (!connected_ok) {
2099 DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
2105 * Ok - we have an anonymous connection to the IPC$ share.
2106 * Now start the NT Domain stuff :-).
2109 if(cli_nt_session_open(&cli, PIPE_NETLOGON, False) == False) {
2110 DEBUG(0,("domain_client_validate: unable to open the domain client session to \
2111 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
2112 cli_nt_session_close(&cli);
2118 if(cli_nt_setup_creds(&cli, trust_passwd) == False) {
2119 DEBUG(0,("domain_client_validate: unable to setup the PDC credentials to machine \
2120 %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
2121 cli_nt_session_close(&cli);
2127 /* We really don't care what LUID we give the user. */
2128 generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
2130 if(cli_nt_login_network(&cli, domain, user, smb_uid_low, (char *)local_challenge,
2131 smb_apasswd, smb_ntpasswd, &ctr, &info3) == False) {
2132 DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
2133 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
2134 cli_nt_session_close(&cli);
2141 * Here, if we really want it, we have lots of info about the user in info3.
2146 * We don't actually need to do this - plus it fails currently with
2147 * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
2151 if(cli_nt_logoff(&cli, &ctr) == False) {
2152 DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
2153 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
2154 cli_nt_session_close(&cli);
2161 cli_nt_session_close(&cli);