added automount home directory support. contributed by simeon@bangor.co.uk
[Samba.git] / source / smbd / password.c
blob2c24913c86a631897c8da202b21f7b08c72eaaed
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"
24 #if (defined(NETGROUP) && defined (AUTOMOUNT))
25 #include "rpcsvc/ypclnt.h"
26 #endif
28 extern int DEBUGLEVEL;
29 extern int Protocol;
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]="";
39 #ifdef SMB_PASSWD
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;
50 struct timeval tval;
51 int v1,v2;
52 GetTimeOfDay(&tval);
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(challenge,"SAMBA",(char *)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;
69 return(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);
79 return(True);
81 #endif
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)
95 return NULL;
96 vuid -= VUID_OFFSET;
97 if((vuid >= (uint16)num_validated_users) ||
98 (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1))
99 return NULL;
100 return &validated_users[vuid];
103 /****************************************************************************
104 invalidate a uid
105 ****************************************************************************/
106 void invalidate_vuid(uint16 vuid)
108 user_struct *vuser = get_valid_user_struct(vuid);
109 if(vuser == 0)
110 return;
112 vuser->uid = -1;
113 vuser->gid = -1;
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);
131 if(vuser == 0)
132 return 0;
133 return(vuser->name);
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)
143 user_struct *vuser;
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();
151 int home_server_len;
152 #endif
153 struct passwd *pwfile; /* for getting real name from passwd file */
154 int real_name_len;
156 int i;
157 for(i = 0; i < num_validated_users; i++) {
158 vuser = &validated_users[i];
159 if( vuser->uid == uid )
160 return i; /* User already validated */
163 validated_users = (user_struct *)Realloc(validated_users,
164 sizeof(user_struct)*
165 (num_validated_users+1));
167 if (!validated_users)
169 DEBUG(0,("Failed to realloc users struct!\n"));
170 num_validated_users = 0;
171 return UID_FIELD_INVALID;
174 vuser = &validated_users[num_validated_users];
175 num_validated_users++;
177 vuser->uid = uid;
178 vuser->gid = gid;
179 vuser->guest = guest;
180 strcpy(vuser->name,name);
182 vuser->user_ngroups = 0;
183 vuser->user_groups = NULL;
184 vuser->user_igroups = NULL;
186 /* Find all the groups this uid is in and store them.
187 Used by become_user() */
188 setup_groups(name,uid,gid,
189 &vuser->user_ngroups,
190 &vuser->user_igroups,
191 &vuser->user_groups);
193 DEBUG(3,("uid %d registered to name %s\n",uid,name));
195 #if (defined(NETGROUP) && defined (AUTOMOUNT))
196 vuser->home_share = NULL;
197 DEBUG(3, ("Setting default HOMESHR to: \\\\logon server\\HOMES\n"));
198 vuser->home_share = Realloc(vuser->home_share, 32);
199 strcpy(vuser->home_share,"\\\\%L\\HOMES");
201 if (nis_error = yp_get_default_domain(&nis_domain))
202 DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
203 DEBUG(3, ("NIS Domain: %s\n", nis_domain));
205 if (nis_error = yp_match(nis_domain, nis_map, vuser->name, strlen(vuser->name),
206 &nis_result, &nis_result_len))
207 DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error)));
208 if (!nis_error && lp_nis_home_map()) {
209 home_server_len = strcspn(nis_result,":");
210 DEBUG(3, ("NIS lookup succeeded\n\tHome server length: %d\n",home_server_len));
211 vuser->home_share = (char *)Realloc(vuser->home_share, home_server_len+12);
212 DEBUG(3, ("\tAllocated %d bytes for HOMESHR\n",home_server_len+12 ));
213 strcpy(vuser->home_share,"\\\\");
214 strncat(vuser->home_share, nis_result, home_server_len);
215 strcat(vuser->home_share,"\\homes");
216 DEBUG(2,("\tUser = %s\n\tUID = %d\n\tNIS result = %s\n\tHOMESHR = %s\n",
217 vuser->name, vuser->uid, nis_result, vuser->home_share));
219 #endif
221 vuser->real_name = NULL;
222 DEBUG(3, ("Clearing default real name\n"));
223 vuser->real_name = Realloc(vuser->real_name, 15);
224 strcpy(vuser->real_name, "<Full Name>\0");
225 if (lp_unix_realname()) {
226 pwfile=getpwnam(vuser->name);
227 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
228 real_name_len = strcspn(pwfile->pw_gecos, ",");
229 DEBUG(3, ("Real name length: %d\n", real_name_len));
230 vuser->real_name = (char *)Realloc(vuser->real_name, real_name_len+1);
231 strncpy(vuser->real_name, pwfile->pw_gecos, real_name_len);
232 vuser->real_name[real_name_len]='\0';
235 return (uint16)((num_validated_users - 1) + VUID_OFFSET);
239 /****************************************************************************
240 add a name to the session users list
241 ****************************************************************************/
242 void add_session_user(char *user)
244 fstring suser;
245 StrnCpy(suser,user,sizeof(suser)-1);
247 if (!Get_Pwnam(suser,True)) return;
249 if (suser && *suser && !in_list(suser,session_users,False))
251 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
252 DEBUG(1,("Too many session users??\n"));
253 else
255 strcat(session_users," ");
256 strcat(session_users,suser);
262 #ifdef NO_GETSPNAM
263 /* a fake shadow password routine which just fills a fake spwd struct
264 * with the sp_pwdp field. (sreiz@aie.nl)
266 static struct spwd *getspnam(char *username) /* fake shadow password routine */
268 FILE *f;
269 char line[1024];
270 static char pw[20];
271 static struct spwd static_spwd;
273 static_spwd.sp_pwdp=0;
274 if (!(f=fopen("/etc/master.passwd", "r")))
275 return 0;
276 while (fgets(line, 1024, f)) {
277 if (!strncmp(line, username, strlen(username)) &&
278 line[strlen(username)]==':') { /* found entry */
279 char *p, *q;
281 p=line+strlen(username)+1;
282 if ((q=strchr(p, ':'))) {
283 *q=0;
284 if (q-p+1>20)
285 break;
286 strcpy(pw, p);
287 static_spwd.sp_pwdp=pw;
289 break;
292 fclose(f);
293 if (static_spwd.sp_pwdp)
294 return &static_spwd;
295 return 0;
297 #endif
300 #ifdef OSF1_ENH_SEC
301 /****************************************************************************
302 an enhanced crypt for OSF1
303 ****************************************************************************/
304 static char *osf1_bigcrypt(char *password,char *salt1)
306 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
307 char *p1;
308 char *p2=password;
309 char salt[3];
310 int i;
311 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
312 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
313 parts++;
315 StrnCpy(salt,salt1,2);
316 StrnCpy(result,salt1,2);
318 for (i=0; i<parts;i++)
320 p1 = crypt(p2,salt);
321 strcat(result,p1+2);
322 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
323 p2 += AUTH_CLEARTEXT_SEG_CHARS;
326 return(result);
328 #endif
331 /****************************************************************************
332 update the enhanced security database. Only relevant for OSF1 at the moment.
333 ****************************************************************************/
334 static void update_protected_database( char *user, BOOL result)
336 #ifdef OSF1_ENH_SEC
337 struct pr_passwd *mypasswd;
338 time_t starttime;
340 mypasswd = getprpwnam (user);
341 starttime = time (NULL);
343 if (result)
345 mypasswd->ufld.fd_slogin = starttime;
346 mypasswd->ufld.fd_nlogins = 0;
348 putprpwnam(user,mypasswd);
350 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
352 else
354 mypasswd->ufld.fd_ulogin = starttime;
355 mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
356 if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
358 mypasswd->uflg.fg_lock = 0;
359 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
361 putprpwnam ( user , mypasswd );
362 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
364 #else
365 DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
366 #endif
370 #ifdef USE_PAM
371 /*******************************************************************
372 check on PAM authentication
373 ********************************************************************/
375 /* We first need some helper functions */
376 #include <security/pam_appl.h>
377 /* Static variables used to communicate between the conversation function
378 * and the server_login function
380 static char *PAM_username;
381 static char *PAM_password;
383 /* PAM conversation function
384 * Here we assume (for now, at least) that echo on means login name, and
385 * echo off means password.
387 static int PAM_conv (int num_msg,
388 const struct pam_message **msg,
389 struct pam_response **resp,
390 void *appdata_ptr) {
391 int count = 0, replies = 0;
392 struct pam_response *reply = NULL;
393 int size = sizeof(struct pam_response);
395 #define GET_MEM if (reply) realloc(reply, size); else reply = malloc(size); \
396 if (!reply) return PAM_CONV_ERR; \
397 size += sizeof(struct pam_response)
398 #define COPY_STRING(s) (s) ? strdup(s) : NULL
400 for (count = 0; count < num_msg; count++) {
401 switch (msg[count]->msg_style) {
402 case PAM_PROMPT_ECHO_ON:
403 GET_MEM;
404 reply[replies].resp_retcode = PAM_SUCCESS;
405 reply[replies++].resp = COPY_STRING(PAM_username);
406 /* PAM frees resp */
407 break;
408 case PAM_PROMPT_ECHO_OFF:
409 GET_MEM;
410 reply[replies].resp_retcode = PAM_SUCCESS;
411 reply[replies++].resp = COPY_STRING(PAM_password);
412 /* PAM frees resp */
413 break;
414 case PAM_TEXT_INFO:
415 /* ignore it... */
416 break;
417 case PAM_ERROR_MSG:
418 default:
419 /* Must be an error of some sort... */
420 free (reply);
421 return PAM_CONV_ERR;
424 if (reply) *resp = reply;
425 return PAM_SUCCESS;
427 static struct pam_conv PAM_conversation = {
428 &PAM_conv,
429 NULL
433 static BOOL pam_auth(char *this_user,char *password)
435 pam_handle_t *pamh;
436 int pam_error;
438 /* Now use PAM to do authentication. For now, we won't worry about
439 * session logging, only authentication. Bail out if there are any
440 * errors. Since this is a limited protocol, and an even more limited
441 * function within a server speaking this protocol, we can't be as
442 * verbose as would otherwise make sense.
443 * Query: should we be using PAM_SILENT to shut PAM up?
445 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
446 pam_end(pamh, 0); return False; \
448 PAM_password = password;
449 PAM_username = this_user;
450 pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
451 PAM_BAIL;
452 pam_error = pam_authenticate(pamh, 0);
453 PAM_BAIL;
454 /* It is not clear to me that account management is the right thing
455 * to do, but it is not clear that it isn't, either. This can be
456 * removed if no account management should be done. Alternately,
457 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
458 pam_error = pam_acct_mgmt(pamh, 0);
459 PAM_BAIL;
460 pam_end(pamh, PAM_SUCCESS);
461 /* If this point is reached, the user has been authenticated. */
462 return(True);
464 #endif
467 #ifdef AFS_AUTH
468 /*******************************************************************
469 check on AFS authentication
470 ********************************************************************/
471 static BOOL afs_auth(char *this_user,char *password)
473 long password_expires = 0;
474 char *reason;
476 /* For versions of AFS prior to 3.3, this routine has few arguments, */
477 /* but since I can't find the old documentation... :-) */
478 setpag();
479 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
480 this_user,
481 (char *) 0, /* instance */
482 (char *) 0, /* cell */
483 password,
484 0, /* lifetime, default */
485 &password_expires, /*days 'til it expires */
486 0, /* spare 2 */
487 &reason) == 0)
488 return(True);
489 return(False);
491 #endif
494 #ifdef DFS_AUTH
496 sec_login_handle_t my_dce_sec_context;
497 int dcelogin_atmost_once = 0;
499 /*******************************************************************
500 check on a DCE/DFS authentication
501 ********************************************************************/
502 static BOOL dfs_auth(char *this_user,char *password)
504 error_status_t err;
505 int err2;
506 int prterr;
507 boolean32 password_reset;
508 sec_passwd_rec_t my_dce_password;
509 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
510 unsigned char dce_errstr[dce_c_error_string_len];
513 * We only go for a DCE login context if the given password
514 * matches that stored in the local password file..
515 * Assumes local passwd file is kept in sync w/ DCE RGY!
518 if (!strcmp((char *)crypt(password,this_salt),this_crypted) ||
519 dcelogin_atmost_once)
520 return(False);
522 if (sec_login_setup_identity(
523 (unsigned char *)this_user,
524 sec_login_no_flags,
525 &my_dce_sec_context,
526 &err) == 0)
528 dce_error_inq_text(err, dce_errstr, &err2);
529 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
530 this_user,dce_errstr));
531 return(False);
534 my_dce_password.version_number = sec_passwd_c_version_none;
535 my_dce_password.pepper = NULL;
536 my_dce_password.key.key_type = sec_passwd_plain;
537 my_dce_password.key.tagged_union.plain = (idl_char *)password;
539 if (sec_login_valid_and_cert_ident(my_dce_sec_context,
540 &my_dce_password,
541 &password_reset,
542 &auth_src,
543 &err) == 0 )
545 dce_error_inq_text(err, dce_errstr, &err2);
546 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
547 this_user,dce_errstr));
549 return(False);
552 sec_login_set_context(my_dce_sec_context, &err);
553 if (err != error_status_ok )
555 dce_error_inq_text(err, dce_errstr, &err2);
556 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
557 this_user,dce_errstr));
558 sec_login_purge_context(my_dce_sec_context, &err);
559 return(False);
561 else
563 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
564 this_user, getpid()));
567 dcelogin_atmost_once = 1;
568 return (True);
571 void dfs_unlogin(void)
573 error_status_t err;
574 int err2;
575 unsigned char dce_errstr[dce_c_error_string_len];
577 sec_login_purge_context(my_dce_sec_context, &err);
578 if (err != error_status_ok )
580 dce_error_inq_text(err, dce_errstr, &err2);
581 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
582 getpid(), dce_errstr));
586 #endif
589 #ifdef LINUX_BIGCRYPT
590 /****************************************************************************
591 an enhanced crypt for Linux to handle password longer than 8 characters
592 ****************************************************************************/
593 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
595 #define LINUX_PASSWORD_SEG_CHARS 8
596 char salt[3];
597 int i;
599 StrnCpy(salt,salt1,2);
600 crypted +=2;
602 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
603 char * p = crypt(password,salt) + 2;
604 if(strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
605 return(0);
606 password += LINUX_PASSWORD_SEG_CHARS;
607 crypted += strlen(p);
610 return(1);
612 #endif
615 /****************************************************************************
616 apply a function to upper/lower case combinations
617 of a string and return true if one of them returns true.
618 try all combinations with N uppercase letters.
619 offset is the first char to try and change (start with 0)
620 it assumes the string starts lowercased
621 ****************************************************************************/
622 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(),int N)
624 int len = strlen(s);
625 int i;
627 #ifdef PASSWORD_LENGTH
628 len = MIN(len,PASSWORD_LENGTH);
629 #endif
631 if (N <= 0 || offset >= len)
632 return(fn(s));
634 for (i=offset;i<(len-(N-1));i++)
636 char c = s[i];
637 if (!islower(c)) continue;
638 s[i] = toupper(c);
639 if (string_combinations2(s,i+1,fn,N-1))
640 return(True);
641 s[i] = c;
643 return(False);
646 /****************************************************************************
647 apply a function to upper/lower case combinations
648 of a string and return true if one of them returns true.
649 try all combinations with up to N uppercase letters.
650 offset is the first char to try and change (start with 0)
651 it assumes the string starts lowercased
652 ****************************************************************************/
653 static BOOL string_combinations(char *s,BOOL (*fn)(),int N)
655 int n;
656 for (n=1;n<=N;n++)
657 if (string_combinations2(s,0,fn,n)) return(True);
658 return(False);
663 /****************************************************************************
664 core of password checking routine
665 ****************************************************************************/
666 BOOL password_check(char *password)
669 #ifdef USE_PAM
670 /* This falls through if the password check fails
671 - if NO_CRYPT is defined this causes an error msg
672 saying Warning - no crypt available
673 - if NO_CRYPT is NOT defined this is a potential security hole
674 as it may authenticate via the crypt call when PAM
675 settings say it should fail.
676 if (pam_auth(this_user,password)) return(True);
677 Hence we make a direct return to avoid a second chance!!!
679 return (pam_auth(this_user,password));
680 #endif
682 #ifdef AFS_AUTH
683 if (afs_auth(this_user,password)) return(True);
684 #endif
686 #ifdef DFS_AUTH
687 if (dfs_auth(this_user,password)) return(True);
688 #endif
690 #ifdef PWDAUTH
691 if (pwdauth(this_user,password) == 0)
692 return(True);
693 #endif
695 #ifdef OSF1_ENH_SEC
696 return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
697 #endif
699 #ifdef ULTRIX_AUTH
700 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
701 #endif
703 #ifdef LINUX_BIGCRYPT
704 return(linux_bigcrypt(password,this_salt,this_crypted));
705 #endif
707 #ifdef NO_CRYPT
708 DEBUG(1,("Warning - no crypt available\n"));
709 return(False);
710 #else
711 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
712 #endif
715 #ifdef SMB_PASSWD
716 /****************************************************************************
717 core of smb password checking routine.
718 ****************************************************************************/
719 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
721 /* Finish the encryption of part_passwd. */
722 unsigned char p21[21];
723 unsigned char p24[24];
725 if(part_passwd == NULL)
726 DEBUG(10,("No password set - allowing access\n"));
727 /* No password set - always true ! */
728 if(part_passwd == NULL)
729 return 1;
731 memset(p21,'\0',21);
732 memcpy(p21,part_passwd,16);
733 E_P24(p21, c8, p24);
734 #if DEBUG_PASSWORD
736 int i;
737 DEBUG(100,("Part password (P16) was |"));
738 for(i = 0; i < 16; i++)
739 DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
740 DEBUG(100,("|\n"));
741 DEBUG(100,("Password from client was |"));
742 for(i = 0; i < 24; i++)
743 DEBUG(100,("%X ", (unsigned char)password[i]));
744 DEBUG(100,("|\n"));
745 DEBUG(100,("Given challenge was |"));
746 for(i = 0; i < 8; i++)
747 DEBUG(100,("%X ", (unsigned char)c8[i]));
748 DEBUG(100,("|\n"));
749 DEBUG(100,("Value from encryption was |"));
750 for(i = 0; i < 24; i++)
751 DEBUG(100,("%X ", (unsigned char)p24[i]));
752 DEBUG(100,("|\n"));
754 #endif
755 return (memcmp(p24, password, 24) == 0);
757 #endif
759 /****************************************************************************
760 check if a username/password is OK
761 ****************************************************************************/
762 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
764 pstring pass2;
765 int level = lp_passwordlevel();
766 struct passwd *pass;
767 #ifdef SMB_PASSWD
768 char challenge[8];
769 struct smb_passwd *smb_pass;
770 BOOL challenge_done = False;
771 #endif
773 if (password) password[pwlen] = 0;
775 #ifdef SMB_PASSWD
776 if (pwlen == 24)
777 challenge_done = last_challenge(challenge);
778 #endif
780 #if DEBUG_PASSWORD
781 #ifdef SMB_PASSWD
782 if (challenge_done)
784 int i;
785 DEBUG(100,("checking user=[%s] pass=[",user));
786 for( i = 0; i < 24; i++)
787 DEBUG(100,("%0x ", (unsigned char)password[i]));
788 DEBUG(100,("]\n"));
790 else
791 #endif
792 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
793 #endif
795 if (!password)
796 return(False);
798 if (((!*password) || (!pwlen)) && !lp_null_passwords())
799 return(False);
801 if (pwd && !user)
803 pass = (struct passwd *) pwd;
804 user = pass->pw_name;
806 else
807 pass = Get_Pwnam(user,True);
809 #ifdef SMB_PASSWD
811 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
813 if((pwlen == 24) && challenge_done)
815 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
817 if (!pass)
819 DEBUG(3,("Couldn't find user %s\n",user));
820 return(False);
823 smb_pass = get_smbpwnam(user);
824 if(!smb_pass)
826 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
827 return(False);
830 /* Ensure the uid's match */
831 if(smb_pass->smb_userid != pass->pw_uid)
833 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
834 return(False);
837 if(Protocol >= PROTOCOL_NT1)
839 /* We have the NT MD4 hash challenge available - see if we can
840 use it (ie. does it exist in the smbpasswd file).
842 if(smb_pass->smb_nt_passwd != NULL)
844 DEBUG(4,("Checking NT MD4 password\n"));
845 if(smb_password_check(password,
846 smb_pass->smb_nt_passwd,
847 (char *)challenge))
849 update_protected_database(user,True);
850 return(True);
852 DEBUG(4,("NT MD4 password check failed\n"));
856 /* Try against the lanman password */
858 if (smb_password_check(password,
859 smb_pass->smb_passwd,
860 (char *)challenge)) {
861 update_protected_database(user,True);
862 return(True);
865 DEBUG(3,("Error smb_password_check failed\n"));
867 #endif
869 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
871 if (!pass)
873 DEBUG(3,("Couldn't find user %s\n",user));
874 return(False);
877 #ifdef SHADOW_PWD
879 struct spwd *spass;
881 /* many shadow systems require you to be root to get the password,
882 in most cases this should already be the case when this
883 function is called, except perhaps for IPC password changing
884 requests */
886 spass = getspnam(pass->pw_name);
887 if (spass && spass->sp_pwdp)
888 pass->pw_passwd = spass->sp_pwdp;
890 #endif
892 #ifdef SecureWare
894 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
895 if (pr_pw && pr_pw->ufld.fd_encrypt)
896 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
898 #endif
900 #ifdef HPUX_10_TRUSTED
902 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
903 if (pr_pw && pr_pw->ufld.fd_encrypt)
904 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
906 #endif
908 #ifdef OSF1_ENH_SEC
910 struct pr_passwd *mypasswd;
911 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
912 mypasswd = getprpwnam (user);
913 if ( mypasswd )
915 strcpy(pass->pw_name,mypasswd->ufld.fd_name);
916 strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
918 else
920 DEBUG(5,("No entry for user %s in protected database !\n",user));
921 return(False);
924 #endif
926 #ifdef ULTRIX_AUTH
928 AUTHORIZATION *ap = getauthuid( pass->pw_uid );
929 if (ap)
931 strcpy( pass->pw_passwd, ap->a_password );
932 endauthent();
935 #endif
937 /* extract relevant info */
938 strcpy(this_user,pass->pw_name);
939 strcpy(this_salt,pass->pw_passwd);
940 strcpy(this_crypted,pass->pw_passwd);
942 if (!*this_crypted) {
943 if (!lp_null_passwords()) {
944 DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
945 return(False);
947 #ifndef PWDAUTH
948 if (!*password) {
949 DEBUG(3,("Allowing access to %s with null password\n",this_user));
950 return(True);
952 #endif
955 /* try it as it came to us */
956 if (password_check(password))
958 update_protected_database(user,True);
959 return(True);
962 /* if the password was given to us with mixed case then we don't
963 need to proceed as we know it hasn't been case modified by the
964 client */
965 if (strhasupper(password) && strhaslower(password))
966 return(False);
968 /* make a copy of it */
969 StrnCpy(pass2,password,sizeof(pstring)-1);
971 /* try all lowercase */
972 strlower(password);
973 if (password_check(password))
975 update_protected_database(user,True);
976 return(True);
979 /* give up? */
980 if(level < 1)
982 update_protected_database(user,False);
984 /* restore it */
985 strcpy(password,pass2);
987 return(False);
990 /* last chance - all combinations of up to level chars upper! */
991 strlower(password);
993 if (string_combinations(password,password_check,level))
995 update_protected_database(user,True);
996 return(True);
999 update_protected_database(user,False);
1001 /* restore it */
1002 strcpy(password,pass2);
1004 return(False);
1009 /****************************************************************************
1010 check if a username is valid
1011 ****************************************************************************/
1012 BOOL user_ok(char *user,int snum)
1014 pstring valid, invalid;
1015 BOOL ret;
1017 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
1018 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
1020 string_sub(valid,"%S",lp_servicename(snum));
1021 string_sub(invalid,"%S",lp_servicename(snum));
1023 ret = !user_in_list(user,invalid);
1025 if (ret && valid && *valid)
1026 ret = user_in_list(user,valid);
1028 if (ret && lp_onlyuser(snum)) {
1029 char *user_list = lp_username(snum);
1030 string_sub(user_list,"%S",lp_servicename(snum));
1031 ret = user_in_list(user,user_list);
1034 return(ret);
1040 /****************************************************************************
1041 validate a group username entry. Return the username or NULL
1042 ****************************************************************************/
1043 static char *validate_group(char *group,char *password,int pwlen,int snum)
1045 #ifdef NETGROUP
1047 char *host, *user, *domain;
1048 setnetgrent(group);
1049 while (getnetgrent(&host, &user, &domain)) {
1050 if (user) {
1051 if (user_ok(user, snum) &&
1052 password_ok(user,password,pwlen,NULL)) {
1053 endnetgrent();
1054 return(user);
1058 endnetgrent();
1060 #endif
1062 #if HAVE_GETGRNAM
1064 struct group *gptr = (struct group *)getgrnam(group);
1065 char **member;
1066 if (gptr)
1068 member = gptr->gr_mem;
1069 while (member && *member)
1071 static fstring name;
1072 strcpy(name,*member);
1073 if (user_ok(name,snum) &&
1074 password_ok(name,password,pwlen,NULL))
1075 return(&name[0]);
1076 member++;
1078 #ifdef GROUP_CHECK_PWENT
1080 struct passwd *pwd;
1081 static fstring tm;
1083 setpwent ();
1084 while (pwd = getpwent ()) {
1085 if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
1086 /* This Entry have PASSWORD and same GID then check pwd */
1087 if (password_ok(NULL, password, pwlen, pwd)) {
1088 strcpy(tm, pwd->pw_name);
1089 endpwent ();
1090 return tm;
1094 endpwent ();
1096 #endif /* GROUP_CHECK_PWENT */
1099 #endif
1100 return(NULL);
1105 /****************************************************************************
1106 check for authority to login to a service with a given username/password
1107 ****************************************************************************/
1108 BOOL authorise_login(int snum,char *user,char *password, int pwlen,
1109 BOOL *guest,BOOL *force,uint16 vuid)
1111 BOOL ok = False;
1113 *guest = False;
1115 #if DEBUG_PASSWORD
1116 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1117 #endif
1119 /* there are several possabilities:
1120 1) login as the given user with given password
1121 2) login as a previously registered username with the given password
1122 3) login as a session list username with the given password
1123 4) login as a previously validated user/password pair
1124 5) login as the "user =" user with given password
1125 6) login as the "user =" user with no password (guest connection)
1126 7) login as guest user with no password
1128 if the service is guest_only then steps 1 to 5 are skipped
1131 if (GUEST_ONLY(snum)) *force = True;
1133 if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1136 user_struct *vuser = get_valid_user_struct(vuid);
1138 /* check the given username and password */
1139 if (!ok && (*user) && user_ok(user,snum)) {
1140 ok = password_ok(user,password, pwlen, NULL);
1141 if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
1144 /* check for a previously registered guest username */
1145 if (!ok && (vuser != 0) && vuser->guest) {
1146 if (user_ok(vuser->name,snum) &&
1147 password_ok(vuser->name, password, pwlen, NULL)) {
1148 strcpy(user, vuser->name);
1149 vuser->guest = False;
1150 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
1151 ok = True;
1156 /* now check the list of session users */
1157 if (!ok)
1159 char *auser;
1160 char *user_list = strdup(session_users);
1161 if (!user_list) return(False);
1163 for (auser=strtok(user_list,LIST_SEP);
1164 !ok && auser;
1165 auser = strtok(NULL,LIST_SEP))
1167 fstring user2;
1168 strcpy(user2,auser);
1169 if (!user_ok(user2,snum)) continue;
1171 if (password_ok(user2,password, pwlen, NULL)) {
1172 ok = True;
1173 strcpy(user,user2);
1174 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1177 free(user_list);
1180 /* check for a previously validated username/password pair */
1181 if (!ok && !lp_revalidate(snum) &&
1182 (vuser != 0) && !vuser->guest &&
1183 user_ok(vuser->name,snum)) {
1184 strcpy(user,vuser->name);
1185 *guest = False;
1186 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1187 ok = True;
1190 /* check for a rhosts entry */
1191 if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1192 ok = True;
1193 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1196 /* check the user= fields and the given password */
1197 if (!ok && lp_username(snum)) {
1198 char *auser;
1199 pstring user_list;
1200 StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1202 string_sub(user_list,"%S",lp_servicename(snum));
1204 for (auser=strtok(user_list,LIST_SEP);
1205 auser && !ok;
1206 auser = strtok(NULL,LIST_SEP))
1208 if (*auser == '@')
1210 auser = validate_group(auser+1,password,pwlen,snum);
1211 if (auser)
1213 ok = True;
1214 strcpy(user,auser);
1215 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1218 else
1220 fstring user2;
1221 strcpy(user2,auser);
1222 if (user_ok(user2,snum) &&
1223 password_ok(user2,password,pwlen,NULL))
1225 ok = True;
1226 strcpy(user,user2);
1227 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1232 } /* not guest only */
1234 /* check for a normal guest connection */
1235 if (!ok && GUEST_OK(snum))
1237 fstring guestname;
1238 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1239 if (Get_Pwnam(guestname,True))
1241 strcpy(user,guestname);
1242 ok = True;
1243 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1245 else
1246 DEBUG(0,("Invalid guest account %s??\n",guestname));
1247 *guest = True;
1248 *force = True;
1251 if (ok && !user_ok(user,snum))
1253 DEBUG(0,("rejected invalid user %s\n",user));
1254 ok = False;
1257 return(ok);
1261 /****************************************************************************
1262 read the a hosts.equiv or .rhosts file and check if it
1263 allows this user from this machine
1264 ****************************************************************************/
1265 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1267 pstring buf;
1268 int plus_allowed = 1;
1269 char *file_host;
1270 char *file_user;
1271 FILE *fp = fopen(equiv_file, "r");
1272 DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1273 if (! fp) return False;
1274 while(fgets(buf, sizeof(buf), fp))
1276 trim_string(buf," "," ");
1278 if (buf[0] != '#' && buf[0] != '\n')
1280 BOOL is_group = False;
1281 int plus = 1;
1282 char *bp = buf;
1283 if (strcmp(buf, "NO_PLUS\n") == 0)
1285 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1286 plus_allowed = 0;
1288 else {
1289 if (buf[0] == '+')
1291 bp++;
1292 if (*bp == '\n' && plus_allowed)
1294 /* a bare plus means everbody allowed */
1295 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1296 fclose(fp);
1297 return True;
1300 else if (buf[0] == '-')
1302 bp++;
1303 plus = 0;
1305 if (*bp == '@')
1307 is_group = True;
1308 bp++;
1310 file_host = strtok(bp, " \t\n");
1311 file_user = strtok(NULL, " \t\n");
1312 DEBUG(7, ("check_user_equiv %s %s\n", file_host, file_user));
1313 if (file_host && *file_host)
1315 BOOL host_ok = False;
1317 #ifdef NETGROUP
1318 if (is_group)
1320 static char *mydomain = NULL;
1321 if (!mydomain)
1322 yp_get_default_domain(&mydomain);
1323 if (mydomain && innetgr(file_host,remote,user,mydomain))
1324 host_ok = True;
1326 #else
1327 if (is_group)
1329 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1330 continue;
1332 #endif
1334 /* is it this host */
1335 /* the fact that remote has come from a call of gethostbyaddr
1336 * means that it may have the fully qualified domain name
1337 * so we could look up the file version to get it into
1338 * a canonical form, but I would rather just type it
1339 * in full in the equiv file
1341 if (!host_ok && !is_group && strequal(remote, file_host))
1342 host_ok = True;
1344 if (!host_ok)
1345 continue;
1347 /* is it this user */
1348 if (file_user == 0 || strequal(user, file_user))
1350 fclose(fp);
1351 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1352 (plus ? "+" : "-"), file_host,
1353 (file_user ? file_user : "")));
1354 return (plus ? True : False);
1360 fclose(fp);
1361 return False;
1365 /****************************************************************************
1366 check for a possible hosts equiv or rhosts entry for the user
1367 ****************************************************************************/
1368 BOOL check_hosts_equiv(char *user)
1370 char *fname = NULL;
1371 pstring rhostsfile;
1372 struct passwd *pass = Get_Pwnam(user,True);
1374 if (!pass)
1375 return(False);
1377 fname = lp_hosts_equiv();
1379 /* note: don't allow hosts.equiv on root */
1380 if (fname && *fname && (pass->pw_uid != 0))
1382 if (check_user_equiv(user,client_name(),fname))
1383 return(True);
1386 if (lp_use_rhosts())
1388 char *home = get_home_dir(user);
1389 if (home)
1391 sprintf(rhostsfile, "%s/.rhosts", home);
1392 if (check_user_equiv(user,client_name(),rhostsfile))
1393 return(True);
1397 return(False);
1401 int password_client = -1;
1402 static fstring pserver;
1404 /****************************************************************************
1405 attempted support for server level security
1406 ****************************************************************************/
1407 BOOL server_cryptkey(char *buf)
1409 pstring inbuf,outbuf;
1410 fstring pass_protocol;
1411 extern fstring remote_machine;
1412 char *p;
1413 int len;
1414 fstring desthost;
1415 struct in_addr dest_ip;
1416 int port = SMB_PORT;
1417 BOOL ret;
1419 if (password_client >= 0)
1420 close(password_client);
1421 password_client = -1;
1423 if (Protocol < PROTOCOL_NT1) {
1424 strcpy(pass_protocol,"LM1.2X002");
1425 } else {
1426 strcpy(pass_protocol,"NT LM 0.12");
1429 bzero(inbuf,sizeof(inbuf));
1430 bzero(outbuf,sizeof(outbuf));
1432 for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
1433 strcpy(desthost,p);
1434 standard_sub_basic(desthost);
1435 strupper(desthost);
1437 dest_ip = *interpret_addr2(desthost);
1438 if (zero_ip(dest_ip)) {
1439 DEBUG(1,("Can't resolve address for %s\n",p));
1440 continue;
1443 if (ismyip(dest_ip)) {
1444 DEBUG(1,("Password server loop - disabling password server %s\n",p));
1445 continue;
1448 password_client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT);
1449 if (password_client >= 0) {
1450 DEBUG(3,("connected to password server %s\n",p));
1451 StrnCpy(pserver,p,sizeof(pserver)-1);
1452 break;
1456 if (password_client < 0) {
1457 DEBUG(1,("password server not available\n"));
1458 return(False);
1462 /* send a session request (RFC 8002) */
1464 /* put in the destination name */
1465 len = 4;
1466 p = outbuf+len;
1467 name_mangle(desthost,p,' ');
1468 len += name_len(p);
1470 /* and my name */
1471 p = outbuf+len;
1472 name_mangle(remote_machine,p,' ');
1473 len += name_len(p);
1475 _smb_setlen(outbuf,len);
1476 CVAL(outbuf,0) = 0x81;
1478 send_smb(password_client,outbuf);
1481 if (!receive_smb(password_client,inbuf,5000) ||
1482 CVAL(inbuf,0) != 0x82) {
1483 DEBUG(1,("%s rejected the session\n",pserver));
1484 close(password_client); password_client = -1;
1485 return(False);
1488 DEBUG(3,("got session\n"));
1490 bzero(outbuf,smb_size);
1492 /* setup the protocol string */
1493 set_message(outbuf,0,strlen(pass_protocol)+2,True);
1494 p = smb_buf(outbuf);
1495 *p++ = 2;
1496 strcpy(p,pass_protocol);
1498 CVAL(outbuf,smb_com) = SMBnegprot;
1499 CVAL(outbuf,smb_flg) = 0x8;
1500 SSVAL(outbuf,smb_flg2,0x1);
1502 send_smb(password_client,outbuf);
1503 ret = receive_smb(password_client,inbuf,5000);
1505 if (!ret || CVAL(inbuf,smb_rcls) || SVAL(inbuf,smb_vwv0)) {
1506 DEBUG(1,("%s rejected the protocol\n",pserver));
1507 close(password_client); password_client= -1;
1508 return(False);
1511 if (!(CVAL(inbuf,smb_vwv1) & 1)) {
1512 DEBUG(1,("%s isn't in user level security mode\n",pserver));
1513 close(password_client); password_client= -1;
1514 return(False);
1517 memcpy(buf,inbuf,smb_len(inbuf)+4);
1519 DEBUG(3,("password server OK\n"));
1521 return(True);
1524 /****************************************************************************
1525 attempted support for server level security
1526 ****************************************************************************/
1527 BOOL server_validate(char *buf)
1529 pstring inbuf,outbuf;
1530 BOOL ret;
1532 if (password_client < 0) {
1533 DEBUG(1,("%s not connected\n",pserver));
1534 return(False);
1537 bzero(inbuf,sizeof(inbuf));
1538 memcpy(outbuf,buf,sizeof(outbuf));
1540 /* send a session setup command */
1541 CVAL(outbuf,smb_flg) = 0x8;
1542 SSVAL(outbuf,smb_flg2,0x1);
1543 CVAL(outbuf,smb_vwv0) = 0xFF;
1545 set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
1547 SCVAL(inbuf,smb_rcls,1);
1549 send_smb(password_client,outbuf);
1550 ret = receive_smb(password_client,inbuf,5000);
1552 if (!ret || CVAL(inbuf,smb_rcls) != 0) {
1553 DEBUG(1,("password server %s rejected the password\n",pserver));
1554 return(False);
1557 /* if logged in as guest then reject */
1558 if ((SVAL(inbuf,smb_vwv2) & 1) != 0) {
1559 DEBUG(1,("password server %s gave us guest only\n",pserver));
1560 return(False);
1563 DEBUG(3,("password server %s accepted the password\n",pserver));
1565 #if !KEEP_PASSWORD_SERVER_OPEN
1566 close(password_client); password_client= -1;
1567 #endif
1569 return(True);