2 Unix SMB/Netbios implementation.
4 Password and authentication handling
5 Copyright (C) Andrew Tridgell 1992-1997
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 /* these are kept here to keep the string_combinations function simple */
35 static char this_user[100]="";
36 static char this_salt[100]="";
37 static char this_crypted[100]="";
40 /* Data to do lanman1/2 password challenge. */
41 static unsigned char saved_challenge[8];
42 static BOOL challenge_sent=False;
44 /*******************************************************************
45 Get the next challenge value - no repeats.
46 ********************************************************************/
47 void generate_next_challenge(char *challenge)
49 static int counter = 0;
53 v1 = (counter++) + getpid() + tval.tv_sec;
54 v2 = (counter++) * getpid() + tval.tv_usec;
55 SIVAL(challenge,0,v1);
56 SIVAL(challenge,4,v2);
57 E1((uchar *)challenge,(uchar *)"SAMBA",(uchar *)saved_challenge);
58 memcpy(challenge,saved_challenge,8);
59 challenge_sent = True;
62 /*******************************************************************
63 set the last challenge sent, usually from a password server
64 ********************************************************************/
65 BOOL set_challenge(char *challenge)
67 memcpy(saved_challenge,challenge,8);
68 challenge_sent = True;
72 /*******************************************************************
73 get the last challenge sent
74 ********************************************************************/
75 BOOL last_challenge(char *challenge)
77 if (!challenge_sent) return(False);
78 memcpy(challenge,saved_challenge,8);
83 /* this holds info on user ids that are already validated for this VC */
84 static user_struct *validated_users = NULL;
85 static int num_validated_users = 0;
87 /****************************************************************************
88 check if a uid has been validated, and return an pointer to the user_struct
89 if it has. NULL if not. vuid is biased by an offset. This allows us to
90 tell random client vuid's (normally zero) from valid vuids.
91 ****************************************************************************/
92 user_struct *get_valid_user_struct(uint16 vuid)
94 if(vuid == UID_FIELD_INVALID)
97 if((vuid >= (uint16)num_validated_users) ||
98 (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1))
100 return &validated_users[vuid];
103 /****************************************************************************
105 ****************************************************************************/
106 void invalidate_vuid(uint16 vuid)
108 user_struct *vuser = get_valid_user_struct(vuid);
114 vuser->user_ngroups = 0;
115 if(vuser->user_groups &&
116 (vuser->user_groups != (gid_t *)vuser->user_igroups))
117 free(vuser->user_groups);
118 vuser->user_groups = NULL;
119 if(vuser->user_igroups)
120 free(vuser->user_igroups);
121 vuser->user_igroups = NULL;
125 /****************************************************************************
126 return a validated username
127 ****************************************************************************/
128 char *validated_username(uint16 vuid)
130 user_struct *vuser = get_valid_user_struct(vuid);
136 /****************************************************************************
137 register a uid/name pair as being valid and that a valid password
138 has been given. vuid is biased by an offset. This allows us to
139 tell random client vuid's (normally zero) from valid vuids.
140 ****************************************************************************/
141 uint16 register_vuid(int uid,int gid, char *name,BOOL guest)
145 #if (defined(NETGROUP) && defined (AUTOMOUNT))
146 int nis_error; /* returned by yp all functions */
147 char *nis_result; /* yp_match inits this */
148 int nis_result_len; /* and set this */
149 char *nis_domain; /* yp_get_default_domain inits this */
150 char *nis_map = (char *)lp_nis_home_map_name();
153 struct passwd *pwfile; /* for getting real name from passwd file */
158 * After observing MS-Exchange services writing to a Samba share
159 * I belive this code is incorrect. Each service does it's own
160 * sessionsetup_and_X for the same user, and as each service shuts
161 * down, it does a user_logoff_and_X. As we are consolidating multiple
162 * sessionsetup_and_X's onto the same vuid here, when the first service
163 * shuts down, it invalidates all the open files for the other services.
164 * Hence I am removing this code and forcing each sessionsetup_and_X
166 * Jeremy Allison. (jallison@whistle.com).
170 for(i = 0; i < num_validated_users; i++) {
171 vuser = &validated_users[i];
172 if( vuser->uid == uid )
173 return (uint16)(i + VUID_OFFSET); /* User already validated */
177 validated_users = (user_struct *)Realloc(validated_users,
179 (num_validated_users+1));
181 if (!validated_users)
183 DEBUG(0,("Failed to realloc users struct!\n"));
184 num_validated_users = 0;
185 return UID_FIELD_INVALID;
188 vuser = &validated_users[num_validated_users];
189 num_validated_users++;
193 vuser->guest = guest;
194 strcpy(vuser->name,name);
196 vuser->user_ngroups = 0;
197 vuser->user_groups = NULL;
198 vuser->user_igroups = NULL;
200 /* Find all the groups this uid is in and store them.
201 Used by become_user() */
202 setup_groups(name,uid,gid,
203 &vuser->user_ngroups,
204 &vuser->user_igroups,
205 &vuser->user_groups);
207 DEBUG(3,("uid %d registered to name %s\n",uid,name));
209 #if (defined(NETGROUP) && defined (AUTOMOUNT))
210 vuser->home_share = NULL;
211 DEBUG(3, ("Setting default HOMESHR to: \\\\logon server\\HOMES\n"));
212 vuser->home_share = Realloc(vuser->home_share, 32);
213 strcpy(vuser->home_share,"\\\\%L\\HOMES");
215 if (nis_error = yp_get_default_domain(&nis_domain))
216 DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
217 DEBUG(3, ("NIS Domain: %s\n", nis_domain));
219 if (nis_error = yp_match(nis_domain, nis_map, vuser->name, strlen(vuser->name),
220 &nis_result, &nis_result_len))
221 DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
222 if (!nis_error && lp_nis_home_map()) {
223 home_server_len = strcspn(nis_result,":");
224 DEBUG(3, ("NIS lookup succeeded\n\tHome server length: %d\n",home_server_len));
225 vuser->home_share = (char *)Realloc(vuser->home_share, home_server_len+12);
226 DEBUG(3, ("\tAllocated %d bytes for HOMESHR\n",home_server_len+12 ));
227 strcpy(vuser->home_share,"\\\\");
228 strncat(vuser->home_share, nis_result, home_server_len);
229 strcat(vuser->home_share,"\\homes");
230 DEBUG(2,("\tUser = %s\n\tUID = %d\n\tNIS result = %s\n\tHOMESHR = %s\n",
231 vuser->name, vuser->uid, nis_result, vuser->home_share));
235 vuser->real_name = NULL;
236 DEBUG(3, ("Clearing default real name\n"));
237 vuser->real_name = Realloc(vuser->real_name, 15);
238 strcpy(vuser->real_name, "<Full Name>\0");
239 if (lp_unix_realname()) {
240 if((pwfile=getpwnam(vuser->name))!= NULL)
242 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
243 real_name_len = strcspn(pwfile->pw_gecos, ",");
244 DEBUG(3, ("Real name length: %d\n", real_name_len));
245 vuser->real_name = (char *)Realloc(vuser->real_name, real_name_len+1);
246 strncpy(vuser->real_name, pwfile->pw_gecos, real_name_len);
247 vuser->real_name[real_name_len]='\0';
251 return (uint16)((num_validated_users - 1) + VUID_OFFSET);
255 /****************************************************************************
256 add a name to the session users list
257 ****************************************************************************/
258 void add_session_user(char *user)
261 StrnCpy(suser,user,sizeof(suser)-1);
263 if (!Get_Pwnam(suser,True)) return;
265 if (suser && *suser && !in_list(suser,session_users,False))
267 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
268 DEBUG(1,("Too many session users??\n"));
271 strcat(session_users," ");
272 strcat(session_users,suser);
279 /* a fake shadow password routine which just fills a fake spwd struct
280 * with the sp_pwdp field. (sreiz@aie.nl)
282 static struct spwd *getspnam(char *username) /* fake shadow password routine */
287 static struct spwd static_spwd;
289 static_spwd.sp_pwdp=0;
290 if (!(f=fopen("/etc/master.passwd", "r")))
292 while (fgets(line, 1024, f)) {
293 if (!strncmp(line, username, strlen(username)) &&
294 line[strlen(username)]==':') { /* found entry */
297 p=line+strlen(username)+1;
298 if ((q=strchr(p, ':'))) {
303 static_spwd.sp_pwdp=pw;
309 if (static_spwd.sp_pwdp)
317 /****************************************************************************
318 an enhanced crypt for OSF1
319 ****************************************************************************/
320 static char *osf1_bigcrypt(char *password,char *salt1)
322 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
327 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
328 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
331 StrnCpy(salt,salt1,2);
332 StrnCpy(result,salt1,2);
334 for (i=0; i<parts;i++)
338 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
339 p2 += AUTH_CLEARTEXT_SEG_CHARS;
347 /****************************************************************************
348 update the enhanced security database. Only relevant for OSF1 at the moment.
349 ****************************************************************************/
350 static void update_protected_database( char *user, BOOL result)
353 struct pr_passwd *mypasswd;
356 mypasswd = getprpwnam (user);
357 starttime = time (NULL);
361 mypasswd->ufld.fd_slogin = starttime;
362 mypasswd->ufld.fd_nlogins = 0;
364 putprpwnam(user,mypasswd);
366 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
370 mypasswd->ufld.fd_ulogin = starttime;
371 mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
372 if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
374 mypasswd->uflg.fg_lock = 0;
375 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
377 putprpwnam ( user , mypasswd );
378 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
381 DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
387 /*******************************************************************
388 check on PAM authentication
389 ********************************************************************/
391 /* We first need some helper functions */
392 #include <security/pam_appl.h>
393 /* Static variables used to communicate between the conversation function
394 * and the server_login function
396 static char *PAM_username;
397 static char *PAM_password;
399 /* PAM conversation function
400 * Here we assume (for now, at least) that echo on means login name, and
401 * echo off means password.
403 static int PAM_conv (int num_msg,
404 const struct pam_message **msg,
405 struct pam_response **resp,
407 int count = 0, replies = 0;
408 struct pam_response *reply = NULL;
409 int size = sizeof(struct pam_response);
411 #define GET_MEM if (reply) realloc(reply, size); else reply = malloc(size); \
412 if (!reply) return PAM_CONV_ERR; \
413 size += sizeof(struct pam_response)
414 #define COPY_STRING(s) (s) ? strdup(s) : NULL
416 for (count = 0; count < num_msg; count++) {
417 switch (msg[count]->msg_style) {
418 case PAM_PROMPT_ECHO_ON:
420 reply[replies].resp_retcode = PAM_SUCCESS;
421 reply[replies++].resp = COPY_STRING(PAM_username);
424 case PAM_PROMPT_ECHO_OFF:
426 reply[replies].resp_retcode = PAM_SUCCESS;
427 reply[replies++].resp = COPY_STRING(PAM_password);
435 /* Must be an error of some sort... */
440 if (reply) *resp = reply;
443 static struct pam_conv PAM_conversation = {
449 static BOOL pam_auth(char *this_user,char *password)
454 /* Now use PAM to do authentication. For now, we won't worry about
455 * session logging, only authentication. Bail out if there are any
456 * errors. Since this is a limited protocol, and an even more limited
457 * function within a server speaking this protocol, we can't be as
458 * verbose as would otherwise make sense.
459 * Query: should we be using PAM_SILENT to shut PAM up?
461 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
462 pam_end(pamh, 0); return False; \
464 PAM_password = password;
465 PAM_username = this_user;
466 pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
468 pam_error = pam_authenticate(pamh, 0);
470 /* It is not clear to me that account management is the right thing
471 * to do, but it is not clear that it isn't, either. This can be
472 * removed if no account management should be done. Alternately,
473 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
474 pam_error = pam_acct_mgmt(pamh, 0);
476 pam_end(pamh, PAM_SUCCESS);
477 /* If this point is reached, the user has been authenticated. */
484 /*******************************************************************
485 check on AFS authentication
486 ********************************************************************/
487 static BOOL afs_auth(char *this_user,char *password)
489 long password_expires = 0;
492 /* For versions of AFS prior to 3.3, this routine has few arguments, */
493 /* but since I can't find the old documentation... :-) */
495 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
497 (char *) 0, /* instance */
498 (char *) 0, /* cell */
500 0, /* lifetime, default */
501 &password_expires, /*days 'til it expires */
512 sec_login_handle_t my_dce_sec_context;
513 int dcelogin_atmost_once = 0;
515 /*******************************************************************
516 check on a DCE/DFS authentication
517 ********************************************************************/
518 static BOOL dfs_auth(char *this_user,char *password)
523 boolean32 password_reset;
524 sec_passwd_rec_t my_dce_password;
525 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
526 unsigned char dce_errstr[dce_c_error_string_len];
529 * We only go for a DCE login context if the given password
530 * matches that stored in the local password file..
531 * Assumes local passwd file is kept in sync w/ DCE RGY!
534 if (!strcmp((char *)crypt(password,this_salt),this_crypted) ||
535 dcelogin_atmost_once)
538 if (sec_login_setup_identity(
539 (unsigned char *)this_user,
544 dce_error_inq_text(err, dce_errstr, &err2);
545 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
546 this_user,dce_errstr));
550 my_dce_password.version_number = sec_passwd_c_version_none;
551 my_dce_password.pepper = NULL;
552 my_dce_password.key.key_type = sec_passwd_plain;
553 my_dce_password.key.tagged_union.plain = (idl_char *)password;
555 if (sec_login_valid_and_cert_ident(my_dce_sec_context,
561 dce_error_inq_text(err, dce_errstr, &err2);
562 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
563 this_user,dce_errstr));
568 sec_login_set_context(my_dce_sec_context, &err);
569 if (err != error_status_ok )
571 dce_error_inq_text(err, dce_errstr, &err2);
572 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
573 this_user,dce_errstr));
574 sec_login_purge_context(my_dce_sec_context, &err);
579 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
580 this_user, getpid()));
583 dcelogin_atmost_once = 1;
587 void dfs_unlogin(void)
591 unsigned char dce_errstr[dce_c_error_string_len];
593 sec_login_purge_context(my_dce_sec_context, &err);
594 if (err != error_status_ok )
596 dce_error_inq_text(err, dce_errstr, &err2);
597 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
598 getpid(), dce_errstr));
605 /*******************************************************************
606 check on Kerberos authentication
607 ********************************************************************/
608 static BOOL krb5_auth(char *this_user,char *password)
610 krb5_data tgtname = {
615 krb5_context kcontext;
616 krb5_principal kprinc;
617 krb5_principal server;
620 krb5_address **addrs = (krb5_address **)0;
621 krb5_preauthtype *preauth = NULL;
622 krb5_keytab keytab = NULL;
624 krb5_ccache ccache = NULL;
628 if ( retval=krb5_init_context(&kcontext))
633 if ( retval = krb5_timeofday(kcontext, &now) )
638 if ( retval = krb5_cc_default(kcontext, &ccache) )
643 if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
648 memset((char *)&kcreds, 0, sizeof(kcreds));
650 kcreds.client = kprinc;
652 if ((retval = krb5_build_principal_ext(kcontext, &server,
653 krb5_princ_realm(kcontext, kprinc)->length,
654 krb5_princ_realm(kcontext, kprinc)->data,
657 krb5_princ_realm(kcontext, kprinc)->length,
658 krb5_princ_realm(kcontext, kprinc)->data,
664 kcreds.server = server;
666 retval = krb5_get_in_tkt_with_password(kcontext,
683 #endif /* KRB5_AUTH */
685 #ifdef LINUX_BIGCRYPT
686 /****************************************************************************
687 an enhanced crypt for Linux to handle password longer than 8 characters
688 ****************************************************************************/
689 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
691 #define LINUX_PASSWORD_SEG_CHARS 8
695 StrnCpy(salt,salt1,2);
698 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
699 char * p = crypt(password,salt) + 2;
700 if(strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
702 password += LINUX_PASSWORD_SEG_CHARS;
703 crypted += strlen(p);
711 /****************************************************************************
712 apply a function to upper/lower case combinations
713 of a string and return true if one of them returns true.
714 try all combinations with N uppercase letters.
715 offset is the first char to try and change (start with 0)
716 it assumes the string starts lowercased
717 ****************************************************************************/
718 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(),int N)
723 #ifdef PASSWORD_LENGTH
724 len = MIN(len,PASSWORD_LENGTH);
727 if (N <= 0 || offset >= len)
730 for (i=offset;i<(len-(N-1));i++)
733 if (!islower(c)) continue;
735 if (string_combinations2(s,i+1,fn,N-1))
742 /****************************************************************************
743 apply a function to upper/lower case combinations
744 of a string and return true if one of them returns true.
745 try all combinations with up to N uppercase letters.
746 offset is the first char to try and change (start with 0)
747 it assumes the string starts lowercased
748 ****************************************************************************/
749 static BOOL string_combinations(char *s,BOOL (*fn)(),int N)
753 if (string_combinations2(s,0,fn,n)) return(True);
759 /****************************************************************************
760 core of password checking routine
761 ****************************************************************************/
762 BOOL password_check(char *password)
766 /* This falls through if the password check fails
767 - if NO_CRYPT is defined this causes an error msg
768 saying Warning - no crypt available
769 - if NO_CRYPT is NOT defined this is a potential security hole
770 as it may authenticate via the crypt call when PAM
771 settings say it should fail.
772 if (pam_auth(this_user,password)) return(True);
773 Hence we make a direct return to avoid a second chance!!!
775 return (pam_auth(this_user,password));
779 if (afs_auth(this_user,password)) return(True);
783 if (dfs_auth(this_user,password)) return(True);
787 if (krb5_auth(this_user,password)) return(True);
791 if (pwdauth(this_user,password) == 0)
796 return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
800 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
803 #ifdef LINUX_BIGCRYPT
804 return(linux_bigcrypt(password,this_salt,this_crypted));
808 DEBUG(1,("Warning - no crypt available\n"));
811 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
816 /****************************************************************************
817 core of smb password checking routine.
818 ****************************************************************************/
819 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
821 /* Finish the encryption of part_passwd. */
822 unsigned char p21[21];
823 unsigned char p24[24];
825 if(part_passwd == NULL)
826 DEBUG(10,("No password set - allowing access\n"));
827 /* No password set - always true ! */
828 if(part_passwd == NULL)
832 memcpy(p21,part_passwd,16);
837 DEBUG(100,("Part password (P16) was |"));
838 for(i = 0; i < 16; i++)
839 DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
841 DEBUG(100,("Password from client was |"));
842 for(i = 0; i < 24; i++)
843 DEBUG(100,("%X ", (unsigned char)password[i]));
845 DEBUG(100,("Given challenge was |"));
846 for(i = 0; i < 8; i++)
847 DEBUG(100,("%X ", (unsigned char)c8[i]));
849 DEBUG(100,("Value from encryption was |"));
850 for(i = 0; i < 24; i++)
851 DEBUG(100,("%X ", (unsigned char)p24[i]));
855 return (memcmp(p24, password, 24) == 0);
859 /****************************************************************************
860 check if a username/password is OK
861 ****************************************************************************/
862 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
865 int level = lp_passwordlevel();
869 struct smb_passwd *smb_pass;
870 BOOL challenge_done = False;
873 if (password) password[pwlen] = 0;
877 challenge_done = last_challenge(challenge);
885 DEBUG(100,("checking user=[%s] pass=[",user));
886 for( i = 0; i < 24; i++)
887 DEBUG(100,("%0x ", (unsigned char)password[i]));
892 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
898 if (((!*password) || (!pwlen)) && !lp_null_passwords())
903 pass = (struct passwd *) pwd;
904 user = pass->pw_name;
907 pass = Get_Pwnam(user,True);
911 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
913 if((pwlen == 24) && challenge_done)
915 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
919 DEBUG(3,("Couldn't find user %s\n",user));
923 smb_pass = get_smbpwnam(user);
926 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
930 /* Ensure the uid's match */
931 if(smb_pass->smb_userid != pass->pw_uid)
933 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
937 if(Protocol >= PROTOCOL_NT1)
939 /* We have the NT MD4 hash challenge available - see if we can
940 use it (ie. does it exist in the smbpasswd file).
942 if(smb_pass->smb_nt_passwd != NULL)
944 DEBUG(4,("Checking NT MD4 password\n"));
945 if(smb_password_check(password,
946 smb_pass->smb_nt_passwd,
947 (unsigned char *)challenge))
949 update_protected_database(user,True);
952 DEBUG(4,("NT MD4 password check failed\n"));
956 /* Try against the lanman password */
958 if (smb_password_check(password,
959 smb_pass->smb_passwd,
960 (unsigned char *)challenge)) {
961 update_protected_database(user,True);
965 DEBUG(3,("Error smb_password_check failed\n"));
969 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
973 DEBUG(3,("Couldn't find user %s\n",user));
981 /* many shadow systems require you to be root to get the password,
982 in most cases this should already be the case when this
983 function is called, except perhaps for IPC password changing
986 spass = getspnam(pass->pw_name);
987 if (spass && spass->sp_pwdp)
988 pass->pw_passwd = spass->sp_pwdp;
990 #elif defined(IA_UINFO)
992 /* Need to get password with SVR4.2's ia_ functions instead of
993 get{sp,pw}ent functions. Required by UnixWare 2.x, tested on
994 version 2.1. (tangent@cyberport.com) */
996 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
997 ia_get_logpwd(uinfo, &(pass->pw_passwd));
1003 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1004 if (pr_pw && pr_pw->ufld.fd_encrypt)
1005 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1009 #ifdef HPUX_10_TRUSTED
1011 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1012 if (pr_pw && pr_pw->ufld.fd_encrypt)
1013 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1019 struct pr_passwd *mypasswd;
1020 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
1021 mypasswd = getprpwnam (user);
1024 strcpy(pass->pw_name,mypasswd->ufld.fd_name);
1025 strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
1029 DEBUG(5,("No entry for user %s in protected database !\n",user));
1037 AUTHORIZATION *ap = getauthuid( pass->pw_uid );
1040 strcpy( pass->pw_passwd, ap->a_password );
1046 /* extract relevant info */
1047 strcpy(this_user,pass->pw_name);
1048 strcpy(this_salt,pass->pw_passwd);
1049 strcpy(this_crypted,pass->pw_passwd);
1051 if (!*this_crypted) {
1052 if (!lp_null_passwords()) {
1053 DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
1058 DEBUG(3,("Allowing access to %s with null password\n",this_user));
1064 /* try it as it came to us */
1065 if (password_check(password))
1067 update_protected_database(user,True);
1071 /* if the password was given to us with mixed case then we don't
1072 need to proceed as we know it hasn't been case modified by the
1074 if (strhasupper(password) && strhaslower(password))
1077 /* make a copy of it */
1078 StrnCpy(pass2,password,sizeof(pstring)-1);
1080 /* try all lowercase */
1082 if (password_check(password))
1084 update_protected_database(user,True);
1091 update_protected_database(user,False);
1094 strcpy(password,pass2);
1099 /* last chance - all combinations of up to level chars upper! */
1102 if (string_combinations(password,password_check,level))
1104 update_protected_database(user,True);
1108 update_protected_database(user,False);
1111 strcpy(password,pass2);
1118 /****************************************************************************
1119 check if a username is valid
1120 ****************************************************************************/
1121 BOOL user_ok(char *user,int snum)
1123 pstring valid, invalid;
1126 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
1127 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
1129 string_sub(valid,"%S",lp_servicename(snum));
1130 string_sub(invalid,"%S",lp_servicename(snum));
1132 ret = !user_in_list(user,invalid);
1134 if (ret && valid && *valid)
1135 ret = user_in_list(user,valid);
1137 if (ret && lp_onlyuser(snum)) {
1138 char *user_list = lp_username(snum);
1139 string_sub(user_list,"%S",lp_servicename(snum));
1140 ret = user_in_list(user,user_list);
1149 /****************************************************************************
1150 validate a group username entry. Return the username or NULL
1151 ****************************************************************************/
1152 static char *validate_group(char *group,char *password,int pwlen,int snum)
1156 char *host, *user, *domain;
1158 while (getnetgrent(&host, &user, &domain)) {
1160 if (user_ok(user, snum) &&
1161 password_ok(user,password,pwlen,NULL)) {
1173 struct group *gptr = (struct group *)getgrnam(group);
1177 member = gptr->gr_mem;
1178 while (member && *member)
1180 static fstring name;
1181 strcpy(name,*member);
1182 if (user_ok(name,snum) &&
1183 password_ok(name,password,pwlen,NULL))
1187 #ifdef GROUP_CHECK_PWENT
1193 while (pwd = getpwent ()) {
1194 if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
1195 /* This Entry have PASSWORD and same GID then check pwd */
1196 if (password_ok(NULL, password, pwlen, pwd)) {
1197 strcpy(tm, pwd->pw_name);
1205 #endif /* GROUP_CHECK_PWENT */
1214 /****************************************************************************
1215 check for authority to login to a service with a given username/password
1216 ****************************************************************************/
1217 BOOL authorise_login(int snum,char *user,char *password, int pwlen,
1218 BOOL *guest,BOOL *force,uint16 vuid)
1225 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1228 /* there are several possibilities:
1229 1) login as the given user with given password
1230 2) login as a previously registered username with the given password
1231 3) login as a session list username with the given password
1232 4) login as a previously validated user/password pair
1233 5) login as the "user =" user with given password
1234 6) login as the "user =" user with no password (guest connection)
1235 7) login as guest user with no password
1237 if the service is guest_only then steps 1 to 5 are skipped
1240 if (GUEST_ONLY(snum)) *force = True;
1242 if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1245 user_struct *vuser = get_valid_user_struct(vuid);
1247 /* check the given username and password */
1248 if (!ok && (*user) && user_ok(user,snum)) {
1249 ok = password_ok(user,password, pwlen, NULL);
1250 if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
1253 /* check for a previously registered guest username */
1254 if (!ok && (vuser != 0) && vuser->guest) {
1255 if (user_ok(vuser->name,snum) &&
1256 password_ok(vuser->name, password, pwlen, NULL)) {
1257 strcpy(user, vuser->name);
1258 vuser->guest = False;
1259 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
1265 /* now check the list of session users */
1269 char *user_list = strdup(session_users);
1270 if (!user_list) return(False);
1272 for (auser=strtok(user_list,LIST_SEP);
1274 auser = strtok(NULL,LIST_SEP))
1277 strcpy(user2,auser);
1278 if (!user_ok(user2,snum)) continue;
1280 if (password_ok(user2,password, pwlen, NULL)) {
1283 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1289 /* check for a previously validated username/password pair */
1290 if (!ok && !lp_revalidate(snum) &&
1291 (vuser != 0) && !vuser->guest &&
1292 user_ok(vuser->name,snum)) {
1293 strcpy(user,vuser->name);
1295 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1299 /* check for a rhosts entry */
1300 if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1302 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1305 /* check the user= fields and the given password */
1306 if (!ok && lp_username(snum)) {
1309 StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1311 string_sub(user_list,"%S",lp_servicename(snum));
1313 for (auser=strtok(user_list,LIST_SEP);
1315 auser = strtok(NULL,LIST_SEP))
1319 auser = validate_group(auser+1,password,pwlen,snum);
1324 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1330 strcpy(user2,auser);
1331 if (user_ok(user2,snum) &&
1332 password_ok(user2,password,pwlen,NULL))
1336 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1341 } /* not guest only */
1343 /* check for a normal guest connection */
1344 if (!ok && GUEST_OK(snum))
1347 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1348 if (Get_Pwnam(guestname,True))
1350 strcpy(user,guestname);
1352 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1355 DEBUG(0,("Invalid guest account %s??\n",guestname));
1360 if (ok && !user_ok(user,snum))
1362 DEBUG(0,("rejected invalid user %s\n",user));
1370 /****************************************************************************
1371 read the a hosts.equiv or .rhosts file and check if it
1372 allows this user from this machine
1373 ****************************************************************************/
1374 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1377 int plus_allowed = 1;
1380 FILE *fp = fopen(equiv_file, "r");
1381 DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1382 if (! fp) return False;
1383 while(fgets(buf, sizeof(buf), fp))
1385 trim_string(buf," "," ");
1387 if (buf[0] != '#' && buf[0] != '\n')
1389 BOOL is_group = False;
1392 if (strcmp(buf, "NO_PLUS\n") == 0)
1394 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1401 if (*bp == '\n' && plus_allowed)
1403 /* a bare plus means everbody allowed */
1404 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1409 else if (buf[0] == '-')
1419 file_host = strtok(bp, " \t\n");
1420 file_user = strtok(NULL, " \t\n");
1421 DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)",
1422 file_user ? file_user : "(null)" ));
1423 if (file_host && *file_host)
1425 BOOL host_ok = False;
1430 static char *mydomain = NULL;
1432 yp_get_default_domain(&mydomain);
1433 if (mydomain && innetgr(file_host,remote,user,mydomain))
1439 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1444 /* is it this host */
1445 /* the fact that remote has come from a call of gethostbyaddr
1446 * means that it may have the fully qualified domain name
1447 * so we could look up the file version to get it into
1448 * a canonical form, but I would rather just type it
1449 * in full in the equiv file
1451 if (!host_ok && !is_group && strequal(remote, file_host))
1457 /* is it this user */
1458 if (file_user == 0 || strequal(user, file_user))
1461 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1462 (plus ? "+" : "-"), file_host,
1463 (file_user ? file_user : "")));
1464 return (plus ? True : False);
1475 /****************************************************************************
1476 check for a possible hosts equiv or rhosts entry for the user
1477 ****************************************************************************/
1478 BOOL check_hosts_equiv(char *user)
1482 struct passwd *pass = Get_Pwnam(user,True);
1487 fname = lp_hosts_equiv();
1489 /* note: don't allow hosts.equiv on root */
1490 if (fname && *fname && (pass->pw_uid != 0))
1492 if (check_user_equiv(user,client_name(),fname))
1496 if (lp_use_rhosts())
1498 char *home = get_home_dir(user);
1501 sprintf(rhostsfile, "%s/.rhosts", home);
1502 if (check_user_equiv(user,client_name(),rhostsfile))
1511 int password_client = -1;
1512 static fstring pserver;
1514 /****************************************************************************
1515 attempted support for server level security
1516 ****************************************************************************/
1517 BOOL server_cryptkey(char *buf)
1519 pstring inbuf,outbuf;
1520 fstring pass_protocol;
1521 extern fstring remote_machine;
1525 struct in_addr dest_ip;
1526 int port = SMB_PORT;
1529 if (password_client >= 0)
1530 close(password_client);
1531 password_client = -1;
1533 if (Protocol < PROTOCOL_NT1) {
1534 strcpy(pass_protocol,"LM1.2X002");
1536 strcpy(pass_protocol,"NT LM 0.12");
1539 bzero(inbuf,sizeof(inbuf));
1540 bzero(outbuf,sizeof(outbuf));
1542 for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
1544 standard_sub_basic(desthost);
1547 dest_ip = *interpret_addr2(desthost);
1548 if (zero_ip(dest_ip)) {
1549 DEBUG(1,("Can't resolve address for %s\n",p));
1553 if (ismyip(dest_ip)) {
1554 DEBUG(1,("Password server loop - disabling password server %s\n",p));
1558 password_client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT);
1559 if (password_client >= 0) {
1560 DEBUG(3,("connected to password server %s\n",p));
1561 StrnCpy(pserver,p,sizeof(pserver)-1);
1566 if (password_client < 0) {
1567 DEBUG(1,("password server not available\n"));
1572 /* send a session request (RFC 8002) */
1574 /* put in the destination name */
1577 name_mangle(desthost,p,' ');
1582 name_mangle(remote_machine,p,' ');
1585 _smb_setlen(outbuf,len);
1586 CVAL(outbuf,0) = 0x81;
1588 send_smb(password_client,outbuf);
1591 if (!receive_smb(password_client,inbuf,5000) ||
1592 CVAL(inbuf,0) != 0x82) {
1593 DEBUG(1,("%s rejected the session\n",pserver));
1594 close(password_client); password_client = -1;
1598 DEBUG(3,("got session\n"));
1600 bzero(outbuf,smb_size);
1602 /* setup the protocol string */
1603 set_message(outbuf,0,strlen(pass_protocol)+2,True);
1604 p = smb_buf(outbuf);
1606 strcpy(p,pass_protocol);
1608 CVAL(outbuf,smb_com) = SMBnegprot;
1609 CVAL(outbuf,smb_flg) = 0x8;
1610 SSVAL(outbuf,smb_flg2,0x1);
1612 send_smb(password_client,outbuf);
1613 ret = receive_smb(password_client,inbuf,5000);
1615 if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
1616 DEBUG(1,("%s rejected the protocol\n",pserver));
1617 close(password_client); password_client= -1;
1621 if (!(CVAL(inbuf,smb_vwv1) & 1)) {
1622 DEBUG(1,("%s isn't in user level security mode\n",pserver));
1623 close(password_client); password_client= -1;
1627 memcpy(buf,inbuf,smb_len(inbuf)+4);
1629 DEBUG(3,("password server OK\n"));
1634 /****************************************************************************
1635 attempted support for server level security
1636 ****************************************************************************/
1637 BOOL server_validate(char *buf)
1639 pstring inbuf,outbuf;
1642 if (password_client < 0) {
1643 DEBUG(1,("%s not connected\n",pserver));
1647 bzero(inbuf,sizeof(inbuf));
1648 memcpy(outbuf,buf,sizeof(outbuf));
1650 /* send a session setup command */
1651 CVAL(outbuf,smb_flg) = 0x8;
1652 SSVAL(outbuf,smb_flg2,0x1);
1653 CVAL(outbuf,smb_vwv0) = 0xFF;
1655 set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
1657 SCVAL(inbuf,smb_rcls,1);
1659 send_smb(password_client,outbuf);
1660 ret = receive_smb(password_client,inbuf,5000);
1662 if (!ret || CVAL(inbuf,smb_rcls) != 0) {
1663 DEBUG(1,("password server %s rejected the password\n",pserver));
1667 /* if logged in as guest then reject */
1668 if ((SVAL(inbuf,smb_vwv2) & 1) != 0) {
1669 DEBUG(1,("password server %s gave us guest only\n",pserver));
1673 DEBUG(3,("password server %s accepted the password\n",pserver));
1675 #if !KEEP_PASSWORD_SERVER_OPEN
1676 close(password_client); password_client= -1;