This commit was manufactured by cvs2svn to create tag
[Samba/gbeck.git] / source / passdb / pass_check.c
blobd847407bbb4c6272a7de8ed6c06dc4630f7e3c8e
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);
618 for (i=0; i<parts;i++) {
619 p1 = crypt(p2,salt);
620 strncat(result,p1+2,AUTH_MAX_PASSWD_LENGTH-strlen(p1+2)-1);
621 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
622 p2 += AUTH_CLEARTEXT_SEG_CHARS;
625 return(result);
627 #endif
630 /****************************************************************************
631 apply a function to upper/lower case combinations
632 of a string and return true if one of them returns true.
633 try all combinations with N uppercase letters.
634 offset is the first char to try and change (start with 0)
635 it assumes the string starts lowercased
636 ****************************************************************************/
637 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(char *),int N)
639 int len = strlen(s);
640 int i;
642 #ifdef PASSWORD_LENGTH
643 len = MIN(len,PASSWORD_LENGTH);
644 #endif
646 if (N <= 0 || offset >= len) {
647 return(fn(s));
650 for (i=offset;i<(len-(N-1));i++) {
651 char c = s[i];
652 if (!islower(c)) continue;
653 s[i] = toupper(c);
654 if (string_combinations2(s,i+1,fn,N-1))
655 return(True);
656 s[i] = c;
658 return(False);
661 /****************************************************************************
662 apply a function to upper/lower case combinations
663 of a string and return true if one of them returns true.
664 try all combinations with up to N uppercase letters.
665 offset is the first char to try and change (start with 0)
666 it assumes the string starts lowercased
667 ****************************************************************************/
668 static BOOL string_combinations(char *s,BOOL (*fn)(char *),int N)
670 int n;
671 for (n=1;n<=N;n++)
672 if (string_combinations2(s,0,fn,n)) return(True);
673 return(False);
677 /****************************************************************************
678 core of password checking routine
679 ****************************************************************************/
680 static BOOL password_check(char *password)
683 #ifdef HAVE_PAM
684 /* This falls through if the password check fails
685 - if HAVE_CRYPT is not defined this causes an error msg
686 saying Warning - no crypt available
687 - if HAVE_CRYPT is defined this is a potential security hole
688 as it may authenticate via the crypt call when PAM
689 settings say it should fail.
690 if (pam_auth(user,password)) return(True);
691 Hence we make a direct return to avoid a second chance!!!
693 return (pam_auth(this_user,password));
694 #endif
696 #ifdef WITH_AFS
697 if (afs_auth(this_user,password)) return(True);
698 #endif
700 #ifdef WITH_DFS
701 if (dfs_auth(this_user,password)) return(True);
702 #endif
704 #ifdef KRB5_AUTH
705 if (krb5_auth(this_user,password)) return(True);
706 #endif
708 #ifdef KRB4_AUTH
709 if (krb4_auth(this_user,password)) return(True);
710 #endif
712 #ifdef OSF1_ENH_SEC
714 BOOL ret = (strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
715 if(!ret) {
716 DEBUG(2,("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
717 ret = (strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
719 return ret;
721 #endif
723 #ifdef ULTRIX_AUTH
724 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
725 #endif
727 #ifdef LINUX_BIGCRYPT
728 return(linux_bigcrypt(password,this_salt,this_crypted));
729 #endif
731 #ifdef HAVE_BIGCRYPT
732 return(strcmp(bigcrypt(password,this_salt),this_crypted) == 0);
733 #endif
735 #ifndef HAVE_CRYPT
736 DEBUG(1,("Warning - no crypt available\n"));
737 return(False);
738 #else
739 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
740 #endif
745 /****************************************************************************
746 check if a username/password is OK
747 the function pointer fn() points to a function to call when a successful
748 match is found and is used to update the encrypted password file
749 return True on correct match, False otherwise
750 ****************************************************************************/
751 BOOL pass_check(char *user,char *password, int pwlen, struct passwd *pwd,
752 BOOL (*fn)(char *, char *))
754 pstring pass2;
755 int level = lp_passwordlevel();
756 struct passwd *pass;
758 if (password) password[pwlen] = 0;
760 #if DEBUG_PASSWORD
761 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
762 #endif
764 if (!password) {
765 return(False);
768 if (((!*password) || (!pwlen)) && !lp_null_passwords()) {
769 return(False);
772 if (pwd && !user) {
773 pass = (struct passwd *) pwd;
774 user = pass->pw_name;
775 } else {
776 pass = Get_Pwnam(user,True);
780 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
782 if (!pass) {
783 DEBUG(3,("Couldn't find user %s\n",user));
784 return(False);
787 #ifdef HAVE_GETSPNAM
789 struct spwd *spass;
791 /* many shadow systems require you to be root to get
792 the password, in most cases this should already be
793 the case when this function is called, except
794 perhaps for IPC password changing requests */
796 spass = getspnam(pass->pw_name);
797 if (spass && spass->sp_pwdp) {
798 pass->pw_passwd = spass->sp_pwdp;
801 #elif defined(IA_UINFO)
803 /* Need to get password with SVR4.2's ia_ functions
804 instead of get{sp,pw}ent functions. Required by
805 UnixWare 2.x, tested on version
806 2.1. (tangent@cyberport.com) */
807 uinfo_t uinfo;
808 if (ia_openinfo(pass->pw_name, &uinfo) != -1) {
809 ia_get_logpwd(uinfo, &(pass->pw_passwd));
812 #endif
814 #ifdef HAVE_GETPRPWNAM
816 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
817 if (pr_pw && pr_pw->ufld.fd_encrypt)
818 pass->pw_passwd = pr_pw->ufld.fd_encrypt;
820 #endif
822 #ifdef OSF1_ENH_SEC
824 struct pr_passwd *mypasswd;
825 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",
826 user));
827 mypasswd = getprpwnam (user);
828 if (mypasswd) {
829 fstrcpy(pass->pw_name,mypasswd->ufld.fd_name);
830 fstrcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
831 } else {
832 DEBUG(5,("No entry for user %s in protected database !\n",
833 user));
834 return(False);
837 #endif
839 #ifdef ULTRIX_AUTH
841 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
842 if (ap) {
843 fstrcpy(pass->pw_passwd, ap->a_password);
844 endauthent();
847 #endif
849 /* extract relevant info */
850 fstrcpy(this_user,pass->pw_name);
851 fstrcpy(this_salt,pass->pw_passwd);
852 /* crypt on some platforms (HPUX in particular)
853 won't work with more than 2 salt characters. */
854 this_salt[2] = 0;
856 fstrcpy(this_crypted,pass->pw_passwd);
858 if (!*this_crypted) {
859 if (!lp_null_passwords()) {
860 DEBUG(2,("Disallowing %s with null password\n",
861 this_user));
862 return(False);
864 if (!*password) {
865 DEBUG(3,("Allowing access to %s with null password\n",
866 this_user));
867 return(True);
871 /* try it as it came to us */
872 if (password_check(password)) {
873 if (fn) fn(user,password);
874 return(True);
877 /* if the password was given to us with mixed case then we don't
878 need to proceed as we know it hasn't been case modified by the
879 client */
880 if (strhasupper(password) && strhaslower(password)) {
881 return(False);
884 /* make a copy of it */
885 StrnCpy(pass2,password,sizeof(pstring)-1);
887 /* try all lowercase */
888 strlower(password);
889 if (password_check(password)) {
890 if (fn) fn(user,password);
891 return(True);
894 /* give up? */
895 if (level < 1) {
897 /* restore it */
898 fstrcpy(password,pass2);
900 return(False);
903 /* last chance - all combinations of up to level chars upper! */
904 strlower(password);
906 if (string_combinations(password,password_check,level)) {
907 if (fn) fn(user,password);
908 return(True);
911 /* restore it */
912 fstrcpy(password,pass2);
914 return(False);