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 && (vuser->groups != (gid_t *)vuser->igroups))
143 if (vuser->igroups) free(vuser->igroups);
144 if (vuser->sids ) free(vuser->sids);
147 vuser->igroups = NULL;
148 vuser->groups = NULL;
152 /****************************************************************************
153 return a validated username
154 ****************************************************************************/
155 char *validated_username(uint16 vuid)
157 user_struct *vuser = get_valid_user_struct(vuid);
164 /****************************************************************************
165 Setup the groups a user belongs to.
166 ****************************************************************************/
167 int setup_groups(char *user, int uid, int gid, int *p_ngroups,
168 int **p_igroups, gid_t **p_groups)
170 if (-1 == initgroups(user,gid))
174 DEBUG(0,("Unable to initgroups!\n"));
175 if (gid < 0 || gid > 16000 || uid < 0 || uid > 16000)
176 DEBUG(0,("This is probably a problem with the account %s\n",user));
184 ngroups = getgroups(0,&grp);
187 igroups = (int *)malloc(sizeof(int)*ngroups);
188 for (i=0;i<ngroups;i++)
189 igroups[i] = 0x42424242;
190 ngroups = getgroups(ngroups,(gid_t *)igroups);
192 if (igroups[0] == 0x42424242)
195 *p_ngroups = ngroups;
197 /* The following bit of code is very strange. It is due to the
198 fact that some OSes use int* and some use gid_t* for
199 getgroups, and some (like SunOS) use both, one in prototypes,
200 and one in man pages and the actual code. Thus we detect it
201 dynamically using some very ugly code */
204 /* does getgroups return ints or gid_t ?? */
205 static BOOL groups_use_ints = True;
207 if (groups_use_ints &&
209 SVAL(igroups,2) == 0x4242)
210 groups_use_ints = False;
212 for (i=0;groups_use_ints && i<ngroups;i++)
213 if (igroups[i] == 0x42424242)
214 groups_use_ints = False;
218 *p_igroups = igroups;
219 *p_groups = (gid_t *)igroups;
223 gid_t *groups = (gid_t *)igroups;
224 igroups = (int *)malloc(sizeof(int)*ngroups);
225 for (i=0;i<ngroups;i++)
227 igroups[i] = groups[i];
229 *p_igroups = igroups;
230 *p_groups = (gid_t *)groups;
233 DEBUG(3,("%s is in %d groups\n",user,ngroups));
234 for (i=0;i<ngroups;i++)
235 DEBUG(3,("%d ",igroups[i]));
242 /****************************************************************************
243 register a uid/name pair as being valid and that a valid password
244 has been given. vuid is biased by an offset. This allows us to
245 tell random client vuid's (normally zero) from valid vuids.
246 ****************************************************************************/
247 uint16 register_vuid(int uid,int gid, char *unix_name, char *requested_name, BOOL guest)
250 struct passwd *pwfile; /* for getting real name from passwd file */
252 /* Ensure no vuid gets registered in share level security. */
253 if(lp_security() == SEC_SHARE)
254 return UID_FIELD_INVALID;
258 * After observing MS-Exchange services writing to a Samba share
259 * I belive this code is incorrect. Each service does its own
260 * sessionsetup_and_X for the same user, and as each service shuts
261 * down, it does a user_logoff_and_X. As we are consolidating multiple
262 * sessionsetup_and_X's onto the same vuid here, when the first service
263 * shuts down, it invalidates all the open files for the other services.
264 * Hence I am removing this code and forcing each sessionsetup_and_X
266 * Jeremy Allison. (jallison@whistle.com).
270 for(i = 0; i < num_validated_users; i++) {
271 vuser = &validated_users[i];
272 if ( vuser->uid == uid )
273 return (uint16)(i + VUID_OFFSET); /* User already validated */
277 validated_users = (user_struct *)Realloc(validated_users,
279 (num_validated_users+1));
281 if (!validated_users)
283 DEBUG(0,("Failed to realloc users struct!\n"));
284 num_validated_users = 0;
285 return UID_FIELD_INVALID;
288 vuser = &validated_users[num_validated_users];
289 num_validated_users++;
293 vuser->guest = guest;
294 fstrcpy(vuser->name,unix_name);
295 fstrcpy(vuser->requested_name,requested_name);
301 vuser->groups = NULL;
302 vuser->igroups = NULL;
304 /* Find all the groups this uid is in and store them.
305 Used by become_user() */
306 setup_groups(unix_name,uid,gid,
311 DEBUG(3,("uid %d registered to name %s\n",uid,unix_name));
313 DEBUG(3, ("Clearing default real name\n"));
314 fstrcpy(vuser->real_name, "<Full Name>\0");
315 if (lp_unix_realname()) {
316 if ((pwfile=getpwnam(vuser->name))!= NULL)
318 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
319 fstrcpy(vuser->real_name, pwfile->pw_gecos);
323 return (uint16)((num_validated_users - 1) + VUID_OFFSET);
327 /****************************************************************************
328 add a name to the session users list
329 ****************************************************************************/
330 void add_session_user(char *user)
333 StrnCpy(suser,user,sizeof(suser)-1);
335 if (!Get_Pwnam(suser,True)) return;
337 if (suser && *suser && !in_list(suser,session_users,False))
339 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
340 DEBUG(1,("Too many session users??\n"));
343 pstrcat(session_users," ");
344 pstrcat(session_users,suser);
351 /****************************************************************************
352 an enhanced crypt for OSF1
353 ****************************************************************************/
354 static char *osf1_bigcrypt(char *password,char *salt1)
356 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
361 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
362 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
365 StrnCpy(salt,salt1,2);
366 StrnCpy(result,salt1,2);
368 for (i=0; i<parts;i++)
371 strncat(result,p1+2,AUTH_MAX_PASSWD_LENGTH-strlen(p1+2)-1);
372 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
373 p2 += AUTH_CLEARTEXT_SEG_CHARS;
380 /****************************************************************************
381 update the encrypted smbpasswd file from the plaintext username and password
382 *****************************************************************************/
383 BOOL update_smbpassword_file( char *user, fstring password)
385 struct smb_passwd *smbpw;
389 smbpw = getsmbpwnam(user);
394 DEBUG(0,("update_smbpassword_file: getsmbpwnam returned NULL\n"));
398 /* Here, the flag is one, because we want to ignore the XXXXXXX'd out password */
399 ret = change_oem_password( smbpw, password, True);
401 DEBUG(3,("update_smbpasswd_file: change_oem_password returned False\n"));
406 /****************************************************************************
407 update the enhanced security database. Only relevant for OSF1 at the moment.
408 ****************************************************************************/
409 static void update_protected_database( char *user, BOOL result)
412 struct pr_passwd *mypasswd;
415 mypasswd = getprpwnam (user);
416 starttime = time (NULL);
420 mypasswd->ufld.fd_slogin = starttime;
421 mypasswd->ufld.fd_nlogins = 0;
423 putprpwnam(user,mypasswd);
425 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
429 mypasswd->ufld.fd_ulogin = starttime;
430 mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
431 if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
433 mypasswd->uflg.fg_lock = 0;
434 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
436 putprpwnam ( user , mypasswd );
437 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
440 DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
446 /*******************************************************************
447 check on PAM authentication
448 ********************************************************************/
450 /* We first need some helper functions */
451 #include <security/pam_appl.h>
452 /* Static variables used to communicate between the conversation function
453 * and the server_login function
455 static char *PAM_username;
456 static char *PAM_password;
458 /* PAM conversation function
459 * Here we assume (for now, at least) that echo on means login name, and
460 * echo off means password.
462 static int PAM_conv (int num_msg,
463 const struct pam_message **msg,
464 struct pam_response **resp,
467 struct pam_response *reply = NULL;
469 #define COPY_STRING(s) (s) ? strdup(s) : NULL
471 reply = malloc(sizeof(struct pam_response) * num_msg);
472 if (!reply) return PAM_CONV_ERR;
474 for (replies = 0; replies < num_msg; replies++) {
475 switch (msg[replies]->msg_style) {
476 case PAM_PROMPT_ECHO_ON:
477 reply[replies].resp_retcode = PAM_SUCCESS;
478 reply[replies].resp = COPY_STRING(PAM_username);
481 case PAM_PROMPT_ECHO_OFF:
482 reply[replies].resp_retcode = PAM_SUCCESS;
483 reply[replies].resp = COPY_STRING(PAM_password);
490 reply[replies].resp_retcode = PAM_SUCCESS;
491 reply[replies].resp = NULL;
494 /* Must be an error of some sort... */
499 if (reply) *resp = reply;
502 static struct pam_conv PAM_conversation = {
508 static BOOL pam_auth(char *this_user,char *password)
513 /* Now use PAM to do authentication. For now, we won't worry about
514 * session logging, only authentication. Bail out if there are any
515 * errors. Since this is a limited protocol, and an even more limited
516 * function within a server speaking this protocol, we can't be as
517 * verbose as would otherwise make sense.
518 * Query: should we be using PAM_SILENT to shut PAM up?
520 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
521 pam_end(pamh, 0); return False; \
523 PAM_password = password;
524 PAM_username = this_user;
525 pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
527 /* Setting PAM_SILENT stops generation of error messages to syslog
528 * to enable debugging on Red Hat Linux set:
530 * auth required /lib/security/pam_pwdb.so nullok shadow audit
531 * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
533 pam_error = pam_authenticate(pamh, PAM_SILENT);
535 /* It is not clear to me that account management is the right thing
536 * to do, but it is not clear that it isn't, either. This can be
537 * removed if no account management should be done. Alternately,
538 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
539 pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
541 pam_end(pamh, PAM_SUCCESS);
542 /* If this point is reached, the user has been authenticated. */
549 /*******************************************************************
550 check on AFS authentication
551 ********************************************************************/
552 static BOOL afs_auth(char *this_user,char *password)
554 long password_expires = 0;
557 /* For versions of AFS prior to 3.3, this routine has few arguments, */
558 /* but since I can't find the old documentation... :-) */
560 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
562 (char *) 0, /* instance */
563 (char *) 0, /* cell */
565 0, /* lifetime, default */
566 &password_expires, /*days 'til it expires */
577 /*****************************************************************
578 This new version of the DFS_AUTH code was donated by Karsten Muuss
579 <muuss@or.uni-bonn.de>. It fixes the following problems with the
582 - Server credentials may expire
583 - Client credential cache files have wrong owner
584 - purge_context() function is called with invalid argument
586 This new code was modified to ensure that on exit the uid/gid is
587 still root, and the original directory is restored. JRA.
588 ******************************************************************/
590 sec_login_handle_t my_dce_sec_context;
591 int dcelogin_atmost_once = 0;
593 /*******************************************************************
594 check on a DCE/DFS authentication
595 ********************************************************************/
596 static BOOL dfs_auth(char *this_user,char *password)
601 signed32 expire_time, current_time;
602 boolean32 password_reset;
604 sec_passwd_rec_t passwd_rec;
605 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
606 unsigned char dce_errstr[dce_c_error_string_len];
608 if (dcelogin_atmost_once) return(False);
612 * We only go for a DCE login context if the given password
613 * matches that stored in the local password file..
614 * Assumes local passwd file is kept in sync w/ DCE RGY!
617 if ( strcmp((char *)crypt(password,this_salt),this_crypted) )
621 sec_login_get_current_context(&my_dce_sec_context, &err);
622 if (err != error_status_ok ) {
623 dce_error_inq_text(err, dce_errstr, &err2);
624 DEBUG(0,("DCE can't get current context. %s\n", dce_errstr));
629 sec_login_certify_identity(my_dce_sec_context, &err);
630 if (err != error_status_ok ) {
631 dce_error_inq_text(err, dce_errstr, &err2);
632 DEBUG(0,("DCE can't get current context. %s\n", dce_errstr));
637 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
638 if (err != error_status_ok ) {
639 dce_error_inq_text(err, dce_errstr, &err2);
640 DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
647 if (expire_time < (current_time + 60)) {
649 sec_passwd_rec_t *key;
651 sec_login_get_pwent(my_dce_sec_context,
652 (sec_login_passwd_t*)&pw, &err);
653 if (err != error_status_ok ) {
654 dce_error_inq_text(err, dce_errstr, &err2);
655 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
660 sec_login_refresh_identity(my_dce_sec_context, &err);
661 if (err != error_status_ok ) {
662 dce_error_inq_text(err, dce_errstr, &err2);
663 DEBUG(0,("DCE can't refresh identity. %s\n", dce_errstr));
668 sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
669 (unsigned char *)pw->pw_name,
670 sec_c_key_version_none,
672 if (err != error_status_ok ) {
673 dce_error_inq_text(err, dce_errstr, &err2);
674 DEBUG(0,("DCE can't get key for %s. %s\n", pw->pw_name, dce_errstr));
679 sec_login_valid_and_cert_ident(my_dce_sec_context, key,
680 &password_reset, &auth_src, &err);
681 if (err != error_status_ok ) {
682 dce_error_inq_text(err, dce_errstr, &err2);
683 DEBUG(0,("DCE can't validate and certify identity for %s. %s\n",
684 pw->pw_name, dce_errstr));
687 sec_key_mgmt_free_key(key, &err);
688 if (err != error_status_ok ) {
689 dce_error_inq_text(err, dce_errstr, &err2);
690 DEBUG(0,("DCE can't free key.\n", dce_errstr));
694 if (sec_login_setup_identity((unsigned char *)this_user,
700 dce_error_inq_text(err, dce_errstr, &err2);
701 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
702 this_user,dce_errstr));
706 sec_login_get_pwent(my_dce_sec_context,
707 (sec_login_passwd_t*)&pw, &err);
708 if (err != error_status_ok ) {
709 dce_error_inq_text(err, dce_errstr, &err2);
710 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
715 sec_login_purge_context(&my_dce_sec_context, &err);
716 if (err != error_status_ok ) {
717 dce_error_inq_text(err, dce_errstr, &err2);
718 DEBUG(0,("DCE can't purge context. %s\n", dce_errstr));
724 * NB. I'd like to change these to call something like become_user()
725 * instead but currently we don't have a connection
726 * context to become the correct user. This is already
727 * fairly platform specific code however, so I think
728 * this should be ok. I have added code to go
729 * back to being root on error though. JRA.
732 if (setregid(-1, pw->pw_gid) != 0) {
733 DEBUG(0,("Can't set egid to %d (%s)\n", pw->pw_gid, strerror(errno)));
737 if (setreuid(-1, pw->pw_uid) != 0) {
739 DEBUG(0,("Can't set euid to %d (%s)\n", pw->pw_uid, strerror(errno)));
743 if (sec_login_setup_identity((unsigned char *)this_user,
749 dce_error_inq_text(err, dce_errstr, &err2);
750 /* Go back to root, JRA. */
753 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
754 this_user,dce_errstr));
758 sec_login_get_pwent(my_dce_sec_context,
759 (sec_login_passwd_t*)&pw, &err);
760 if (err != error_status_ok ) {
761 dce_error_inq_text(err, dce_errstr, &err2);
762 /* Go back to root, JRA. */
765 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
770 passwd_rec.version_number = sec_passwd_c_version_none;
771 passwd_rec.pepper = NULL;
772 passwd_rec.key.key_type = sec_passwd_plain;
773 passwd_rec.key.tagged_union.plain = (idl_char *)password;
775 sec_login_validate_identity(my_dce_sec_context,
776 &passwd_rec, &password_reset,
778 if (err != error_status_ok ) {
779 dce_error_inq_text(err, dce_errstr, &err2);
780 /* Go back to root, JRA. */
783 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
784 this_user,dce_errstr));
789 sec_login_certify_identity(my_dce_sec_context, &err);
790 if (err != error_status_ok ) {
791 dce_error_inq_text(err, dce_errstr, &err2);
792 /* Go back to root, JRA. */
795 DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr));
800 if (auth_src != sec_login_auth_src_network) {
801 DEBUG(0,("DCE context has no network credentials.\n"));
804 sec_login_set_context(my_dce_sec_context, &err);
805 if (err != error_status_ok ) {
806 dce_error_inq_text(err, dce_errstr, &err2);
807 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
808 this_user,dce_errstr));
810 sec_login_purge_context(&my_dce_sec_context, &err);
811 /* Go back to root, JRA. */
817 sec_login_get_pwent(my_dce_sec_context,
818 (sec_login_passwd_t*)&pw, &err);
819 if (err != error_status_ok ) {
820 dce_error_inq_text(err, dce_errstr, &err2);
821 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
823 /* Go back to root, JRA. */
829 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
830 this_user, getpid()));
832 DEBUG(3,("DCE principal: %s\n"
835 pw->pw_name, pw->pw_uid, pw->pw_gid));
836 DEBUG(3,(" info: %s\n"
839 pw->pw_gecos, pw->pw_dir, pw->pw_shell));
841 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
842 if (err != error_status_ok ) {
843 dce_error_inq_text(err, dce_errstr, &err2);
844 /* Go back to root, JRA. */
847 DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
855 DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time))));
857 dcelogin_atmost_once = 1;
861 void dfs_unlogin(void)
865 unsigned char dce_errstr[dce_c_error_string_len];
867 sec_login_purge_context(&my_dce_sec_context, &err);
868 if (err != error_status_ok )
870 dce_error_inq_text(err, dce_errstr, &err2);
871 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
872 getpid(), dce_errstr));
878 /*******************************************************************
879 check on Kerberos authentication
880 ********************************************************************/
881 static BOOL krb5_auth(char *this_user,char *password)
883 krb5_data tgtname = {
888 krb5_context kcontext;
889 krb5_principal kprinc;
890 krb5_principal server;
893 krb5_address **addrs = (krb5_address **)0;
894 krb5_preauthtype *preauth = NULL;
895 krb5_keytab keytab = NULL;
897 krb5_ccache ccache = NULL;
901 if ( retval=krb5_init_context(&kcontext))
906 if ( retval = krb5_timeofday(kcontext, &now) )
911 if ( retval = krb5_cc_default(kcontext, &ccache) )
916 if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
921 memset((char *)&kcreds, 0, sizeof(kcreds));
923 kcreds.client = kprinc;
925 if ((retval = krb5_build_principal_ext(kcontext, &server,
926 krb5_princ_realm(kcontext, kprinc)->length,
927 krb5_princ_realm(kcontext, kprinc)->data,
930 krb5_princ_realm(kcontext, kprinc)->length,
931 krb5_princ_realm(kcontext, kprinc)->data,
937 kcreds.server = server;
939 retval = krb5_get_in_tkt_with_password(kcontext,
956 #endif /* KRB5_AUTH */
959 /*******************************************************************
960 check on Kerberos authentication
961 ********************************************************************/
962 static BOOL krb4_auth(char *this_user,char *password)
964 char realm[REALM_SZ];
965 char tkfile[MAXPATHLEN];
967 if (krb_get_lrealm(realm, 1) != KSUCCESS)
968 (void) safe_strcpy(realm, KRB_REALM, sizeof (realm) - 1);
970 (void) slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d", getpid());
972 krb_set_tkt_string(tkfile);
973 if (krb_verify_user(this_user, "", realm,
975 "rmcd") == KSUCCESS) {
982 #endif /* KRB4_AUTH */
984 #ifdef LINUX_BIGCRYPT
985 /****************************************************************************
986 an enhanced crypt for Linux to handle password longer than 8 characters
987 ****************************************************************************/
988 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
990 #define LINUX_PASSWORD_SEG_CHARS 8
994 StrnCpy(salt,salt1,2);
997 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
998 char * p = crypt(password,salt) + 2;
999 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
1001 password += LINUX_PASSWORD_SEG_CHARS;
1002 crypted += strlen(p);
1010 /****************************************************************************
1011 apply a function to upper/lower case combinations
1012 of a string and return true if one of them returns true.
1013 try all combinations with N uppercase letters.
1014 offset is the first char to try and change (start with 0)
1015 it assumes the string starts lowercased
1016 ****************************************************************************/
1017 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(char *),int N)
1019 int len = strlen(s);
1022 #ifdef PASSWORD_LENGTH
1023 len = MIN(len,PASSWORD_LENGTH);
1026 if (N <= 0 || offset >= len)
1029 for (i=offset;i<(len-(N-1));i++)
1032 if (!islower(c)) continue;
1034 if (string_combinations2(s,i+1,fn,N-1))
1041 /****************************************************************************
1042 apply a function to upper/lower case combinations
1043 of a string and return true if one of them returns true.
1044 try all combinations with up to N uppercase letters.
1045 offset is the first char to try and change (start with 0)
1046 it assumes the string starts lowercased
1047 ****************************************************************************/
1048 static BOOL string_combinations(char *s,BOOL (*fn)(char *),int N)
1052 if (string_combinations2(s,0,fn,n)) return(True);
1058 /****************************************************************************
1059 core of password checking routine
1060 ****************************************************************************/
1061 BOOL password_check(char *password)
1065 /* This falls through if the password check fails
1066 - if HAVE_CRYPT is not defined this causes an error msg
1067 saying Warning - no crypt available
1068 - if HAVE_CRYPT is defined this is a potential security hole
1069 as it may authenticate via the crypt call when PAM
1070 settings say it should fail.
1071 if (pam_auth(this_user,password)) return(True);
1072 Hence we make a direct return to avoid a second chance!!!
1074 return (pam_auth(this_user,password));
1078 if (afs_auth(this_user,password)) return(True);
1082 if (dfs_auth(this_user,password)) return(True);
1086 if (krb5_auth(this_user,password)) return(True);
1090 if (krb4_auth(this_user,password)) return(True);
1095 BOOL ret = (strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
1097 DEBUG(2,("password_check: OSF1_ENH_SEC failed. Trying normal crypt.\n"));
1098 ret = (strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
1105 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
1108 #ifdef LINUX_BIGCRYPT
1109 return(linux_bigcrypt(password,this_salt,this_crypted));
1112 #ifdef HAVE_BIGCRYPT
1113 return(strcmp(bigcrypt(password,this_salt),this_crypted) == 0);
1117 DEBUG(1,("Warning - no crypt available\n"));
1120 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
1124 /****************************************************************************
1125 core of smb password checking routine.
1126 ****************************************************************************/
1127 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
1129 /* Finish the encryption of part_passwd. */
1130 unsigned char p21[21];
1131 unsigned char p24[24];
1133 if (part_passwd == NULL)
1134 DEBUG(10,("No password set - allowing access\n"));
1135 /* No password set - always true ! */
1136 if (part_passwd == NULL)
1139 memset(p21,'\0',21);
1140 memcpy(p21,part_passwd,16);
1141 E_P24(p21, c8, p24);
1145 DEBUG(100,("Part password (P16) was |"));
1146 for(i = 0; i < 16; i++)
1147 DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
1149 DEBUG(100,("Password from client was |"));
1150 for(i = 0; i < 24; i++)
1151 DEBUG(100,("%X ", (unsigned char)password[i]));
1153 DEBUG(100,("Given challenge was |"));
1154 for(i = 0; i < 8; i++)
1155 DEBUG(100,("%X ", (unsigned char)c8[i]));
1157 DEBUG(100,("Value from encryption was |"));
1158 for(i = 0; i < 24; i++)
1159 DEBUG(100,("%X ", (unsigned char)p24[i]));
1163 return (memcmp(p24, password, 24) == 0);
1166 /****************************************************************************
1167 Do a specific test for an smb password being correct, given a smb_password and
1168 the lanman and NT responses.
1169 ****************************************************************************/
1171 BOOL smb_password_ok(struct smb_passwd *smb_pass,
1172 uchar lm_pass[24], uchar nt_pass[24])
1176 if (!lm_pass || !smb_pass) return(False);
1178 if(smb_pass->acct_ctrl & ACB_DISABLED)
1180 DEBUG(3,("smb_password_ok: account for user %s was disabled.\n", smb_pass->smb_name));
1184 if (!last_challenge(challenge))
1186 DEBUG(1,("smb_password_ok: no challenge done - password failed\n"));
1190 DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n", smb_pass->smb_name));
1192 if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL))
1194 /* We have the NT MD4 hash challenge available - see if we can
1195 use it (ie. does it exist in the smbpasswd file).
1197 DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
1198 if (smb_password_check((char *)nt_pass, (uchar *)smb_pass->smb_nt_passwd, challenge))
1200 DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n"));
1203 DEBUG(4,("smb_password_ok: NT MD4 password check failed\n"));
1206 /* Try against the lanman password. smb_pass->smb_passwd == NULL means
1207 no password, allow access. */
1209 DEBUG(4,("Checking LM MD4 password\n"));
1211 if((smb_pass->smb_passwd == NULL) && (smb_pass->acct_ctrl & ACB_PWNOTREQ))
1213 DEBUG(4,("smb_password_ok: no password required for user %s\n", smb_pass->smb_name));
1217 if((smb_pass->smb_passwd != NULL) && smb_password_check((char *)lm_pass, (uchar *)smb_pass->smb_passwd, challenge))
1219 DEBUG(4,("smb_password_ok: LM MD4 password check succeeded\n"));
1223 DEBUG(4,("smb_password_ok: LM MD4 password check failed\n"));
1228 /****************************************************************************
1229 check if a username/password is OK
1230 ****************************************************************************/
1231 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
1234 int level = lp_passwordlevel();
1235 struct passwd *pass;
1237 struct smb_passwd *smb_pass;
1238 BOOL update_encrypted = lp_update_encrypted();
1239 BOOL challenge_done = False;
1241 if (password) password[pwlen] = 0;
1244 challenge_done = last_challenge(challenge);
1250 DEBUG(100,("checking user=[%s] pass=[",user));
1251 for( i = 0; i < 24; i++)
1252 DEBUG(100,("%0x ", (unsigned char)password[i]));
1255 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
1262 if (((!*password) || (!pwlen)) && !lp_null_passwords())
1267 pass = (struct passwd *) pwd;
1268 user = pass->pw_name;
1271 pass = Get_Pwnam(user,True);
1273 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
1275 if ((pwlen == 24) && challenge_done)
1277 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
1281 DEBUG(3,("Couldn't find user %s\n",user));
1285 smb_pass = getsmbpwnam(user);
1289 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
1293 /* Quit if the account was disabled. */
1294 if(smb_pass->acct_ctrl & ACB_DISABLED)
1296 DEBUG(3,("password_ok: account for user %s was disabled.\n", user));
1300 /* Ensure the uid's match */
1301 if (smb_pass->smb_userid != pass->pw_uid)
1303 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
1307 if(smb_password_ok( smb_pass, (unsigned char *)password,(uchar *)password))
1309 update_protected_database(user,True);
1313 DEBUG(3,("Error smb_password_check failed\n"));
1316 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
1320 DEBUG(3,("Couldn't find user %s\n",user));
1324 #ifdef HAVE_GETSPNAM
1328 /* many shadow systems require you to be root to get the password,
1329 in most cases this should already be the case when this
1330 function is called, except perhaps for IPC password changing
1333 spass = getspnam(pass->pw_name);
1334 if (spass && spass->sp_pwdp)
1335 pass->pw_passwd = spass->sp_pwdp;
1337 #elif defined(IA_UINFO)
1339 /* Need to get password with SVR4.2's ia_ functions instead of
1340 get{sp,pw}ent functions. Required by UnixWare 2.x, tested on
1341 version 2.1. (tangent@cyberport.com) */
1343 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
1344 ia_get_logpwd(uinfo, &(pass->pw_passwd));
1348 #ifdef HAVE_GETPRPWNAM
1350 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1351 if (pr_pw && pr_pw->ufld.fd_encrypt)
1352 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1358 struct pr_passwd *mypasswd;
1359 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
1360 mypasswd = getprpwnam (user);
1363 fstrcpy(pass->pw_name,mypasswd->ufld.fd_name);
1364 fstrcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
1368 DEBUG(5,("No entry for user %s in protected database !\n",user));
1376 AUTHORIZATION *ap = getauthuid( pass->pw_uid );
1379 fstrcpy( pass->pw_passwd, ap->a_password );
1385 /* extract relevant info */
1386 fstrcpy(this_user,pass->pw_name);
1387 fstrcpy(this_salt,pass->pw_passwd);
1388 /* crypt on some platforms (HPUX in particular)
1389 won't work with more than 2 salt characters. */
1392 fstrcpy(this_crypted,pass->pw_passwd);
1394 if (!*this_crypted) {
1395 if (!lp_null_passwords()) {
1396 DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
1400 DEBUG(3,("Allowing access to %s with null password\n",this_user));
1405 /* try it as it came to us */
1406 if (password_check(password))
1408 update_protected_database(user,True);
1409 if (update_encrypted)
1410 update_smbpassword_file(user,password);
1414 /* if the password was given to us with mixed case then we don't
1415 need to proceed as we know it hasn't been case modified by the
1417 if (strhasupper(password) && strhaslower(password))
1420 /* make a copy of it */
1421 StrnCpy(pass2,password,sizeof(pstring)-1);
1423 /* try all lowercase */
1425 if (password_check(password))
1427 update_protected_database(user,True);
1428 if (update_encrypted)
1429 update_smbpassword_file(user,password);
1436 update_protected_database(user,False);
1439 fstrcpy(password,pass2);
1444 /* last chance - all combinations of up to level chars upper! */
1447 if (string_combinations(password,password_check,level))
1449 update_protected_database(user,True);
1450 if (update_encrypted)
1451 update_smbpassword_file(user,password);
1455 update_protected_database(user,False);
1458 fstrcpy(password,pass2);
1465 /****************************************************************************
1466 check if a username is valid
1467 ****************************************************************************/
1468 BOOL user_ok(char *user,int snum)
1470 pstring valid, invalid;
1473 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
1474 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
1476 string_sub(valid,"%S",lp_servicename(snum));
1477 string_sub(invalid,"%S",lp_servicename(snum));
1479 ret = !user_in_list(user,invalid);
1481 if (ret && valid && *valid)
1482 ret = user_in_list(user,valid);
1484 if (ret && lp_onlyuser(snum)) {
1485 char *user_list = lp_username(snum);
1486 string_sub(user_list,"%S",lp_servicename(snum));
1487 ret = user_in_list(user,user_list);
1496 /****************************************************************************
1497 validate a group username entry. Return the username or NULL
1498 ****************************************************************************/
1499 static char *validate_group(char *group,char *password,int pwlen,int snum)
1501 #ifdef HAVE_NETGROUP
1503 char *host, *user, *domain;
1505 while (getnetgrent(&host, &user, &domain)) {
1507 if (user_ok(user, snum) &&
1508 password_ok(user,password,pwlen,NULL)) {
1518 #ifdef HAVE_GETGRNAM
1520 struct group *gptr = (struct group *)getgrnam(group);
1524 member = gptr->gr_mem;
1525 while (member && *member)
1527 static fstring name;
1528 fstrcpy(name,*member);
1529 if (user_ok(name,snum) &&
1530 password_ok(name,password,pwlen,NULL))
1534 #ifdef GROUP_CHECK_PWENT
1540 while (pwd = getpwent ()) {
1541 if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
1542 /* This Entry have PASSWORD and same GID then check pwd */
1543 if (password_ok(NULL, password, pwlen, pwd)) {
1544 fstrcpy(tm, pwd->pw_name);
1552 #endif /* GROUP_CHECK_PWENT */
1561 /****************************************************************************
1562 check for authority to login to a service with a given username/password
1563 ****************************************************************************/
1564 BOOL authorise_login(int snum,char *user,char *password, int pwlen,
1565 BOOL *guest,BOOL *force,uint16 vuid)
1572 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1575 /* there are several possibilities:
1576 1) login as the given user with given password
1577 2) login as a previously registered username with the given password
1578 3) login as a session list username with the given password
1579 4) login as a previously validated user/password pair
1580 5) login as the "user =" user with given password
1581 6) login as the "user =" user with no password (guest connection)
1582 7) login as guest user with no password
1584 if the service is guest_only then steps 1 to 5 are skipped
1587 if (GUEST_ONLY(snum)) *force = True;
1589 if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1592 user_struct *vuser = get_valid_user_struct(vuid);
1594 /* check the given username and password */
1595 if (!ok && (*user) && user_ok(user,snum)) {
1596 ok = password_ok(user,password, pwlen, NULL);
1597 if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
1600 /* check for a previously registered guest username */
1601 if (!ok && (vuser != 0) && vuser->guest) {
1602 if (user_ok(vuser->name,snum) &&
1603 password_ok(vuser->name, password, pwlen, NULL)) {
1604 fstrcpy(user, vuser->name);
1605 vuser->guest = False;
1606 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
1612 /* now check the list of session users */
1616 char *user_list = strdup(session_users);
1617 if (!user_list) return(False);
1619 for (auser=strtok(user_list,LIST_SEP);
1621 auser = strtok(NULL,LIST_SEP))
1624 fstrcpy(user2,auser);
1625 if (!user_ok(user2,snum)) continue;
1627 if (password_ok(user2,password, pwlen, NULL)) {
1629 fstrcpy(user,user2);
1630 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1636 /* check for a previously validated username/password pair */
1637 if (!ok && (!lp_revalidate(snum) || lp_security() > SEC_SHARE) &&
1638 (vuser != 0) && !vuser->guest &&
1639 user_ok(vuser->name,snum)) {
1640 fstrcpy(user,vuser->name);
1642 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1646 /* check for a rhosts entry */
1647 if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1649 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1652 /* check the user= fields and the given password */
1653 if (!ok && lp_username(snum)) {
1656 StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1658 string_sub(user_list,"%S",lp_servicename(snum));
1660 for (auser=strtok(user_list,LIST_SEP);
1662 auser = strtok(NULL,LIST_SEP))
1666 auser = validate_group(auser+1,password,pwlen,snum);
1670 fstrcpy(user,auser);
1671 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1677 fstrcpy(user2,auser);
1678 if (user_ok(user2,snum) &&
1679 password_ok(user2,password,pwlen,NULL))
1682 fstrcpy(user,user2);
1683 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1688 } /* not guest only */
1690 /* check for a normal guest connection */
1691 if (!ok && GUEST_OK(snum))
1694 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1695 if (Get_Pwnam(guestname,True))
1697 fstrcpy(user,guestname);
1699 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1702 DEBUG(0,("Invalid guest account %s??\n",guestname));
1707 if (ok && !user_ok(user,snum))
1709 DEBUG(0,("rejected invalid user %s\n",user));
1717 /****************************************************************************
1718 read the a hosts.equiv or .rhosts file and check if it
1719 allows this user from this machine
1720 ****************************************************************************/
1721 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1724 int plus_allowed = 1;
1727 FILE *fp = fopen(equiv_file, "r");
1728 DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1729 if (! fp) return False;
1730 while(fgets(buf, sizeof(buf), fp))
1732 trim_string(buf," "," ");
1734 if (buf[0] != '#' && buf[0] != '\n')
1736 BOOL is_group = False;
1739 if (strcmp(buf, "NO_PLUS\n") == 0)
1741 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1748 if (*bp == '\n' && plus_allowed)
1750 /* a bare plus means everbody allowed */
1751 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1756 else if (buf[0] == '-')
1766 file_host = strtok(bp, " \t\n");
1767 file_user = strtok(NULL, " \t\n");
1768 DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)",
1769 file_user ? file_user : "(null)" ));
1770 if (file_host && *file_host)
1772 BOOL host_ok = False;
1774 #ifdef HAVE_NETGROUP
1777 static char *mydomain = NULL;
1779 yp_get_default_domain(&mydomain);
1780 if (mydomain && innetgr(file_host,remote,user,mydomain))
1786 DEBUG(1,("Netgroups not configured\n"));
1791 /* is it this host */
1792 /* the fact that remote has come from a call of gethostbyaddr
1793 * means that it may have the fully qualified domain name
1794 * so we could look up the file version to get it into
1795 * a canonical form, but I would rather just type it
1796 * in full in the equiv file
1798 if (!host_ok && !is_group && strequal(remote, file_host))
1804 /* is it this user */
1805 if (file_user == 0 || strequal(user, file_user))
1808 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1809 (plus ? "+" : "-"), file_host,
1810 (file_user ? file_user : "")));
1811 return (plus ? True : False);
1822 /****************************************************************************
1823 check for a possible hosts equiv or rhosts entry for the user
1824 ****************************************************************************/
1825 BOOL check_hosts_equiv(char *user)
1829 struct passwd *pass = Get_Pwnam(user,True);
1834 fname = lp_hosts_equiv();
1836 /* note: don't allow hosts.equiv on root */
1837 if (fname && *fname && (pass->pw_uid != 0)) {
1839 if (check_user_equiv(user,client_name(Client),fname))
1843 if (lp_use_rhosts())
1845 char *home = get_home_dir(user);
1848 slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
1849 if (check_user_equiv(user,client_name(Client),rhostsfile))
1858 static struct cli_state pw_cli;
1860 /****************************************************************************
1861 return the client state structure
1862 ****************************************************************************/
1863 struct cli_state *server_client(void)
1868 /****************************************************************************
1869 support for server level security
1870 ****************************************************************************/
1871 struct cli_state *server_cryptkey(void)
1874 struct in_addr dest_ip;
1875 extern fstring local_machine;
1877 BOOL connected_ok = False;
1879 if (!cli_initialise(&pw_cli))
1882 p = lp_passwordserver();
1883 while(p && next_token( &p, desthost, LIST_SEP)) {
1884 standard_sub_basic(desthost);
1887 if(!resolve_name( desthost, &dest_ip)) {
1888 DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
1892 if (ismyip(dest_ip)) {
1893 DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
1897 if (cli_connect(&pw_cli, desthost, &dest_ip)) {
1898 DEBUG(3,("connected to password server %s\n",desthost));
1899 connected_ok = True;
1904 if (!connected_ok) {
1905 DEBUG(0,("password server not available\n"));
1906 cli_shutdown(&pw_cli);
1910 if (!cli_session_request(&pw_cli, desthost, 0x20, local_machine)) {
1911 DEBUG(1,("%s rejected the session\n",desthost));
1912 cli_shutdown(&pw_cli);
1916 DEBUG(3,("got session\n"));
1918 if (!cli_negprot(&pw_cli)) {
1919 DEBUG(1,("%s rejected the negprot\n",desthost));
1920 cli_shutdown(&pw_cli);
1924 if (pw_cli.protocol < PROTOCOL_LANMAN2 ||
1925 !(pw_cli.sec_mode & 1)) {
1926 DEBUG(1,("%s isn't in user level security mode\n",desthost));
1927 cli_shutdown(&pw_cli);
1931 DEBUG(3,("password server OK\n"));
1936 /****************************************************************************
1937 validate a password with the password server
1938 ****************************************************************************/
1939 BOOL server_validate(char *user, char *domain,
1940 char *pass, int passlen,
1941 char *ntpass, int ntpasslen)
1943 extern fstring local_machine;
1944 static unsigned char badpass[24];
1946 if (!pw_cli.initialised) {
1947 DEBUG(1,("password server %s is not connected\n", pw_cli.desthost));
1951 if(badpass[0] == 0) {
1952 memset(badpass, 0x1f, sizeof(badpass));
1955 if((passlen == sizeof(badpass)) && !memcmp(badpass, pass, passlen)) {
1956 /* Very unlikely, our random bad password is the same as the users
1958 memset(badpass, badpass[0]+1, sizeof(badpass));
1962 * Attempt a session setup with a totally incorrect password.
1963 * If this succeeds with the guest bit *NOT* set then the password
1964 * server is broken and is not correctly setting the guest bit. We
1965 * need to detect this as some versions of NT4.x are broken. JRA.
1968 if (cli_session_setup(&pw_cli, user, (char *)badpass, sizeof(badpass),
1969 (char *)badpass, sizeof(badpass), domain)) {
1970 if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) == 0) {
1971 DEBUG(0,("server_validate: password server %s allows users as non-guest \
1972 with a bad password.\n", pw_cli.desthost));
1973 DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
1974 use this machine as the password server.\n"));
1975 cli_ulogoff(&pw_cli);
1978 cli_ulogoff(&pw_cli);
1982 * Now we know the password server will correctly set the guest bit, or is
1983 * not guest enabled, we can try with the real password.
1986 if (!cli_session_setup(&pw_cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
1987 DEBUG(1,("password server %s rejected the password\n", pw_cli.desthost));
1991 /* if logged in as guest then reject */
1992 if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) != 0) {
1993 DEBUG(1,("password server %s gave us guest only\n", pw_cli.desthost));
1994 cli_ulogoff(&pw_cli);
1999 * This patch from Rob Nielsen <ran@adc.com> makes doing
2000 * the NetWksaUserLogon a dynamic, rather than compile-time
2001 * parameter, defaulting to on. This is somewhat dangerous
2002 * as it allows people to turn off this neccessary check,
2003 * but so many people have had problems with this that I
2004 * think it is a neccessary change. JRA.
2007 if (lp_net_wksta_user_logon()) {
2008 DEBUG(3,("trying NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
2010 if (!cli_send_tconX(&pw_cli, "IPC$", "IPC", "", 1)) {
2011 DEBUG(0,("password server %s refused IPC$ connect\n", pw_cli.desthost));
2012 cli_ulogoff(&pw_cli);
2016 if (!cli_NetWkstaUserLogon(&pw_cli,user,local_machine)) {
2017 DEBUG(0,("password server %s failed NetWkstaUserLogon\n", pw_cli.desthost));
2019 cli_ulogoff(&pw_cli);
2023 if (pw_cli.privilages == 0) {
2024 DEBUG(0,("password server %s gave guest privilages\n", pw_cli.desthost));
2026 cli_ulogoff(&pw_cli);
2030 if (!strequal(pw_cli.eff_name, user)) {
2031 DEBUG(0,("password server %s gave different username %s\n",
2035 cli_ulogoff(&pw_cli);
2041 DEBUG(3,("skipping NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
2044 DEBUG(3,("password server %s accepted the password\n", pw_cli.desthost));
2046 cli_ulogoff(&pw_cli);
2051 /***********************************************************************
2052 Do the same as security=server, but using NT Domain calls and a session
2053 key from the machine password.
2054 ************************************************************************/
2056 BOOL domain_client_validate( char *user, char *domain,
2057 char *smb_apasswd, int smb_apasslen,
2058 char *smb_ntpasswd, int smb_ntpasslen)
2060 unsigned char local_challenge[8];
2061 unsigned char local_lm_response[24];
2062 unsigned char local_nt_reponse[24];
2063 unsigned char trust_passwd[16];
2065 fstring remote_machine;
2067 struct in_addr dest_ip;
2068 NET_ID_INFO_CTR ctr;
2069 NET_USER_INFO_3 info3;
2070 struct cli_state cli;
2072 BOOL connected_ok = False;
2075 * Check that the requested domain is not our own machine name.
2076 * If it is, we should never check the PDC here, we use our own local
2080 if(strequal( domain, global_myname)) {
2081 DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
2086 * Next, check that the passwords given were encrypted.
2089 if(((smb_apasslen != 24) && (smb_apasslen != 0)) ||
2090 ((smb_ntpasslen != 24) && (smb_ntpasslen != 0))) {
2093 * Not encrypted - do so.
2096 DEBUG(3,("domain_client_validate: User passwords not in encrypted format.\n"));
2097 generate_random_buffer( local_challenge, 8, False);
2098 SMBencrypt( (uchar *)smb_apasswd, local_challenge, local_lm_response);
2099 SMBNTencrypt((uchar *)smb_ntpasswd, local_challenge, local_nt_reponse);
2102 smb_apasswd = (char *)local_lm_response;
2103 smb_ntpasswd = (char *)local_nt_reponse;
2107 * Encrypted - get the challenge we sent for these
2111 if (!last_challenge(local_challenge)) {
2112 DEBUG(0,("domain_client_validate: no challenge done - password failed\n"));
2118 * Get the machine account password.
2120 if(!trust_password_lock( global_myworkgroup, global_myname, False)) {
2121 DEBUG(0,("domain_client_validate: unable to open the machine account password file for \
2122 machine %s in domain %s.\n", global_myname, global_myworkgroup ));
2126 if(get_trust_account_password( trust_passwd, &lct) == False) {
2127 DEBUG(0,("domain_client_validate: unable to read the machine account password for \
2128 machine %s in domain %s.\n", global_myname, global_myworkgroup ));
2129 trust_password_unlock();
2133 trust_password_unlock();
2136 * Here we should check the last change time to see if the machine
2137 * password needs changing..... TODO... JRA.
2140 if(time(NULL) > lct + lp_machine_password_timeout())
2141 global_machine_pasword_needs_changing = True;
2144 * At this point, smb_apasswd points to the lanman response to
2145 * the challenge in local_challenge, and smb_ntpasswd points to
2146 * the NT response to the challenge in local_challenge. Ship
2147 * these over the secure channel to a domain controller and
2148 * see if they were valid.
2151 memset(&cli, '\0', sizeof(struct cli_state));
2152 if(cli_initialise(&cli) == False) {
2153 DEBUG(0,("domain_client_validate: unable to initialize client connection.\n"));
2158 * Treat each name in the 'password server =' line as a potential
2159 * PDC/BDC. Contact each in turn and try and authenticate.
2162 p = lp_passwordserver();
2163 while(p && next_token( &p, remote_machine, LIST_SEP)) {
2165 standard_sub_basic(remote_machine);
2166 strupper(remote_machine);
2168 if(!resolve_name( remote_machine, &dest_ip)) {
2169 DEBUG(1,("domain_client_validate: Can't resolve address for %s\n", remote_machine));
2173 if (ismyip(dest_ip)) {
2174 DEBUG(1,("domain_client_validate: Password server loop - not using password server %s\n",remote_machine));
2178 if (!cli_connect(&cli, remote_machine, &dest_ip)) {
2179 DEBUG(0,("domain_client_validate: unable to connect to SMB server on \
2180 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2184 if (!cli_session_request(&cli, remote_machine, 0x20, global_myname)) {
2185 DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
2186 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2191 cli.protocol = PROTOCOL_NT1;
2193 if (!cli_negprot(&cli)) {
2194 DEBUG(0,("domain_client_validate: machine %s rejected the negotiate protocol. \
2195 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2200 if (cli.protocol != PROTOCOL_NT1) {
2201 DEBUG(0,("domain_client_validate: machine %s didn't negotiate NT protocol.\n",
2208 * Do an anonymous session setup.
2211 if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
2212 DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
2213 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2218 if (!(cli.sec_mode & 1)) {
2219 DEBUG(1,("domain_client_validate: machine %s isn't in user level security mode\n",
2225 if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
2226 DEBUG(0,("domain_client_validate: machine %s rejected the tconX on the IPC$ share. \
2227 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2233 * We have an anonymous connection to IPC$.
2235 connected_ok = True;
2239 if (!connected_ok) {
2240 DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
2246 * Ok - we have an anonymous connection to the IPC$ share.
2247 * Now start the NT Domain stuff :-).
2250 if(cli_nt_session_open(&cli, PIPE_NETLOGON, False) == False) {
2251 DEBUG(0,("domain_client_validate: unable to open the domain client session to \
2252 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
2253 cli_nt_session_close(&cli);
2259 if(cli_nt_setup_creds(&cli, trust_passwd) == False) {
2260 DEBUG(0,("domain_client_validate: unable to setup the PDC credentials to machine \
2261 %s. Error was : %s.\n", remote_machine, cli_errstr(&cli)));
2262 cli_nt_session_close(&cli);
2268 /* We really don't care what LUID we give the user. */
2269 generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
2271 if(cli_nt_login_network(&cli, domain, user, smb_uid_low, (char *)local_challenge,
2272 ((smb_apasslen != 0) ? smb_apasswd : NULL),
2273 ((smb_ntpasslen != 0) ? smb_ntpasswd : NULL),
2274 &ctr, &info3) == False) {
2275 DEBUG(0,("domain_client_validate: unable to validate password for user %s in domain \
2276 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
2277 cli_nt_session_close(&cli);
2284 * Here, if we really want it, we have lots of info about the user in info3.
2289 * We don't actually need to do this - plus it fails currently with
2290 * NT_STATUS_INVALID_INFO_CLASS - we need to know *exactly* what to
2294 if(cli_nt_logoff(&cli, &ctr) == False) {
2295 DEBUG(0,("domain_client_validate: unable to log off user %s in domain \
2296 %s to Domain controller %s. Error was %s.\n", user, domain, remote_machine, cli_errstr(&cli)));
2297 cli_nt_session_close(&cli);
2304 cli_nt_session_close(&cli);