This commit was manufactured by cvs2svn to create branch 'SAMBA_2_0'.
[Samba.git] / source / auth / pass_check.c
blobf6cfdae6c110379e8e9e944d70aa02acd4927103
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Password checking
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.
22 /* this module is for checking a username/password against a system
23 password database. The SMB encrypted password support is elsewhere */
25 #include "includes.h"
27 extern int DEBUGLEVEL;
29 /* these are kept here to keep the string_combinations function simple */
30 static char this_user[100]="";
31 static char this_salt[100]="";
32 static char this_crypted[100]="";
35 #ifdef HAVE_PAM
36 /*******************************************************************
37 check on PAM authentication
38 ********************************************************************/
40 /* We first need some helper functions */
41 #include <security/pam_appl.h>
42 /* Static variables used to communicate between the conversation function
43 * and the server_login function
45 static char *PAM_username;
46 static char *PAM_password;
48 /* PAM conversation function
49 * Here we assume (for now, at least) that echo on means login name, and
50 * echo off means password.
52 static int PAM_conv (int num_msg,
53 const struct pam_message **msg,
54 struct pam_response **resp,
55 void *appdata_ptr) {
56 int replies = 0;
57 struct pam_response *reply = NULL;
59 #define COPY_STRING(s) (s) ? strdup(s) : NULL
61 reply = malloc(sizeof(struct pam_response) * num_msg);
62 if (!reply) return PAM_CONV_ERR;
64 for (replies = 0; replies < num_msg; replies++) {
65 switch (msg[replies]->msg_style) {
66 case PAM_PROMPT_ECHO_ON:
67 reply[replies].resp_retcode = PAM_SUCCESS;
68 reply[replies].resp = COPY_STRING(PAM_username);
69 /* PAM frees resp */
70 break;
71 case PAM_PROMPT_ECHO_OFF:
72 reply[replies].resp_retcode = PAM_SUCCESS;
73 reply[replies].resp = COPY_STRING(PAM_password);
74 /* PAM frees resp */
75 break;
76 case PAM_TEXT_INFO:
77 /* fall through */
78 case PAM_ERROR_MSG:
79 /* ignore it... */
80 reply[replies].resp_retcode = PAM_SUCCESS;
81 reply[replies].resp = NULL;
82 break;
83 default:
84 /* Must be an error of some sort... */
85 free (reply);
86 return PAM_CONV_ERR;
89 if (reply) *resp = reply;
90 return PAM_SUCCESS;
92 static struct pam_conv PAM_conversation = {
93 &PAM_conv,
94 NULL
98 static BOOL pam_auth(char *user,char *password)
100 pam_handle_t *pamh;
101 int pam_error;
103 /* Now use PAM to do authentication. For now, we won't worry about
104 * session logging, only authentication. Bail out if there are any
105 * errors. Since this is a limited protocol, and an even more limited
106 * function within a server speaking this protocol, we can't be as
107 * verbose as would otherwise make sense.
108 * Query: should we be using PAM_SILENT to shut PAM up?
110 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
111 pam_end(pamh, 0); return False; \
113 PAM_password = password;
114 PAM_username = user;
115 pam_error = pam_start("samba", user, &PAM_conversation, &pamh);
116 PAM_BAIL;
117 /* Setting PAM_SILENT stops generation of error messages to syslog
118 * to enable debugging on Red Hat Linux set:
119 * /etc/pam.d/samba:
120 * auth required /lib/security/pam_pwdb.so nullok shadow audit
121 * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
123 pam_error = pam_authenticate(pamh, PAM_SILENT);
124 PAM_BAIL;
125 /* It is not clear to me that account management is the right thing
126 * to do, but it is not clear that it isn't, either. This can be
127 * removed if no account management should be done. Alternately,
128 * put a pam_allow.so entry in /etc/pam.conf for account handling. */
129 pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
130 PAM_BAIL;
131 pam_end(pamh, PAM_SUCCESS);
132 /* If this point is reached, the user has been authenticated. */
133 return(True);
135 #endif
138 #ifdef WITH_AFS
139 /*******************************************************************
140 check on AFS authentication
141 ********************************************************************/
142 static BOOL afs_auth(char *user,char *password)
144 long password_expires = 0;
145 char *reason;
147 /* For versions of AFS prior to 3.3, this routine has few arguments, */
148 /* but since I can't find the old documentation... :-) */
149 setpag();
150 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
151 user,
152 (char *) 0, /* instance */
153 (char *) 0, /* cell */
154 password,
155 0, /* lifetime, default */
156 &password_expires, /*days 'til it expires */
157 0, /* spare 2 */
158 &reason) == 0) {
159 return(True);
161 return(False);
163 #endif
166 #ifdef WITH_DFS
168 /*****************************************************************
169 This new version of the DFS_AUTH code was donated by Karsten Muuss
170 <muuss@or.uni-bonn.de>. It fixes the following problems with the
171 old code :
173 - Server credentials may expire
174 - Client credential cache files have wrong owner
175 - purge_context() function is called with invalid argument
177 This new code was modified to ensure that on exit the uid/gid is
178 still root, and the original directory is restored. JRA.
179 ******************************************************************/
181 sec_login_handle_t my_dce_sec_context;
182 int dcelogin_atmost_once = 0;
184 /*******************************************************************
185 check on a DCE/DFS authentication
186 ********************************************************************/
187 static BOOL dfs_auth(char *user,char *password)
189 error_status_t err;
190 int err2;
191 int prterr;
192 signed32 expire_time, current_time;
193 boolean32 password_reset;
194 struct passwd *pw;
195 sec_passwd_rec_t passwd_rec;
196 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
197 unsigned char dce_errstr[dce_c_error_string_len];
199 if (dcelogin_atmost_once) return(False);
201 #ifdef HAVE_CRYPT
203 * We only go for a DCE login context if the given password
204 * matches that stored in the local password file..
205 * Assumes local passwd file is kept in sync w/ DCE RGY!
208 if (strcmp((char *)crypt(password,this_salt),this_crypted)) {
209 return(False);
211 #endif
213 sec_login_get_current_context(&my_dce_sec_context, &err);
214 if (err != error_status_ok ) {
215 dce_error_inq_text(err, dce_errstr, &err2);
216 DEBUG(0,("DCE can't get current context. %s\n", dce_errstr));
218 return(False);
221 sec_login_certify_identity(my_dce_sec_context, &err);
222 if (err != error_status_ok) {
223 dce_error_inq_text(err, dce_errstr, &err2);
224 DEBUG(0,("DCE can't get current context. %s\n", dce_errstr));
226 return(False);
229 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
230 if (err != error_status_ok) {
231 dce_error_inq_text(err, dce_errstr, &err2);
232 DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
234 return(False);
237 time(&current_time);
239 if (expire_time < (current_time + 60)) {
240 struct passwd *pw;
241 sec_passwd_rec_t *key;
243 sec_login_get_pwent(my_dce_sec_context,
244 (sec_login_passwd_t*)&pw, &err);
245 if (err != error_status_ok ) {
246 dce_error_inq_text(err, dce_errstr, &err2);
247 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
249 return(False);
252 sec_login_refresh_identity(my_dce_sec_context, &err);
253 if (err != error_status_ok) {
254 dce_error_inq_text(err, dce_errstr, &err2);
255 DEBUG(0,("DCE can't refresh identity. %s\n",
256 dce_errstr));
258 return(False);
261 sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
262 (unsigned char *)pw->pw_name,
263 sec_c_key_version_none,
264 (void**)&key, &err);
265 if (err != error_status_ok) {
266 dce_error_inq_text(err, dce_errstr, &err2);
267 DEBUG(0,("DCE can't get key for %s. %s\n",
268 pw->pw_name, dce_errstr));
270 return(False);
273 sec_login_valid_and_cert_ident(my_dce_sec_context, key,
274 &password_reset, &auth_src,
275 &err);
276 if (err != error_status_ok ) {
277 dce_error_inq_text(err, dce_errstr, &err2);
278 DEBUG(0,("DCE can't validate and certify identity for %s. %s\n",
279 pw->pw_name, dce_errstr));
282 sec_key_mgmt_free_key(key, &err);
283 if (err != error_status_ok ) {
284 dce_error_inq_text(err, dce_errstr, &err2);
285 DEBUG(0,("DCE can't free key.\n", dce_errstr));
289 if (sec_login_setup_identity((unsigned char *)user,
290 sec_login_no_flags,
291 &my_dce_sec_context,
292 &err) == 0) {
293 dce_error_inq_text(err, dce_errstr, &err2);
294 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
295 user,dce_errstr));
296 return(False);
299 sec_login_get_pwent(my_dce_sec_context,
300 (sec_login_passwd_t*)&pw, &err);
301 if (err != error_status_ok) {
302 dce_error_inq_text(err, dce_errstr, &err2);
303 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
305 return(False);
308 sec_login_purge_context(&my_dce_sec_context, &err);
309 if (err != error_status_ok) {
310 dce_error_inq_text(err, dce_errstr, &err2);
311 DEBUG(0,("DCE can't purge context. %s\n", dce_errstr));
313 return(False);
317 * NB. I'd like to change these to call something like become_user()
318 * instead but currently we don't have a connection
319 * context to become the correct user. This is already
320 * fairly platform specific code however, so I think
321 * this should be ok. I have added code to go
322 * back to being root on error though. JRA.
325 if (setregid(-1, pw->pw_gid) != 0) {
326 DEBUG(0,("Can't set egid to %d (%s)\n",
327 pw->pw_gid, strerror(errno)));
328 return False;
331 if (setreuid(-1, pw->pw_uid) != 0) {
332 setgid(0);
333 DEBUG(0,("Can't set euid to %d (%s)\n",
334 pw->pw_uid, strerror(errno)));
335 return False;
338 if (sec_login_setup_identity((unsigned char *)user,
339 sec_login_no_flags,
340 &my_dce_sec_context,
341 &err) == 0) {
342 dce_error_inq_text(err, dce_errstr, &err2);
343 /* Go back to root, JRA. */
344 setuid(0);
345 setgid(0);
346 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
347 user,dce_errstr));
348 return(False);
351 sec_login_get_pwent(my_dce_sec_context,
352 (sec_login_passwd_t*)&pw, &err);
353 if (err != error_status_ok ) {
354 dce_error_inq_text(err, dce_errstr, &err2);
355 /* Go back to root, JRA. */
356 setuid(0);
357 setgid(0);
358 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
360 return(False);
363 passwd_rec.version_number = sec_passwd_c_version_none;
364 passwd_rec.pepper = NULL;
365 passwd_rec.key.key_type = sec_passwd_plain;
366 passwd_rec.key.tagged_union.plain = (idl_char *)password;
368 sec_login_validate_identity(my_dce_sec_context,
369 &passwd_rec, &password_reset,
370 &auth_src, &err);
371 if (err != error_status_ok ) {
372 dce_error_inq_text(err, dce_errstr, &err2);
373 /* Go back to root, JRA. */
374 setuid(0);
375 setgid(0);
376 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
377 user,dce_errstr));
379 return(False);
382 sec_login_certify_identity(my_dce_sec_context, &err);
383 if (err != error_status_ok) {
384 dce_error_inq_text(err, dce_errstr, &err2);
385 /* Go back to root, JRA. */
386 setuid(0);
387 setgid(0);
388 DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr));
390 return(False);
393 if (auth_src != sec_login_auth_src_network) {
394 DEBUG(0,("DCE context has no network credentials.\n"));
397 sec_login_set_context(my_dce_sec_context, &err);
398 if (err != error_status_ok) {
399 dce_error_inq_text(err, dce_errstr, &err2);
400 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
401 user,dce_errstr));
403 sec_login_purge_context(&my_dce_sec_context, &err);
404 /* Go back to root, JRA. */
405 setuid(0);
406 setgid(0);
407 return(False);
410 sec_login_get_pwent(my_dce_sec_context,
411 (sec_login_passwd_t*)&pw, &err);
412 if (err != error_status_ok) {
413 dce_error_inq_text(err, dce_errstr, &err2);
414 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
416 /* Go back to root, JRA. */
417 setuid(0);
418 setgid(0);
419 return(False);
422 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
423 user, getpid()));
425 DEBUG(3,("DCE principal: %s\n"
426 " uid: %d\n"
427 " gid: %d\n",
428 pw->pw_name, pw->pw_uid, pw->pw_gid));
429 DEBUG(3,(" info: %s\n"
430 " dir: %s\n"
431 " shell: %s\n",
432 pw->pw_gecos, pw->pw_dir, pw->pw_shell));
434 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
435 if (err != error_status_ok) {
436 dce_error_inq_text(err, dce_errstr, &err2);
437 /* Go back to root, JRA. */
438 setuid(0);
439 setgid(0);
440 DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
442 return(False);
445 setuid(0);
446 setgid(0);
448 DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time))));
450 dcelogin_atmost_once = 1;
451 return (True);
454 void dfs_unlogin(void)
456 error_status_t err;
457 int err2;
458 unsigned char dce_errstr[dce_c_error_string_len];
460 sec_login_purge_context(&my_dce_sec_context, &err);
461 if (err != error_status_ok) {
462 dce_error_inq_text(err, dce_errstr, &err2);
463 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
464 getpid(), dce_errstr));
467 #endif
469 #ifdef KRB5_AUTH
470 /*******************************************************************
471 check on Kerberos authentication
472 ********************************************************************/
473 static BOOL krb5_auth(char *user,char *password)
475 krb5_data tgtname = {
477 KRB5_TGS_NAME_SIZE,
478 KRB5_TGS_NAME
480 krb5_context kcontext;
481 krb5_principal kprinc;
482 krb5_principal server;
483 krb5_creds kcreds;
484 int options = 0;
485 krb5_address **addrs = (krb5_address **)0;
486 krb5_preauthtype *preauth = NULL;
487 krb5_keytab keytab = NULL;
488 krb5_timestamp now;
489 krb5_ccache ccache = NULL;
490 int retval;
491 char *name;
493 if (retval=krb5_init_context(&kcontext)) {
494 return(False);
497 if (retval = krb5_timeofday(kcontext, &now)) {
498 return(False);
501 if (retval = krb5_cc_default(kcontext, &ccache)) {
502 return(False);
505 if (retval = krb5_parse_name(kcontext, user, &kprinc)) {
506 return(False);
509 ZERO_STRUCT(kcreds);
511 kcreds.client = kprinc;
513 if ((retval = krb5_build_principal_ext(kcontext, &server,
514 krb5_princ_realm(kcontext, kprinc)->length,
515 krb5_princ_realm(kcontext, kprinc)->data,
516 tgtname.length,
517 tgtname.data,
518 krb5_princ_realm(kcontext, kprinc)->length,
519 krb5_princ_realm(kcontext, kprinc)->data,
520 0))) {
521 return(False);
524 kcreds.server = server;
526 retval = krb5_get_in_tkt_with_password(kcontext,
527 options,
528 addrs,
529 NULL,
530 preauth,
531 password,
533 &kcreds,
536 if (retval) {
537 return(False);
540 return(True);
542 #endif /* KRB5_AUTH */
544 #ifdef KRB4_AUTH
545 #include <krb.h>
547 /*******************************************************************
548 check on Kerberos authentication
549 ********************************************************************/
550 static BOOL krb4_auth(char *user,char *password)
552 char realm[REALM_SZ];
553 char tkfile[MAXPATHLEN];
555 if (krb_get_lrealm(realm, 1) != KSUCCESS) {
556 (void) safe_strcpy(realm, KRB_REALM, sizeof (realm) - 1);
559 (void) slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d",
560 (int)getpid());
562 krb_set_tkt_string(tkfile);
563 if (krb_verify_user(user, "", realm,
564 password, 0,
565 "rmcd") == KSUCCESS) {
566 unlink(tkfile);
567 return 1;
569 unlink(tkfile);
570 return 0;
572 #endif /* KRB4_AUTH */
574 #ifdef LINUX_BIGCRYPT
575 /****************************************************************************
576 an enhanced crypt for Linux to handle password longer than 8 characters
577 ****************************************************************************/
578 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
580 #define LINUX_PASSWORD_SEG_CHARS 8
581 char salt[3];
582 int i;
584 StrnCpy(salt,salt1,2);
585 crypted +=2;
587 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
588 char * p = crypt(password,salt) + 2;
589 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
590 return(0);
591 password += LINUX_PASSWORD_SEG_CHARS;
592 crypted += strlen(p);
595 return(1);
597 #endif
599 #ifdef OSF1_ENH_SEC
600 /****************************************************************************
601 an enhanced crypt for OSF1
602 ****************************************************************************/
603 static char *osf1_bigcrypt(char *password,char *salt1)
605 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
606 char *p1;
607 char *p2=password;
608 char salt[3];
609 int i;
610 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
611 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS) {
612 parts++;
615 StrnCpy(salt,salt1,2);
616 StrnCpy(result,salt1,2);
617 result[2]='\0';
619 for (i=0; i<parts;i++) {
620 p1 = crypt(p2,salt);
621 strncat(result,p1+2,AUTH_MAX_PASSWD_LENGTH-strlen(p1+2)-1);
622 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
623 p2 += AUTH_CLEARTEXT_SEG_CHARS;
626 return(result);
628 #endif
631 /****************************************************************************
632 apply a function to upper/lower case combinations
633 of a string and return true if one of them returns true.
634 try all combinations with N uppercase letters.
635 offset is the first char to try and change (start with 0)
636 it assumes the string starts lowercased
637 ****************************************************************************/
638 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(char *),int N)
640 int len = strlen(s);
641 int i;
643 #ifdef PASSWORD_LENGTH
644 len = MIN(len,PASSWORD_LENGTH);
645 #endif
647 if (N <= 0 || offset >= len) {
648 return(fn(s));
651 for (i=offset;i<(len-(N-1));i++) {
652 char c = s[i];
653 if (!islower(c)) continue;
654 s[i] = toupper(c);
655 if (string_combinations2(s,i+1,fn,N-1))
656 return(True);
657 s[i] = c;
659 return(False);
662 /****************************************************************************
663 apply a function to upper/lower case combinations
664 of a string and return true if one of them returns true.
665 try all combinations with up to N uppercase letters.
666 offset is the first char to try and change (start with 0)
667 it assumes the string starts lowercased
668 ****************************************************************************/
669 static BOOL string_combinations(char *s,BOOL (*fn)(char *),int N)
671 int n;
672 for (n=1;n<=N;n++)
673 if (string_combinations2(s,0,fn,n)) return(True);
674 return(False);
678 /****************************************************************************
679 core of password checking routine
680 ****************************************************************************/
681 static BOOL password_check(char *password)
684 #ifdef HAVE_PAM
685 /* This falls through if the password check fails
686 - if HAVE_CRYPT is not defined this causes an error msg
687 saying Warning - no crypt available
688 - if HAVE_CRYPT is defined this is a potential security hole
689 as it may authenticate via the crypt call when PAM
690 settings say it should fail.
691 if (pam_auth(user,password)) return(True);
692 Hence we make a direct return to avoid a second chance!!!
694 return (pam_auth(this_user,password));
695 #endif
697 #ifdef WITH_AFS
698 if (afs_auth(this_user,password)) return(True);
699 #endif
701 #ifdef WITH_DFS
702 if (dfs_auth(this_user,password)) return(True);
703 #endif
705 #ifdef KRB5_AUTH
706 if (krb5_auth(this_user,password)) return(True);
707 #endif
709 #ifdef KRB4_AUTH
710 if (krb4_auth(this_user,password)) return(True);
711 #endif
713 #ifdef OSF1_ENH_SEC
715 BOOL ret = (strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
716 if(!ret) {
717 DEBUG(2,("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
718 ret = (strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
720 return ret;
722 #endif
724 #ifdef ULTRIX_AUTH
725 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
726 #endif
728 #ifdef LINUX_BIGCRYPT
729 return(linux_bigcrypt(password,this_salt,this_crypted));
730 #endif
732 #ifdef HAVE_BIGCRYPT
733 return(strcmp(bigcrypt(password,this_salt),this_crypted) == 0);
734 #endif
736 #ifndef HAVE_CRYPT
737 DEBUG(1,("Warning - no crypt available\n"));
738 return(False);
739 #else
740 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
741 #endif
746 /****************************************************************************
747 check if a username/password is OK
748 the function pointer fn() points to a function to call when a successful
749 match is found and is used to update the encrypted password file
750 return True on correct match, False otherwise
751 ****************************************************************************/
752 BOOL pass_check(char *user,char *password, int pwlen, struct passwd *pwd,
753 BOOL (*fn)(char *, char *))
755 pstring pass2;
756 int level = lp_passwordlevel();
757 struct passwd *pass;
759 if (password) password[pwlen] = 0;
761 #if DEBUG_PASSWORD
762 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
763 #endif
765 if (!password) {
766 return(False);
769 if (((!*password) || (!pwlen)) && !lp_null_passwords()) {
770 return(False);
773 if (pwd && !user) {
774 pass = (struct passwd *) pwd;
775 user = pass->pw_name;
776 } else {
777 pass = Get_Pwnam(user,True);
781 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
783 if (!pass) {
784 DEBUG(3,("Couldn't find user %s\n",user));
785 return(False);
788 #ifdef HAVE_GETSPNAM
790 struct spwd *spass;
792 /* many shadow systems require you to be root to get
793 the password, in most cases this should already be
794 the case when this function is called, except
795 perhaps for IPC password changing requests */
797 spass = getspnam(pass->pw_name);
798 if (spass && spass->sp_pwdp) {
799 pass->pw_passwd = spass->sp_pwdp;
802 #elif defined(IA_UINFO)
804 /* Need to get password with SVR4.2's ia_ functions
805 instead of get{sp,pw}ent functions. Required by
806 UnixWare 2.x, tested on version
807 2.1. (tangent@cyberport.com) */
808 uinfo_t uinfo;
809 if (ia_openinfo(pass->pw_name, &uinfo) != -1) {
810 ia_get_logpwd(uinfo, &(pass->pw_passwd));
813 #endif
815 #ifdef HAVE_GETPRPWNAM
817 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
818 if (pr_pw && pr_pw->ufld.fd_encrypt)
819 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
821 #endif
823 #ifdef OSF1_ENH_SEC
825 struct pr_passwd *mypasswd;
826 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",
827 user));
828 mypasswd = getprpwnam (user);
829 if (mypasswd) {
830 fstrcpy(pass->pw_name,mypasswd->ufld.fd_name);
831 fstrcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
832 } else {
833 DEBUG(5,("No entry for user %s in protected database !\n",
834 user));
835 return(False);
838 #endif
840 #ifdef ULTRIX_AUTH
842 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
843 if (ap) {
844 fstrcpy(pass->pw_passwd, ap->a_password);
845 endauthent();
848 #endif
850 /* extract relevant info */
851 fstrcpy(this_user,pass->pw_name);
852 fstrcpy(this_salt,pass->pw_passwd);
853 /* crypt on some platforms (HPUX in particular)
854 won't work with more than 2 salt characters. */
855 this_salt[2] = 0;
857 fstrcpy(this_crypted,pass->pw_passwd);
859 if (!*this_crypted) {
860 if (!lp_null_passwords()) {
861 DEBUG(2,("Disallowing %s with null password\n",
862 this_user));
863 return(False);
865 if (!*password) {
866 DEBUG(3,("Allowing access to %s with null password\n",
867 this_user));
868 return(True);
872 /* try it as it came to us */
873 if (password_check(password)) {
874 if (fn) fn(user,password);
875 return(True);
878 /* if the password was given to us with mixed case then we don't
879 need to proceed as we know it hasn't been case modified by the
880 client */
881 if (strhasupper(password) && strhaslower(password)) {
882 return(False);
885 /* make a copy of it */
886 StrnCpy(pass2,password,sizeof(pstring)-1);
888 /* try all lowercase */
889 strlower(password);
890 if (password_check(password)) {
891 if (fn) fn(user,password);
892 return(True);
895 /* give up? */
896 if (level < 1) {
898 /* restore it */
899 fstrcpy(password,pass2);
901 return(False);
904 /* last chance - all combinations of up to level chars upper! */
905 strlower(password);
907 if (string_combinations(password,password_check,level)) {
908 if (fn) fn(user,password);
909 return(True);
912 /* restore it */
913 fstrcpy(password,pass2);
915 return(False);