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(NETGROUP) && defined (AUTOMOUNT))
25 #include "rpcsvc/ypclnt.h"
28 extern int DEBUGLEVEL;
31 /* users from session setup */
32 static pstring session_users="";
34 extern pstring myname;
36 /* these are kept here to keep the string_combinations function simple */
37 static char this_user[100]="";
38 static char this_salt[100]="";
39 static char this_crypted[100]="";
41 /* Data to do lanman1/2 password challenge. */
42 static unsigned char saved_challenge[8];
43 static BOOL challenge_sent=False;
45 /*******************************************************************
46 Get the next challenge value - no repeats.
47 ********************************************************************/
48 void generate_next_challenge(char *challenge)
52 * Leave this ifdef'd out while we test
53 * the new crypto random number generator.
56 unsigned char buf[16];
57 static int counter = 0;
61 /* get a sort-of random number */
63 v1 = (counter++) + getpid() + tval.tv_sec;
64 v2 = (counter++) * getpid() + tval.tv_usec;
65 SIVAL(challenge,0,v1);
66 SIVAL(challenge,4,v2);
68 /* mash it up with md4 */
69 mdfour(buf, (unsigned char *)challenge, 8);
73 generate_random_buffer(buf,8,False);
75 memcpy(saved_challenge, buf, 8);
76 memcpy(challenge,buf,8);
77 challenge_sent = True;
80 /*******************************************************************
81 set the last challenge sent, usually from a password server
82 ********************************************************************/
83 BOOL set_challenge(char *challenge)
85 memcpy(saved_challenge,challenge,8);
86 challenge_sent = True;
90 /*******************************************************************
91 get the last challenge sent
92 ********************************************************************/
93 BOOL last_challenge(char *challenge)
95 if (!challenge_sent) return(False);
96 memcpy(challenge,saved_challenge,8);
100 /* this holds info on user ids that are already validated for this VC */
101 static user_struct *validated_users = NULL;
102 static int num_validated_users = 0;
104 /****************************************************************************
105 check if a uid has been validated, and return an pointer to the user_struct
106 if it has. NULL if not. vuid is biased by an offset. This allows us to
107 tell random client vuid's (normally zero) from valid vuids.
108 ****************************************************************************/
109 user_struct *get_valid_user_struct(uint16 vuid)
111 if (vuid == UID_FIELD_INVALID)
114 if ((vuid >= (uint16)num_validated_users) ||
115 (validated_users[vuid].uid == -1) || (validated_users[vuid].gid == -1))
117 return &validated_users[vuid];
120 /****************************************************************************
122 ****************************************************************************/
123 void invalidate_vuid(uint16 vuid)
125 user_struct *vuser = get_valid_user_struct(vuid);
127 if (vuser == NULL) return;
134 /* same number of igroups as groups as attrs */
137 if (vuser->groups && (vuser->groups != (gid_t *)vuser->igroups))
140 if (vuser->igroups) free(vuser->igroups);
141 if (vuser->attrs ) free(vuser->attrs);
142 if (vuser->sids ) free(vuser->sids);
146 vuser->igroups = NULL;
147 vuser->groups = NULL;
151 /****************************************************************************
152 return a validated username
153 ****************************************************************************/
154 char *validated_username(uint16 vuid)
156 user_struct *vuser = get_valid_user_struct(vuid);
163 /****************************************************************************
164 Setup the groups a user belongs to.
165 ****************************************************************************/
166 int setup_groups(char *user, int uid, int gid, int *p_ngroups,
167 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));
185 ngroups = getgroups(0,&grp);
188 igroups = (int *)malloc(sizeof(int)*ngroups);
189 attrs = (int *)malloc(sizeof(int)*ngroups);
190 for (i=0;i<ngroups;i++)
192 attrs [i] = 0x7; /* XXXX don't know what NT user attributes are yet! */
193 igroups[i] = 0x42424242;
195 ngroups = getgroups(ngroups,(gid_t *)igroups);
197 if (igroups[0] == 0x42424242)
200 *p_ngroups = ngroups;
203 /* The following bit of code is very strange. It is due to the
204 fact that some OSes use int* and some use gid_t* for
205 getgroups, and some (like SunOS) use both, one in prototypes,
206 and one in man pages and the actual code. Thus we detect it
207 dynamically using some very ugly code */
210 /* does getgroups return ints or gid_t ?? */
211 static BOOL groups_use_ints = True;
213 if (groups_use_ints &&
215 SVAL(igroups,2) == 0x4242)
216 groups_use_ints = False;
218 for (i=0;groups_use_ints && i<ngroups;i++)
219 if (igroups[i] == 0x42424242)
220 groups_use_ints = False;
224 *p_igroups = igroups;
225 *p_groups = (gid_t *)igroups;
229 gid_t *groups = (gid_t *)igroups;
230 igroups = (int *)malloc(sizeof(int)*ngroups);
231 for (i=0;i<ngroups;i++)
233 igroups[i] = groups[i];
235 *p_igroups = igroups;
236 *p_groups = (gid_t *)groups;
239 DEBUG(3,("%s is in %d groups\n",user,ngroups));
240 for (i=0;i<ngroups;i++)
241 DEBUG(3,("%d ",igroups[i]));
248 /****************************************************************************
249 register a uid/name pair as being valid and that a valid password
250 has been given. vuid is biased by an offset. This allows us to
251 tell random client vuid's (normally zero) from valid vuids.
252 ****************************************************************************/
253 uint16 register_vuid(int uid,int gid, char *name,BOOL guest)
256 struct passwd *pwfile; /* for getting real name from passwd file */
258 /* Ensure no vuid gets registered in share level security. */
259 if(lp_security() == SEC_SHARE)
260 return UID_FIELD_INVALID;
264 * After observing MS-Exchange services writing to a Samba share
265 * I belive this code is incorrect. Each service does its own
266 * sessionsetup_and_X for the same user, and as each service shuts
267 * down, it does a user_logoff_and_X. As we are consolidating multiple
268 * sessionsetup_and_X's onto the same vuid here, when the first service
269 * shuts down, it invalidates all the open files for the other services.
270 * Hence I am removing this code and forcing each sessionsetup_and_X
272 * Jeremy Allison. (jallison@whistle.com).
276 for(i = 0; i < num_validated_users; i++) {
277 vuser = &validated_users[i];
278 if ( vuser->uid == uid )
279 return (uint16)(i + VUID_OFFSET); /* User already validated */
283 validated_users = (user_struct *)Realloc(validated_users,
285 (num_validated_users+1));
287 if (!validated_users)
289 DEBUG(0,("Failed to realloc users struct!\n"));
290 num_validated_users = 0;
291 return UID_FIELD_INVALID;
294 vuser = &validated_users[num_validated_users];
295 num_validated_users++;
299 vuser->guest = guest;
300 strcpy(vuser->name,name);
306 vuser->groups = NULL;
307 vuser->igroups = NULL;
310 /* Find all the groups this uid is in and store them.
311 Used by become_user() */
312 setup_groups(name,uid,gid,
318 DEBUG(3,("uid %d registered to name %s\n",uid,name));
320 DEBUG(3, ("Clearing default real name\n"));
321 fstrcpy(vuser->real_name, "<Full Name>\0");
322 if (lp_unix_realname()) {
323 if ((pwfile=getpwnam(vuser->name))!= NULL)
325 DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
326 fstrcpy(vuser->real_name, pwfile->pw_gecos);
330 return (uint16)((num_validated_users - 1) + VUID_OFFSET);
334 /****************************************************************************
335 add a name to the session users list
336 ****************************************************************************/
337 void add_session_user(char *user)
340 StrnCpy(suser,user,sizeof(suser)-1);
342 if (!Get_Pwnam(suser,True)) return;
344 if (suser && *suser && !in_list(suser,session_users,False))
346 if (strlen(suser) + strlen(session_users) + 2 >= sizeof(pstring))
347 DEBUG(1,("Too many session users??\n"));
350 strcat(session_users," ");
351 strcat(session_users,suser);
358 /* a fake shadow password routine which just fills a fake spwd struct
359 * with the sp_pwdp field. (sreiz@aie.nl)
361 static struct spwd *getspnam(char *username) /* fake shadow password routine */
366 static struct spwd static_spwd;
368 static_spwd.sp_pwdp=0;
369 if (!(f=fopen("/etc/master.passwd", "r")))
371 while (fgets(line, 1024, f)) {
372 if (!strncmp(line, username, strlen(username)) &&
373 line[strlen(username)]==':') { /* found entry */
376 p=line+strlen(username)+1;
377 if ((q=strchr(p, ':'))) {
382 static_spwd.sp_pwdp=pw;
388 if (static_spwd.sp_pwdp)
396 /****************************************************************************
397 an enhanced crypt for OSF1
398 ****************************************************************************/
399 static char *osf1_bigcrypt(char *password,char *salt1)
401 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
406 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
407 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
410 StrnCpy(salt,salt1,2);
411 StrnCpy(result,salt1,2);
413 for (i=0; i<parts;i++)
417 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
418 p2 += AUTH_CLEARTEXT_SEG_CHARS;
426 /****************************************************************************
427 update the enhanced security database. Only relevant for OSF1 at the moment.
428 ****************************************************************************/
429 static void update_protected_database( char *user, BOOL result)
432 struct pr_passwd *mypasswd;
435 mypasswd = getprpwnam (user);
436 starttime = time (NULL);
440 mypasswd->ufld.fd_slogin = starttime;
441 mypasswd->ufld.fd_nlogins = 0;
443 putprpwnam(user,mypasswd);
445 DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
449 mypasswd->ufld.fd_ulogin = starttime;
450 mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
451 if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
453 mypasswd->uflg.fg_lock = 0;
454 DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
456 putprpwnam ( user , mypasswd );
457 DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
460 DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
466 /*******************************************************************
467 check on PAM authentication
468 ********************************************************************/
470 /* We first need some helper functions */
471 #include <security/pam_appl.h>
472 /* Static variables used to communicate between the conversation function
473 * and the server_login function
475 static char *PAM_username;
476 static char *PAM_password;
478 /* PAM conversation function
479 * Here we assume (for now, at least) that echo on means login name, and
480 * echo off means password.
482 static int PAM_conv (int num_msg,
483 const struct pam_message **msg,
484 struct pam_response **resp,
487 struct pam_response *reply = NULL;
489 #define COPY_STRING(s) (s) ? strdup(s) : NULL
491 reply = malloc(sizeof(struct pam_response) * num_msg);
492 if (!reply) return PAM_CONV_ERR;
494 for (replies = 0; replies < num_msg; replies++) {
495 switch (msg[replies]->msg_style) {
496 case PAM_PROMPT_ECHO_ON:
497 reply[replies].resp_retcode = PAM_SUCCESS;
498 reply[replies].resp = COPY_STRING(PAM_username);
501 case PAM_PROMPT_ECHO_OFF:
502 reply[replies].resp_retcode = PAM_SUCCESS;
503 reply[replies].resp = COPY_STRING(PAM_password);
510 reply[replies].resp_retcode = PAM_SUCCESS;
511 reply[replies].resp = NULL;
514 /* Must be an error of some sort... */
519 if (reply) *resp = reply;
522 static struct pam_conv PAM_conversation = {
528 static BOOL pam_auth(char *this_user,char *password)
533 /* Now use PAM to do authentication. For now, we won't worry about
534 * session logging, only authentication. Bail out if there are any
535 * errors. Since this is a limited protocol, and an even more limited
536 * function within a server speaking this protocol, we can't be as
537 * verbose as would otherwise make sense.
538 * Query: should we be using PAM_SILENT to shut PAM up?
540 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
541 pam_end(pamh, 0); return False; \
543 PAM_password = password;
544 PAM_username = this_user;
545 pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
547 /* Setting PAM_SILENT stops generation of error messages to syslog
548 * to enable debugging on Red Hat Linux set:
550 * auth required /lib/security/pam_pwdb.so nullok shadow audit
551 * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
553 pam_error = pam_authenticate(pamh, PAM_SILENT);
555 /* It is not clear to me that account management is the right thing
556 * to do, but it is not clear that it isn't, either. This can be
557 * removed if no account management should be done. Alternately,
558 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
559 pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
561 pam_end(pamh, PAM_SUCCESS);
562 /* If this point is reached, the user has been authenticated. */
569 /*******************************************************************
570 check on AFS authentication
571 ********************************************************************/
572 static BOOL afs_auth(char *this_user,char *password)
574 long password_expires = 0;
577 /* For versions of AFS prior to 3.3, this routine has few arguments, */
578 /* but since I can't find the old documentation... :-) */
580 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
582 (char *) 0, /* instance */
583 (char *) 0, /* cell */
585 0, /* lifetime, default */
586 &password_expires, /*days 'til it expires */
597 sec_login_handle_t my_dce_sec_context;
598 int dcelogin_atmost_once = 0;
600 /*******************************************************************
601 check on a DCE/DFS authentication
602 ********************************************************************/
603 static BOOL dfs_auth(char *this_user,char *password)
608 boolean32 password_reset;
609 sec_passwd_rec_t my_dce_password;
610 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
611 unsigned char dce_errstr[dce_c_error_string_len];
614 * We only go for a DCE login context if the given password
615 * matches that stored in the local password file..
616 * Assumes local passwd file is kept in sync w/ DCE RGY!
619 /* Fix for original (broken) code from Brett Wooldridge <brettw@austin.ibm.com> */
620 if (dcelogin_atmost_once)
622 /* This can be ifdefed as the DCE check below is stricter... */
624 if ( strcmp((char *)crypt(password,this_salt),this_crypted) )
628 if (sec_login_setup_identity(
629 (unsigned char *)this_user,
634 dce_error_inq_text(err, dce_errstr, &err2);
635 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
636 this_user,dce_errstr));
640 my_dce_password.version_number = sec_passwd_c_version_none;
641 my_dce_password.pepper = NULL;
642 my_dce_password.key.key_type = sec_passwd_plain;
643 my_dce_password.key.tagged_union.plain = (idl_char *)password;
645 if (sec_login_valid_and_cert_ident(my_dce_sec_context,
651 dce_error_inq_text(err, dce_errstr, &err2);
652 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
653 this_user,dce_errstr));
658 sec_login_set_context(my_dce_sec_context, &err);
659 if (err != error_status_ok )
661 dce_error_inq_text(err, dce_errstr, &err2);
662 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
663 this_user,dce_errstr));
664 sec_login_purge_context(my_dce_sec_context, &err);
669 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
670 this_user, getpid()));
673 dcelogin_atmost_once = 1;
677 void dfs_unlogin(void)
681 unsigned char dce_errstr[dce_c_error_string_len];
683 sec_login_purge_context(my_dce_sec_context, &err);
684 if (err != error_status_ok )
686 dce_error_inq_text(err, dce_errstr, &err2);
687 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
688 getpid(), dce_errstr));
695 /*******************************************************************
696 check on Kerberos authentication
697 ********************************************************************/
698 static BOOL krb5_auth(char *this_user,char *password)
700 krb5_data tgtname = {
705 krb5_context kcontext;
706 krb5_principal kprinc;
707 krb5_principal server;
710 krb5_address **addrs = (krb5_address **)0;
711 krb5_preauthtype *preauth = NULL;
712 krb5_keytab keytab = NULL;
714 krb5_ccache ccache = NULL;
718 if ( retval=krb5_init_context(&kcontext))
723 if ( retval = krb5_timeofday(kcontext, &now) )
728 if ( retval = krb5_cc_default(kcontext, &ccache) )
733 if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
738 memset((char *)&kcreds, 0, sizeof(kcreds));
740 kcreds.client = kprinc;
742 if ((retval = krb5_build_principal_ext(kcontext, &server,
743 krb5_princ_realm(kcontext, kprinc)->length,
744 krb5_princ_realm(kcontext, kprinc)->data,
747 krb5_princ_realm(kcontext, kprinc)->length,
748 krb5_princ_realm(kcontext, kprinc)->data,
754 kcreds.server = server;
756 retval = krb5_get_in_tkt_with_password(kcontext,
773 #endif /* KRB5_AUTH */
776 /*******************************************************************
777 check on Kerberos authentication
778 ********************************************************************/
779 static BOOL krb4_auth(char *this_user,char *password)
781 char realm[REALM_SZ];
782 char tkfile[MAXPATHLEN];
784 if (krb_get_lrealm(realm, 1) != KSUCCESS)
785 (void) strncpy(realm, KRB_REALM, sizeof (realm));
787 (void) sprintf(tkfile, "/tmp/samba_tkt_%d", getpid());
789 krb_set_tkt_string(tkfile);
790 if (krb_verify_user(this_user, "", realm,
792 "rmcd") == KSUCCESS) {
799 #endif /* KRB4_AUTH */
801 #ifdef LINUX_BIGCRYPT
802 /****************************************************************************
803 an enhanced crypt for Linux to handle password longer than 8 characters
804 ****************************************************************************/
805 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
807 #define LINUX_PASSWORD_SEG_CHARS 8
811 StrnCpy(salt,salt1,2);
814 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
815 char * p = crypt(password,salt) + 2;
816 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
818 password += LINUX_PASSWORD_SEG_CHARS;
819 crypted += strlen(p);
827 /****************************************************************************
828 apply a function to upper/lower case combinations
829 of a string and return true if one of them returns true.
830 try all combinations with N uppercase letters.
831 offset is the first char to try and change (start with 0)
832 it assumes the string starts lowercased
833 ****************************************************************************/
834 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(char *),int N)
839 #ifdef PASSWORD_LENGTH
840 len = MIN(len,PASSWORD_LENGTH);
843 if (N <= 0 || offset >= len)
846 for (i=offset;i<(len-(N-1));i++)
849 if (!islower(c)) continue;
851 if (string_combinations2(s,i+1,fn,N-1))
858 /****************************************************************************
859 apply a function to upper/lower case combinations
860 of a string and return true if one of them returns true.
861 try all combinations with up to N uppercase letters.
862 offset is the first char to try and change (start with 0)
863 it assumes the string starts lowercased
864 ****************************************************************************/
865 static BOOL string_combinations(char *s,BOOL (*fn)(char *),int N)
869 if (string_combinations2(s,0,fn,n)) return(True);
875 /****************************************************************************
876 core of password checking routine
877 ****************************************************************************/
878 BOOL password_check(char *password)
882 /* This falls through if the password check fails
883 - if NO_CRYPT is defined this causes an error msg
884 saying Warning - no crypt available
885 - if NO_CRYPT is NOT defined this is a potential security hole
886 as it may authenticate via the crypt call when PAM
887 settings say it should fail.
888 if (pam_auth(this_user,password)) return(True);
889 Hence we make a direct return to avoid a second chance!!!
891 return (pam_auth(this_user,password));
895 if (afs_auth(this_user,password)) return(True);
899 if (dfs_auth(this_user,password)) return(True);
903 if (krb5_auth(this_user,password)) return(True);
907 if (krb4_auth(this_user,password)) return(True);
911 if (pwdauth(this_user,password) == 0)
916 return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
920 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
923 #ifdef LINUX_BIGCRYPT
924 return(linux_bigcrypt(password,this_salt,this_crypted));
927 #ifdef HPUX_10_TRUSTED
928 return(bigcrypt(password,this_salt,this_crypted));
932 DEBUG(1,("Warning - no crypt available\n"));
935 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
939 /****************************************************************************
940 core of smb password checking routine.
941 ****************************************************************************/
942 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8)
944 /* Finish the encryption of part_passwd. */
945 unsigned char p21[21];
946 unsigned char p24[24];
948 if (part_passwd == NULL)
949 DEBUG(10,("No password set - allowing access\n"));
950 /* No password set - always true ! */
951 if (part_passwd == NULL)
955 memcpy(p21,part_passwd,16);
960 DEBUG(100,("Part password (P16) was |"));
961 for(i = 0; i < 16; i++)
962 DEBUG(100,("%X ", (unsigned char)part_passwd[i]));
964 DEBUG(100,("Password from client was |"));
965 for(i = 0; i < 24; i++)
966 DEBUG(100,("%X ", (unsigned char)password[i]));
968 DEBUG(100,("Given challenge was |"));
969 for(i = 0; i < 8; i++)
970 DEBUG(100,("%X ", (unsigned char)c8[i]));
972 DEBUG(100,("Value from encryption was |"));
973 for(i = 0; i < 24; i++)
974 DEBUG(100,("%X ", (unsigned char)p24[i]));
978 return (memcmp(p24, password, 24) == 0);
981 /****************************************************************************
982 Do a specific test for an smb password being correct, given a smb_password and
983 the lanman and NT responses.
984 ****************************************************************************/
986 BOOL smb_password_ok(struct smb_passwd *smb_pass,
987 uchar lm_pass[24], uchar nt_pass[24])
991 if (!lm_pass || !smb_pass) return(False);
993 if(smb_pass->acct_ctrl & ACB_DISABLED)
995 DEBUG(3,("smb_password_ok: account for user %s was disabled.\n", smb_pass->smb_name));
999 if (!last_challenge(challenge))
1001 DEBUG(1,("smb_password_ok: no challenge done - password failed\n"));
1005 DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n", smb_pass->smb_name));
1007 if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL))
1009 /* We have the NT MD4 hash challenge available - see if we can
1010 use it (ie. does it exist in the smbpasswd file).
1012 DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
1013 if (smb_password_check(nt_pass, smb_pass->smb_nt_passwd, challenge))
1015 DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n"));
1018 DEBUG(4,("smb_password_ok: NT MD4 password check failed\n"));
1021 /* Try against the lanman password. smb_pass->smb_passwd == NULL means
1022 no password, allow access. */
1024 DEBUG(4,("Checking LM MD4 password\n"));
1026 if((smb_pass->smb_passwd == NULL) && (smb_pass->acct_ctrl & ACB_PWNOTREQ))
1028 DEBUG(4,("smb_password_ok: no password required for user %s\n", smb_pass->smb_name));
1032 if((smb_pass->smb_passwd != NULL) && smb_password_check(lm_pass, smb_pass->smb_passwd, challenge))
1034 DEBUG(4,("smb_password_ok: LM MD4 password check succeeded\n"));
1038 DEBUG(4,("smb_password_ok: LM MD4 password check failed\n"));
1043 /****************************************************************************
1044 check if a username/password is OK
1045 ****************************************************************************/
1046 BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
1049 int level = lp_passwordlevel();
1050 struct passwd *pass;
1052 struct smb_passwd *smb_pass;
1053 BOOL challenge_done = False;
1055 if (password) password[pwlen] = 0;
1058 challenge_done = last_challenge(challenge);
1064 DEBUG(100,("checking user=[%s] pass=[",user));
1065 for( i = 0; i < 24; i++)
1066 DEBUG(100,("%0x ", (unsigned char)password[i]));
1069 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
1076 if (((!*password) || (!pwlen)) && !lp_null_passwords())
1081 pass = (struct passwd *) pwd;
1082 user = pass->pw_name;
1085 pass = Get_Pwnam(user,True);
1087 DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
1089 if ((pwlen == 24) && challenge_done)
1091 DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
1095 DEBUG(3,("Couldn't find user %s\n",user));
1099 smb_pass = getsmbpwnam(user);
1103 DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
1107 /* Quit if the account was disabled. */
1108 if(smb_pass->acct_ctrl & ACB_DISABLED)
1110 DEBUG(3,("password_ok: account for user %s was disabled.\n", user));
1114 /* Ensure the uid's match */
1115 if (smb_pass->smb_userid != pass->pw_uid)
1117 DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
1121 if(smb_password_ok( smb_pass, password, password))
1123 update_protected_database(user,True);
1127 DEBUG(3,("Error smb_password_check failed\n"));
1130 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
1134 DEBUG(3,("Couldn't find user %s\n",user));
1142 /* many shadow systems require you to be root to get the password,
1143 in most cases this should already be the case when this
1144 function is called, except perhaps for IPC password changing
1147 spass = getspnam(pass->pw_name);
1148 if (spass && spass->sp_pwdp)
1149 pass->pw_passwd = spass->sp_pwdp;
1151 #elif defined(IA_UINFO)
1153 /* Need to get password with SVR4.2's ia_ functions instead of
1154 get{sp,pw}ent functions. Required by UnixWare 2.x, tested on
1155 version 2.1. (tangent@cyberport.com) */
1157 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
1158 ia_get_logpwd(uinfo, &(pass->pw_passwd));
1164 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1165 if (pr_pw && pr_pw->ufld.fd_encrypt)
1166 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1170 #ifdef HPUX_10_TRUSTED
1172 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
1173 if (pr_pw && pr_pw->ufld.fd_encrypt)
1174 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
1180 struct pr_passwd *mypasswd;
1181 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
1182 mypasswd = getprpwnam (user);
1185 strcpy(pass->pw_name,mypasswd->ufld.fd_name);
1186 strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
1190 DEBUG(5,("No entry for user %s in protected database !\n",user));
1198 AUTHORIZATION *ap = getauthuid( pass->pw_uid );
1201 strcpy( pass->pw_passwd, ap->a_password );
1207 /* extract relevant info */
1208 strcpy(this_user,pass->pw_name);
1209 strcpy(this_salt,pass->pw_passwd);
1211 /* The crypt on HPUX won't work with more than 2 salt characters. */
1214 strcpy(this_crypted,pass->pw_passwd);
1216 if (!*this_crypted) {
1217 if (!lp_null_passwords()) {
1218 DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
1223 DEBUG(3,("Allowing access to %s with null password\n",this_user));
1229 /* try it as it came to us */
1230 if (password_check(password))
1232 update_protected_database(user,True);
1236 /* if the password was given to us with mixed case then we don't
1237 need to proceed as we know it hasn't been case modified by the
1239 if (strhasupper(password) && strhaslower(password))
1242 /* make a copy of it */
1243 StrnCpy(pass2,password,sizeof(pstring)-1);
1245 /* try all lowercase */
1247 if (password_check(password))
1249 update_protected_database(user,True);
1256 update_protected_database(user,False);
1259 strcpy(password,pass2);
1264 /* last chance - all combinations of up to level chars upper! */
1267 if (string_combinations(password,password_check,level))
1269 update_protected_database(user,True);
1273 update_protected_database(user,False);
1276 strcpy(password,pass2);
1283 /****************************************************************************
1284 check if a username is valid
1285 ****************************************************************************/
1286 BOOL user_ok(char *user,int snum)
1288 pstring valid, invalid;
1291 StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
1292 StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
1294 string_sub(valid,"%S",lp_servicename(snum));
1295 string_sub(invalid,"%S",lp_servicename(snum));
1297 ret = !user_in_list(user,invalid);
1299 if (ret && valid && *valid)
1300 ret = user_in_list(user,valid);
1302 if (ret && lp_onlyuser(snum)) {
1303 char *user_list = lp_username(snum);
1304 string_sub(user_list,"%S",lp_servicename(snum));
1305 ret = user_in_list(user,user_list);
1314 /****************************************************************************
1315 validate a group username entry. Return the username or NULL
1316 ****************************************************************************/
1317 static char *validate_group(char *group,char *password,int pwlen,int snum)
1321 char *host, *user, *domain;
1323 while (getnetgrent(&host, &user, &domain)) {
1325 if (user_ok(user, snum) &&
1326 password_ok(user,password,pwlen,NULL)) {
1338 struct group *gptr = (struct group *)getgrnam(group);
1342 member = gptr->gr_mem;
1343 while (member && *member)
1345 static fstring name;
1346 strcpy(name,*member);
1347 if (user_ok(name,snum) &&
1348 password_ok(name,password,pwlen,NULL))
1352 #ifdef GROUP_CHECK_PWENT
1358 while (pwd = getpwent ()) {
1359 if (*(pwd->pw_passwd) && pwd->pw_gid == gptr->gr_gid) {
1360 /* This Entry have PASSWORD and same GID then check pwd */
1361 if (password_ok(NULL, password, pwlen, pwd)) {
1362 strcpy(tm, pwd->pw_name);
1370 #endif /* GROUP_CHECK_PWENT */
1379 /****************************************************************************
1380 check for authority to login to a service with a given username/password
1381 ****************************************************************************/
1382 BOOL authorise_login(int snum,char *user,char *password, int pwlen,
1383 BOOL *guest,BOOL *force,uint16 vuid)
1390 DEBUG(100,("checking authorisation on user=%s pass=%s\n",user,password));
1393 /* there are several possibilities:
1394 1) login as the given user with given password
1395 2) login as a previously registered username with the given password
1396 3) login as a session list username with the given password
1397 4) login as a previously validated user/password pair
1398 5) login as the "user =" user with given password
1399 6) login as the "user =" user with no password (guest connection)
1400 7) login as guest user with no password
1402 if the service is guest_only then steps 1 to 5 are skipped
1405 if (GUEST_ONLY(snum)) *force = True;
1407 if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
1410 user_struct *vuser = get_valid_user_struct(vuid);
1412 /* check the given username and password */
1413 if (!ok && (*user) && user_ok(user,snum)) {
1414 ok = password_ok(user,password, pwlen, NULL);
1415 if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
1418 /* check for a previously registered guest username */
1419 if (!ok && (vuser != 0) && vuser->guest) {
1420 if (user_ok(vuser->name,snum) &&
1421 password_ok(vuser->name, password, pwlen, NULL)) {
1422 strcpy(user, vuser->name);
1423 vuser->guest = False;
1424 DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
1430 /* now check the list of session users */
1434 char *user_list = strdup(session_users);
1435 if (!user_list) return(False);
1437 for (auser=strtok(user_list,LIST_SEP);
1439 auser = strtok(NULL,LIST_SEP))
1442 strcpy(user2,auser);
1443 if (!user_ok(user2,snum)) continue;
1445 if (password_ok(user2,password, pwlen, NULL)) {
1448 DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
1454 /* check for a previously validated username/password pair */
1455 if (!ok && !lp_revalidate(snum) &&
1456 (vuser != 0) && !vuser->guest &&
1457 user_ok(vuser->name,snum)) {
1458 strcpy(user,vuser->name);
1460 DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
1464 /* check for a rhosts entry */
1465 if (!ok && user_ok(user,snum) && check_hosts_equiv(user)) {
1467 DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
1470 /* check the user= fields and the given password */
1471 if (!ok && lp_username(snum)) {
1474 StrnCpy(user_list,lp_username(snum),sizeof(pstring));
1476 string_sub(user_list,"%S",lp_servicename(snum));
1478 for (auser=strtok(user_list,LIST_SEP);
1480 auser = strtok(NULL,LIST_SEP))
1484 auser = validate_group(auser+1,password,pwlen,snum);
1489 DEBUG(3,("ACCEPTED: group username and given password ok\n"));
1495 strcpy(user2,auser);
1496 if (user_ok(user2,snum) &&
1497 password_ok(user2,password,pwlen,NULL))
1501 DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
1506 } /* not guest only */
1508 /* check for a normal guest connection */
1509 if (!ok && GUEST_OK(snum))
1512 StrnCpy(guestname,lp_guestaccount(snum),sizeof(guestname)-1);
1513 if (Get_Pwnam(guestname,True))
1515 strcpy(user,guestname);
1517 DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
1520 DEBUG(0,("Invalid guest account %s??\n",guestname));
1525 if (ok && !user_ok(user,snum))
1527 DEBUG(0,("rejected invalid user %s\n",user));
1535 /****************************************************************************
1536 read the a hosts.equiv or .rhosts file and check if it
1537 allows this user from this machine
1538 ****************************************************************************/
1539 static BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
1542 int plus_allowed = 1;
1545 FILE *fp = fopen(equiv_file, "r");
1546 DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
1547 if (! fp) return False;
1548 while(fgets(buf, sizeof(buf), fp))
1550 trim_string(buf," "," ");
1552 if (buf[0] != '#' && buf[0] != '\n')
1554 BOOL is_group = False;
1557 if (strcmp(buf, "NO_PLUS\n") == 0)
1559 DEBUG(6, ("check_user_equiv NO_PLUS\n"));
1566 if (*bp == '\n' && plus_allowed)
1568 /* a bare plus means everbody allowed */
1569 DEBUG(6, ("check_user_equiv everybody allowed\n"));
1574 else if (buf[0] == '-')
1584 file_host = strtok(bp, " \t\n");
1585 file_user = strtok(NULL, " \t\n");
1586 DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)",
1587 file_user ? file_user : "(null)" ));
1588 if (file_host && *file_host)
1590 BOOL host_ok = False;
1595 static char *mydomain = NULL;
1597 yp_get_default_domain(&mydomain);
1598 if (mydomain && innetgr(file_host,remote,user,mydomain))
1604 DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
1609 /* is it this host */
1610 /* the fact that remote has come from a call of gethostbyaddr
1611 * means that it may have the fully qualified domain name
1612 * so we could look up the file version to get it into
1613 * a canonical form, but I would rather just type it
1614 * in full in the equiv file
1616 if (!host_ok && !is_group && strequal(remote, file_host))
1622 /* is it this user */
1623 if (file_user == 0 || strequal(user, file_user))
1626 DEBUG(5, ("check_user_equiv matched %s%s %s\n",
1627 (plus ? "+" : "-"), file_host,
1628 (file_user ? file_user : "")));
1629 return (plus ? True : False);
1640 /****************************************************************************
1641 check for a possible hosts equiv or rhosts entry for the user
1642 ****************************************************************************/
1643 BOOL check_hosts_equiv(char *user)
1647 struct passwd *pass = Get_Pwnam(user,True);
1652 fname = lp_hosts_equiv();
1654 /* note: don't allow hosts.equiv on root */
1655 if (fname && *fname && (pass->pw_uid != 0)) {
1657 if (check_user_equiv(user,client_name(Client),fname))
1661 if (lp_use_rhosts())
1663 char *home = get_home_dir(user);
1666 sprintf(rhostsfile, "%s/.rhosts", home);
1667 if (check_user_equiv(user,client_name(Client),rhostsfile))
1676 static struct cli_state pw_cli;
1678 /****************************************************************************
1679 return the client state structure
1680 ****************************************************************************/
1681 struct cli_state *server_client(void)
1686 /****************************************************************************
1687 support for server level security
1688 ****************************************************************************/
1689 struct cli_state *server_cryptkey(void)
1692 struct in_addr dest_ip;
1693 extern fstring local_machine;
1695 BOOL connected_ok = False;
1697 if (!cli_initialise(&pw_cli))
1700 p = lp_passwordserver();
1701 while(p && next_token( &p, desthost, LIST_SEP)) {
1702 standard_sub_basic(desthost);
1705 if(!resolve_name( desthost, &dest_ip)) {
1706 DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
1710 if (ismyip(dest_ip)) {
1711 DEBUG(1,("Password server loop - disabling password server %s\n",desthost));
1715 if (cli_connect(&pw_cli, desthost, &dest_ip)) {
1716 DEBUG(3,("connected to password server %s\n",desthost));
1717 connected_ok = True;
1722 if (!connected_ok) {
1723 DEBUG(0,("password server not available\n"));
1724 cli_shutdown(&pw_cli);
1728 if (!cli_session_request(&pw_cli, desthost, 0x20, local_machine)) {
1729 DEBUG(1,("%s rejected the session\n",desthost));
1730 cli_shutdown(&pw_cli);
1734 DEBUG(3,("got session\n"));
1736 if (!cli_negprot(&pw_cli)) {
1737 DEBUG(1,("%s rejected the negprot\n",desthost));
1738 cli_shutdown(&pw_cli);
1742 if (pw_cli.protocol < PROTOCOL_LANMAN2 ||
1743 !(pw_cli.sec_mode & 1)) {
1744 DEBUG(1,("%s isn't in user level security mode\n",desthost));
1745 cli_shutdown(&pw_cli);
1749 DEBUG(3,("password server OK\n"));
1754 /****************************************************************************
1755 validate a password with the password server
1756 ****************************************************************************/
1757 BOOL server_validate(char *user, char *domain,
1758 char *pass, int passlen,
1759 char *ntpass, int ntpasslen)
1761 extern fstring local_machine;
1762 static unsigned char badpass[24];
1764 if (!pw_cli.initialised) {
1765 DEBUG(1,("password server %s is not connected\n", pw_cli.desthost));
1769 if(badpass[0] == 0) {
1770 memset(badpass, 0x1f, sizeof(badpass));
1773 if((passlen == sizeof(badpass)) && !memcmp(badpass, pass, passlen)) {
1774 /* Very unlikely, our random bad password is the same as the users
1776 memset(badpass, badpass[0]+1, sizeof(badpass));
1780 * Attempt a session setup with a totally incorrect password.
1781 * If this succeeds with the guest bit *NOT* set then the password
1782 * server is broken and is not correctly setting the guest bit. We
1783 * need to detect this as some versions of NT4.x are broken. JRA.
1786 if (cli_session_setup(&pw_cli, user, badpass, sizeof(badpass), badpass, sizeof(badpass),
1788 if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) == 0) {
1789 DEBUG(0,("server_validate: password server %s allows users as non-guest \
1790 with a bad password.\n", pw_cli.desthost));
1791 DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \
1792 use this machine as the password server.\n"));
1793 cli_ulogoff(&pw_cli);
1796 cli_ulogoff(&pw_cli);
1800 * Now we know the password server will correctly set the guest bit, or is
1801 * not guest enabled, we can try with the real password.
1804 if (!cli_session_setup(&pw_cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
1805 DEBUG(1,("password server %s rejected the password\n", pw_cli.desthost));
1809 /* if logged in as guest then reject */
1810 if ((SVAL(pw_cli.inbuf,smb_vwv2) & 1) != 0) {
1811 DEBUG(1,("password server %s gave us guest only\n", pw_cli.desthost));
1812 cli_ulogoff(&pw_cli);
1816 if (!cli_send_tconX(&pw_cli, "IPC$", "IPC", "", 1)) {
1817 DEBUG(1,("password server %s refused IPC$ connect\n", pw_cli.desthost));
1818 cli_ulogoff(&pw_cli);
1823 * This patch from Rob Nielsen <ran@adc.com> makes doing
1824 * the NetWksaUserLogon a dynamic, rather than compile-time
1825 * parameter, defaulting to on. This is somewhat dangerous
1826 * as it allows people to turn off this neccessary check,
1827 * but so many people have had problems with this that I
1828 * think it is a neccessary change. JRA.
1831 if (lp_net_wksta_user_logon()) {
1832 DEBUG(3,("trying NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
1833 if (!cli_NetWkstaUserLogon(&pw_cli,user,local_machine)) {
1834 DEBUG(1,("password server %s failed NetWkstaUserLogon\n", pw_cli.desthost));
1836 cli_ulogoff(&pw_cli);
1840 if (pw_cli.privilages == 0) {
1841 DEBUG(1,("password server %s gave guest privilages\n", pw_cli.desthost));
1843 cli_ulogoff(&pw_cli);
1847 if (!strequal(pw_cli.eff_name, user)) {
1848 DEBUG(1,("password server %s gave different username %s\n",
1852 cli_ulogoff(&pw_cli);
1857 DEBUG(3,("skipping NetWkstaUserLogon with password server %s\n", pw_cli.desthost));
1860 DEBUG(3,("password server %s accepted the password\n", pw_cli.desthost));
1863 cli_ulogoff(&pw_cli);
1868 #ifdef DOMAIN_CLIENT
1869 /***********************************************************************
1870 Do the same as security=server, but using NT Domain calls and a session
1871 key from the machine password.
1872 ************************************************************************/
1874 BOOL domain_client_validate( char *user, char *domain,
1875 char *smb_apasswd, int smb_apasslen,
1876 char *smb_ntpasswd, int smb_ntpasslen)
1878 unsigned char local_lm_hash[21];
1879 unsigned char local_nt_hash[21];
1880 unsigned char local_challenge[8];
1881 unsigned char local_lm_response[24];
1882 unsigned char local_nt_reponse[24];
1883 BOOL encrypted = True;
1884 fstring remote_machine;
1886 struct in_addr dest_ip;
1887 struct cli_state cli;
1888 BOOL connected_ok = False;
1891 * Check that the requested domain is not our own machine name.
1892 * If it is, we should never check the PDC here, we use our own local
1896 if(strequal( domain, myname)) {
1897 DEBUG(3,("domain_client_validate: Requested domain was for this machine.\n"));
1902 * Next, check that the passwords given were encrypted.
1905 if(smb_apasslen != 24 || smb_ntpasslen != 24) {
1908 * Not encrypted - do so.
1911 DEBUG(3,("domain_client_validate: User passwords not in encrypted format.\n"));
1913 memset(local_lm_hash, '\0', sizeof(local_lm_hash));
1914 E_P16((uchar *) smb_apasswd, local_lm_hash);
1915 memset(local_nt_hash, '\0', sizeof(local_nt_hash));
1916 E_md4hash((uchar *) smb_ntpasswd, local_nt_hash);
1917 generate_random_buffer( local_challenge, 8, False);
1918 E_P24(local_lm_hash, local_challenge, local_lm_response);
1919 E_P24(local_nt_hash, local_challenge, local_nt_reponse);
1922 smb_apasswd = (char *)local_lm_response;
1923 smb_ntpasswd = (char *)local_nt_reponse;
1927 * Encrypted - get the challenge we sent for these
1931 if (!last_challenge(local_challenge)) {
1932 DEBUG(0,("domain_client_validate: no challenge done - password failed\n"));
1938 * At this point, smb_apasswd points to the lanman response to
1939 * the challenge in local_challenge, and smb_ntpasswd points to
1940 * the NT response to the challenge in local_challenge. Ship
1941 * these over the secure channel to a domain controller and
1942 * see if they were valid.
1946 * Treat each name in the 'password server =' line as a potential
1947 * PDC/BDC. Contact each in turn and try and authenticate.
1950 p = lp_passwordserver();
1951 while(p && next_token( &p, remote_machine, LIST_SEP)) {
1953 standard_sub_basic(remote_machine);
1954 strupper(remote_machine);
1956 if(!resolve_name( remote_machine, &dest_ip)) {
1957 DEBUG(1,("domain_client_validate: Can't resolve address for %s\n", remote_machine));
1961 if (ismyip(dest_ip)) {
1962 DEBUG(1,("domain_client_validate: Password server loop - not using password server %s\n",remote_machine));
1966 memset(&cli, '\0', sizeof(struct cli_state));
1968 if (!cli_connect(&cli, remote_machine, &dest_ip)) {
1969 DEBUG(0,("domain_client_validate: unable to connect to SMB server on \
1970 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1974 if (!cli_session_request(&cli, remote_machine, 0x20, myname)) {
1975 DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
1976 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1981 cli.protocol = PROTOCOL_NT1;
1983 if (!cli_negprot(&cli)) {
1984 DEBUG(0,("domain_client_validate: machine %s rejected the negotiate protocol. \
1985 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1990 if (cli.protocol != PROTOCOL_NT1) {
1991 DEBUG(0,("domain_client_validate: machine %s didn't negotiate NT protocol.\n",
1998 * Do an anonymous session setup.
2001 if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
2002 DEBUG(0,("domain_client_validate: machine %s rejected the session setup. \
2003 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2008 if (!(cli.sec_mode & 1)) {
2009 DEBUG(1,("domain_client_validate: machine %s isn't in user level security mode\n",
2015 if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
2016 DEBUG(0,("domain_client_validate: machine %s rejected the tconX on the IPC$ share. \
2017 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
2023 * We have an anonymous connection to IPC$.
2025 connected_ok = True;
2029 if (!connected_ok) {
2030 DEBUG(0,("domain_client_validate: Domain password server not available.\n"));
2036 * Ok - we have an anonymous connection to the IPC$ share.
2037 * Now start the NT Domain stuff :-).
2042 #endif /* DOMAIN_CLIENT */