Initial version imported to CVS
[Samba.git] / source / smbd / password.c
blob87c1fef94c5b243a0dc552588e1374b2e8533ca9
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Password and authentication handling
5 Copyright (C) Andrew Tridgell 1992-1995
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.
22 #include "includes.h"
23 #include "loadparm.h"
25 extern int DEBUGLEVEL;
26 extern int Protocol;
28 /* users from session setup */
29 static pstring session_users="";
31 /* these are kept here to keep the string_combinations function simple */
32 static char this_user[100]="";
33 static char this_salt[100]="";
34 static char this_crypted[100]="";
36 #ifdef SMB_PASSWD
37 /* Data to do lanman1/2 password challenge. */
38 static unsigned char saved_challenge[8];
39 static BOOL challenge_sent=False;
41 /*******************************************************************
42 Get the next challenge value - no repeats.
43 ********************************************************************/
44 void generate_next_challenge(char *challenge)
46 extern void E1(char *,char *,char *);
47 static int counter = 0;
48 struct timeval tval;
49 int v1,v2;
50 GetTimeOfDay(&tval);
51 v1 = (counter++) + getpid() + tval.tv_sec;
52 v2 = (counter++) * getpid() + tval.tv_usec;
53 SIVAL(challenge,0,v1);
54 SIVAL(challenge,4,v2);
55 E1(challenge,"SAMBA",saved_challenge);
56 memcpy(challenge,saved_challenge,8);
57 challenge_sent = True;
60 /*******************************************************************
61 set the last challenge sent, usually from a password server
62 ********************************************************************/
63 BOOL set_challenge(char *challenge)
65 memcpy(saved_challenge,challenge,8);
66 challenge_sent = True;
67 return(True);
70 /*******************************************************************
71 get the last challenge sent
72 ********************************************************************/
73 BOOL last_challenge(char *challenge)
75 if (!challenge_sent) return(False);
76 memcpy(challenge,saved_challenge,8);
77 return(True);
79 #endif
81 /* this holds info on user ids that are already validated for this VC */
82 static user_struct *validated_users = NULL;
83 static int num_validated_users = 0;
85 /****************************************************************************
86 check if a uid has been validated, and return an index if it has. -1 if not
87 ****************************************************************************/
88 int valid_uid(int uid)
90 int i;
91 if (uid == -1) return(-1);
93 for (i=0;i<num_validated_users;i++)
94 if (validated_users[i].uid == uid)
96 DEBUG(3,("valid uid %d mapped to vuid %d (user=%s)\n",
97 uid,i,validated_users[i].name));
98 return(i);
100 return(-1);
103 /****************************************************************************
104 check if a uid has been validated, and return an pointer to the user_struct
105 if it has. NULL if not
106 ****************************************************************************/
107 user_struct *get_valid_user_struct(int uid)
109 int vuid = valid_uid(uid);
110 if(vuid == -1 || validated_users[vuid].guest)
111 return NULL;
112 return &validated_users[vuid];
115 /****************************************************************************
116 invalidate a uid
117 ****************************************************************************/
118 void invalidate_uid(int uid)
120 int i;
121 for (i=0;i<num_validated_users;i++)
122 if (validated_users[i].uid == uid)
124 user_struct *vuser = &validated_users[i];
125 vuser->uid = -1;
126 vuser->gid = -1;
127 vuser->user_ngroups = 0;
128 if(vuser->user_groups &&
129 (vuser->user_groups != (gid_t *)vuser->user_igroups))
130 free(vuser->user_groups);
131 vuser->user_groups = NULL;
132 if(vuser->user_igroups)
133 free(vuser->user_igroups);
134 vuser->user_igroups = NULL;
139 /****************************************************************************
140 return a validated username
141 ****************************************************************************/
142 char *validated_username(int vuid)
144 return(validated_users[vuid].name);
147 /****************************************************************************
148 register a uid/name pair as being valid and that a valid password
149 has been given.
150 ****************************************************************************/
151 void register_uid(int uid,int gid, char *name,BOOL guest)
153 user_struct *vuser;
155 if (valid_uid(uid) >= 0)
156 return;
157 validated_users = (user_struct *)Realloc(validated_users,
158 sizeof(user_struct)*
159 (num_validated_users+1));
161 if (!validated_users)
163 DEBUG(0,("Failed to realloc users struct!\n"));
164 return;
167 vuser = &validated_users[num_validated_users];
168 vuser->uid = uid;
169 vuser->gid = gid;
170 vuser->guest = guest;
171 strcpy(vuser->name,name);
173 vuser->user_ngroups = 0;
174 vuser->user_groups = NULL;
175 vuser->user_igroups = NULL;
177 /* Find all the groups this uid is in and store them.
178 Used by become_user() */
179 setup_groups(name,uid,gid,
180 &vuser->user_ngroups,
181 &vuser->user_igroups,
182 &vuser->user_groups);
184 DEBUG(3,("uid %d registered to name %s\n",uid,name));
186 num_validated_users++;
190 /****************************************************************************
191 add a name to the session users list
192 ****************************************************************************/
193 void add_session_user(char *user)
195 fstring suser;
196 StrnCpy(suser,user,sizeof(suser)-1);
198 if (!Get_Pwnam(suser,True)) return;
200 if (suser && *suser && !in_list(suser,session_users,False))
202 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
203 DEBUG(1,("Too many session users??\n"));
204 else
206 strcat(session_users," ");
207 strcat(session_users,suser);
213 #ifdef NO_GETSPNAM
214 /* a fake shadow password routine which just fills a fake spwd struct
215 * with the sp_pwdp field. (sreiz@aie.nl)
217 static struct spwd *getspnam(char *username) /* fake shadow password routine */
219 FILE *f;
220 char line[1024];
221 static char pw[20];
222 static struct spwd static_spwd;
224 static_spwd.sp_pwdp=0;
225 if (!(f=fopen("/etc/master.passwd", "r")))
226 return 0;
227 while (fgets(line, 1024, f)) {
228 if (!strncmp(line, username, strlen(username)) &&
229 line[strlen(username)]==':') { /* found entry */
230 char *p, *q;
232 p=line+strlen(username)+1;
233 if ((q=strchr(p, ':'))) {
234 *q=0;
235 if (q-p+1>20)
236 break;
237 strcpy(pw, p);
238 static_spwd.sp_pwdp=pw;
240 break;
243 fclose(f);
244 if (static_spwd.sp_pwdp)
245 return &static_spwd;
246 return 0;
248 #endif
251 #ifdef OSF1_ENH_SEC
252 /****************************************************************************
253 an enhanced crypt for OSF1
254 ****************************************************************************/
255 static char *osf1_bigcrypt(char *password,char *salt1)
257 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
258 char *p1;
259 char *p2=password;
260 char salt[3];
261 int i;
262 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
263 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
264 parts++;
266 StrnCpy(salt,salt1,2);
267 StrnCpy(result,salt1,2);
269 for (i=0; i<parts;i++)
271 p1 = crypt(p2,salt);
272 strcat(result,p1+2);
273 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
274 p2 += AUTH_CLEARTEXT_SEG_CHARS;
277 return(result);
279 #endif
282 /****************************************************************************
283 update the enhanced security database. Only relevant for OSF1 at the moment.
284 ****************************************************************************/
285 static void update_protected_database( char *user, BOOL result)
287 #ifdef OSF1_ENH_SEC
288 struct pr_passwd *mypasswd;
289 time_t starttime;
290 long tz;
292 mypasswd = getprpwnam (user);
293 starttime = time (NULL);
294 tz = mktime ( localtime ( &starttime ) );
296 if (result)
298 mypasswd->ufld.fd_slogin = tz;
299 mypasswd->ufld.fd_nlogins = 0;
301 putprpwnam(user,mypasswd);
303 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
305 else
307 mypasswd->ufld.fd_ulogin = tz;
308 mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
309 if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
311 mypasswd->uflg.fg_lock = 0;
312 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
314 putprpwnam ( user , mypasswd );
315 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
317 #else
318 DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
319 #endif
323 #ifdef AFS_AUTH
324 /*******************************************************************
325 check on AFS authentication
326 ********************************************************************/
327 static BOOL afs_auth(char *this_user,char *password)
329 long password_expires = 0;
330 char *reason;
332 /* For versions of AFS prior to 3.3, this routine has few arguments, */
333 /* but since I can't find the old documentation... :-) */
334 setpag();
335 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
336 this_user,
337 (char *) 0, /* instance */
338 (char *) 0, /* cell */
339 password,
340 0, /* lifetime, default */
341 &password_expires, /*days 'til it expires */
342 0, /* spare 2 */
343 &reason) == 0)
344 return(True);
345 return(False);
347 #endif
350 #ifdef DFS_AUTH
352 sec_login_handle_t my_dce_sec_context;
353 int dcelogin_atmost_once = 0;
355 /*******************************************************************
356 check on a DCE/DFS authentication
357 ********************************************************************/
358 static BOOL dfs_auth(char *this_user,char *password)
360 error_status_t err;
361 int err2;
362 int prterr;
363 boolean32 password_reset;
364 sec_passwd_rec_t my_dce_password;
365 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
366 unsigned char dce_errstr[dce_c_error_string_len];
369 * We only go for a DCE login context if the given password
370 * matches that stored in the local password file..
371 * Assumes local passwd file is kept in sync w/ DCE RGY!
374 if (!strcmp((char *)crypt(password,this_salt),this_crypted) ||
375 dcelogin_atmost_once)
376 return(False);
378 if (sec_login_setup_identity(
379 (unsigned char *)this_user,
380 sec_login_no_flags,
381 &my_dce_sec_context,
382 &err) == 0)
384 dce_error_inq_text(err, dce_errstr, &err2);
385 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
386 this_user,dce_errstr));
387 return(False);
390 my_dce_password.version_number = sec_passwd_c_version_none;
391 my_dce_password.pepper = NULL;
392 my_dce_password.key.key_type = sec_passwd_plain;
393 my_dce_password.key.tagged_union.plain = (idl_char *)password;
395 if (sec_login_valid_and_cert_ident(my_dce_sec_context,
396 &my_dce_password,
397 &password_reset,
398 &auth_src,
399 &err) == 0 )
401 dce_error_inq_text(err, dce_errstr, &err2);
402 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
403 this_user,dce_errstr));
405 return(False);
408 sec_login_set_context(my_dce_sec_context, &err);
409 if (err != error_status_ok )
411 dce_error_inq_text(err, dce_errstr, &err2);
412 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
413 this_user,dce_errstr));
414 sec_login_purge_context(my_dce_sec_context, &err);
415 return(False);
417 else
419 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
420 this_user, getpid()));
423 dcelogin_atmost_once = 1;
424 return (True);
427 void dfs_unlogin(void)
429 error_status_t err;
430 int err2;
431 unsigned char dce_errstr[dce_c_error_string_len];
433 sec_login_purge_context(my_dce_sec_context, &err);
434 if (err != error_status_ok )
436 dce_error_inq_text(err, dce_errstr, &err2);
437 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
438 getpid(), dce_errstr));
442 #endif
445 #ifdef LINUX_BIGCRYPT
446 /****************************************************************************
447 an enhanced crypt for Linux to handle password longer than 8 characters
448 ****************************************************************************/
449 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
451 #define LINUX_PASSWORD_SEG_CHARS 8
452 char salt[3];
453 int i;
455 StrnCpy(salt,salt1,2);
456 crypted +=2;
458 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
459 char * p = crypt(password,salt) + 2;
460 if(strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
461 return(0);
462 password += LINUX_PASSWORD_SEG_CHARS;
463 crypted += strlen(p);
466 return(1);
468 #endif
471 /****************************************************************************
472 apply a function to upper/lower case combinations
473 of a string and return true if one of them returns true.
474 try all combinations with N uppercase letters.
475 offset is the first char to try and change (start with 0)
476 it assumes the string starts lowercased
477 ****************************************************************************/
478 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(),int N)
480 int len = strlen(s);
481 int i;
483 #ifdef PASSWORD_LENGTH
484 len = MIN(len,PASSWORD_LENGTH);
485 #endif
487 if (N <= 0 || offset >= len)
488 return(fn(s));
490 for (i=offset;i<(len-(N-1));i++)
492 char c = s[i];
493 if (!islower(c)) continue;
494 s[i] = toupper(c);
495 if (string_combinations2(s,i+1,fn,N-1))
496 return(True);
497 s[i] = c;
499 return(False);
502 /****************************************************************************
503 apply a function to upper/lower case combinations
504 of a string and return true if one of them returns true.
505 try all combinations with up to N uppercase letters.
506 offset is the first char to try and change (start with 0)
507 it assumes the string starts lowercased
508 ****************************************************************************/
509 static BOOL string_combinations(char *s,BOOL (*fn)(),int N)
511 int n;
512 for (n=1;n<=N;n++)
513 if (string_combinations2(s,0,fn,n)) return(True);
514 return(False);
519 /****************************************************************************
520 core of password checking routine
521 ****************************************************************************/
522 BOOL password_check(char *password)
524 #ifdef AFS_AUTH
525 if (afs_auth(this_user,password)) return(True);
526 #endif
528 #ifdef DFS_AUTH
529 if (dfs_auth(this_user,password)) return(True);
530 #endif
532 #ifdef PWDAUTH
533 if (pwdauth(this_user,password) == 0)
534 return(True);
535 #endif
537 #ifdef OSF1_ENH_SEC
538 return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
539 #endif
541 #ifdef ULTRIX_AUTH
542 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
543 #endif
545 #ifdef LINUX_BIGCRYPT
546 return(linux_bigcrypt(password,this_salt,this_crypted));
547 #endif
549 #ifdef NO_CRYPT
550 DEBUG(1,("Warning - no crypt available\n"));
551 return(False);
552 #else
553 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
554 #endif
557 #ifdef SMB_PASSWD
558 /****************************************************************************
559 core of smb password checking routine.
560 ****************************************************************************/
561 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
563 /* Finish the encryption of part_passwd. */
564 unsigned char p21[21];
565 unsigned char p24[24];
567 if(part_passwd == NULL)
568 DEBUG(10,("No password set - allowing access\n"));
569 /* No password set - always true ! */
570 if(part_passwd == NULL)
571 return 1;
573 memset(p21,'\0',21);
574 memcpy(p21,part_passwd,16);
575 E_P24(p21, c8, p24);
576 #if DEBUG_PASSWORD
578 int i;
579 DEBUG(100,("Part password (P16) was |"));
580 for(i = 0; i < 16; i++)
581 DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
582 DEBUG(100,("|\n"));
583 DEBUG(100,("Password from client was |"));
584 for(i = 0; i < 24; i++)
585 DEBUG(100,("%X ", (unsigned char)password[i]));
586 DEBUG(100,("|\n"));
587 DEBUG(100,("Given challenge was |"));
588 for(i = 0; i < 8; i++)
589 DEBUG(100,("%X ", (unsigned char)c8[i]));
590 DEBUG(100,("|\n"));
591 DEBUG(100,("Value from encryption was |"));
592 for(i = 0; i < 24; i++)
593 DEBUG(100,("%X ", (unsigned char)p24[i]));
594 DEBUG(100,("|\n"));
596 #endif
597 return (memcmp(p24, password, 24) == 0);
599 #endif
601 /****************************************************************************
602 check if a username/password is OK
603 ****************************************************************************/
604 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd, BOOL is_nt_password)
606 pstring pass2;
607 int level = lp_passwordlevel();
608 struct passwd *pass;
609 #ifdef SMB_PASSWD
610 char challenge[8];
611 struct smb_passwd *smb_pass;
612 BOOL challenge_done = False;
613 #endif
615 if (password) password[pwlen] = 0;
617 #ifdef SMB_PASSWD
618 if (pwlen == 24)
619 challenge_done = last_challenge(challenge);
620 #endif
622 #if DEBUG_PASSWORD
623 #ifdef SMB_PASSWD
624 if (challenge_done)
626 int i;
627 DEBUG(100,("checking user=[%s] pass=[",user));
628 for( i = 0; i < 24; i++)
629 DEBUG(100,("%0x ", (unsigned char)password[i]));
630 DEBUG(100,("]\n"));
632 else
633 #endif
634 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
635 #endif
637 if (!password)
638 return(False);
640 if (((!*password) || (!pwlen)) && !lp_null_passwords())
641 return(False);
643 if (pwd && !user)
645 pass = (struct passwd *) pwd;
646 user = pass->pw_name;
648 else
649 pass = Get_Pwnam(user,True);
651 #ifdef SMB_PASSWD
653 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
655 if((pwlen == 24) && challenge_done)
657 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
659 if (!pass)
661 DEBUG(3,("Couldn't find user %s\n",user));
662 return(False);
665 smb_pass = get_smbpwnam(user);
666 if(!smb_pass)
668 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
669 return(False);
672 /* Ensure the uid's match */
673 if(smb_pass->smb_userid != pass->pw_uid)
675 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
676 return(False);
679 if(Protocol >= PROTOCOL_NT1 && is_nt_password)
681 /* We have the NT MD4 hash challenge available - see if we can
682 use it (ie. does it exist in the smbpasswd file).
684 if(smb_pass->smb_nt_passwd != NULL)
686 DEBUG(4,("Checking NT MD4 password\n"));
687 if(smb_password_check(password, smb_pass->smb_nt_passwd, challenge))
689 update_protected_database(user,True);
690 return(True);
692 DEBUG(4,("NT MD4 password check failed\n"));
693 return (False);
697 /* Try against the lanman password */
699 if(smb_password_check(password, smb_pass->smb_passwd, challenge))
701 update_protected_database(user,True);
702 return(True);
705 DEBUG(3,("Error smb_password_check failed\n"));
707 #endif
709 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
711 if (!pass)
713 DEBUG(3,("Couldn't find user %s\n",user));
714 return(False);
717 #ifdef SHADOW_PWD
719 struct spwd *spass;
721 /* many shadow systems require you to be root to get the password,
722 in most cases this should already be the case when this
723 function is called, except perhaps for IPC password changing
724 requests */
726 spass = getspnam(pass->pw_name);
727 if (spass && spass->sp_pwdp)
728 pass->pw_passwd = spass->sp_pwdp;
730 #endif
732 #ifdef SecureWare
734 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
735 if (pr_pw && pr_pw->ufld.fd_encrypt)
736 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
738 #endif
740 #ifdef HPUX_10_TRUSTED
742 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
743 if (pr_pw && pr_pw->ufld.fd_encrypt)
744 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
746 #endif
748 #ifdef OSF1_ENH_SEC
750 struct pr_passwd *mypasswd;
751 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
752 mypasswd = getprpwnam (user);
753 if ( mypasswd )
755 strcpy(pass->pw_name,mypasswd->ufld.fd_name);
756 strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
758 else
760 DEBUG(5,("No entry for user %s in protected database !\n",user));
761 return(False);
764 #endif
766 #ifdef ULTRIX_AUTH
768 AUTHORIZATION *ap = getauthuid( pass->pw_uid );
769 if (ap)
771 strcpy( pass->pw_passwd, ap->a_password );
772 endauthent();
775 #endif
777 /* extract relevant info */
778 strcpy(this_user,pass->pw_name);
779 strcpy(this_salt,pass->pw_passwd);
780 strcpy(this_crypted,pass->pw_passwd);
782 if (!*this_crypted) {
783 if (!lp_null_passwords()) {
784 DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
785 return(False);
787 #ifndef PWDAUTH
788 if (!*password) {
789 DEBUG(3,("Allowing access to %s with null password\n",this_user));
790 return(True);
792 #endif
795 /* try it as it came to us */
796 if (password_check(password))
798 update_protected_database(user,True);
799 return(True);
802 /* if the password was given to us with mixed case then we don't
803 need to proceed as we know it hasn't been case modified by the
804 client */
805 if (strhasupper(password) && strhaslower(password))
806 return(False);
808 /* make a copy of it */
809 StrnCpy(pass2,password,sizeof(pstring)-1);
811 /* try all lowercase */
812 strlower(password);
813 if (password_check(password))
815 update_protected_database(user,True);
816 return(True);
819 /* give up? */
820 if(level < 1)
822 update_protected_database(user,False);
824 /* restore it */
825 strcpy(password,pass2);
827 return(False);
830 /* last chance - all combinations of up to level chars upper! */
831 strlower(password);
833 if (string_combinations(password,password_check,level))
835 update_protected_database(user,True);
836 return(True);
839 update_protected_database(user,False);
841 /* restore it */
842 strcpy(password,pass2);
844 return(False);
849 /****************************************************************************
850 check if a username is valid
851 ****************************************************************************/
852 BOOL user_ok(char *user,int snum)
854 pstring valid, invalid;
855 BOOL ret;
857 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
858 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
860 string_sub(valid,"%S",lp_servicename(snum));
861 string_sub(invalid,"%S",lp_servicename(snum));
863 ret = !user_in_list(user,invalid);
865 if (ret && valid && *valid)
866 ret = user_in_list(user,valid);
868 if (ret && lp_onlyuser(snum)) {
869 char *user_list = lp_username(snum);
870 string_sub(user_list,"%S",lp_servicename(snum));
871 ret = user_in_list(user,user_list);
874 return(ret);
880 /****************************************************************************
881 validate a group username entry. Return the username or NULL
882 ****************************************************************************/
883 static char *validate_group(char *group,char *password,int pwlen,int snum)
885 #ifdef NETGROUP
887 char *host, *user, *domain;
888 setnetgrent(group);
889 while (getnetgrent(&host, &user, &domain)) {
890 if (user) {
891 if (user_ok(user, snum) &&
892 password_ok(user,password,pwlen,NULL,False)) {
893 endnetgrent();
894 return(user);
898 endnetgrent();
900 #endif
902 #if HAVE_GETGRNAM
904 struct group *gptr = (struct group *)getgrnam(group);
905 char **member;
906 if (gptr)
908 member = gptr->gr_mem;
909 while (member && *member)
911 static fstring name;
912 strcpy(name,*member);
913 if (user_ok(name,snum) &&
914 password_ok(name,password,pwlen,NULL,False))
915 return(&name[0]);
916 member++;
918 #ifdef GROUP_CHECK_PWENT
920 struct passwd *pwd;
921 static fstring tm;
923 setpwent ();
924 while (pwd = getpwent ()) {
925 if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
926 /* This Entry have PASSWORD and same GID then check pwd */
927 if (password_ok(NULL, password, pwlen, pwd,False)) {
928 strcpy(tm, pwd->pw_name);
929 endpwent ();
930 return tm;
934 endpwent ();
936 #endif /* GROUP_CHECK_PWENT */
939 #endif
940 return(NULL);
945 /****************************************************************************
946 check for authority to login to a service with a given username/password
947 ****************************************************************************/
948 BOOL authorise_login(int snum,char *user,char *password, int pwlen,
949 BOOL *guest,BOOL *force,int vuid)
951 BOOL ok = False;
953 *guest = False;
955 #if DEBUG_PASSWORD
956 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
957 #endif
959 /* there are several possabilities:
960 1) login as the given user with given password
961 2) login as a previously registered username with the given password
962 3) login as a session list username with the given password
963 4) login as a previously validated user/password pair
964 5) login as the "user =" user with given password
965 6) login as the "user =" user with no password (guest connection)
966 7) login as guest user with no password
968 if the service is guest_only then steps 1 to 5 are skipped
971 if (GUEST_ONLY(snum)) *force = True;
973 if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
976 /* check the given username and password */
977 if (!ok && (*user) && user_ok(user,snum)) {
978 ok = password_ok(user,password, pwlen, NULL, False);
979 if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
982 /* check for a previously registered guest username */
983 if (!ok && (vuid >= 0) && validated_users[vuid].guest) {
984 if (user_ok(validated_users[vuid].name,snum) &&
985 password_ok(validated_users[vuid].name, password, pwlen, NULL, False)) {
986 strcpy(user, validated_users[vuid].name);
987 validated_users[vuid].guest = False;
988 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
989 ok = True;
994 /* now check the list of session users */
995 if (!ok)
997 char *auser;
998 char *user_list = strdup(session_users);
999 if (!user_list) return(False);
1001 for (auser=strtok(user_list,LIST_SEP);
1002 !ok && auser;
1003 auser = strtok(NULL,LIST_SEP))
1005 fstring user2;
1006 strcpy(user2,auser);
1007 if (!user_ok(user2,snum)) continue;
1009 if (password_ok(user2,password, pwlen, NULL, False)) {
1010 ok = True;
1011 strcpy(user,user2);
1012 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1015 free(user_list);
1018 /* check for a previously validated username/password pair */
1019 if (!ok && !lp_revalidate(snum) &&
1020 (vuid >= 0) && !validated_users[vuid].guest &&
1021 user_ok(validated_users[vuid].name,snum)) {
1022 strcpy(user,validated_users[vuid].name);
1023 *guest = False;
1024 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1025 ok = True;
1028 /* check for a rhosts entry */
1029 if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1030 ok = True;
1031 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1034 /* check the user= fields and the given password */
1035 if (!ok && lp_username(snum)) {
1036 char *auser;
1037 pstring user_list;
1038 StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1040 string_sub(user_list,"%S",lp_servicename(snum));
1042 for (auser=strtok(user_list,LIST_SEP);
1043 auser && !ok;
1044 auser = strtok(NULL,LIST_SEP))
1046 if (*auser == '@')
1048 auser = validate_group(auser+1,password,pwlen,snum);
1049 if (auser)
1051 ok = True;
1052 strcpy(user,auser);
1053 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1056 else
1058 fstring user2;
1059 strcpy(user2,auser);
1060 if (user_ok(user2,snum) &&
1061 password_ok(user2,password,pwlen,NULL, False))
1063 ok = True;
1064 strcpy(user,user2);
1065 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1070 } /* not guest only */
1072 /* check for a normal guest connection */
1073 if (!ok && GUEST_OK(snum))
1075 fstring guestname;
1076 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1077 if (Get_Pwnam(guestname,True))
1079 strcpy(user,guestname);
1080 ok = True;
1081 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1083 else
1084 DEBUG(0,("Invalid guest account %s??\n",guestname));
1085 *guest = True;
1086 *force = True;
1089 if (ok && !user_ok(user,snum))
1091 DEBUG(0,("rejected invalid user %s\n",user));
1092 ok = False;
1095 return(ok);
1099 /****************************************************************************
1100 read the a hosts.equiv or .rhosts file and check if it
1101 allows this user from this machine
1102 ****************************************************************************/
1103 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1105 pstring buf;
1106 int plus_allowed = 1;
1107 char *file_host;
1108 char *file_user;
1109 FILE *fp = fopen(equiv_file, "r");
1110 DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1111 if (! fp) return False;
1112 while(fgets(buf, sizeof(buf), fp))
1114 trim_string(buf," "," ");
1116 if (buf[0] != '#' && buf[0] != '\n')
1118 BOOL is_group = False;
1119 int plus = 1;
1120 char *bp = buf;
1121 if (strcmp(buf, "NO_PLUS\n") == 0)
1123 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1124 plus_allowed = 0;
1126 else {
1127 if (buf[0] == '+')
1129 bp++;
1130 if (*bp == '\n' && plus_allowed)
1132 /* a bare plus means everbody allowed */
1133 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1134 fclose(fp);
1135 return True;
1138 else if (buf[0] == '-')
1140 bp++;
1141 plus = 0;
1143 if (*bp == '@')
1145 is_group = True;
1146 bp++;
1148 file_host = strtok(bp, " \t\n");
1149 file_user = strtok(NULL, " \t\n");
1150 DEBUG(7, ("check_user_equiv %s %s\n", file_host, file_user));
1151 if (file_host && *file_host)
1153 BOOL host_ok = False;
1155 #ifdef NETGROUP
1156 /* THIS IS UNTESTED!! */
1157 if (is_group)
1159 static char *mydomain = NULL;
1160 if (!mydomain)
1161 yp_get_default_domain(&mydomain);
1162 if (mydomain && innetgr(remote,file_host,user,mydomain))
1163 host_ok = True;
1165 #else
1166 if (is_group)
1168 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1169 continue;
1171 #endif
1173 /* is it this host */
1174 /* the fact that remote has come from a call of gethostbyaddr
1175 * means that it may have the fully qualified domain name
1176 * so we could look up the file version to get it into
1177 * a canonical form, but I would rather just type it
1178 * in full in the equiv file
1180 if (!host_ok && !is_group && strequal(remote, file_host))
1181 host_ok = True;
1183 if (!host_ok)
1184 continue;
1186 /* is it this user */
1187 if (file_user == 0 || strequal(user, file_user))
1189 fclose(fp);
1190 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1191 (plus ? "+" : "-"), file_host,
1192 (file_user ? file_user : "")));
1193 return (plus ? True : False);
1199 fclose(fp);
1200 return False;
1204 /****************************************************************************
1205 check for a possible hosts equiv or rhosts entry for the user
1206 ****************************************************************************/
1207 BOOL check_hosts_equiv(char *user)
1209 char *fname = NULL;
1210 pstring rhostsfile;
1211 struct passwd *pass = Get_Pwnam(user,True);
1213 extern struct from_host Client_info;
1214 extern int Client;
1216 if (!pass)
1217 return(False);
1219 fromhost(Client,&Client_info);
1221 fname = lp_hosts_equiv();
1223 /* note: don't allow hosts.equiv on root */
1224 if (fname && *fname && (pass->pw_uid != 0))
1226 if (check_user_equiv(user,Client_info.name,fname))
1227 return(True);
1230 if (lp_use_rhosts())
1232 char *home = get_home_dir(user);
1233 if (home)
1235 sprintf(rhostsfile, "%s/.rhosts", home);
1236 if (check_user_equiv(user,Client_info.name,rhostsfile))
1237 return(True);
1241 return(False);
1245 static int password_client = -1;
1246 static fstring pserver;
1248 /****************************************************************************
1249 attempted support for server level security
1250 ****************************************************************************/
1251 BOOL server_cryptkey(char *buf)
1253 pstring inbuf,outbuf;
1254 fstring pass_protocol;
1255 extern fstring remote_machine;
1256 char *p;
1257 int len;
1258 fstring desthost;
1259 struct in_addr dest_ip;
1260 extern struct in_addr myip;
1261 int port = 139;
1262 BOOL ret;
1264 if (password_client >= 0)
1265 close(password_client);
1266 password_client = -1;
1268 if (Protocol < PROTOCOL_NT1) {
1269 strcpy(pass_protocol,"LM1.2X002");
1270 } else {
1271 strcpy(pass_protocol,"NT LM 0.12");
1274 bzero(inbuf,sizeof(inbuf));
1275 bzero(outbuf,sizeof(outbuf));
1277 for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
1278 strcpy(desthost,p);
1279 standard_sub_basic(desthost);
1280 strupper(desthost);
1282 dest_ip = *interpret_addr2(desthost);
1283 if (zero_ip(dest_ip)) {
1284 DEBUG(1,("Can't resolve address for %s\n",p));
1285 continue;
1288 if (memcmp(&dest_ip,&myip,sizeof(dest_ip)) == 0) {
1289 DEBUG(1,("Password server loop - disabling password server %s\n",p));
1290 continue;
1293 password_client = open_socket_out(SOCK_STREAM, &dest_ip, port);
1294 if (password_client >= 0) {
1295 DEBUG(3,("connected to password server %s\n",p));
1296 StrnCpy(pserver,p,sizeof(pserver)-1);
1297 break;
1301 if (password_client < 0) {
1302 DEBUG(1,("password server not available\n"));
1303 return(False);
1307 /* send a session request (RFC 8002) */
1309 /* put in the destination name */
1310 len = 4;
1311 p = outbuf+len;
1312 name_mangle(desthost,p,' ');
1313 len += name_len(p);
1315 /* and my name */
1316 p = outbuf+len;
1317 name_mangle(remote_machine,p,' ');
1318 len += name_len(p);
1320 _smb_setlen(outbuf,len);
1321 CVAL(outbuf,0) = 0x81;
1323 send_smb(password_client,outbuf);
1324 receive_smb(password_client,inbuf,5000);
1326 if (CVAL(inbuf,0) != 0x82) {
1327 DEBUG(1,("%s rejected the session\n",pserver));
1328 close(password_client); password_client = -1;
1329 return(False);
1332 DEBUG(3,("got session\n"));
1334 bzero(outbuf,smb_size);
1336 /* setup the protocol string */
1337 set_message(outbuf,0,strlen(pass_protocol)+2,True);
1338 p = smb_buf(outbuf);
1339 *p++ = 2;
1340 strcpy(p,pass_protocol);
1342 CVAL(outbuf,smb_com) = SMBnegprot;
1343 CVAL(outbuf,smb_flg) = 0x8;
1344 SSVAL(outbuf,smb_flg2,0x1);
1346 send_smb(password_client,outbuf);
1347 ret = receive_smb(password_client,inbuf,5000);
1349 if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
1350 DEBUG(1,("%s rejected the protocol\n",pserver));
1351 close(password_client); password_client= -1;
1352 return(False);
1355 if (!(CVAL(inbuf,smb_vwv1) & 1)) {
1356 DEBUG(1,("%s isn't in user level security mode\n",pserver));
1357 close(password_client); password_client= -1;
1358 return(False);
1361 memcpy(buf,inbuf,smb_len(inbuf)+4);
1363 DEBUG(3,("password server OK\n"));
1365 return(True);
1368 /****************************************************************************
1369 attempted support for server level security
1370 ****************************************************************************/
1371 BOOL server_validate(char *buf)
1373 pstring inbuf,outbuf;
1374 BOOL ret;
1376 if (password_client < 0) {
1377 DEBUG(1,("%s not connected\n",pserver));
1378 return(False);
1381 bzero(inbuf,sizeof(inbuf));
1382 memcpy(outbuf,buf,sizeof(outbuf));
1384 /* send a session setup command */
1385 CVAL(outbuf,smb_flg) = 0x8;
1386 SSVAL(outbuf,smb_flg2,0x1);
1387 CVAL(outbuf,smb_vwv0) = 0xFF;
1389 set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
1391 SCVAL(inbuf,smb_rcls,1);
1393 send_smb(password_client,outbuf);
1394 ret = receive_smb(password_client,inbuf,5000);
1396 if (!ret || CVAL(inbuf,smb_rcls) != 0) {
1397 DEBUG(1,("password server %s rejected the password\n",pserver));
1398 return(False);
1401 /* if logged in as guest then reject */
1402 if ((SVAL(inbuf,smb_vwv2) & 1) != 0) {
1403 DEBUG(1,("password server %s gave us guest only\n",pserver));
1404 return(False);
1407 DEBUG(3,("password server %s accepted the password\n",pserver));
1409 #ifndef KEEP_PASSWORD_SERVER_OPEN
1410 close(password_client); password_client= -1;
1411 #endif
1413 return(True);