a simple SMB torture tester. This will allow us to evaluate locking
[Samba.git] / source / smbd / password.c
blobb759f684304d799cea55c19ef19793c8465c9fb5
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
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.
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 /* Data to do lanman1/2 password challenge. */
40 static unsigned char saved_challenge[8];
41 static BOOL challenge_sent=False;
43 /*******************************************************************
44 Get the next challenge value - no repeats.
45 ********************************************************************/
46 void generate_next_challenge(char *challenge)
48 unsigned char buf[16];
49 static int counter = 0;
50 struct timeval tval;
51 int v1,v2;
53 /* get a sort-of random number */
54 GetTimeOfDay(&tval);
55 v1 = (counter++) + getpid() + tval.tv_sec;
56 v2 = (counter++) * getpid() + tval.tv_usec;
57 SIVAL(challenge,0,v1);
58 SIVAL(challenge,4,v2);
60 /* mash it up with md4 */
61 mdfour(buf, (unsigned char *)challenge, 8);
63 memcpy(saved_challenge, buf, 8);
64 memcpy(challenge,buf,8);
65 challenge_sent = True;
68 /*******************************************************************
69 set the last challenge sent, usually from a password server
70 ********************************************************************/
71 BOOL set_challenge(char *challenge)
73 memcpy(saved_challenge,challenge,8);
74 challenge_sent = True;
75 return(True);
78 /*******************************************************************
79 get the last challenge sent
80 ********************************************************************/
81 BOOL last_challenge(char *challenge)
83 if (!challenge_sent) return(False);
84 memcpy(challenge,saved_challenge,8);
85 return(True);
88 /* this holds info on user ids that are already validated for this VC */
89 static user_struct *validated_users = NULL;
90 static int num_validated_users = 0;
92 /****************************************************************************
93 check if a uid has been validated, and return an pointer to the user_struct
94 if it has. NULL if not. vuid is biased by an offset. This allows us to
95 tell random client vuid's (normally zero) from valid vuids.
96 ****************************************************************************/
97 user_struct *get_valid_user_struct(uint16 vuid)
99 if (vuid == UID_FIELD_INVALID)
100 return NULL;
101 vuid -= VUID_OFFSET;
102 if ((vuid >= (uint16)num_validated_users) ||
103 (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1))
104 return NULL;
105 return &validated_users[vuid];
108 /****************************************************************************
109 invalidate a uid
110 ****************************************************************************/
111 void invalidate_vuid(uint16 vuid)
113 user_struct *vuser = get_valid_user_struct(vuid);
115 if (vuser == NULL) return;
117 vuser->uid = -1;
118 vuser->gid = -1;
120 vuser->n_sids = 0;
122 /* same number of igroups as groups as attrs */
123 vuser->n_groups = 0;
125 if (vuser->groups && (vuser->groups != (gid_t *)vuser->igroups))
126 free(vuser->groups);
128 if (vuser->igroups) free(vuser->igroups);
129 if (vuser->attrs ) free(vuser->attrs);
130 if (vuser->sids ) free(vuser->sids);
132 vuser->attrs = NULL;
133 vuser->sids = NULL;
134 vuser->igroups = NULL;
135 vuser->groups = NULL;
139 /****************************************************************************
140 return a validated username
141 ****************************************************************************/
142 char *validated_username(uint16 vuid)
144 user_struct *vuser = get_valid_user_struct(vuid);
145 if (vuser == NULL)
146 return 0;
147 return(vuser->name);
150 /****************************************************************************
151 register a uid/name pair as being valid and that a valid password
152 has been given. vuid is biased by an offset. This allows us to
153 tell random client vuid's (normally zero) from valid vuids.
154 ****************************************************************************/
155 uint16 register_vuid(int uid,int gid, char *name,BOOL guest)
157 user_struct *vuser;
158 struct passwd *pwfile; /* for getting real name from passwd file */
160 #if 0
162 * After observing MS-Exchange services writing to a Samba share
163 * I belive this code is incorrect. Each service does its own
164 * sessionsetup_and_X for the same user, and as each service shuts
165 * down, it does a user_logoff_and_X. As we are consolidating multiple
166 * sessionsetup_and_X's onto the same vuid here, when the first service
167 * shuts down, it invalidates all the open files for the other services.
168 * Hence I am removing this code and forcing each sessionsetup_and_X
169 * to get a new vuid.
170 * Jeremy Allison. (jallison@whistle.com).
173 int i;
174 for(i = 0; i < num_validated_users; i++) {
175 vuser = &validated_users[i];
176 if ( vuser->uid == uid )
177 return (uint16)(i + VUID_OFFSET); /* User already validated */
179 #endif
181 validated_users = (user_struct *)Realloc(validated_users,
182 sizeof(user_struct)*
183 (num_validated_users+1));
185 if (!validated_users)
187 DEBUG(0,("Failed to realloc users struct!\n"));
188 num_validated_users = 0;
189 return UID_FIELD_INVALID;
192 vuser = &validated_users[num_validated_users];
193 num_validated_users++;
195 vuser->uid = uid;
196 vuser->gid = gid;
197 vuser->guest = guest;
198 strcpy(vuser->name,name);
200 vuser->n_sids = 0;
201 vuser->sids = NULL;
203 vuser->n_groups = 0;
204 vuser->groups = NULL;
205 vuser->igroups = NULL;
206 vuser->attrs = NULL;
208 /* Find all the groups this uid is in and store them.
209 Used by become_user() */
210 setup_groups(name,uid,gid,
211 &vuser->n_groups,
212 &vuser->igroups,
213 &vuser->groups,
214 &vuser->attrs);
216 DEBUG(3,("uid %d registered to name %s\n",uid,name));
218 DEBUG(3, ("Clearing default real name\n"));
219 fstrcpy(vuser->real_name, "<Full Name>\0");
220 if (lp_unix_realname()) {
221 if ((pwfile=getpwnam(vuser->name))!= NULL)
223 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
224 fstrcpy(vuser->real_name, pwfile->pw_gecos);
228 return (uint16)((num_validated_users - 1) + VUID_OFFSET);
232 /****************************************************************************
233 add a name to the session users list
234 ****************************************************************************/
235 void add_session_user(char *user)
237 fstring suser;
238 StrnCpy(suser,user,sizeof(suser)-1);
240 if (!Get_Pwnam(suser,True)) return;
242 if (suser && *suser && !in_list(suser,session_users,False))
244 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
245 DEBUG(1,("Too many session users??\n"));
246 else
248 strcat(session_users," ");
249 strcat(session_users,suser);
255 #ifdef NO_GETSPNAM
256 /* a fake shadow password routine which just fills a fake spwd struct
257 * with the sp_pwdp field. (sreiz@aie.nl)
259 static struct spwd *getspnam(char *username) /* fake shadow password routine */
261 FILE *f;
262 char line[1024];
263 static char pw[20];
264 static struct spwd static_spwd;
266 static_spwd.sp_pwdp=0;
267 if (!(f=fopen("/etc/master.passwd", "r")))
268 return 0;
269 while (fgets(line, 1024, f)) {
270 if (!strncmp(line, username, strlen(username)) &&
271 line[strlen(username)]==':') { /* found entry */
272 char *p, *q;
274 p=line+strlen(username)+1;
275 if ((q=strchr(p, ':'))) {
276 *q=0;
277 if (q-p+1>20)
278 break;
279 strcpy(pw, p);
280 static_spwd.sp_pwdp=pw;
282 break;
285 fclose(f);
286 if (static_spwd.sp_pwdp)
287 return &static_spwd;
288 return 0;
290 #endif
293 #ifdef OSF1_ENH_SEC
294 /****************************************************************************
295 an enhanced crypt for OSF1
296 ****************************************************************************/
297 static char *osf1_bigcrypt(char *password,char *salt1)
299 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
300 char *p1;
301 char *p2=password;
302 char salt[3];
303 int i;
304 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
305 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
306 parts++;
308 StrnCpy(salt,salt1,2);
309 StrnCpy(result,salt1,2);
311 for (i=0; i<parts;i++)
313 p1 = crypt(p2,salt);
314 strcat(result,p1+2);
315 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
316 p2 += AUTH_CLEARTEXT_SEG_CHARS;
319 return(result);
321 #endif
324 /****************************************************************************
325 update the enhanced security database. Only relevant for OSF1 at the moment.
326 ****************************************************************************/
327 static void update_protected_database( char *user, BOOL result)
329 #ifdef OSF1_ENH_SEC
330 struct pr_passwd *mypasswd;
331 time_t starttime;
333 mypasswd = getprpwnam (user);
334 starttime = time (NULL);
336 if (result)
338 mypasswd->ufld.fd_slogin = starttime;
339 mypasswd->ufld.fd_nlogins = 0;
341 putprpwnam(user,mypasswd);
343 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
345 else
347 mypasswd->ufld.fd_ulogin = starttime;
348 mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
349 if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
351 mypasswd->uflg.fg_lock = 0;
352 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
354 putprpwnam ( user , mypasswd );
355 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
357 #else
358 DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
359 #endif
363 #ifdef USE_PAM
364 /*******************************************************************
365 check on PAM authentication
366 ********************************************************************/
368 /* We first need some helper functions */
369 #include <security/pam_appl.h>
370 /* Static variables used to communicate between the conversation function
371 * and the server_login function
373 static char *PAM_username;
374 static char *PAM_password;
376 /* PAM conversation function
377 * Here we assume (for now, at least) that echo on means login name, and
378 * echo off means password.
380 static int PAM_conv (int num_msg,
381 struct pam_message **msg,
382 struct pam_response **resp,
383 void *appdata_ptr) {
384 int replies = 0;
385 struct pam_response *reply = NULL;
387 #define COPY_STRING(s) (s) ? strdup(s) : NULL
389 reply = malloc(sizeof(struct pam_response) * num_msg);
390 if (!reply) return PAM_CONV_ERR;
392 for (replies = 0; replies < num_msg; replies++) {
393 switch (msg[replies]->msg_style) {
394 case PAM_PROMPT_ECHO_ON:
395 reply[replies].resp_retcode = PAM_SUCCESS;
396 reply[replies].resp = COPY_STRING(PAM_username);
397 /* PAM frees resp */
398 break;
399 case PAM_PROMPT_ECHO_OFF:
400 reply[replies].resp_retcode = PAM_SUCCESS;
401 reply[replies].resp = COPY_STRING(PAM_password);
402 /* PAM frees resp */
403 break;
404 case PAM_TEXT_INFO:
405 /* fall through */
406 case PAM_ERROR_MSG:
407 /* ignore it... */
408 reply[replies].resp_retcode = PAM_SUCCESS;
409 reply[replies].resp = NULL;
410 break;
411 default:
412 /* Must be an error of some sort... */
413 free (reply);
414 return PAM_CONV_ERR;
417 if (reply) *resp = reply;
418 return PAM_SUCCESS;
420 static struct pam_conv PAM_conversation = {
421 &PAM_conv,
422 NULL
426 static BOOL pam_auth(char *this_user,char *password)
428 pam_handle_t *pamh;
429 int pam_error;
431 /* Now use PAM to do authentication. For now, we won't worry about
432 * session logging, only authentication. Bail out if there are any
433 * errors. Since this is a limited protocol, and an even more limited
434 * function within a server speaking this protocol, we can't be as
435 * verbose as would otherwise make sense.
436 * Query: should we be using PAM_SILENT to shut PAM up?
438 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
439 pam_end(pamh, 0); return False; \
441 PAM_password = password;
442 PAM_username = this_user;
443 pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
444 PAM_BAIL;
445 pam_error = pam_authenticate(pamh, 0);
446 PAM_BAIL;
447 /* It is not clear to me that account management is the right thing
448 * to do, but it is not clear that it isn't, either. This can be
449 * removed if no account management should be done. Alternately,
450 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
451 pam_error = pam_acct_mgmt(pamh, 0);
452 PAM_BAIL;
453 pam_end(pamh, PAM_SUCCESS);
454 /* If this point is reached, the user has been authenticated. */
455 return(True);
457 #endif
460 #ifdef AFS_AUTH
461 /*******************************************************************
462 check on AFS authentication
463 ********************************************************************/
464 static BOOL afs_auth(char *this_user,char *password)
466 long password_expires = 0;
467 char *reason;
469 /* For versions of AFS prior to 3.3, this routine has few arguments, */
470 /* but since I can't find the old documentation... :-) */
471 setpag();
472 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
473 this_user,
474 (char *) 0, /* instance */
475 (char *) 0, /* cell */
476 password,
477 0, /* lifetime, default */
478 &password_expires, /*days 'til it expires */
479 0, /* spare 2 */
480 &reason) == 0)
481 return(True);
482 return(False);
484 #endif
487 #ifdef DFS_AUTH
489 sec_login_handle_t my_dce_sec_context;
490 int dcelogin_atmost_once = 0;
492 /*******************************************************************
493 check on a DCE/DFS authentication
494 ********************************************************************/
495 static BOOL dfs_auth(char *this_user,char *password)
497 error_status_t err;
498 int err2;
499 int prterr;
500 boolean32 password_reset;
501 sec_passwd_rec_t my_dce_password;
502 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
503 unsigned char dce_errstr[dce_c_error_string_len];
506 * We only go for a DCE login context if the given password
507 * matches that stored in the local password file..
508 * Assumes local passwd file is kept in sync w/ DCE RGY!
511 if (!strcmp((char *)crypt(password,this_salt),this_crypted) ||
512 dcelogin_atmost_once)
513 return(False);
515 if (sec_login_setup_identity(
516 (unsigned char *)this_user,
517 sec_login_no_flags,
518 &my_dce_sec_context,
519 &err) == 0)
521 dce_error_inq_text(err, dce_errstr, &err2);
522 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
523 this_user,dce_errstr));
524 return(False);
527 my_dce_password.version_number = sec_passwd_c_version_none;
528 my_dce_password.pepper = NULL;
529 my_dce_password.key.key_type = sec_passwd_plain;
530 my_dce_password.key.tagged_union.plain = (idl_char *)password;
532 if (sec_login_valid_and_cert_ident(my_dce_sec_context,
533 &my_dce_password,
534 &password_reset,
535 &auth_src,
536 &err) == 0 )
538 dce_error_inq_text(err, dce_errstr, &err2);
539 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
540 this_user,dce_errstr));
542 return(False);
545 sec_login_set_context(my_dce_sec_context, &err);
546 if (err != error_status_ok )
548 dce_error_inq_text(err, dce_errstr, &err2);
549 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
550 this_user,dce_errstr));
551 sec_login_purge_context(my_dce_sec_context, &err);
552 return(False);
554 else
556 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
557 this_user, getpid()));
560 dcelogin_atmost_once = 1;
561 return (True);
564 void dfs_unlogin(void)
566 error_status_t err;
567 int err2;
568 unsigned char dce_errstr[dce_c_error_string_len];
570 sec_login_purge_context(my_dce_sec_context, &err);
571 if (err != error_status_ok )
573 dce_error_inq_text(err, dce_errstr, &err2);
574 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
575 getpid(), dce_errstr));
579 #endif
581 #ifdef KRB5_AUTH
582 /*******************************************************************
583 check on Kerberos authentication
584 ********************************************************************/
585 static BOOL krb5_auth(char *this_user,char *password)
587 krb5_data tgtname = {
589 KRB5_TGS_NAME_SIZE,
590 KRB5_TGS_NAME
592 krb5_context kcontext;
593 krb5_principal kprinc;
594 krb5_principal server;
595 krb5_creds kcreds;
596 int options = 0;
597 krb5_address **addrs = (krb5_address **)0;
598 krb5_preauthtype *preauth = NULL;
599 krb5_keytab keytab = NULL;
600 krb5_timestamp now;
601 krb5_ccache ccache = NULL;
602 int retval;
603 char *name;
605 if ( retval=krb5_init_context(&kcontext))
607 return(False);
610 if ( retval = krb5_timeofday(kcontext, &now) )
612 return(False);
615 if ( retval = krb5_cc_default(kcontext, &ccache) )
617 return(False);
620 if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
622 return(False);
625 memset((char *)&kcreds, 0, sizeof(kcreds));
627 kcreds.client = kprinc;
629 if ((retval = krb5_build_principal_ext(kcontext, &server,
630 krb5_princ_realm(kcontext, kprinc)->length,
631 krb5_princ_realm(kcontext, kprinc)->data,
632 tgtname.length,
633 tgtname.data,
634 krb5_princ_realm(kcontext, kprinc)->length,
635 krb5_princ_realm(kcontext, kprinc)->data,
636 0)))
638 return(False);
641 kcreds.server = server;
643 retval = krb5_get_in_tkt_with_password(kcontext,
644 options,
645 addrs,
646 NULL,
647 preauth,
648 password,
650 &kcreds,
653 if ( retval )
655 return(False);
658 return(True);
660 #endif /* KRB5_AUTH */
662 #ifdef LINUX_BIGCRYPT
663 /****************************************************************************
664 an enhanced crypt for Linux to handle password longer than 8 characters
665 ****************************************************************************/
666 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
668 #define LINUX_PASSWORD_SEG_CHARS 8
669 char salt[3];
670 int i;
672 StrnCpy(salt,salt1,2);
673 crypted +=2;
675 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
676 char * p = crypt(password,salt) + 2;
677 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
678 return(0);
679 password += LINUX_PASSWORD_SEG_CHARS;
680 crypted += strlen(p);
683 return(1);
685 #endif
688 /****************************************************************************
689 apply a function to upper/lower case combinations
690 of a string and return true if one of them returns true.
691 try all combinations with N uppercase letters.
692 offset is the first char to try and change (start with 0)
693 it assumes the string starts lowercased
694 ****************************************************************************/
695 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(),int N)
697 int len = strlen(s);
698 int i;
700 #ifdef PASSWORD_LENGTH
701 len = MIN(len,PASSWORD_LENGTH);
702 #endif
704 if (N <= 0 || offset >= len)
705 return(fn(s));
707 for (i=offset;i<(len-(N-1));i++)
709 char c = s[i];
710 if (!islower(c)) continue;
711 s[i] = toupper(c);
712 if (string_combinations2(s,i+1,fn,N-1))
713 return(True);
714 s[i] = c;
716 return(False);
719 /****************************************************************************
720 apply a function to upper/lower case combinations
721 of a string and return true if one of them returns true.
722 try all combinations with up to N uppercase letters.
723 offset is the first char to try and change (start with 0)
724 it assumes the string starts lowercased
725 ****************************************************************************/
726 static BOOL string_combinations(char *s,BOOL (*fn)(),int N)
728 int n;
729 for (n=1;n<=N;n++)
730 if (string_combinations2(s,0,fn,n)) return(True);
731 return(False);
736 /****************************************************************************
737 core of password checking routine
738 ****************************************************************************/
739 BOOL password_check(char *password)
742 #ifdef USE_PAM
743 /* This falls through if the password check fails
744 - if NO_CRYPT is defined this causes an error msg
745 saying Warning - no crypt available
746 - if NO_CRYPT is NOT defined this is a potential security hole
747 as it may authenticate via the crypt call when PAM
748 settings say it should fail.
749 if (pam_auth(this_user,password)) return(True);
750 Hence we make a direct return to avoid a second chance!!!
752 return (pam_auth(this_user,password));
753 #endif
755 #ifdef AFS_AUTH
756 if (afs_auth(this_user,password)) return(True);
757 #endif
759 #ifdef DFS_AUTH
760 if (dfs_auth(this_user,password)) return(True);
761 #endif
763 #ifdef KRB5_AUTH
764 if (krb5_auth(this_user,password)) return(True);
765 #endif
767 #ifdef PWDAUTH
768 if (pwdauth(this_user,password) == 0)
769 return(True);
770 #endif
772 #ifdef OSF1_ENH_SEC
773 return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
774 #endif
776 #ifdef ULTRIX_AUTH
777 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
778 #endif
780 #ifdef LINUX_BIGCRYPT
781 return(linux_bigcrypt(password,this_salt,this_crypted));
782 #endif
784 #ifdef NO_CRYPT
785 DEBUG(1,("Warning - no crypt available\n"));
786 return(False);
787 #else
788 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
789 #endif
792 /****************************************************************************
793 core of smb password checking routine.
794 ****************************************************************************/
795 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
797 /* Finish the encryption of part_passwd. */
798 unsigned char p21[21];
799 unsigned char p24[24];
801 if (part_passwd == NULL)
802 DEBUG(10,("No password set - allowing access\n"));
803 /* No password set - always true ! */
804 if (part_passwd == NULL)
805 return 1;
807 memset(p21,'\0',21);
808 memcpy(p21,part_passwd,16);
809 E_P24(p21, c8, p24);
810 #if DEBUG_PASSWORD
812 int i;
813 DEBUG(100,("Part password (P16) was |"));
814 for(i = 0; i < 16; i++)
815 DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
816 DEBUG(100,("|\n"));
817 DEBUG(100,("Password from client was |"));
818 for(i = 0; i < 24; i++)
819 DEBUG(100,("%X ", (unsigned char)password[i]));
820 DEBUG(100,("|\n"));
821 DEBUG(100,("Given challenge was |"));
822 for(i = 0; i < 8; i++)
823 DEBUG(100,("%X ", (unsigned char)c8[i]));
824 DEBUG(100,("|\n"));
825 DEBUG(100,("Value from encryption was |"));
826 for(i = 0; i < 24; i++)
827 DEBUG(100,("%X ", (unsigned char)p24[i]));
828 DEBUG(100,("|\n"));
830 #endif
831 return (memcmp(p24, password, 24) == 0);
834 /****************************************************************************
835 check if a username/password is OK
836 ****************************************************************************/
837 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
839 pstring pass2;
840 int level = lp_passwordlevel();
841 struct passwd *pass;
842 char challenge[8];
843 struct smb_passwd *smb_pass;
844 BOOL challenge_done = False;
846 if (password) password[pwlen] = 0;
848 if (pwlen == 24)
849 challenge_done = last_challenge(challenge);
851 #if DEBUG_PASSWORD
852 if (challenge_done)
854 int i;
855 DEBUG(100,("checking user=[%s] pass=[",user));
856 for( i = 0; i < 24; i++)
857 DEBUG(100,("%0x ", (unsigned char)password[i]));
858 DEBUG(100,("]\n"));
859 } else {
860 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
862 #endif
864 if (!password)
865 return(False);
867 if (((!*password) || (!pwlen)) && !lp_null_passwords())
868 return(False);
870 if (pwd && !user)
872 pass = (struct passwd *) pwd;
873 user = pass->pw_name;
875 else
876 pass = Get_Pwnam(user,True);
878 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
880 if ((pwlen == 24) && challenge_done)
882 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
884 if (!pass)
886 DEBUG(3,("Couldn't find user %s\n",user));
887 return(False);
890 smb_pass = get_smbpwnam(user);
891 if (!smb_pass)
893 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
894 return(False);
897 /* Ensure the uid's match */
898 if (smb_pass->smb_userid != pass->pw_uid)
900 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
901 return(False);
904 if (Protocol >= PROTOCOL_NT1)
906 /* We have the NT MD4 hash challenge available - see if we can
907 use it (ie. does it exist in the smbpasswd file).
909 if (smb_pass->smb_nt_passwd != NULL)
911 DEBUG(4,("Checking NT MD4 password\n"));
912 if (smb_password_check(password,
913 smb_pass->smb_nt_passwd,
914 (unsigned char *)challenge))
916 update_protected_database(user,True);
917 return(True);
919 DEBUG(4,("NT MD4 password check failed\n"));
923 /* Try against the lanman password */
925 if (smb_password_check(password,
926 smb_pass->smb_passwd,
927 (unsigned char *)challenge)) {
928 update_protected_database(user,True);
929 return(True);
932 DEBUG(3,("Error smb_password_check failed\n"));
935 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
937 if (!pass)
939 DEBUG(3,("Couldn't find user %s\n",user));
940 return(False);
943 #ifdef SHADOW_PWD
945 struct spwd *spass;
947 /* many shadow systems require you to be root to get the password,
948 in most cases this should already be the case when this
949 function is called, except perhaps for IPC password changing
950 requests */
952 spass = getspnam(pass->pw_name);
953 if (spass && spass->sp_pwdp)
954 pass->pw_passwd = spass->sp_pwdp;
956 #elif defined(IA_UINFO)
958 /* Need to get password with SVR4.2's ia_ functions instead of
959 get{sp,pw}ent functions. Required by UnixWare 2.x, tested on
960 version 2.1. (tangent@cyberport.com) */
961 uinfo_t uinfo;
962 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
963 ia_get_logpwd(uinfo, &(pass->pw_passwd));
965 #endif
967 #ifdef SecureWare
969 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
970 if (pr_pw && pr_pw->ufld.fd_encrypt)
971 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
973 #endif
975 #ifdef HPUX_10_TRUSTED
977 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
978 if (pr_pw && pr_pw->ufld.fd_encrypt)
979 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
981 #endif
983 #ifdef OSF1_ENH_SEC
985 struct pr_passwd *mypasswd;
986 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
987 mypasswd = getprpwnam (user);
988 if ( mypasswd )
990 strcpy(pass->pw_name,mypasswd->ufld.fd_name);
991 strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
993 else
995 DEBUG(5,("No entry for user %s in protected database !\n",user));
996 return(False);
999 #endif
1001 #ifdef ULTRIX_AUTH
1003 AUTHORIZATION *ap = getauthuid( pass->pw_uid );
1004 if (ap)
1006 strcpy( pass->pw_passwd, ap->a_password );
1007 endauthent();
1010 #endif
1012 /* extract relevant info */
1013 strcpy(this_user,pass->pw_name);
1014 strcpy(this_salt,pass->pw_passwd);
1015 this_salt[2] = 0;
1016 strcpy(this_crypted,pass->pw_passwd);
1018 if (!*this_crypted) {
1019 if (!lp_null_passwords()) {
1020 DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
1021 return(False);
1023 #ifndef PWDAUTH
1024 if (!*password) {
1025 DEBUG(3,("Allowing access to %s with null password\n",this_user));
1026 return(True);
1028 #endif
1031 /* try it as it came to us */
1032 if (password_check(password))
1034 update_protected_database(user,True);
1035 return(True);
1038 /* if the password was given to us with mixed case then we don't
1039 need to proceed as we know it hasn't been case modified by the
1040 client */
1041 if (strhasupper(password) && strhaslower(password))
1042 return(False);
1044 /* make a copy of it */
1045 StrnCpy(pass2,password,sizeof(pstring)-1);
1047 /* try all lowercase */
1048 strlower(password);
1049 if (password_check(password))
1051 update_protected_database(user,True);
1052 return(True);
1055 /* give up? */
1056 if (level < 1)
1058 update_protected_database(user,False);
1060 /* restore it */
1061 strcpy(password,pass2);
1063 return(False);
1066 /* last chance - all combinations of up to level chars upper! */
1067 strlower(password);
1069 if (string_combinations(password,password_check,level))
1071 update_protected_database(user,True);
1072 return(True);
1075 update_protected_database(user,False);
1077 /* restore it */
1078 strcpy(password,pass2);
1080 return(False);
1085 /****************************************************************************
1086 check if a username is valid
1087 ****************************************************************************/
1088 BOOL user_ok(char *user,int snum)
1090 pstring valid, invalid;
1091 BOOL ret;
1093 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
1094 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
1096 string_sub(valid,"%S",lp_servicename(snum));
1097 string_sub(invalid,"%S",lp_servicename(snum));
1099 ret = !user_in_list(user,invalid);
1101 if (ret && valid && *valid)
1102 ret = user_in_list(user,valid);
1104 if (ret && lp_onlyuser(snum)) {
1105 char *user_list = lp_username(snum);
1106 string_sub(user_list,"%S",lp_servicename(snum));
1107 ret = user_in_list(user,user_list);
1110 return(ret);
1116 /****************************************************************************
1117 validate a group username entry. Return the username or NULL
1118 ****************************************************************************/
1119 static char *validate_group(char *group,char *password,int pwlen,int snum)
1121 #ifdef NETGROUP
1123 char *host, *user, *domain;
1124 setnetgrent(group);
1125 while (getnetgrent(&host, &user, &domain)) {
1126 if (user) {
1127 if (user_ok(user, snum) &&
1128 password_ok(user,password,pwlen,NULL)) {
1129 endnetgrent();
1130 return(user);
1134 endnetgrent();
1136 #endif
1138 #if HAVE_GETGRNAM
1140 struct group *gptr = (struct group *)getgrnam(group);
1141 char **member;
1142 if (gptr)
1144 member = gptr->gr_mem;
1145 while (member && *member)
1147 static fstring name;
1148 strcpy(name,*member);
1149 if (user_ok(name,snum) &&
1150 password_ok(name,password,pwlen,NULL))
1151 return(&name[0]);
1152 member++;
1154 #ifdef GROUP_CHECK_PWENT
1156 struct passwd *pwd;
1157 static fstring tm;
1159 setpwent ();
1160 while (pwd = getpwent ()) {
1161 if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
1162 /* This Entry have PASSWORD and same GID then check pwd */
1163 if (password_ok(NULL, password, pwlen, pwd)) {
1164 strcpy(tm, pwd->pw_name);
1165 endpwent ();
1166 return tm;
1170 endpwent ();
1172 #endif /* GROUP_CHECK_PWENT */
1175 #endif
1176 return(NULL);
1181 /****************************************************************************
1182 check for authority to login to a service with a given username/password
1183 ****************************************************************************/
1184 BOOL authorise_login(int snum,char *user,char *password, int pwlen,
1185 BOOL *guest,BOOL *force,uint16 vuid)
1187 BOOL ok = False;
1189 *guest = False;
1191 #if DEBUG_PASSWORD
1192 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1193 #endif
1195 /* there are several possibilities:
1196 1) login as the given user with given password
1197 2) login as a previously registered username with the given password
1198 3) login as a session list username with the given password
1199 4) login as a previously validated user/password pair
1200 5) login as the "user =" user with given password
1201 6) login as the "user =" user with no password (guest connection)
1202 7) login as guest user with no password
1204 if the service is guest_only then steps 1 to 5 are skipped
1207 if (GUEST_ONLY(snum)) *force = True;
1209 if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1212 user_struct *vuser = get_valid_user_struct(vuid);
1214 /* check the given username and password */
1215 if (!ok && (*user) && user_ok(user,snum)) {
1216 ok = password_ok(user,password, pwlen, NULL);
1217 if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
1220 /* check for a previously registered guest username */
1221 if (!ok && (vuser != 0) && vuser->guest) {
1222 if (user_ok(vuser->name,snum) &&
1223 password_ok(vuser->name, password, pwlen, NULL)) {
1224 strcpy(user, vuser->name);
1225 vuser->guest = False;
1226 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
1227 ok = True;
1232 /* now check the list of session users */
1233 if (!ok)
1235 char *auser;
1236 char *user_list = strdup(session_users);
1237 if (!user_list) return(False);
1239 for (auser=strtok(user_list,LIST_SEP);
1240 !ok && auser;
1241 auser = strtok(NULL,LIST_SEP))
1243 fstring user2;
1244 strcpy(user2,auser);
1245 if (!user_ok(user2,snum)) continue;
1247 if (password_ok(user2,password, pwlen, NULL)) {
1248 ok = True;
1249 strcpy(user,user2);
1250 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1253 free(user_list);
1256 /* check for a previously validated username/password pair */
1257 if (!ok && !lp_revalidate(snum) &&
1258 (vuser != 0) && !vuser->guest &&
1259 user_ok(vuser->name,snum)) {
1260 strcpy(user,vuser->name);
1261 *guest = False;
1262 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1263 ok = True;
1266 /* check for a rhosts entry */
1267 if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1268 ok = True;
1269 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1272 /* check the user= fields and the given password */
1273 if (!ok && lp_username(snum)) {
1274 char *auser;
1275 pstring user_list;
1276 StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1278 string_sub(user_list,"%S",lp_servicename(snum));
1280 for (auser=strtok(user_list,LIST_SEP);
1281 auser && !ok;
1282 auser = strtok(NULL,LIST_SEP))
1284 if (*auser == '@')
1286 auser = validate_group(auser+1,password,pwlen,snum);
1287 if (auser)
1289 ok = True;
1290 strcpy(user,auser);
1291 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1294 else
1296 fstring user2;
1297 strcpy(user2,auser);
1298 if (user_ok(user2,snum) &&
1299 password_ok(user2,password,pwlen,NULL))
1301 ok = True;
1302 strcpy(user,user2);
1303 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1308 } /* not guest only */
1310 /* check for a normal guest connection */
1311 if (!ok && GUEST_OK(snum))
1313 fstring guestname;
1314 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1315 if (Get_Pwnam(guestname,True))
1317 strcpy(user,guestname);
1318 ok = True;
1319 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1321 else
1322 DEBUG(0,("Invalid guest account %s??\n",guestname));
1323 *guest = True;
1324 *force = True;
1327 if (ok && !user_ok(user,snum))
1329 DEBUG(0,("rejected invalid user %s\n",user));
1330 ok = False;
1333 return(ok);
1337 /****************************************************************************
1338 read the a hosts.equiv or .rhosts file and check if it
1339 allows this user from this machine
1340 ****************************************************************************/
1341 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1343 pstring buf;
1344 int plus_allowed = 1;
1345 char *file_host;
1346 char *file_user;
1347 FILE *fp = fopen(equiv_file, "r");
1348 DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1349 if (! fp) return False;
1350 while(fgets(buf, sizeof(buf), fp))
1352 trim_string(buf," "," ");
1354 if (buf[0] != '#' && buf[0] != '\n')
1356 BOOL is_group = False;
1357 int plus = 1;
1358 char *bp = buf;
1359 if (strcmp(buf, "NO_PLUS\n") == 0)
1361 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1362 plus_allowed = 0;
1364 else {
1365 if (buf[0] == '+')
1367 bp++;
1368 if (*bp == '\n' && plus_allowed)
1370 /* a bare plus means everbody allowed */
1371 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1372 fclose(fp);
1373 return True;
1376 else if (buf[0] == '-')
1378 bp++;
1379 plus = 0;
1381 if (*bp == '@')
1383 is_group = True;
1384 bp++;
1386 file_host = strtok(bp, " \t\n");
1387 file_user = strtok(NULL, " \t\n");
1388 DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)",
1389 file_user ? file_user : "(null)" ));
1390 if (file_host && *file_host)
1392 BOOL host_ok = False;
1394 #ifdef NETGROUP
1395 if (is_group)
1397 static char *mydomain = NULL;
1398 if (!mydomain)
1399 yp_get_default_domain(&mydomain);
1400 if (mydomain && innetgr(file_host,remote,user,mydomain))
1401 host_ok = True;
1403 #else
1404 if (is_group)
1406 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1407 continue;
1409 #endif
1411 /* is it this host */
1412 /* the fact that remote has come from a call of gethostbyaddr
1413 * means that it may have the fully qualified domain name
1414 * so we could look up the file version to get it into
1415 * a canonical form, but I would rather just type it
1416 * in full in the equiv file
1418 if (!host_ok && !is_group && strequal(remote, file_host))
1419 host_ok = True;
1421 if (!host_ok)
1422 continue;
1424 /* is it this user */
1425 if (file_user == 0 || strequal(user, file_user))
1427 fclose(fp);
1428 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1429 (plus ? "+" : "-"), file_host,
1430 (file_user ? file_user : "")));
1431 return (plus ? True : False);
1437 fclose(fp);
1438 return False;
1442 /****************************************************************************
1443 check for a possible hosts equiv or rhosts entry for the user
1444 ****************************************************************************/
1445 BOOL check_hosts_equiv(char *user)
1447 char *fname = NULL;
1448 pstring rhostsfile;
1449 struct passwd *pass = Get_Pwnam(user,True);
1451 if (!pass)
1452 return(False);
1454 fname = lp_hosts_equiv();
1456 /* note: don't allow hosts.equiv on root */
1457 if (fname && *fname && (pass->pw_uid != 0))
1459 if (check_user_equiv(user,client_name(),fname))
1460 return(True);
1463 if (lp_use_rhosts())
1465 char *home = get_home_dir(user);
1466 if (home)
1468 sprintf(rhostsfile, "%s/.rhosts", home);
1469 if (check_user_equiv(user,client_name(),rhostsfile))
1470 return(True);
1474 return(False);
1478 static struct cli_state cli;
1480 /****************************************************************************
1481 return the client state structure
1482 ****************************************************************************/
1483 struct cli_state *server_client(void)
1485 return &cli;
1488 /****************************************************************************
1489 support for server level security
1490 ****************************************************************************/
1491 struct cli_state *server_cryptkey(void)
1493 fstring desthost;
1494 struct in_addr dest_ip;
1495 extern fstring local_machine;
1496 char *p;
1498 if (!cli_initialise(&cli))
1499 return NULL;
1501 for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
1502 fstrcpy(desthost,p);
1503 standard_sub_basic(desthost);
1504 strupper(desthost);
1506 dest_ip = *interpret_addr2(desthost);
1507 if (zero_ip(dest_ip)) {
1508 DEBUG(1,("Can't resolve address for %s\n",p));
1509 continue;
1512 if (ismyip(dest_ip)) {
1513 DEBUG(1,("Password server loop - disabling password server %s\n",p));
1514 continue;
1517 if (cli_connect(&cli, desthost, &dest_ip)) {
1518 DEBUG(3,("connected to password server %s\n",p));
1519 break;
1523 if (!p) {
1524 DEBUG(1,("password server not available\n"));
1525 cli_shutdown(&cli);
1526 return NULL;
1529 if (!cli_session_request(&cli, desthost, 0x20, local_machine)) {
1530 DEBUG(1,("%s rejected the session\n",desthost));
1531 cli_shutdown(&cli);
1532 return NULL;
1535 DEBUG(3,("got session\n"));
1537 if (!cli_negprot(&cli)) {
1538 DEBUG(1,("%s rejected the negprot\n",desthost));
1539 cli_shutdown(&cli);
1540 return NULL;
1543 if (cli.protocol < PROTOCOL_LANMAN2 ||
1544 !(cli.sec_mode & 1)) {
1545 DEBUG(1,("%s isn't in user level security mode\n",desthost));
1546 cli_shutdown(&cli);
1547 return NULL;
1550 DEBUG(3,("password server OK\n"));
1552 return &cli;
1555 /****************************************************************************
1556 validate a password with the password server
1557 ****************************************************************************/
1558 BOOL server_validate(char *user, char *domain,
1559 char *pass, int passlen,
1560 char *ntpass, int ntpasslen)
1562 extern fstring local_machine;
1564 if (!cli.initialised) {
1565 DEBUG(1,("password server %s is not connected\n", cli.desthost));
1566 return(False);
1569 if (!cli_session_setup(&cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
1570 DEBUG(1,("password server %s rejected the password\n", cli.desthost));
1571 return False;
1574 /* if logged in as guest then reject */
1575 if ((SVAL(cli.inbuf,smb_vwv2) & 1) != 0) {
1576 DEBUG(1,("password server %s gave us guest only\n", cli.desthost));
1577 return(False);
1581 if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
1582 DEBUG(1,("password server %s refused IPC$ connect\n", cli.desthost));
1583 return False;
1587 if (!cli_NetWkstaUserLogon(&cli,user,local_machine)) {
1588 DEBUG(1,("password server %s failed NetWkstaUserLogon\n", cli.desthost));
1589 cli_tdis(&cli);
1590 return False;
1593 if (cli.privilages == 0) {
1594 DEBUG(1,("password server %s gave guest privilages\n", cli.desthost));
1595 cli_tdis(&cli);
1596 return False;
1599 if (!strequal(cli.eff_name, user)) {
1600 DEBUG(1,("password server %s gave different username %s\n",
1601 cli.desthost,
1602 cli.eff_name));
1603 cli_tdis(&cli);
1604 return False;
1607 DEBUG(3,("password server %s accepted the password\n", cli.desthost));
1609 cli_tdis(&cli);
1611 return(True);