2 Unix SMB/Netbios implementation.
4 Password and authentication handling
5 Copyright (C) Andrew Tridgell 1992-1998
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(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT))
25 #include "rpcsvc/ypclnt.h"
28 extern int DEBUGLEVEL;
31 BOOL global_machine_pasword_needs_changing;
33 /* users from session setup */
34 static pstring session_users="";
36 extern pstring global_myname;
37 extern fstring global_myworkgroup;
39 /* these are kept here to keep the string_combinations function simple */
40 static char this_user[100]="";
41 static char this_salt[100]="";
42 static char this_crypted[100]="";
44 /* Data to do lanman1/2 password challenge. */
45 static unsigned char saved_challenge[8];
46 static BOOL challenge_sent=False;
48 /*******************************************************************
49 Get the next challenge value - no repeats.
50 ********************************************************************/
51 void generate_next_challenge(char *challenge)
55 * Leave this ifdef'd out while we test
56 * the new crypto random number generator.
59 unsigned char buf[16];
60 static int counter = 0;
64 /* get a sort-of random number */
66 v1 = (counter++) + getpid() + tval.tv_sec;
67 v2 = (counter++) * getpid() + tval.tv_usec;
68 SIVAL(challenge,0,v1);
69 SIVAL(challenge,4,v2);
71 /* mash it up with md4 */
72 mdfour(buf, (unsigned char *)challenge, 8);
76 generate_random_buffer(buf,8,False);
78 memcpy(saved_challenge, buf, 8);
79 memcpy(challenge,buf,8);
80 challenge_sent = True;
83 /*******************************************************************
84 set the last challenge sent, usually from a password server
85 ********************************************************************/
86 BOOL set_challenge(char *challenge)
88 memcpy(saved_challenge,challenge,8);
89 challenge_sent = True;
93 /*******************************************************************
94 get the last challenge sent
95 ********************************************************************/
96 BOOL last_challenge(unsigned char *challenge)
98 if (!challenge_sent) return(False);
99 memcpy(challenge,saved_challenge,8);
103 /* this holds info on user ids that are already validated for this VC */
104 static user_struct *validated_users = NULL;
105 static int num_validated_users = 0;
107 /****************************************************************************
108 check if a uid has been validated, and return an pointer to the user_struct
109 if it has. NULL if not. vuid is biased by an offset. This allows us to
110 tell random client vuid's (normally zero) from valid vuids.
111 ****************************************************************************/
112 user_struct *get_valid_user_struct(uint16 vuid)
114 if (vuid == UID_FIELD_INVALID)
117 if ((vuid >= (uint16)num_validated_users) ||
118 (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1))
120 return &validated_users[vuid];
123 /****************************************************************************
125 ****************************************************************************/
126 void invalidate_vuid(uint16 vuid)
128 user_struct *vuser = get_valid_user_struct(vuid);
130 if (vuser == NULL) return;
137 /* same number of igroups as groups */
140 if (vuser->groups) free(vuser->groups);
142 if (vuser->sids) free(vuser->sids);
145 vuser->groups = NULL;
149 /****************************************************************************
150 return a validated username
151 ****************************************************************************/
152 char *validated_username(uint16 vuid)
154 user_struct *vuser = get_valid_user_struct(vuid);
161 /****************************************************************************
162 Setup the groups a user belongs to.
163 ****************************************************************************/
164 int setup_groups(char *user, int uid, int gid, int *p_ngroups, GID_T **p_groups)
170 if (-1 == initgroups(user,gid)) {
172 DEBUG(0,("Unable to initgroups!\n"));
173 if (gid < 0 || gid > 16000 || uid < 0 || uid > 16000) {
174 DEBUG(0,("This is probably a problem with the account %s\n",
181 ngroups = getgroups(0,&grp);
182 if (ngroups <= 0) ngroups = 32;
184 groups = (GID_T *)malloc(sizeof(groups[0])*ngroups);
186 ngroups = getgroups(ngroups,(gid_t *)groups);
188 (*p_ngroups) = ngroups;
190 (*p_groups) = groups;
192 DEBUG(3,("%s is in %d groups\n",user,ngroups));
193 for (i=0;i<ngroups;i++) {
194 DEBUG(3,("%d ",(int)groups[i]));
202 /****************************************************************************
203 register a uid/name pair as being valid and that a valid password
204 has been given. vuid is biased by an offset. This allows us to
205 tell random client vuid's (normally zero) from valid vuids.
206 ****************************************************************************/
207 uint16 register_vuid(int uid,int gid, char *unix_name, char *requested_name, BOOL guest)
210 struct passwd *pwfile; /* for getting real name from passwd file */
212 /* Ensure no vuid gets registered in share level security. */
213 if(lp_security() == SEC_SHARE)
214 return UID_FIELD_INVALID;
218 * After observing MS-Exchange services writing to a Samba share
219 * I belive this code is incorrect. Each service does its own
220 * sessionsetup_and_X for the same user, and as each service shuts
221 * down, it does a user_logoff_and_X. As we are consolidating multiple
222 * sessionsetup_and_X's onto the same vuid here, when the first service
223 * shuts down, it invalidates all the open files for the other services.
224 * Hence I am removing this code and forcing each sessionsetup_and_X
226 * Jeremy Allison. (jallison@whistle.com).
230 for(i = 0; i < num_validated_users; i++) {
231 vuser = &validated_users[i];
232 if ( vuser->uid == uid )
233 return (uint16)(i + VUID_OFFSET); /* User already validated */
237 validated_users = (user_struct *)Realloc(validated_users,
239 (num_validated_users+1));
241 if (!validated_users)
243 DEBUG(0,("Failed to realloc users struct!\n"));
244 num_validated_users = 0;
245 return UID_FIELD_INVALID;
248 vuser = &validated_users[num_validated_users];
249 num_validated_users++;
253 vuser->guest = guest;
254 fstrcpy(vuser->name,unix_name);
255 fstrcpy(vuser->requested_name,requested_name);
261 vuser->groups = NULL;
263 /* Find all the groups this uid is in and store them.
264 Used by become_user() */
265 setup_groups(unix_name,uid,gid,
269 DEBUG(3,("uid %d registered to name %s\n",uid,unix_name));
271 DEBUG(3, ("Clearing default real name\n"));
272 fstrcpy(vuser->real_name, "<Full Name>\0");
273 if (lp_unix_realname()) {
274 if ((pwfile=getpwnam(vuser->name))!= NULL)
276 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
277 fstrcpy(vuser->real_name, pwfile->pw_gecos);
281 return (uint16)((num_validated_users - 1) + VUID_OFFSET);
285 /****************************************************************************
286 add a name to the session users list
287 ****************************************************************************/
288 void add_session_user(char *user)
291 StrnCpy(suser,user,sizeof(suser)-1);
293 if (!Get_Pwnam(suser,True)) return;
295 if (suser && *suser && !in_list(suser,session_users,False))
297 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
298 DEBUG(1,("Too many session users??\n"));
301 pstrcat(session_users," ");
302 pstrcat(session_users,suser);
309 /****************************************************************************
310 an enhanced crypt for OSF1
311 ****************************************************************************/
312 static char *osf1_bigcrypt(char *password,char *salt1)
314 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
319 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
320 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
323 StrnCpy(salt,salt1,2);
324 StrnCpy(result,salt1,2);
326 for (i=0; i<parts;i++)
329 strncat(result,p1+2,AUTH_MAX_PASSWD_LENGTH-strlen(p1+2)-1);
330 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
331 p2 += AUTH_CLEARTEXT_SEG_CHARS;
338 /****************************************************************************
339 update the encrypted smbpasswd file from the plaintext username and password
340 *****************************************************************************/
341 BOOL update_smbpassword_file( char *user, fstring password)
343 struct smb_passwd *smbpw;
347 smbpw = getsmbpwnam(user);
352 DEBUG(0,("update_smbpassword_file: getsmbpwnam returned NULL\n"));
356 /* Here, the flag is one, because we want to ignore the XXXXXXX'd out password */
357 ret = change_oem_password( smbpw, password, True);
359 DEBUG(3,("update_smbpasswd_file: change_oem_password returned False\n"));
364 /****************************************************************************
365 update the enhanced security database. Only relevant for OSF1 at the moment.
366 ****************************************************************************/
367 static void update_protected_database( char *user, BOOL result)
370 struct pr_passwd *mypasswd;
373 mypasswd = getprpwnam (user);
374 starttime = time (NULL);
378 mypasswd->ufld.fd_slogin = starttime;
379 mypasswd->ufld.fd_nlogins = 0;
381 putprpwnam(user,mypasswd);
383 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
387 mypasswd->ufld.fd_ulogin = starttime;
388 mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
389 if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
391 mypasswd->uflg.fg_lock = 0;
392 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
394 putprpwnam ( user , mypasswd );
395 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
398 DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
404 /*******************************************************************
405 check on PAM authentication
406 ********************************************************************/
408 /* We first need some helper functions */
409 #include <security/pam_appl.h>
410 /* Static variables used to communicate between the conversation function
411 * and the server_login function
413 static char *PAM_username;
414 static char *PAM_password;
416 /* PAM conversation function
417 * Here we assume (for now, at least) that echo on means login name, and
418 * echo off means password.
420 static int PAM_conv (int num_msg,
421 const struct pam_message **msg,
422 struct pam_response **resp,
425 struct pam_response *reply = NULL;
427 #define COPY_STRING(s) (s) ? strdup(s) : NULL
429 reply = malloc(sizeof(struct pam_response) * num_msg);
430 if (!reply) return PAM_CONV_ERR;
432 for (replies = 0; replies < num_msg; replies++) {
433 switch (msg[replies]->msg_style) {
434 case PAM_PROMPT_ECHO_ON:
435 reply[replies].resp_retcode = PAM_SUCCESS;
436 reply[replies].resp = COPY_STRING(PAM_username);
439 case PAM_PROMPT_ECHO_OFF:
440 reply[replies].resp_retcode = PAM_SUCCESS;
441 reply[replies].resp = COPY_STRING(PAM_password);
448 reply[replies].resp_retcode = PAM_SUCCESS;
449 reply[replies].resp = NULL;
452 /* Must be an error of some sort... */
457 if (reply) *resp = reply;
460 static struct pam_conv PAM_conversation = {
466 static BOOL pam_auth(char *this_user,char *password)
471 /* Now use PAM to do authentication. For now, we won't worry about
472 * session logging, only authentication. Bail out if there are any
473 * errors. Since this is a limited protocol, and an even more limited
474 * function within a server speaking this protocol, we can't be as
475 * verbose as would otherwise make sense.
476 * Query: should we be using PAM_SILENT to shut PAM up?
478 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
479 pam_end(pamh, 0); return False; \
481 PAM_password = password;
482 PAM_username = this_user;
483 pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
485 /* Setting PAM_SILENT stops generation of error messages to syslog
486 * to enable debugging on Red Hat Linux set:
488 * auth required /lib/security/pam_pwdb.so nullok shadow audit
489 * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
491 pam_error = pam_authenticate(pamh, PAM_SILENT);
493 /* It is not clear to me that account management is the right thing
494 * to do, but it is not clear that it isn't, either. This can be
495 * removed if no account management should be done. Alternately,
496 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
497 pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
499 pam_end(pamh, PAM_SUCCESS);
500 /* If this point is reached, the user has been authenticated. */
507 /*******************************************************************
508 check on AFS authentication
509 ********************************************************************/
510 static BOOL afs_auth(char *this_user,char *password)
512 long password_expires = 0;
515 /* For versions of AFS prior to 3.3, this routine has few arguments, */
516 /* but since I can't find the old documentation... :-) */
518 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
520 (char *) 0, /* instance */
521 (char *) 0, /* cell */
523 0, /* lifetime, default */
524 &password_expires, /*days 'til it expires */
535 /*****************************************************************
536 This new version of the DFS_AUTH code was donated by Karsten Muuss
537 <muuss@or.uni-bonn.de>. It fixes the following problems with the
540 - Server credentials may expire
541 - Client credential cache files have wrong owner
542 - purge_context() function is called with invalid argument
544 This new code was modified to ensure that on exit the uid/gid is
545 still root, and the original directory is restored. JRA.
546 ******************************************************************/
548 sec_login_handle_t my_dce_sec_context;
549 int dcelogin_atmost_once = 0;
551 /*******************************************************************
552 check on a DCE/DFS authentication
553 ********************************************************************/
554 static BOOL dfs_auth(char *this_user,char *password)
559 signed32 expire_time, current_time;
560 boolean32 password_reset;
562 sec_passwd_rec_t passwd_rec;
563 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
564 unsigned char dce_errstr[dce_c_error_string_len];
566 if (dcelogin_atmost_once) return(False);
570 * We only go for a DCE login context if the given password
571 * matches that stored in the local password file..
572 * Assumes local passwd file is kept in sync w/ DCE RGY!
575 if ( strcmp((char *)crypt(password,this_salt),this_crypted) )
579 sec_login_get_current_context(&my_dce_sec_context, &err);
580 if (err != error_status_ok ) {
581 dce_error_inq_text(err, dce_errstr, &err2);
582 DEBUG(0,("DCE can't get current context. %s\n", dce_errstr));
587 sec_login_certify_identity(my_dce_sec_context, &err);
588 if (err != error_status_ok ) {
589 dce_error_inq_text(err, dce_errstr, &err2);
590 DEBUG(0,("DCE can't get current context. %s\n", dce_errstr));
595 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
596 if (err != error_status_ok ) {
597 dce_error_inq_text(err, dce_errstr, &err2);
598 DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
605 if (expire_time < (current_time + 60)) {
607 sec_passwd_rec_t *key;
609 sec_login_get_pwent(my_dce_sec_context,
610 (sec_login_passwd_t*)&pw, &err);
611 if (err != error_status_ok ) {
612 dce_error_inq_text(err, dce_errstr, &err2);
613 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
618 sec_login_refresh_identity(my_dce_sec_context, &err);
619 if (err != error_status_ok ) {
620 dce_error_inq_text(err, dce_errstr, &err2);
621 DEBUG(0,("DCE can't refresh identity. %s\n", dce_errstr));
626 sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
627 (unsigned char *)pw->pw_name,
628 sec_c_key_version_none,
630 if (err != error_status_ok ) {
631 dce_error_inq_text(err, dce_errstr, &err2);
632 DEBUG(0,("DCE can't get key for %s. %s\n", pw->pw_name, dce_errstr));
637 sec_login_valid_and_cert_ident(my_dce_sec_context, key,
638 &password_reset, &auth_src, &err);
639 if (err != error_status_ok ) {
640 dce_error_inq_text(err, dce_errstr, &err2);
641 DEBUG(0,("DCE can't validate and certify identity for %s. %s\n",
642 pw->pw_name, dce_errstr));
645 sec_key_mgmt_free_key(key, &err);
646 if (err != error_status_ok ) {
647 dce_error_inq_text(err, dce_errstr, &err2);
648 DEBUG(0,("DCE can't free key.\n", dce_errstr));
652 if (sec_login_setup_identity((unsigned char *)this_user,
658 dce_error_inq_text(err, dce_errstr, &err2);
659 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
660 this_user,dce_errstr));
664 sec_login_get_pwent(my_dce_sec_context,
665 (sec_login_passwd_t*)&pw, &err);
666 if (err != error_status_ok ) {
667 dce_error_inq_text(err, dce_errstr, &err2);
668 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
673 sec_login_purge_context(&my_dce_sec_context, &err);
674 if (err != error_status_ok ) {
675 dce_error_inq_text(err, dce_errstr, &err2);
676 DEBUG(0,("DCE can't purge context. %s\n", dce_errstr));
682 * NB. I'd like to change these to call something like become_user()
683 * instead but currently we don't have a connection
684 * context to become the correct user. This is already
685 * fairly platform specific code however, so I think
686 * this should be ok. I have added code to go
687 * back to being root on error though. JRA.
690 if (setregid(-1, pw->pw_gid) != 0) {
691 DEBUG(0,("Can't set egid to %d (%s)\n", pw->pw_gid, strerror(errno)));
695 if (setreuid(-1, pw->pw_uid) != 0) {
697 DEBUG(0,("Can't set euid to %d (%s)\n", pw->pw_uid, strerror(errno)));
701 if (sec_login_setup_identity((unsigned char *)this_user,
707 dce_error_inq_text(err, dce_errstr, &err2);
708 /* Go back to root, JRA. */
711 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
712 this_user,dce_errstr));
716 sec_login_get_pwent(my_dce_sec_context,
717 (sec_login_passwd_t*)&pw, &err);
718 if (err != error_status_ok ) {
719 dce_error_inq_text(err, dce_errstr, &err2);
720 /* Go back to root, JRA. */
723 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
728 passwd_rec.version_number = sec_passwd_c_version_none;
729 passwd_rec.pepper = NULL;
730 passwd_rec.key.key_type = sec_passwd_plain;
731 passwd_rec.key.tagged_union.plain = (idl_char *)password;
733 sec_login_validate_identity(my_dce_sec_context,
734 &passwd_rec, &password_reset,
736 if (err != error_status_ok ) {
737 dce_error_inq_text(err, dce_errstr, &err2);
738 /* Go back to root, JRA. */
741 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
742 this_user,dce_errstr));
747 sec_login_certify_identity(my_dce_sec_context, &err);
748 if (err != error_status_ok ) {
749 dce_error_inq_text(err, dce_errstr, &err2);
750 /* Go back to root, JRA. */
753 DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr));
758 if (auth_src != sec_login_auth_src_network) {
759 DEBUG(0,("DCE context has no network credentials.\n"));
762 sec_login_set_context(my_dce_sec_context, &err);
763 if (err != error_status_ok ) {
764 dce_error_inq_text(err, dce_errstr, &err2);
765 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
766 this_user,dce_errstr));
768 sec_login_purge_context(&my_dce_sec_context, &err);
769 /* Go back to root, JRA. */
775 sec_login_get_pwent(my_dce_sec_context,
776 (sec_login_passwd_t*)&pw, &err);
777 if (err != error_status_ok ) {
778 dce_error_inq_text(err, dce_errstr, &err2);
779 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
781 /* Go back to root, JRA. */
787 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
788 this_user, getpid()));
790 DEBUG(3,("DCE principal: %s\n"
793 pw->pw_name, pw->pw_uid, pw->pw_gid));
794 DEBUG(3,(" info: %s\n"
797 pw->pw_gecos, pw->pw_dir, pw->pw_shell));
799 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
800 if (err != error_status_ok ) {
801 dce_error_inq_text(err, dce_errstr, &err2);
802 /* Go back to root, JRA. */
805 DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
813 DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time))));
815 dcelogin_atmost_once = 1;
819 void dfs_unlogin(void)
823 unsigned char dce_errstr[dce_c_error_string_len];
825 sec_login_purge_context(&my_dce_sec_context, &err);
826 if (err != error_status_ok )
828 dce_error_inq_text(err, dce_errstr, &err2);
829 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
830 getpid(), dce_errstr));
836 /*******************************************************************
837 check on Kerberos authentication
838 ********************************************************************/
839 static BOOL krb5_auth(char *this_user,char *password)
841 krb5_data tgtname = {
846 krb5_context kcontext;
847 krb5_principal kprinc;
848 krb5_principal server;
851 krb5_address **addrs = (krb5_address **)0;
852 krb5_preauthtype *preauth = NULL;
853 krb5_keytab keytab = NULL;
855 krb5_ccache ccache = NULL;
859 if ( retval=krb5_init_context(&kcontext))
864 if ( retval = krb5_timeofday(kcontext, &now) )
869 if ( retval = krb5_cc_default(kcontext, &ccache) )
874 if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
879 memset((char *)&kcreds, 0, sizeof(kcreds));
881 kcreds.client = kprinc;
883 if ((retval = krb5_build_principal_ext(kcontext, &server,
884 krb5_princ_realm(kcontext, kprinc)->length,
885 krb5_princ_realm(kcontext, kprinc)->data,
888 krb5_princ_realm(kcontext, kprinc)->length,
889 krb5_princ_realm(kcontext, kprinc)->data,
895 kcreds.server = server;
897 retval = krb5_get_in_tkt_with_password(kcontext,
914 #endif /* KRB5_AUTH */
917 /*******************************************************************
918 check on Kerberos authentication
919 ********************************************************************/
920 static BOOL krb4_auth(char *this_user,char *password)
922 char realm[REALM_SZ];
923 char tkfile[MAXPATHLEN];
925 if (krb_get_lrealm(realm, 1) != KSUCCESS)
926 (void) safe_strcpy(realm, KRB_REALM, sizeof (realm) - 1);
928 (void) slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d", getpid());
930 krb_set_tkt_string(tkfile);
931 if (krb_verify_user(this_user, "", realm,
933 "rmcd") == KSUCCESS) {
940 #endif /* KRB4_AUTH */
942 #ifdef LINUX_BIGCRYPT
943 /****************************************************************************
944 an enhanced crypt for Linux to handle password longer than 8 characters
945 ****************************************************************************/
946 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
948 #define LINUX_PASSWORD_SEG_CHARS 8
952 StrnCpy(salt,salt1,2);
955 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
956 char * p = crypt(password,salt) + 2;
957 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
959 password += LINUX_PASSWORD_SEG_CHARS;
960 crypted += strlen(p);
968 /****************************************************************************
969 apply a function to upper/lower case combinations
970 of a string and return true if one of them returns true.
971 try all combinations with N uppercase letters.
972 offset is the first char to try and change (start with 0)
973 it assumes the string starts lowercased
974 ****************************************************************************/
975 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(char *),int N)
980 #ifdef PASSWORD_LENGTH
981 len = MIN(len,PASSWORD_LENGTH);
984 if (N <= 0 || offset >= len)
987 for (i=offset;i<(len-(N-1));i++)
990 if (!islower(c)) continue;
992 if (string_combinations2(s,i+1,fn,N-1))
999 /****************************************************************************
1000 apply a function to upper/lower case combinations
1001 of a string and return true if one of them returns true.
1002 try all combinations with up to N uppercase letters.
1003 offset is the first char to try and change (start with 0)
1004 it assumes the string starts lowercased
1005 ****************************************************************************/
1006 static BOOL string_combinations(char *s,BOOL (*fn)(char *),int N)
1010 if (string_combinations2(s,0,fn,n)) return(True);
1016 /****************************************************************************
1017 core of password checking routine
1018 ****************************************************************************/
1019 BOOL password_check(char *password)
1023 /* This falls through if the password check fails
1024 - if HAVE_CRYPT is not defined this causes an error msg
1025 saying Warning - no crypt available
1026 - if HAVE_CRYPT is defined this is a potential security hole
1027 as it may authenticate via the crypt call when PAM
1028 settings say it should fail.
1029 if (pam_auth(this_user,password)) return(True);
1030 Hence we make a direct return to avoid a second chance!!!
1032 return (pam_auth(this_user,password));
1036 if (afs_auth(this_user,password)) return(True);
1040 if (dfs_auth(this_user,password)) return(True);
1044 if (krb5_auth(this_user,password)) return(True);
1048 if (krb4_auth(this_user,password)) return(True);
1053 BOOL ret = (strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
1055 DEBUG(2,("password_check: OSF1_ENH_SEC failed. Trying normal crypt.\n"));
1056 ret = (strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
1063 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
1066 #ifdef LINUX_BIGCRYPT
1067 return(linux_bigcrypt(password,this_salt,this_crypted));
1070 #ifdef HAVE_BIGCRYPT
1071 return(strcmp(bigcrypt(password,this_salt),this_crypted) == 0);
1075 DEBUG(1,("Warning - no crypt available\n"));
1078 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
1082 /****************************************************************************
1083 core of smb password checking routine.
1084 ****************************************************************************/
1085 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
1087 /* Finish the encryption of part_passwd. */
1088 unsigned char p21[21];
1089 unsigned char p24[24];
1091 if (part_passwd == NULL)
1092 DEBUG(10,("No password set - allowing access\n"));
1093 /* No password set - always true ! */
1094 if (part_passwd == NULL)
1097 memset(p21,'\0',21);
1098 memcpy(p21,part_passwd,16);
1099 E_P24(p21, c8, p24);
1103 DEBUG(100,("Part password (P16) was |"));
1104 for(i = 0; i < 16; i++)
1105 DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
1107 DEBUG(100,("Password from client was |"));
1108 for(i = 0; i < 24; i++)
1109 DEBUG(100,("%X ", (unsigned char)password[i]));
1111 DEBUG(100,("Given challenge was |"));
1112 for(i = 0; i < 8; i++)
1113 DEBUG(100,("%X ", (unsigned char)c8[i]));
1115 DEBUG(100,("Value from encryption was |"));
1116 for(i = 0; i < 24; i++)
1117 DEBUG(100,("%X ", (unsigned char)p24[i]));
1121 return (memcmp(p24, password, 24) == 0);
1124 /****************************************************************************
1125 Do a specific test for an smb password being correct, given a smb_password and
1126 the lanman and NT responses.
1127 ****************************************************************************/
1129 BOOL smb_password_ok(struct smb_passwd *smb_pass,
1130 uchar lm_pass[24], uchar nt_pass[24])
1134 if (!lm_pass || !smb_pass) return(False);
1136 if(smb_pass->acct_ctrl & ACB_DISABLED)
1138 DEBUG(3,("smb_password_ok: account for user %s was disabled.\n", smb_pass->smb_name));
1142 if (!last_challenge(challenge))
1144 DEBUG(1,("smb_password_ok: no challenge done - password failed\n"));
1148 DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n", smb_pass->smb_name));
1150 if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL))
1152 /* We have the NT MD4 hash challenge available - see if we can
1153 use it (ie. does it exist in the smbpasswd file).
1155 DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
1156 if (smb_password_check((char *)nt_pass, (uchar *)smb_pass->smb_nt_passwd, challenge))
1158 DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n"));
1161 DEBUG(4,("smb_password_ok: NT MD4 password check failed\n"));
1164 /* Try against the lanman password. smb_pass->smb_passwd == NULL means
1165 no password, allow access. */
1167 DEBUG(4,("Checking LM MD4 password\n"));
1169 if((smb_pass->smb_passwd == NULL) && (smb_pass->acct_ctrl & ACB_PWNOTREQ))
1171 DEBUG(4,("smb_password_ok: no password required for user %s\n", smb_pass->smb_name));
1175 if((smb_pass->smb_passwd != NULL) && smb_password_check((char *)lm_pass, (uchar *)smb_pass->smb_passwd, challenge))
1177 DEBUG(4,("smb_password_ok: LM MD4 password check succeeded\n"));
1181 DEBUG(4,("smb_password_ok: LM MD4 password check failed\n"));
1186 /****************************************************************************
1187 check if a username/password is OK
1188 ****************************************************************************/
1189 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
1192 int level = lp_passwordlevel();
1193 struct passwd *pass;
1195 struct smb_passwd *smb_pass;
1196 BOOL update_encrypted = lp_update_encrypted();
1197 BOOL challenge_done = False;
1199 if (password) password[pwlen] = 0;
1202 challenge_done = last_challenge(challenge);
1208 DEBUG(100,("checking user=[%s] pass=[",user));
1209 for( i = 0; i < 24; i++)
1210 DEBUG(100,("%0x ", (unsigned char)password[i]));
1213 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
1220 if (((!*password) || (!pwlen)) && !lp_null_passwords())
1225 pass = (struct passwd *) pwd;
1226 user = pass->pw_name;
1229 pass = Get_Pwnam(user,True);
1231 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
1233 if ((pwlen == 24) && challenge_done)
1235 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
1239 DEBUG(3,("Couldn't find user %s\n",user));
1243 smb_pass = getsmbpwnam(user);
1247 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
1251 /* Quit if the account was disabled. */
1252 if(smb_pass->acct_ctrl & ACB_DISABLED)
1254 DEBUG(3,("password_ok: account for user %s was disabled.\n", user));
1258 /* Ensure the uid's match */
1259 if (smb_pass->smb_userid != pass->pw_uid)
1261 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
1265 if(smb_password_ok( smb_pass, (unsigned char *)password,(uchar *)password))
1267 update_protected_database(user,True);
1271 DEBUG(3,("Error smb_password_check failed\n"));
1274 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
1278 DEBUG(3,("Couldn't find user %s\n",user));
1282 #ifdef HAVE_GETSPNAM
1286 /* many shadow systems require you to be root to get the password,
1287 in most cases this should already be the case when this
1288 function is called, except perhaps for IPC password changing
1291 spass = getspnam(pass->pw_name);
1292 if (spass && spass->sp_pwdp)
1293 pass->pw_passwd = spass->sp_pwdp;
1295 #elif defined(IA_UINFO)
1297 /* Need to get password with SVR4.2's ia_ functions instead of
1298 get{sp,pw}ent functions. Required by UnixWare 2.x, tested on
1299 version 2.1. (tangent@cyberport.com) */
1301 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
1302 ia_get_logpwd(uinfo, &(pass->pw_passwd));
1306 #ifdef HAVE_GETPRPWNAM
1308 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1309 if (pr_pw && pr_pw->ufld.fd_encrypt)
1310 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1316 struct pr_passwd *mypasswd;
1317 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
1318 mypasswd = getprpwnam (user);
1321 fstrcpy(pass->pw_name,mypasswd->ufld.fd_name);
1322 fstrcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
1326 DEBUG(5,("No entry for user %s in protected database !\n",user));
1334 AUTHORIZATION *ap = getauthuid( pass->pw_uid );
1337 fstrcpy( pass->pw_passwd, ap->a_password );
1343 /* extract relevant info */
1344 fstrcpy(this_user,pass->pw_name);
1345 fstrcpy(this_salt,pass->pw_passwd);
1346 /* crypt on some platforms (HPUX in particular)
1347 won't work with more than 2 salt characters. */
1350 fstrcpy(this_crypted,pass->pw_passwd);
1352 if (!*this_crypted) {
1353 if (!lp_null_passwords()) {
1354 DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
1358 DEBUG(3,("Allowing access to %s with null password\n",this_user));
1363 /* try it as it came to us */
1364 if (password_check(password))
1366 update_protected_database(user,True);
1367 if (update_encrypted)
1368 update_smbpassword_file(user,password);
1372 /* if the password was given to us with mixed case then we don't
1373 need to proceed as we know it hasn't been case modified by the
1375 if (strhasupper(password) && strhaslower(password))
1378 /* make a copy of it */
1379 StrnCpy(pass2,password,sizeof(pstring)-1);
1381 /* try all lowercase */
1383 if (password_check(password))
1385 update_protected_database(user,True);
1386 if (update_encrypted)
1387 update_smbpassword_file(user,password);
1394 update_protected_database(user,False);
1397 fstrcpy(password,pass2);
1402 /* last chance - all combinations of up to level chars upper! */
1405 if (string_combinations(password,password_check,level))
1407 update_protected_database(user,True);
1408 if (update_encrypted)
1409 update_smbpassword_file(user,password);
1413 update_protected_database(user,False);
1416 fstrcpy(password,pass2);
1423 /****************************************************************************
1424 check if a username is valid
1425 ****************************************************************************/
1426 BOOL user_ok(char *user,int snum)
1428 pstring valid, invalid;
1431 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
1432 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
1434 string_sub(valid,"%S",lp_servicename(snum));
1435 string_sub(invalid,"%S",lp_servicename(snum));
1437 ret = !user_in_list(user,invalid);
1439 if (ret && valid && *valid)
1440 ret = user_in_list(user,valid);
1442 if (ret && lp_onlyuser(snum)) {
1443 char *user_list = lp_username(snum);
1444 string_sub(user_list,"%S",lp_servicename(snum));
1445 ret = user_in_list(user,user_list);
1454 /****************************************************************************
1455 validate a group username entry. Return the username or NULL
1456 ****************************************************************************/
1457 static char *validate_group(char *group,char *password,int pwlen,int snum)
1459 #ifdef HAVE_NETGROUP
1461 char *host, *user, *domain;
1463 while (getnetgrent(&host, &user, &domain)) {
1465 if (user_ok(user, snum) &&
1466 password_ok(user,password,pwlen,NULL)) {
1476 #ifdef HAVE_GETGRNAM
1478 struct group *gptr = (struct group *)getgrnam(group);
1482 member = gptr->gr_mem;
1483 while (member && *member)
1485 static fstring name;
1486 fstrcpy(name,*member);
1487 if (user_ok(name,snum) &&
1488 password_ok(name,password,pwlen,NULL))
1492 #ifdef GROUP_CHECK_PWENT
1498 while (pwd = getpwent ()) {
1499 if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
1500 /* This Entry have PASSWORD and same GID then check pwd */
1501 if (password_ok(NULL, password, pwlen, pwd)) {
1502 fstrcpy(tm, pwd->pw_name);
1510 #endif /* GROUP_CHECK_PWENT */
1519 /****************************************************************************
1520 check for authority to login to a service with a given username/password
1521 ****************************************************************************/
1522 BOOL authorise_login(int snum,char *user,char *password, int pwlen,
1523 BOOL *guest,BOOL *force,uint16 vuid)
1530 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1533 /* there are several possibilities:
1534 1) login as the given user with given password
1535 2) login as a previously registered username with the given password
1536 3) login as a session list username with the given password
1537 4) login as a previously validated user/password pair
1538 5) login as the "user =" user with given password
1539 6) login as the "user =" user with no password (guest connection)
1540 7) login as guest user with no password
1542 if the service is guest_only then steps 1 to 5 are skipped
1545 if (GUEST_ONLY(snum)) *force = True;
1547 if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1550 user_struct *vuser = get_valid_user_struct(vuid);
1552 /* check the given username and password */
1553 if (!ok && (*user) && user_ok(user,snum)) {
1554 ok = password_ok(user,password, pwlen, NULL);
1555 if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
1558 /* check for a previously registered guest username */
1559 if (!ok && (vuser != 0) && vuser->guest) {
1560 if (user_ok(vuser->name,snum) &&
1561 password_ok(vuser->name, password, pwlen, NULL)) {
1562 fstrcpy(user, vuser->name);
1563 vuser->guest = False;
1564 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
1570 /* now check the list of session users */
1574 char *user_list = strdup(session_users);
1575 if (!user_list) return(False);
1577 for (auser=strtok(user_list,LIST_SEP);
1579 auser = strtok(NULL,LIST_SEP))
1582 fstrcpy(user2,auser);
1583 if (!user_ok(user2,snum)) continue;
1585 if (password_ok(user2,password, pwlen, NULL)) {
1587 fstrcpy(user,user2);
1588 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1594 /* check for a previously validated username/password pair */
1595 if (!ok && (!lp_revalidate(snum) || lp_security() > SEC_SHARE) &&
1596 (vuser != 0) && !vuser->guest &&
1597 user_ok(vuser->name,snum)) {
1598 fstrcpy(user,vuser->name);
1600 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1604 /* check for a rhosts entry */
1605 if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1607 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1610 /* check the user= fields and the given password */
1611 if (!ok && lp_username(snum)) {
1614 StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1616 string_sub(user_list,"%S",lp_servicename(snum));
1618 for (auser=strtok(user_list,LIST_SEP);
1620 auser = strtok(NULL,LIST_SEP))
1624 auser = validate_group(auser+1,password,pwlen,snum);
1628 fstrcpy(user,auser);
1629 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1635 fstrcpy(user2,auser);
1636 if (user_ok(user2,snum) &&
1637 password_ok(user2,password,pwlen,NULL))
1640 fstrcpy(user,user2);
1641 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1646 } /* not guest only */
1648 /* check for a normal guest connection */
1649 if (!ok && GUEST_OK(snum))
1652 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1653 if (Get_Pwnam(guestname,True))
1655 fstrcpy(user,guestname);
1657 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1660 DEBUG(0,("Invalid guest account %s??\n",guestname));
1665 if (ok && !user_ok(user,snum))
1667 DEBUG(0,("rejected invalid user %s\n",user));
1675 /****************************************************************************
1676 read the a hosts.equiv or .rhosts file and check if it
1677 allows this user from this machine
1678 ****************************************************************************/
1679 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1682 int plus_allowed = 1;
1685 FILE *fp = fopen(equiv_file, "r");
1686 DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1687 if (! fp) return False;
1688 while(fgets(buf, sizeof(buf), fp))
1690 trim_string(buf," "," ");
1692 if (buf[0] != '#' && buf[0] != '\n')
1694 BOOL is_group = False;
1697 if (strcmp(buf, "NO_PLUS\n") == 0)
1699 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1706 if (*bp == '\n' && plus_allowed)
1708 /* a bare plus means everbody allowed */
1709 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1714 else if (buf[0] == '-')
1724 file_host = strtok(bp, " \t\n");
1725 file_user = strtok(NULL, " \t\n");
1726 DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)",
1727 file_user ? file_user : "(null)" ));
1728 if (file_host && *file_host)
1730 BOOL host_ok = False;
1732 #ifdef HAVE_NETGROUP
1735 static char *mydomain = NULL;
1737 yp_get_default_domain(&mydomain);
1738 if (mydomain && innetgr(file_host,remote,user,mydomain))
1744 DEBUG(1,("Netgroups not configured\n"));
1749 /* is it this host */
1750 /* the fact that remote has come from a call of gethostbyaddr
1751 * means that it may have the fully qualified domain name
1752 * so we could look up the file version to get it into
1753 * a canonical form, but I would rather just type it
1754 * in full in the equiv file
1756 if (!host_ok && !is_group && strequal(remote, file_host))
1762 /* is it this user */
1763 if (file_user == 0 || strequal(user, file_user))
1766 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1767 (plus ? "+" : "-"), file_host,
1768 (file_user ? file_user : "")));
1769 return (plus ? True : False);
1780 /****************************************************************************
1781 check for a possible hosts equiv or rhosts entry for the user
1782 ****************************************************************************/
1783 BOOL check_hosts_equiv(char *user)
1787 struct passwd *pass = Get_Pwnam(user,True);
1792 fname = lp_hosts_equiv();
1794 /* note: don't allow hosts.equiv on root */
1795 if (fname && *fname && (pass->pw_uid != 0)) {
1797 if (check_user_equiv(user,client_name(Client),fname))
1801 if (lp_use_rhosts())
1803 char *home = get_home_dir(user);
1806 slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
1807 if (check_user_equiv(user,client_name(Client),rhostsfile))
1816 static struct cli_state pw_cli;
1818 /****************************************************************************
1819 return the client state structure
1820 ****************************************************************************/
1821 struct cli_state *server_client(void)
1826 /****************************************************************************
1827 support for server level security
1828 ****************************************************************************/
1829 struct cli_state *server_cryptkey(void)
1832 struct in_addr dest_ip;
1833 extern fstring local_machine;
1835 BOOL connected_ok = False;
1837 if (!cli_initialise(&pw_cli))
1840 p = lp_passwordserver();
1841 while(p && next_token( &p, desthost, LIST_SEP)) {
1842 standard_sub_basic(desthost);
1845 if(!resolve_name( desthost, &dest_ip)) {
1846 DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
1850 if (ismyip(dest_ip)) {
1851 DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
1855 if (cli_connect(&pw_cli, desthost, &dest_ip)) {
1856 DEBUG(3,("connected to password server %s\n",desthost));
1857 connected_ok = True;
1862 if (!connected_ok) {
1863 DEBUG(0,("password server not available\n"));
1864 cli_shutdown(&pw_cli);
1868 if (!cli_session_request(&pw_cli, desthost, 0x20, local_machine)) {
1869 DEBUG(1,("%s rejected the session\n",desthost));
1870 cli_shutdown(&pw_cli);
1874 DEBUG(3,("got session\n"));
1876 if (!cli_negprot(&pw_cli)) {
1877 DEBUG(1,("%s rejected the negprot\n",desthost));
1878 cli_shutdown(&pw_cli);
1882 if (pw_cli.protocol < PROTOCOL_LANMAN2 ||
1883 !(pw_cli.sec_mode & 1)) {
1884 DEBUG(1,("%s isn't in user level security mode\n",desthost));
1885 cli_shutdown(&pw_cli);
1889 DEBUG(3,("password server OK\n"));
1894 /****************************************************************************
1895 validate a password with the password server
1896 ****************************************************************************/
1897 BOOL server_validate(char *user, char *domain,
1898 char *pass, int passlen,
1899 char *ntpass, int ntpasslen)
1901 extern fstring local_machine;
1902 static unsigned char badpass[24];
1904 if (!pw_cli.initialised) {
1905 DEBUG(1,("password server %s is not connected\n", pw_cli.desthost));
1909 if(badpass[0] == 0) {
1910 memset(badpass, 0x1f, sizeof(badpass));
1913 if((passlen == sizeof(badpass)) && !memcmp(badpass, pass, passlen)) {
1914 /* Very unlikely, our random bad password is the same as the users
1916 memset(badpass, badpass[0]+1, sizeof(badpass));
1920 * Attempt a session setup with a totally incorrect password.
1921 * If this succeeds with the guest bit *NOT* set then the password
1922 * server is broken and is not correctly setting the guest bit. We
1923 * need to detect this as some versions of NT4.x are broken. JRA.
1926 if (cli_session_setup(&pw_cli, user, (char *)badpass, sizeof(badpass),
1927 (char *)badpass, sizeof(badpass), domain)) {
1928 if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) == 0) {
1929 DEBUG(0,("server_validate: password server %s allows users as non-guest \
1930 with a bad password.\n", pw_cli.desthost));
1931 DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
1932 use this machine as the password server.\n"));
1933 cli_ulogoff(&pw_cli);
1936 cli_ulogoff(&pw_cli);
1940 * Now we know the password server will correctly set the guest bit, or is
1941 * not guest enabled, we can try with the real password.
1944 if (!cli_session_setup(&pw_cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
1945 DEBUG(1,("password server %s rejected the password\n", pw_cli.desthost));
1949 /* if logged in as guest then reject */
1950 if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) != 0) {
1951 DEBUG(1,("password server %s gave us guest only\n", pw_cli.desthost));
1952 cli_ulogoff(&pw_cli);
1957 * This patch from Rob Nielsen <ran@adc.com> makes doing
1958 * the NetWksaUserLogon a dynamic, rather than compile-time
1959 * parameter, defaulting to on. This is somewhat dangerous
1960 * as it allows people to turn off this neccessary check,
1961 * but so many people have had problems with this that I
1962 * think it is a neccessary change. JRA.
1965 if (lp_net_wksta_user_logon()) {
1966 DEBUG(3,("trying NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
1968 if (!cli_send_tconX(&pw_cli, "IPC$", "IPC", "", 1)) {
1969 DEBUG(0,("password server %s refused IPC$ connect\n", pw_cli.desthost));
1970 cli_ulogoff(&pw_cli);
1974 if (!cli_NetWkstaUserLogon(&pw_cli,user,local_machine)) {
1975 DEBUG(0,("password server %s failed NetWkstaUserLogon\n", pw_cli.desthost));
1977 cli_ulogoff(&pw_cli);
1981 if (pw_cli.privilages == 0) {
1982 DEBUG(0,("password server %s gave guest privilages\n", pw_cli.desthost));
1984 cli_ulogoff(&pw_cli);
1988 if (!strequal(pw_cli.eff_name, user)) {
1989 DEBUG(0,("password server %s gave different username %s\n",
1993 cli_ulogoff(&pw_cli);
1999 DEBUG(3,("skipping NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
2002 DEBUG(3,("password server %s accepted the password\n", pw_cli.desthost));
2004 cli_ulogoff(&pw_cli);
2009 /***********************************************************************
2010 Do the same as security=server, but using NT Domain calls and a session
2011 key from the machine password.
2012 ************************************************************************/
2014 BOOL domain_client_validate( char *user, char *domain,
2015 char *smb_apasswd, int smb_apasslen,
2016 char *smb_ntpasswd, int smb_ntpasslen)
2018 unsigned char local_challenge[8];
2019 unsigned char local_lm_response[24];
2020 unsigned char local_nt_reponse[24];
2021 unsigned char trust_passwd[16];
2023 fstring remote_machine;
2025 struct in_addr dest_ip;
2026 NET_ID_INFO_CTR ctr;
2027 NET_USER_INFO_3 info3;
2028 struct cli_state cli;
2030 BOOL connected_ok = False;
2033 * Check that the requested domain is not our own machine name.
2034 * If it is, we should never check the PDC here, we use our own local
2038 if(strequal( domain, global_myname)) {
2039 DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
2044 * Next, check that the passwords given were encrypted.
2047 if(((smb_apasslen != 24) && (smb_apasslen != 0)) ||
2048 ((smb_ntpasslen != 24) && (smb_ntpasslen != 0))) {
2051 * Not encrypted - do so.
2054 DEBUG(3,("domain_client_validate: User passwords not in encrypted format.\n"));
2055 generate_random_buffer( local_challenge, 8, False);
2056 SMBencrypt( (uchar *)smb_apasswd, local_challenge, local_lm_response);
2057 SMBNTencrypt((uchar *)smb_ntpasswd, local_challenge, local_nt_reponse);
2060 smb_apasswd = (char *)local_lm_response;
2061 smb_ntpasswd = (char *)local_nt_reponse;
2065 * Encrypted - get the challenge we sent for these
2069 if (!last_challenge(local_challenge)) {
2070 DEBUG(0,("domain_client_validate: no challenge done - password failed\n"));
2076 * Get the machine account password.
2078 if(!trust_password_lock( global_myworkgroup, global_myname, False)) {
2079 DEBUG(0,("domain_client_validate: unable to open the machine account password file for \
2080 machine %s in domain %s.\n", global_myname, global_myworkgroup ));
2084 if(get_trust_account_password( trust_passwd, &lct) == False) {
2085 DEBUG(0,("domain_client_validate: unable to read the machine account password for \
2086 machine %s in domain %s.\n", global_myname, global_myworkgroup ));
2087 trust_password_unlock();
2091 trust_password_unlock();
2094 * Here we should check the last change time to see if the machine
2095 * password needs changing..... TODO... JRA.
2098 if(time(NULL) > lct + lp_machine_password_timeout())
2099 global_machine_pasword_needs_changing = True;
2102 * At this point, smb_apasswd points to the lanman response to
2103 * the challenge in local_challenge, and smb_ntpasswd points to
2104 * the NT response to the challenge in local_challenge. Ship
2105 * these over the secure channel to a domain controller and
2106 * see if they were valid.
2109 memset(&cli, '\0', sizeof(struct cli_state));
2110 if(cli_initialise(&cli) == False) {
2111 DEBUG(0,("domain_client_validate: unable to initialize client connection.\n"));
2116 * Treat each name in the 'password server =' line as a potential
2117 * PDC/BDC. Contact each in turn and try and authenticate.
2120 p = lp_passwordserver();
2121 while(p && next_token( &p, remote_machine, LIST_SEP)) {
2123 standard_sub_basic(remote_machine);
2124 strupper(remote_machine);
2126 if(!resolve_name( remote_machine, &dest_ip)) {
2127 DEBUG(1,("domain_client_validate: Can't resolve address for %s\n", remote_machine));
2131 if (ismyip(dest_ip)) {
2132 DEBUG(1,("domain_client_validate: Password server loop - not using password server %s\n",remote_machine));
2136 if (!cli_connect(&cli, remote_machine, &dest_ip)) {
2137 DEBUG(0,("domain_client_validate: unable to connect to SMB server on \
2138 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2142 if (!cli_session_request(&cli, remote_machine, 0x20, global_myname)) {
2143 DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
2144 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2149 cli.protocol = PROTOCOL_NT1;
2151 if (!cli_negprot(&cli)) {
2152 DEBUG(0,("domain_client_validate: machine %s rejected the negotiate protocol. \
2153 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2158 if (cli.protocol != PROTOCOL_NT1) {
2159 DEBUG(0,("domain_client_validate: machine %s didn't negotiate NT protocol.\n",
2166 * Do an anonymous session setup.
2169 if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
2170 DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
2171 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2176 if (!(cli.sec_mode & 1)) {
2177 DEBUG(1,("domain_client_validate: machine %s isn't in user level security mode\n",
2183 if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
2184 DEBUG(0,("domain_client_validate: machine %s rejected the tconX on the IPC$ share. \
2185 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2191 * We have an anonymous connection to IPC$.
2193 connected_ok = True;
2197 if (!connected_ok) {
2198 DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
2204 * Ok - we have an anonymous connection to the IPC$ share.
2205 * Now start the NT Domain stuff :-).
2208 if(cli_nt_session_open(&cli, PIPE_NETLOGON, False) == False) {
2209 DEBUG(0,("domain_client_validate: unable to open the domain client session to \
2210 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
2211 cli_nt_session_close(&cli);
2217 if(cli_nt_setup_creds(&cli, trust_passwd) == False) {
2218 DEBUG(0,("domain_client_validate: unable to setup the PDC credentials to machine \
2219 %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
2220 cli_nt_session_close(&cli);
2226 /* We really don't care what LUID we give the user. */
2227 generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
2229 if(cli_nt_login_network(&cli, domain, user, smb_uid_low, (char *)local_challenge,
2230 ((smb_apasslen != 0) ? smb_apasswd : NULL),
2231 ((smb_ntpasslen != 0) ? smb_ntpasswd : NULL),
2232 &ctr, &info3) == False) {
2233 DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
2234 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
2235 cli_nt_session_close(&cli);
2242 * Here, if we really want it, we have lots of info about the user in info3.
2247 * We don't actually need to do this - plus it fails currently with
2248 * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
2252 if(cli_nt_logoff(&cli, &ctr) == False) {
2253 DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
2254 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
2255 cli_nt_session_close(&cli);
2262 cli_nt_session_close(&cli);