Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / samba / source / passdb / pass_check.c
blob11ce0d754e8ab06b806281fe89d3e5e186134344
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 WITH_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
140 #include <afs/stds.h>
141 #include <afs/kautils.h>
143 /*******************************************************************
144 check on AFS authentication
145 ********************************************************************/
146 static BOOL afs_auth(char *user,char *password)
148 long password_expires = 0;
149 char *reason;
151 /* For versions of AFS prior to 3.3, this routine has few arguments, */
152 /* but since I can't find the old documentation... :-) */
153 setpag();
154 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
155 user,
156 (char *) 0, /* instance */
157 (char *) 0, /* cell */
158 password,
159 0, /* lifetime, default */
160 &password_expires, /*days 'til it expires */
161 0, /* spare 2 */
162 &reason) == 0) {
163 return(True);
165 DEBUG(1,("AFS authentication for \"%s\" failed (%s)\n", user, reason));
166 return(False);
168 #endif
171 #ifdef WITH_DFS
173 #include <dce/dce_error.h>
174 #include <dce/sec_login.h>
176 /*****************************************************************
177 This new version of the DFS_AUTH code was donated by Karsten Muuss
178 <muuss@or.uni-bonn.de>. It fixes the following problems with the
179 old code :
181 - Server credentials may expire
182 - Client credential cache files have wrong owner
183 - purge_context() function is called with invalid argument
185 This new code was modified to ensure that on exit the uid/gid is
186 still root, and the original directory is restored. JRA.
187 ******************************************************************/
189 sec_login_handle_t my_dce_sec_context;
190 int dcelogin_atmost_once = 0;
192 /*******************************************************************
193 check on a DCE/DFS authentication
194 ********************************************************************/
195 static BOOL dfs_auth(char *user,char *password)
197 error_status_t err;
198 int err2;
199 int prterr;
200 signed32 expire_time, current_time;
201 boolean32 password_reset;
202 struct passwd *pw;
203 sec_passwd_rec_t passwd_rec;
204 sec_login_auth_src_t auth_src = sec_login_auth_src_network;
205 unsigned char dce_errstr[dce_c_error_string_len];
206 gid_t egid;
208 if (dcelogin_atmost_once) return(False);
210 #ifdef HAVE_CRYPT
212 * We only go for a DCE login context if the given password
213 * matches that stored in the local password file..
214 * Assumes local passwd file is kept in sync w/ DCE RGY!
217 if (strcmp((char *)crypt(password,this_salt),this_crypted)) {
218 return(False);
220 #endif
222 sec_login_get_current_context(&my_dce_sec_context, &err);
223 if (err != error_status_ok ) {
224 dce_error_inq_text(err, dce_errstr, &err2);
225 DEBUG(0,("DCE can't get current context. %s\n", dce_errstr));
227 return(False);
230 sec_login_certify_identity(my_dce_sec_context, &err);
231 if (err != error_status_ok) {
232 dce_error_inq_text(err, dce_errstr, &err2);
233 DEBUG(0,("DCE can't get current context. %s\n", dce_errstr));
235 return(False);
238 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
239 if (err != error_status_ok) {
240 dce_error_inq_text(err, dce_errstr, &err2);
241 DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
243 return(False);
246 time(&current_time);
248 if (expire_time < (current_time + 60)) {
249 struct passwd *pw;
250 sec_passwd_rec_t *key;
252 sec_login_get_pwent(my_dce_sec_context,
253 (sec_login_passwd_t*)&pw, &err);
254 if (err != error_status_ok ) {
255 dce_error_inq_text(err, dce_errstr, &err2);
256 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
258 return(False);
261 sec_login_refresh_identity(my_dce_sec_context, &err);
262 if (err != error_status_ok) {
263 dce_error_inq_text(err, dce_errstr, &err2);
264 DEBUG(0,("DCE can't refresh identity. %s\n",
265 dce_errstr));
267 return(False);
270 sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
271 (unsigned char *)pw->pw_name,
272 sec_c_key_version_none,
273 (void**)&key, &err);
274 if (err != error_status_ok) {
275 dce_error_inq_text(err, dce_errstr, &err2);
276 DEBUG(0,("DCE can't get key for %s. %s\n",
277 pw->pw_name, dce_errstr));
279 return(False);
282 sec_login_valid_and_cert_ident(my_dce_sec_context, key,
283 &password_reset, &auth_src,
284 &err);
285 if (err != error_status_ok ) {
286 dce_error_inq_text(err, dce_errstr, &err2);
287 DEBUG(0,("DCE can't validate and certify identity for %s. %s\n",
288 pw->pw_name, dce_errstr));
291 sec_key_mgmt_free_key(key, &err);
292 if (err != error_status_ok ) {
293 dce_error_inq_text(err, dce_errstr, &err2);
294 DEBUG(0,("DCE can't free key.\n", dce_errstr));
298 if (sec_login_setup_identity((unsigned char *)user,
299 sec_login_no_flags,
300 &my_dce_sec_context,
301 &err) == 0) {
302 dce_error_inq_text(err, dce_errstr, &err2);
303 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
304 user,dce_errstr));
305 return(False);
308 sec_login_get_pwent(my_dce_sec_context,
309 (sec_login_passwd_t*)&pw, &err);
310 if (err != error_status_ok) {
311 dce_error_inq_text(err, dce_errstr, &err2);
312 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
314 return(False);
317 sec_login_purge_context(&my_dce_sec_context, &err);
318 if (err != error_status_ok) {
319 dce_error_inq_text(err, dce_errstr, &err2);
320 DEBUG(0,("DCE can't purge context. %s\n", dce_errstr));
322 return(False);
326 * NB. I'd like to change these to call something like become_user()
327 * instead but currently we don't have a connection
328 * context to become the correct user. This is already
329 * fairly platform specific code however, so I think
330 * this should be ok. I have added code to go
331 * back to being root on error though. JRA.
334 egid = getegid();
336 if (set_effective_gid(pw->pw_gid) != 0) {
337 DEBUG(0,("Can't set egid to %d (%s)\n",
338 pw->pw_gid, strerror(errno)));
339 return False;
342 if (set_effective_uid(pw->pw_uid) != 0) {
343 set_effective_gid(egid);
344 DEBUG(0,("Can't set euid to %d (%s)\n",
345 pw->pw_uid, strerror(errno)));
346 return False;
349 if (sec_login_setup_identity((unsigned char *)user,
350 sec_login_no_flags,
351 &my_dce_sec_context,
352 &err) == 0) {
353 dce_error_inq_text(err, dce_errstr, &err2);
354 DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
355 user,dce_errstr));
356 goto err;
359 sec_login_get_pwent(my_dce_sec_context,
360 (sec_login_passwd_t*)&pw, &err);
361 if (err != error_status_ok ) {
362 dce_error_inq_text(err, dce_errstr, &err2);
363 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
364 goto err;
367 passwd_rec.version_number = sec_passwd_c_version_none;
368 passwd_rec.pepper = NULL;
369 passwd_rec.key.key_type = sec_passwd_plain;
370 passwd_rec.key.tagged_union.plain = (idl_char *)password;
372 sec_login_validate_identity(my_dce_sec_context,
373 &passwd_rec, &password_reset,
374 &auth_src, &err);
375 if (err != error_status_ok ) {
376 dce_error_inq_text(err, dce_errstr, &err2);
377 DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
378 user,dce_errstr));
379 goto err;
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 DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr));
386 goto err;
389 if (auth_src != sec_login_auth_src_network) {
390 DEBUG(0,("DCE context has no network credentials.\n"));
393 sec_login_set_context(my_dce_sec_context, &err);
394 if (err != error_status_ok) {
395 dce_error_inq_text(err, dce_errstr, &err2);
396 DEBUG(0,("DCE login failed for principal %s, cant set context: %s\n",
397 user,dce_errstr));
399 sec_login_purge_context(&my_dce_sec_context, &err);
400 goto err;
403 sec_login_get_pwent(my_dce_sec_context,
404 (sec_login_passwd_t*)&pw, &err);
405 if (err != error_status_ok) {
406 dce_error_inq_text(err, dce_errstr, &err2);
407 DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
408 goto err;
411 DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
412 user, getpid()));
414 DEBUG(3,("DCE principal: %s\n"
415 " uid: %d\n"
416 " gid: %d\n",
417 pw->pw_name, pw->pw_uid, pw->pw_gid));
418 DEBUG(3,(" info: %s\n"
419 " dir: %s\n"
420 " shell: %s\n",
421 pw->pw_gecos, pw->pw_dir, pw->pw_shell));
423 sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
424 if (err != error_status_ok) {
425 dce_error_inq_text(err, dce_errstr, &err2);
426 DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
427 goto err;
430 set_effective_uid(0);
431 set_effective_gid(0);
433 DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time))));
435 dcelogin_atmost_once = 1;
436 return (True);
438 err:
440 /* Go back to root, JRA. */
441 set_effective_uid(0);
442 set_effective_gid(egid);
443 return(False);
446 void dfs_unlogin(void)
448 error_status_t err;
449 int err2;
450 unsigned char dce_errstr[dce_c_error_string_len];
452 sec_login_purge_context(&my_dce_sec_context, &err);
453 if (err != error_status_ok) {
454 dce_error_inq_text(err, dce_errstr, &err2);
455 DEBUG(0,("DCE purge login context failed for server instance %d: %s\n",
456 getpid(), dce_errstr));
459 #endif
461 #ifdef KRB5_AUTH
463 #include <krb5.h>
465 /*******************************************************************
466 check on Kerberos authentication
467 ********************************************************************/
468 static BOOL krb5_auth(char *user,char *password)
470 krb5_data tgtname = {
472 KRB5_TGS_NAME_SIZE,
473 KRB5_TGS_NAME
475 krb5_context kcontext;
476 krb5_principal kprinc;
477 krb5_principal server;
478 krb5_creds kcreds;
479 int options = 0;
480 krb5_address **addrs = (krb5_address **)0;
481 krb5_preauthtype *preauth = NULL;
482 krb5_keytab keytab = NULL;
483 krb5_timestamp now;
484 krb5_ccache ccache = NULL;
485 int retval;
486 char *name;
488 if (retval=krb5_init_context(&kcontext)) {
489 return(False);
492 if (retval = krb5_timeofday(kcontext, &now)) {
493 return(False);
496 if (retval = krb5_cc_default(kcontext, &ccache)) {
497 return(False);
500 if (retval = krb5_parse_name(kcontext, user, &kprinc)) {
501 return(False);
504 ZERO_STRUCT(kcreds);
506 kcreds.client = kprinc;
508 if ((retval = krb5_build_principal_ext(kcontext, &server,
509 krb5_princ_realm(kcontext, kprinc)->length,
510 krb5_princ_realm(kcontext, kprinc)->data,
511 tgtname.length,
512 tgtname.data,
513 krb5_princ_realm(kcontext, kprinc)->length,
514 krb5_princ_realm(kcontext, kprinc)->data,
515 0))) {
516 return(False);
519 kcreds.server = server;
521 retval = krb5_get_in_tkt_with_password(kcontext,
522 options,
523 addrs,
524 NULL,
525 preauth,
526 password,
528 &kcreds,
531 if (retval) {
532 return(False);
535 return(True);
537 #endif /* KRB5_AUTH */
539 #ifdef KRB4_AUTH
540 #include <krb.h>
542 /*******************************************************************
543 check on Kerberos authentication
544 ********************************************************************/
545 static BOOL krb4_auth(char *user,char *password)
547 char realm[REALM_SZ];
548 char tkfile[MAXPATHLEN];
550 if (krb_get_lrealm(realm, 1) != KSUCCESS) {
551 (void) safe_strcpy(realm, KRB_REALM, sizeof (realm) - 1);
554 (void) slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d",
555 (int)getpid());
557 krb_set_tkt_string(tkfile);
558 if (krb_verify_user(user, "", realm,
559 password, 0,
560 "rmcd") == KSUCCESS) {
561 unlink(tkfile);
562 return 1;
564 unlink(tkfile);
565 return 0;
567 #endif /* KRB4_AUTH */
569 #ifdef LINUX_BIGCRYPT
570 /****************************************************************************
571 an enhanced crypt for Linux to handle password longer than 8 characters
572 ****************************************************************************/
573 static int linux_bigcrypt(char *password,char *salt1, char *crypted)
575 #define LINUX_PASSWORD_SEG_CHARS 8
576 char salt[3];
577 int i;
579 StrnCpy(salt,salt1,2);
580 crypted +=2;
582 for ( i=strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
583 char * p = crypt(password,salt) + 2;
584 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
585 return(0);
586 password += LINUX_PASSWORD_SEG_CHARS;
587 crypted += strlen(p);
590 return(1);
592 #endif
594 #ifdef OSF1_ENH_SEC
595 /****************************************************************************
596 an enhanced crypt for OSF1
597 ****************************************************************************/
598 static char *osf1_bigcrypt(char *password,char *salt1)
600 static char result[AUTH_MAX_PASSWD_LENGTH] = "";
601 char *p1;
602 char *p2=password;
603 char salt[3];
604 int i;
605 int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
606 if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS) {
607 parts++;
610 StrnCpy(salt,salt1,2);
611 StrnCpy(result,salt1,2);
612 result[2]='\0';
614 for (i=0; i<parts;i++) {
615 p1 = crypt(p2,salt);
616 strncat(result,p1+2,AUTH_MAX_PASSWD_LENGTH-strlen(p1+2)-1);
617 StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
618 p2 += AUTH_CLEARTEXT_SEG_CHARS;
621 return(result);
623 #endif
626 /****************************************************************************
627 apply a function to upper/lower case combinations
628 of a string and return true if one of them returns true.
629 try all combinations with N uppercase letters.
630 offset is the first char to try and change (start with 0)
631 it assumes the string starts lowercased
632 ****************************************************************************/
633 static BOOL string_combinations2(char *s,int offset,BOOL (*fn)(char *),int N)
635 int len = strlen(s);
636 int i;
638 #ifdef PASSWORD_LENGTH
639 len = MIN(len,PASSWORD_LENGTH);
640 #endif
642 if (N <= 0 || offset >= len) {
643 return(fn(s));
646 for (i=offset;i<(len-(N-1));i++) {
647 char c = s[i];
648 if (!islower(c)) continue;
649 s[i] = toupper(c);
650 if (string_combinations2(s,i+1,fn,N-1))
651 return(True);
652 s[i] = c;
654 return(False);
657 /****************************************************************************
658 apply a function to upper/lower case combinations
659 of a string and return true if one of them returns true.
660 try all combinations with up to N uppercase letters.
661 offset is the first char to try and change (start with 0)
662 it assumes the string starts lowercased
663 ****************************************************************************/
664 static BOOL string_combinations(char *s,BOOL (*fn)(char *),int N)
666 int n;
667 for (n=1;n<=N;n++)
668 if (string_combinations2(s,0,fn,n)) return(True);
669 return(False);
673 /****************************************************************************
674 core of password checking routine
675 ****************************************************************************/
676 static BOOL password_check(char *password)
679 #ifdef WITH_PAM
680 /* This falls through if the password check fails
681 - if HAVE_CRYPT is not defined this causes an error msg
682 saying Warning - no crypt available
683 - if HAVE_CRYPT is defined this is a potential security hole
684 as it may authenticate via the crypt call when PAM
685 settings say it should fail.
686 if (pam_auth(user,password)) return(True);
687 Hence we make a direct return to avoid a second chance!!!
689 return (pam_auth(this_user,password));
690 #endif /* WITH_PAM */
692 #ifdef WITH_AFS
693 if (afs_auth(this_user,password)) return(True);
694 #endif /* WITH_AFS */
696 #ifdef WITH_DFS
697 if (dfs_auth(this_user,password)) return(True);
698 #endif /* WITH_DFS */
700 #ifdef KRB5_AUTH
701 if (krb5_auth(this_user,password)) return(True);
702 #endif /* KRB5_AUTH */
704 #ifdef KRB4_AUTH
705 if (krb4_auth(this_user,password)) return(True);
706 #endif /* KRB4_AUTH */
708 #ifdef OSF1_ENH_SEC
710 BOOL ret = (strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
711 if(!ret) {
712 DEBUG(2,("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
713 ret = (strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
715 return ret;
717 #endif /* OSF1_ENH_SEC */
719 #ifdef ULTRIX_AUTH
720 return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
721 #endif /* ULTRIX_AUTH */
723 #ifdef LINUX_BIGCRYPT
724 return(linux_bigcrypt(password,this_salt,this_crypted));
725 #endif /* LINUX_BIGCRYPT */
727 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
730 * Some systems have bigcrypt in the C library but might not
731 * actually use it for the password hashes (HPUX 10.20) is
732 * a noteable example. So we try bigcrypt first, followed
733 * by crypt.
736 if(strcmp(bigcrypt(password,this_salt),this_crypted) == 0)
737 return True;
738 else
739 return (strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
740 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
742 #ifdef HAVE_BIGCRYPT
743 return(strcmp(bigcrypt(password,this_salt),this_crypted) == 0);
744 #endif /* HAVE_BIGCRYPT */
746 #ifndef HAVE_CRYPT
747 DEBUG(1,("Warning - no crypt available\n"));
748 return(False);
749 #else /* HAVE_CRYPT */
750 return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
751 #endif /* HAVE_CRYPT */
752 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
757 /****************************************************************************
758 check if a username/password is OK
759 the function pointer fn() points to a function to call when a successful
760 match is found and is used to update the encrypted password file
761 return True on correct match, False otherwise
762 ****************************************************************************/
763 BOOL pass_check(char *user,char *password, int pwlen, struct passwd *pwd,
764 BOOL (*fn)(char *, char *))
766 pstring pass2;
767 int level = lp_passwordlevel();
768 struct passwd *pass;
770 if (password) password[pwlen] = 0;
772 #if DEBUG_PASSWORD
773 DEBUG(100,("checking user=[%s] pass=[%s]\n",user,password));
774 #endif
776 if (!password) {
777 return(False);
780 if (((!*password) || (!pwlen)) && !lp_null_passwords()) {
781 return(False);
784 if (pwd && !user) {
785 pass = (struct passwd *) pwd;
786 user = pass->pw_name;
787 } else {
788 pass = Get_Pwnam(user,True);
792 DEBUG(4,("Checking password for user %s (l=%d)\n",user,pwlen));
794 if (!pass) {
795 DEBUG(3,("Couldn't find user %s\n",user));
796 return(False);
799 #ifdef HAVE_GETSPNAM
801 struct spwd *spass;
803 /* many shadow systems require you to be root to get
804 the password, in most cases this should already be
805 the case when this function is called, except
806 perhaps for IPC password changing requests */
808 spass = getspnam(pass->pw_name);
809 if (spass && spass->sp_pwdp) {
810 pstrcpy(pass->pw_passwd,spass->sp_pwdp);
813 #elif defined(IA_UINFO)
815 /* Need to get password with SVR4.2's ia_ functions
816 instead of get{sp,pw}ent functions. Required by
817 UnixWare 2.x, tested on version
818 2.1. (tangent@cyberport.com) */
819 uinfo_t uinfo;
820 if (ia_openinfo(pass->pw_name, &uinfo) != -1) {
821 ia_get_logpwd(uinfo, &(pass->pw_passwd));
824 #endif
826 #ifdef HAVE_GETPRPWNAM
828 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
829 if (pr_pw && pr_pw->ufld.fd_encrypt)
830 pstrcpy(pass->pw_passwd,pr_pw->ufld.fd_encrypt);
832 #endif
834 #ifdef OSF1_ENH_SEC
836 struct pr_passwd *mypasswd;
837 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",
838 user));
839 mypasswd = getprpwnam (user);
840 if (mypasswd) {
841 fstrcpy(pass->pw_name,mypasswd->ufld.fd_name);
842 fstrcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
843 } else {
844 DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
845 user));
848 #endif
850 #ifdef ULTRIX_AUTH
852 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
853 if (ap) {
854 fstrcpy(pass->pw_passwd, ap->a_password);
855 endauthent();
858 #endif
860 /* extract relevant info */
861 fstrcpy(this_user,pass->pw_name);
862 fstrcpy(this_salt,pass->pw_passwd);
864 #if defined(HAVE_TRUNCATED_SALT)
865 /* crypt on some platforms (HPUX in particular)
866 won't work with more than 2 salt characters. */
867 this_salt[2] = 0;
868 #endif
870 fstrcpy(this_crypted,pass->pw_passwd);
872 if (!*this_crypted) {
873 if (!lp_null_passwords()) {
874 DEBUG(2,("Disallowing %s with null password\n",
875 this_user));
876 return(False);
878 if (!*password) {
879 DEBUG(3,("Allowing access to %s with null password\n",
880 this_user));
881 return(True);
885 /* try it as it came to us */
886 if (password_check(password)) {
887 if (fn) fn(user,password);
888 return(True);
891 /* if the password was given to us with mixed case then we don't
892 need to proceed as we know it hasn't been case modified by the
893 client */
894 if (strhasupper(password) && strhaslower(password)) {
895 return(False);
898 /* make a copy of it */
899 StrnCpy(pass2,password,sizeof(pstring)-1);
901 /* try all lowercase */
902 strlower(password);
903 if (password_check(password)) {
904 if (fn) fn(user,password);
905 return(True);
908 /* give up? */
909 if (level < 1) {
911 /* restore it */
912 fstrcpy(password,pass2);
914 return(False);
917 /* last chance - all combinations of up to level chars upper! */
918 strlower(password);
920 if (string_combinations(password,password_check,level)) {
921 if (fn) fn(user,password);
922 return(True);
925 /* restore it */
926 fstrcpy(password,pass2);
928 return(False);