2 Unix SMB/Netbios implementation.
4 Password and authentication handling
5 Copyright (C) Andrew Tridgell 1992-1997
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #if (defined(NETGROUP) && defined (AUTOMOUNT))
25 #include "rpcsvc/ypclnt.h"
28 extern int DEBUGLEVEL
;
31 /* users from session setup */
32 static pstring session_users
="";
34 /* these are kept here to keep the string_combinations function simple */
35 static char this_user
[100]="";
36 static char this_salt
[100]="";
37 static char this_crypted
[100]="";
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;
53 /* get a sort-of random number */
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
;
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);
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
)
102 if ((vuid
>= (uint16
)num_validated_users
) ||
103 (validated_users
[vuid
].uid
== -1) || (validated_users
[vuid
].gid
== -1))
105 return &validated_users
[vuid
];
108 /****************************************************************************
110 ****************************************************************************/
111 void invalidate_vuid(uint16 vuid
)
113 user_struct
*vuser
= get_valid_user_struct(vuid
);
115 if (vuser
== NULL
) return;
122 /* same number of igroups as groups as attrs */
125 if (vuser
->groups
&& (vuser
->groups
!= (gid_t
*)vuser
->igroups
))
128 if (vuser
->igroups
) free(vuser
->igroups
);
129 if (vuser
->attrs
) free(vuser
->attrs
);
130 if (vuser
->sids
) free(vuser
->sids
);
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
);
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
)
158 struct passwd
*pwfile
; /* for getting real name from passwd file */
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
170 * Jeremy Allison. (jallison@whistle.com).
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 */
181 validated_users
= (user_struct
*)Realloc(validated_users
,
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
++;
197 vuser
->guest
= guest
;
198 strcpy(vuser
->name
,name
);
204 vuser
->groups
= NULL
;
205 vuser
->igroups
= NULL
;
208 /* Find all the groups this uid is in and store them.
209 Used by become_user() */
210 setup_groups(name
,uid
,gid
,
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
)
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"));
248 strcat(session_users
," ");
249 strcat(session_users
,suser
);
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 */
264 static struct spwd static_spwd
;
266 static_spwd
.sp_pwdp
=0;
267 if (!(f
=fopen("/etc/master.passwd", "r")))
269 while (fgets(line
, 1024, f
)) {
270 if (!strncmp(line
, username
, strlen(username
)) &&
271 line
[strlen(username
)]==':') { /* found entry */
274 p
=line
+strlen(username
)+1;
275 if ((q
=strchr(p
, ':'))) {
280 static_spwd
.sp_pwdp
=pw
;
286 if (static_spwd
.sp_pwdp
)
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
] = "";
304 int parts
= strlen(password
) / AUTH_CLEARTEXT_SEG_CHARS
;
305 if (strlen(password
)%AUTH_CLEARTEXT_SEG_CHARS
)
308 StrnCpy(salt
,salt1
,2);
309 StrnCpy(result
,salt1
,2);
311 for (i
=0; i
<parts
;i
++)
315 StrnCpy(salt
,&result
[2+i
*AUTH_CIPHERTEXT_SEG_CHARS
],2);
316 p2
+= AUTH_CLEARTEXT_SEG_CHARS
;
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
)
330 struct pr_passwd
*mypasswd
;
333 mypasswd
= getprpwnam (user
);
334 starttime
= time (NULL
);
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
));
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
));
358 DEBUG(6,("Updated database with %s %s\n",user
,BOOLSTR(result
)));
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
,
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
);
399 case PAM_PROMPT_ECHO_OFF
:
400 reply
[replies
].resp_retcode
= PAM_SUCCESS
;
401 reply
[replies
].resp
= COPY_STRING(PAM_password
);
408 reply
[replies
].resp_retcode
= PAM_SUCCESS
;
409 reply
[replies
].resp
= NULL
;
412 /* Must be an error of some sort... */
417 if (reply
) *resp
= reply
;
420 static struct pam_conv PAM_conversation
= {
426 static BOOL
pam_auth(char *this_user
,char *password
)
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
);
445 pam_error
= pam_authenticate(pamh
, 0);
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);
453 pam_end(pamh
, PAM_SUCCESS
);
454 /* If this point is reached, the user has been authenticated. */
461 /*******************************************************************
462 check on AFS authentication
463 ********************************************************************/
464 static BOOL
afs_auth(char *this_user
,char *password
)
466 long password_expires
= 0;
469 /* For versions of AFS prior to 3.3, this routine has few arguments, */
470 /* but since I can't find the old documentation... :-) */
472 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION
+KA_USERAUTH_DOSETPAG
,
474 (char *) 0, /* instance */
475 (char *) 0, /* cell */
477 0, /* lifetime, default */
478 &password_expires
, /*days 'til it expires */
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
)
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
)
515 if (sec_login_setup_identity(
516 (unsigned char *)this_user
,
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
));
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
,
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
));
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
);
556 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
557 this_user
, getpid()));
560 dcelogin_atmost_once
= 1;
564 void dfs_unlogin(void)
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
));
582 /*******************************************************************
583 check on Kerberos authentication
584 ********************************************************************/
585 static BOOL
krb5_auth(char *this_user
,char *password
)
587 krb5_data tgtname
= {
592 krb5_context kcontext
;
593 krb5_principal kprinc
;
594 krb5_principal server
;
597 krb5_address
**addrs
= (krb5_address
**)0;
598 krb5_preauthtype
*preauth
= NULL
;
599 krb5_keytab keytab
= NULL
;
601 krb5_ccache ccache
= NULL
;
605 if ( retval
=krb5_init_context(&kcontext
))
610 if ( retval
= krb5_timeofday(kcontext
, &now
) )
615 if ( retval
= krb5_cc_default(kcontext
, &ccache
) )
620 if ( retval
= krb5_parse_name(kcontext
, this_user
, &kprinc
) )
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
,
634 krb5_princ_realm(kcontext
, kprinc
)->length
,
635 krb5_princ_realm(kcontext
, kprinc
)->data
,
641 kcreds
.server
= server
;
643 retval
= krb5_get_in_tkt_with_password(kcontext
,
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
672 StrnCpy(salt
,salt1
,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)
679 password
+= LINUX_PASSWORD_SEG_CHARS
;
680 crypted
+= strlen(p
);
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
)
700 #ifdef PASSWORD_LENGTH
701 len
= MIN(len
,PASSWORD_LENGTH
);
704 if (N
<= 0 || offset
>= len
)
707 for (i
=offset
;i
<(len
-(N
-1));i
++)
710 if (!islower(c
)) continue;
712 if (string_combinations2(s
,i
+1,fn
,N
-1))
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
)
730 if (string_combinations2(s
,0,fn
,n
)) return(True
);
736 /****************************************************************************
737 core of password checking routine
738 ****************************************************************************/
739 BOOL
password_check(char *password
)
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
));
756 if (afs_auth(this_user
,password
)) return(True
);
760 if (dfs_auth(this_user
,password
)) return(True
);
764 if (krb5_auth(this_user
,password
)) return(True
);
768 if (pwdauth(this_user
,password
) == 0)
773 return(strcmp(osf1_bigcrypt(password
,this_salt
),this_crypted
) == 0);
777 return (strcmp((char *)crypt16(password
, this_salt
),this_crypted
) == 0);
780 #ifdef LINUX_BIGCRYPT
781 return(linux_bigcrypt(password
,this_salt
,this_crypted
));
785 DEBUG(1,("Warning - no crypt available\n"));
788 return(strcmp((char *)crypt(password
,this_salt
),this_crypted
) == 0);
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
)
808 memcpy(p21
,part_passwd
,16);
813 DEBUG(100,("Part password (P16) was |"));
814 for(i
= 0; i
< 16; i
++)
815 DEBUG(100,("%X ", (unsigned char)part_passwd
[i
]));
817 DEBUG(100,("Password from client was |"));
818 for(i
= 0; i
< 24; i
++)
819 DEBUG(100,("%X ", (unsigned char)password
[i
]));
821 DEBUG(100,("Given challenge was |"));
822 for(i
= 0; i
< 8; i
++)
823 DEBUG(100,("%X ", (unsigned char)c8
[i
]));
825 DEBUG(100,("Value from encryption was |"));
826 for(i
= 0; i
< 24; i
++)
827 DEBUG(100,("%X ", (unsigned char)p24
[i
]));
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
)
840 int level
= lp_passwordlevel();
843 struct smb_passwd
*smb_pass
;
844 BOOL challenge_done
= False
;
846 if (password
) password
[pwlen
] = 0;
849 challenge_done
= last_challenge(challenge
);
855 DEBUG(100,("checking user=[%s] pass=[",user
));
856 for( i
= 0; i
< 24; i
++)
857 DEBUG(100,("%0x ", (unsigned char)password
[i
]));
860 DEBUG(100,("checking user=[%s] pass=[%s]\n",user
,password
));
867 if (((!*password
) || (!pwlen
)) && !lp_null_passwords())
872 pass
= (struct passwd
*) pwd
;
873 user
= pass
->pw_name
;
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
));
886 DEBUG(3,("Couldn't find user %s\n",user
));
890 smb_pass
= get_smbpwnam(user
);
893 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user
));
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"));
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
);
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
);
932 DEBUG(3,("Error smb_password_check failed\n"));
935 DEBUG(4,("Checking password for user %s (l=%d)\n",user
,pwlen
));
939 DEBUG(3,("Couldn't find user %s\n",user
));
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
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) */
962 if (ia_openinfo(pass
->pw_name
, &uinfo
) != -1)
963 ia_get_logpwd(uinfo
, &(pass
->pw_passwd
));
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
;
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
;
985 struct pr_passwd
*mypasswd
;
986 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user
));
987 mypasswd
= getprpwnam (user
);
990 strcpy(pass
->pw_name
,mypasswd
->ufld
.fd_name
);
991 strcpy(pass
->pw_passwd
,mypasswd
->ufld
.fd_encrypt
);
995 DEBUG(5,("No entry for user %s in protected database !\n",user
));
1003 AUTHORIZATION
*ap
= getauthuid( pass
->pw_uid
);
1006 strcpy( pass
->pw_passwd
, ap
->a_password
);
1012 /* extract relevant info */
1013 strcpy(this_user
,pass
->pw_name
);
1014 strcpy(this_salt
,pass
->pw_passwd
);
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
));
1025 DEBUG(3,("Allowing access to %s with null password\n",this_user
));
1031 /* try it as it came to us */
1032 if (password_check(password
))
1034 update_protected_database(user
,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
1041 if (strhasupper(password
) && strhaslower(password
))
1044 /* make a copy of it */
1045 StrnCpy(pass2
,password
,sizeof(pstring
)-1);
1047 /* try all lowercase */
1049 if (password_check(password
))
1051 update_protected_database(user
,True
);
1058 update_protected_database(user
,False
);
1061 strcpy(password
,pass2
);
1066 /* last chance - all combinations of up to level chars upper! */
1069 if (string_combinations(password
,password_check
,level
))
1071 update_protected_database(user
,True
);
1075 update_protected_database(user
,False
);
1078 strcpy(password
,pass2
);
1085 /****************************************************************************
1086 check if a username is valid
1087 ****************************************************************************/
1088 BOOL
user_ok(char *user
,int snum
)
1090 pstring valid
, invalid
;
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
);
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
)
1123 char *host
, *user
, *domain
;
1125 while (getnetgrent(&host
, &user
, &domain
)) {
1127 if (user_ok(user
, snum
) &&
1128 password_ok(user
,password
,pwlen
,NULL
)) {
1140 struct group
*gptr
= (struct group
*)getgrnam(group
);
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
))
1154 #ifdef GROUP_CHECK_PWENT
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
);
1172 #endif /* GROUP_CHECK_PWENT */
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
)
1192 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user
,password
));
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
));
1232 /* now check the list of session users */
1236 char *user_list
= strdup(session_users
);
1237 if (!user_list
) return(False
);
1239 for (auser
=strtok(user_list
,LIST_SEP
);
1241 auser
= strtok(NULL
,LIST_SEP
))
1244 strcpy(user2
,auser
);
1245 if (!user_ok(user2
,snum
)) continue;
1247 if (password_ok(user2
,password
, pwlen
, NULL
)) {
1250 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
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
);
1262 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1266 /* check for a rhosts entry */
1267 if (!ok
&& user_ok(user
,snum
) && check_hosts_equiv(user
)) {
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
)) {
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
);
1282 auser
= strtok(NULL
,LIST_SEP
))
1286 auser
= validate_group(auser
+1,password
,pwlen
,snum
);
1291 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1297 strcpy(user2
,auser
);
1298 if (user_ok(user2
,snum
) &&
1299 password_ok(user2
,password
,pwlen
,NULL
))
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
))
1314 StrnCpy(guestname
,lp_guestaccount(snum
),sizeof(guestname
)-1);
1315 if (Get_Pwnam(guestname
,True
))
1317 strcpy(user
,guestname
);
1319 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1322 DEBUG(0,("Invalid guest account %s??\n",guestname
));
1327 if (ok
&& !user_ok(user
,snum
))
1329 DEBUG(0,("rejected invalid user %s\n",user
));
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
)
1344 int plus_allowed
= 1;
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
;
1359 if (strcmp(buf
, "NO_PLUS\n") == 0)
1361 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1368 if (*bp
== '\n' && plus_allowed
)
1370 /* a bare plus means everbody allowed */
1371 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1376 else if (buf
[0] == '-')
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
;
1397 static char *mydomain
= NULL
;
1399 yp_get_default_domain(&mydomain
);
1400 if (mydomain
&& innetgr(file_host
,remote
,user
,mydomain
))
1406 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
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
))
1424 /* is it this user */
1425 if (file_user
== 0 || strequal(user
, file_user
))
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
);
1442 /****************************************************************************
1443 check for a possible hosts equiv or rhosts entry for the user
1444 ****************************************************************************/
1445 BOOL
check_hosts_equiv(char *user
)
1449 struct passwd
*pass
= Get_Pwnam(user
,True
);
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
))
1463 if (lp_use_rhosts())
1465 char *home
= get_home_dir(user
);
1468 sprintf(rhostsfile
, "%s/.rhosts", home
);
1469 if (check_user_equiv(user
,client_name(),rhostsfile
))
1478 static struct cli_state cli
;
1480 /****************************************************************************
1481 return the client state structure
1482 ****************************************************************************/
1483 struct cli_state
*server_client(void)
1488 /****************************************************************************
1489 support for server level security
1490 ****************************************************************************/
1491 struct cli_state
*server_cryptkey(void)
1494 struct in_addr dest_ip
;
1495 extern fstring local_machine
;
1498 if (!cli_initialise(&cli
))
1501 for (p
=strtok(lp_passwordserver(),LIST_SEP
); p
; p
= strtok(NULL
,LIST_SEP
)) {
1502 fstrcpy(desthost
,p
);
1503 standard_sub_basic(desthost
);
1506 dest_ip
= *interpret_addr2(desthost
);
1507 if (zero_ip(dest_ip
)) {
1508 DEBUG(1,("Can't resolve address for %s\n",p
));
1512 if (ismyip(dest_ip
)) {
1513 DEBUG(1,("Password server loop - disabling password server %s\n",p
));
1517 if (cli_connect(&cli
, desthost
, &dest_ip
)) {
1518 DEBUG(3,("connected to password server %s\n",p
));
1524 DEBUG(1,("password server not available\n"));
1529 if (!cli_session_request(&cli
, desthost
, 0x20, local_machine
)) {
1530 DEBUG(1,("%s rejected the session\n",desthost
));
1535 DEBUG(3,("got session\n"));
1537 if (!cli_negprot(&cli
)) {
1538 DEBUG(1,("%s rejected the negprot\n",desthost
));
1543 if (cli
.protocol
< PROTOCOL_LANMAN2
||
1544 !(cli
.sec_mode
& 1)) {
1545 DEBUG(1,("%s isn't in user level security mode\n",desthost
));
1550 DEBUG(3,("password server OK\n"));
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
));
1569 if (!cli_session_setup(&cli
, user
, pass
, passlen
, ntpass
, ntpasslen
, domain
)) {
1570 DEBUG(1,("password server %s rejected the password\n", cli
.desthost
));
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
));
1581 if (!cli_send_tconX(&cli
, "IPC$", "IPC", "", 1)) {
1582 DEBUG(1,("password server %s refused IPC$ connect\n", cli
.desthost
));
1587 if (!cli_NetWkstaUserLogon(&cli
,user
,local_machine
)) {
1588 DEBUG(1,("password server %s failed NetWkstaUserLogon\n", cli
.desthost
));
1593 if (cli
.privilages
== 0) {
1594 DEBUG(1,("password server %s gave guest privilages\n", cli
.desthost
));
1599 if (!strequal(cli
.eff_name
, user
)) {
1600 DEBUG(1,("password server %s gave different username %s\n",
1607 DEBUG(3,("password server %s accepted the password\n", cli
.desthost
));