Added Andrew Bartlett's fixes to my changes to his original patch (at the
[sfrench/samba-autobuild/.git] / source3 / passdb / pass_check.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Password checking
5    Copyright (C) Andrew Tridgell 1992-1998
6    
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.
11    
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.
16    
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.
20 */
21
22 /* this module is for checking a username/password against a system
23    password database. The SMB encrypted password support is elsewhere */
24
25 #include "includes.h"
26
27 extern int DEBUGLEVEL;
28
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] = "";
33
34 #ifdef WITH_AFS
35
36 #include <afs/stds.h>
37 #include <afs/kautils.h>
38
39 /*******************************************************************
40 check on AFS authentication
41 ********************************************************************/
42 static BOOL afs_auth(char *user, char *password)
43 {
44         long password_expires = 0;
45         char *reason;
46
47         /* For versions of AFS prior to 3.3, this routine has few arguments, */
48         /* but since I can't find the old documentation... :-)               */
49         setpag();
50         if (ka_UserAuthenticateGeneral
51             (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user, (char *)0,       /* instance */
52              (char *)0,         /* cell */
53              password, 0,       /* lifetime, default */
54              &password_expires, /*days 'til it expires */
55              0,                 /* spare 2 */
56              &reason) == 0)
57         {
58                 return (True);
59         }
60         DEBUG(1,
61               ("AFS authentication for \"%s\" failed (%s)\n", user, reason));
62         return (False);
63 }
64 #endif
65
66
67 #ifdef WITH_DFS
68
69 #include <dce/dce_error.h>
70 #include <dce/sec_login.h>
71
72 /*****************************************************************
73  This new version of the DFS_AUTH code was donated by Karsten Muuss
74  <muuss@or.uni-bonn.de>. It fixes the following problems with the
75  old code :
76
77   - Server credentials may expire
78   - Client credential cache files have wrong owner
79   - purge_context() function is called with invalid argument
80
81  This new code was modified to ensure that on exit the uid/gid is
82  still root, and the original directory is restored. JRA.
83 ******************************************************************/
84
85 sec_login_handle_t my_dce_sec_context;
86 int dcelogin_atmost_once = 0;
87
88 /*******************************************************************
89 check on a DCE/DFS authentication
90 ********************************************************************/
91 static BOOL dfs_auth(char *user, char *password)
92 {
93         error_status_t err;
94         int err2;
95         int prterr;
96         signed32 expire_time, current_time;
97         boolean32 password_reset;
98         struct passwd *pw;
99         sec_passwd_rec_t passwd_rec;
100         sec_login_auth_src_t auth_src = sec_login_auth_src_network;
101         unsigned char dce_errstr[dce_c_error_string_len];
102         gid_t egid;
103
104         if (dcelogin_atmost_once)
105                 return (False);
106
107 #ifdef HAVE_CRYPT
108         /*
109          * We only go for a DCE login context if the given password
110          * matches that stored in the local password file.. 
111          * Assumes local passwd file is kept in sync w/ DCE RGY!
112          */
113
114         if (strcmp((char *)crypt(password, this_salt), this_crypted))
115         {
116                 return (False);
117         }
118 #endif
119
120         sec_login_get_current_context(&my_dce_sec_context, &err);
121         if (err != error_status_ok)
122         {
123                 dce_error_inq_text(err, dce_errstr, &err2);
124                 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
125
126                 return (False);
127         }
128
129         sec_login_certify_identity(my_dce_sec_context, &err);
130         if (err != error_status_ok)
131         {
132                 dce_error_inq_text(err, dce_errstr, &err2);
133                 DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
134
135                 return (False);
136         }
137
138         sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
139         if (err != error_status_ok)
140         {
141                 dce_error_inq_text(err, dce_errstr, &err2);
142                 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
143
144                 return (False);
145         }
146
147         time(&current_time);
148
149         if (expire_time < (current_time + 60))
150         {
151                 struct passwd *pw;
152                 sec_passwd_rec_t *key;
153
154                 sec_login_get_pwent(my_dce_sec_context,
155                                     (sec_login_passwd_t *) & pw, &err);
156                 if (err != error_status_ok)
157                 {
158                         dce_error_inq_text(err, dce_errstr, &err2);
159                         DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
160
161                         return (False);
162                 }
163
164                 sec_login_refresh_identity(my_dce_sec_context, &err);
165                 if (err != error_status_ok)
166                 {
167                         dce_error_inq_text(err, dce_errstr, &err2);
168                         DEBUG(0, ("DCE can't refresh identity. %s\n",
169                                   dce_errstr));
170
171                         return (False);
172                 }
173
174                 sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
175                                      (unsigned char *)pw->pw_name,
176                                      sec_c_key_version_none,
177                                      (void **)&key, &err);
178                 if (err != error_status_ok)
179                 {
180                         dce_error_inq_text(err, dce_errstr, &err2);
181                         DEBUG(0, ("DCE can't get key for %s. %s\n",
182                                   pw->pw_name, dce_errstr));
183
184                         return (False);
185                 }
186
187                 sec_login_valid_and_cert_ident(my_dce_sec_context, key,
188                                                &password_reset, &auth_src,
189                                                &err);
190                 if (err != error_status_ok)
191                 {
192                         dce_error_inq_text(err, dce_errstr, &err2);
193                         DEBUG(0,
194                               ("DCE can't validate and certify identity for %s. %s\n",
195                                pw->pw_name, dce_errstr));
196                 }
197
198                 sec_key_mgmt_free_key(key, &err);
199                 if (err != error_status_ok)
200                 {
201                         dce_error_inq_text(err, dce_errstr, &err2);
202                         DEBUG(0, ("DCE can't free key.\n", dce_errstr));
203                 }
204         }
205
206         if (sec_login_setup_identity((unsigned char *)user,
207                                      sec_login_no_flags,
208                                      &my_dce_sec_context, &err) == 0)
209         {
210                 dce_error_inq_text(err, dce_errstr, &err2);
211                 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
212                           user, dce_errstr));
213                 return (False);
214         }
215
216         sec_login_get_pwent(my_dce_sec_context,
217                             (sec_login_passwd_t *) & pw, &err);
218         if (err != error_status_ok)
219         {
220                 dce_error_inq_text(err, dce_errstr, &err2);
221                 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
222
223                 return (False);
224         }
225
226         sec_login_purge_context(&my_dce_sec_context, &err);
227         if (err != error_status_ok)
228         {
229                 dce_error_inq_text(err, dce_errstr, &err2);
230                 DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
231
232                 return (False);
233         }
234
235         /*
236          * NB. I'd like to change these to call something like become_user()
237          * instead but currently we don't have a connection
238          * context to become the correct user. This is already
239          * fairly platform specific code however, so I think
240          * this should be ok. I have added code to go
241          * back to being root on error though. JRA.
242          */
243
244         egid = getegid();
245
246         set_effective_gid(pw->pw_gid);
247         set_effective_uid(pw->pw_uid);
248
249         if (sec_login_setup_identity((unsigned char *)user,
250                                      sec_login_no_flags,
251                                      &my_dce_sec_context, &err) == 0)
252         {
253                 dce_error_inq_text(err, dce_errstr, &err2);
254                 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
255                           user, dce_errstr));
256                 goto err;
257         }
258
259         sec_login_get_pwent(my_dce_sec_context,
260                             (sec_login_passwd_t *) & pw, &err);
261         if (err != error_status_ok)
262         {
263                 dce_error_inq_text(err, dce_errstr, &err2);
264                 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
265                 goto err;
266         }
267
268         passwd_rec.version_number = sec_passwd_c_version_none;
269         passwd_rec.pepper = NULL;
270         passwd_rec.key.key_type = sec_passwd_plain;
271         passwd_rec.key.tagged_union.plain = (idl_char *) password;
272
273         sec_login_validate_identity(my_dce_sec_context,
274                                     &passwd_rec, &password_reset,
275                                     &auth_src, &err);
276         if (err != error_status_ok)
277         {
278                 dce_error_inq_text(err, dce_errstr, &err2);
279                 DEBUG(0,
280                       ("DCE Identity Validation failed for principal %s: %s\n",
281                        user, dce_errstr));
282                 goto err;
283         }
284
285         sec_login_certify_identity(my_dce_sec_context, &err);
286         if (err != error_status_ok)
287         {
288                 dce_error_inq_text(err, dce_errstr, &err2);
289                 DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
290                 goto err;
291         }
292
293         if (auth_src != sec_login_auth_src_network)
294         {
295                 DEBUG(0, ("DCE context has no network credentials.\n"));
296         }
297
298         sec_login_set_context(my_dce_sec_context, &err);
299         if (err != error_status_ok)
300         {
301                 dce_error_inq_text(err, dce_errstr, &err2);
302                 DEBUG(0,
303                       ("DCE login failed for principal %s, cant set context: %s\n",
304                        user, dce_errstr));
305
306                 sec_login_purge_context(&my_dce_sec_context, &err);
307                 goto err;
308         }
309
310         sec_login_get_pwent(my_dce_sec_context,
311                             (sec_login_passwd_t *) & pw, &err);
312         if (err != error_status_ok)
313         {
314                 dce_error_inq_text(err, dce_errstr, &err2);
315                 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
316                 goto err;
317         }
318
319         DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
320                   user, sys_getpid()));
321
322         DEBUG(3, ("DCE principal: %s\n"
323                   "          uid: %d\n"
324                   "          gid: %d\n",
325                   pw->pw_name, pw->pw_uid, pw->pw_gid));
326         DEBUG(3, ("         info: %s\n"
327                   "          dir: %s\n"
328                   "        shell: %s\n",
329                   pw->pw_gecos, pw->pw_dir, pw->pw_shell));
330
331         sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
332         if (err != error_status_ok)
333         {
334                 dce_error_inq_text(err, dce_errstr, &err2);
335                 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
336                 goto err;
337         }
338
339         set_effective_uid(0);
340         set_effective_gid(0);
341
342         DEBUG(0,
343               ("DCE context expires: %s", asctime(localtime(&expire_time))));
344
345         dcelogin_atmost_once = 1;
346         return (True);
347
348       err:
349
350         /* Go back to root, JRA. */
351         set_effective_uid(0);
352         set_effective_gid(egid);
353         return (False);
354 }
355
356 void dfs_unlogin(void)
357 {
358         error_status_t err;
359         int err2;
360         unsigned char dce_errstr[dce_c_error_string_len];
361
362         sec_login_purge_context(&my_dce_sec_context, &err);
363         if (err != error_status_ok)
364         {
365                 dce_error_inq_text(err, dce_errstr, &err2);
366                 DEBUG(0,
367                       ("DCE purge login context failed for server instance %d: %s\n",
368                        sys_getpid(), dce_errstr));
369         }
370 }
371 #endif
372
373 #ifdef KRB5_AUTH
374
375 #include <krb5.h>
376
377 /*******************************************************************
378 check on Kerberos authentication
379 ********************************************************************/
380 static BOOL krb5_auth(char *user, char *password)
381 {
382         krb5_data tgtname = {
383                 0,
384                 KRB5_TGS_NAME_SIZE,
385                 KRB5_TGS_NAME
386         };
387         krb5_context kcontext;
388         krb5_principal kprinc;
389         krb5_principal server;
390         krb5_creds kcreds;
391         int options = 0;
392         krb5_address **addrs = (krb5_address **) 0;
393         krb5_preauthtype *preauth = NULL;
394         krb5_keytab keytab = NULL;
395         krb5_timestamp now;
396         krb5_ccache ccache = NULL;
397         int retval;
398         char *name;
399
400         if (retval = krb5_init_context(&kcontext))
401         {
402                 return (False);
403         }
404
405         if (retval = krb5_timeofday(kcontext, &now))
406         {
407                 return (False);
408         }
409
410         if (retval = krb5_cc_default(kcontext, &ccache))
411         {
412                 return (False);
413         }
414
415         if (retval = krb5_parse_name(kcontext, user, &kprinc))
416         {
417                 return (False);
418         }
419
420         ZERO_STRUCT(kcreds);
421
422         kcreds.client = kprinc;
423
424         if ((retval = krb5_build_principal_ext(kcontext, &server,
425                                                krb5_princ_realm(kcontext,
426                                                                 kprinc)->
427                                                length,
428                                                krb5_princ_realm(kcontext,
429                                                                 kprinc)->data,
430                                                tgtname.length, tgtname.data,
431                                                krb5_princ_realm(kcontext,
432                                                                 kprinc)->
433                                                length,
434                                                krb5_princ_realm(kcontext,
435                                                                 kprinc)->data,
436                                                0)))
437         {
438                 return (False);
439         }
440
441         kcreds.server = server;
442
443         retval = krb5_get_in_tkt_with_password(kcontext,
444                                                options,
445                                                addrs,
446                                                NULL,
447                                                preauth,
448                                                password, 0, &kcreds, 0);
449
450         if (retval)
451         {
452                 return (False);
453         }
454
455         return (True);
456 }
457 #endif /* KRB5_AUTH */
458
459 #ifdef KRB4_AUTH
460 #include <krb.h>
461
462 /*******************************************************************
463 check on Kerberos authentication
464 ********************************************************************/
465 static BOOL krb4_auth(char *user, char *password)
466 {
467         char realm[REALM_SZ];
468         char tkfile[MAXPATHLEN];
469
470         if (krb_get_lrealm(realm, 1) != KSUCCESS)
471         {
472                 (void)safe_strcpy(realm, KRB_REALM, sizeof(realm) - 1);
473         }
474
475         (void)slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d",
476                        (int)sys_getpid());
477
478         krb_set_tkt_string(tkfile);
479         if (krb_verify_user(user, "", realm, password, 0, "rmcd") == KSUCCESS)
480         {
481                 unlink(tkfile);
482                 return 1;
483         }
484         unlink(tkfile);
485         return 0;
486 }
487 #endif /* KRB4_AUTH */
488
489 #ifdef LINUX_BIGCRYPT
490 /****************************************************************************
491 an enhanced crypt for Linux to handle password longer than 8 characters
492 ****************************************************************************/
493 static int linux_bigcrypt(char *password, char *salt1, char *crypted)
494 {
495 #define LINUX_PASSWORD_SEG_CHARS 8
496         char salt[3];
497         int i;
498
499         StrnCpy(salt, salt1, 2);
500         crypted += 2;
501
502         for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
503                 char *p = crypt(password, salt) + 2;
504                 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
505                         return (0);
506                 password += LINUX_PASSWORD_SEG_CHARS;
507                 crypted += strlen(p);
508         }
509
510         return (1);
511 }
512 #endif
513
514 #ifdef OSF1_ENH_SEC
515 /****************************************************************************
516 an enhanced crypt for OSF1
517 ****************************************************************************/
518 static char *osf1_bigcrypt(char *password, char *salt1)
519 {
520         static char result[AUTH_MAX_PASSWD_LENGTH] = "";
521         char *p1;
522         char *p2 = password;
523         char salt[3];
524         int i;
525         int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
526         if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
527                 parts++;
528
529         StrnCpy(salt, salt1, 2);
530         StrnCpy(result, salt1, 2);
531         result[2] = '\0';
532
533         for (i = 0; i < parts; i++) {
534                 p1 = crypt(p2, salt);
535                 strncat(result, p1 + 2,
536                         AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
537                 StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
538                 p2 += AUTH_CLEARTEXT_SEG_CHARS;
539         }
540
541         return (result);
542 }
543 #endif
544
545
546 /****************************************************************************
547 apply a function to upper/lower case combinations
548 of a string and return true if one of them returns true.
549 try all combinations with N uppercase letters.
550 offset is the first char to try and change (start with 0)
551 it assumes the string starts lowercased
552 ****************************************************************************/
553 static BOOL string_combinations2(char *s, int offset, BOOL (*fn) (char *),
554                                  int N)
555 {
556         int len = strlen(s);
557         int i;
558
559 #ifdef PASSWORD_LENGTH
560         len = MIN(len, PASSWORD_LENGTH);
561 #endif
562
563         if (N <= 0 || offset >= len)
564                 return (fn(s));
565
566         for (i = offset; i < (len - (N - 1)); i++) {
567                 char c = s[i];
568                 if (!islower(c))
569                         continue;
570                 s[i] = toupper(c);
571                 if (string_combinations2(s, i + 1, fn, N - 1))
572                         return (True);
573                 s[i] = c;
574         }
575         return (False);
576 }
577
578 /****************************************************************************
579 apply a function to upper/lower case combinations
580 of a string and return true if one of them returns true.
581 try all combinations with up to N uppercase letters.
582 offset is the first char to try and change (start with 0)
583 it assumes the string starts lowercased
584 ****************************************************************************/
585 static BOOL string_combinations(char *s, BOOL (*fn) (char *), int N)
586 {
587         int n;
588         for (n = 1; n <= N; n++)
589                 if (string_combinations2(s, 0, fn, n))
590                         return (True);
591         return (False);
592 }
593
594
595 /****************************************************************************
596 core of password checking routine
597 ****************************************************************************/
598 static BOOL password_check(char *password)
599 {
600
601 #ifdef WITH_PAM
602         return (smb_pam_passcheck(this_user, password) == NT_STATUS_NOPROBLEMO);
603 #endif /* WITH_PAM */
604
605 #ifdef WITH_AFS
606         if (afs_auth(this_user, password))
607                 return (True);
608 #endif /* WITH_AFS */
609
610 #ifdef WITH_DFS
611         if (dfs_auth(this_user, password))
612                 return (True);
613 #endif /* WITH_DFS */
614
615 #ifdef KRB5_AUTH
616         if (krb5_auth(this_user, password))
617                 return (True);
618 #endif /* KRB5_AUTH */
619
620 #ifdef KRB4_AUTH
621         if (krb4_auth(this_user, password))
622                 return (True);
623 #endif /* KRB4_AUTH */
624
625 #ifdef OSF1_ENH_SEC
626         {
627                 BOOL ret =
628                         (strcmp
629                          (osf1_bigcrypt(password, this_salt),
630                           this_crypted) == 0);
631                 if (!ret) {
632                         DEBUG(2,
633                               ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
634                         ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
635                 }
636                 return ret;
637         }
638 #endif /* OSF1_ENH_SEC */
639
640 #ifdef ULTRIX_AUTH
641         return (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0);
642 #endif /* ULTRIX_AUTH */
643
644 #ifdef LINUX_BIGCRYPT
645         return (linux_bigcrypt(password, this_salt, this_crypted));
646 #endif /* LINUX_BIGCRYPT */
647
648 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
649
650         /*
651          * Some systems have bigcrypt in the C library but might not
652          * actually use it for the password hashes (HPUX 10.20) is
653          * a noteable example. So we try bigcrypt first, followed
654          * by crypt.
655          */
656
657         if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
658                 return True;
659         else
660                 return (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
661 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
662
663 #ifdef HAVE_BIGCRYPT
664         return (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
665 #endif /* HAVE_BIGCRYPT */
666
667 #ifndef HAVE_CRYPT
668         DEBUG(1, ("Warning - no crypt available\n"));
669         return (False);
670 #else /* HAVE_CRYPT */
671         return (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
672 #endif /* HAVE_CRYPT */
673 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
674 }
675
676
677
678 /****************************************************************************
679 check if a username/password is OK
680 the function pointer fn() points to a function to call when a successful
681 match is found and is used to update the encrypted password file 
682 return True on correct match, False otherwise
683 ****************************************************************************/
684
685 BOOL pass_check(char *user, char *password, int pwlen, struct passwd *pwd,
686                 BOOL (*fn) (char *, char *))
687 {
688         pstring pass2;
689         int level = lp_passwordlevel();
690         struct passwd *pass = NULL;
691
692         if (password)
693                 password[pwlen] = 0;
694
695 #if DEBUG_PASSWORD
696         DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
697 #endif
698
699         if (!password)
700                 return (False);
701
702         if (((!*password) || (!pwlen)) && !lp_null_passwords())
703                 return (False);
704
705         if (pwd && !user) {
706                 pass = (struct passwd *)pwd;
707                 user = pass->pw_name;
708         } else {
709                 pass = Get_Pwnam(user, True);
710         }
711
712 #ifdef WITH_PAM
713
714         /*
715          * If we're using PAM we want to short-circuit all the 
716          * checks below and dive straight into the PAM code.
717          */
718
719         fstrcpy(this_user, user);
720
721         DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user, pwlen));
722
723 #else /* Not using PAM */
724
725         DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user, pwlen));
726
727         if (!pass) {
728                 DEBUG(3, ("Couldn't find user %s\n", user));
729                 return (False);
730         }
731
732 #ifdef HAVE_GETSPNAM
733         {
734                 struct spwd *spass;
735
736                 /* many shadow systems require you to be root to get
737                    the password, in most cases this should already be
738                    the case when this function is called, except
739                    perhaps for IPC password changing requests */
740
741                 spass = getspnam(pass->pw_name);
742                 if (spass && spass->sp_pwdp)
743                         pstrcpy(pass->pw_passwd, spass->sp_pwdp);
744         }
745 #elif defined(IA_UINFO)
746         {
747                 /* Need to get password with SVR4.2's ia_ functions
748                    instead of get{sp,pw}ent functions. Required by
749                    UnixWare 2.x, tested on version
750                    2.1. (tangent@cyberport.com) */
751                 uinfo_t uinfo;
752                 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
753                         ia_get_logpwd(uinfo, &(pass->pw_passwd));
754         }
755 #endif
756
757 #ifdef HAVE_GETPRPWNAM
758         {
759                 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
760                 if (pr_pw && pr_pw->ufld.fd_encrypt)
761                         pstrcpy(pass->pw_passwd, pr_pw->ufld.fd_encrypt);
762         }
763 #endif
764
765 #ifdef OSF1_ENH_SEC
766         {
767                 struct pr_passwd *mypasswd;
768                 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
769                           user));
770                 mypasswd = getprpwnam(user);
771                 if (mypasswd) {
772                         fstrcpy(pass->pw_name, mypasswd->ufld.fd_name);
773                         fstrcpy(pass->pw_passwd, mypasswd->ufld.fd_encrypt);
774                 } else {
775                         DEBUG(5,
776                               ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
777                                user));
778                 }
779         }
780 #endif
781
782 #ifdef ULTRIX_AUTH
783         {
784                 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
785                 if (ap) {
786                         fstrcpy(pass->pw_passwd, ap->a_password);
787                         endauthent();
788                 }
789         }
790 #endif
791
792         /* extract relevant info */
793         fstrcpy(this_user, pass->pw_name);
794         fstrcpy(this_salt, pass->pw_passwd);
795
796 #if defined(HAVE_TRUNCATED_SALT)
797         /* crypt on some platforms (HPUX in particular)
798            won't work with more than 2 salt characters. */
799         this_salt[2] = 0;
800 #endif
801
802         fstrcpy(this_crypted, pass->pw_passwd);
803
804         if (!*this_crypted) {
805                 if (!lp_null_passwords()) {
806                         DEBUG(2, ("Disallowing %s with null password\n",
807                                   this_user));
808                         return (False);
809                 }
810                 if (!*password) {
811                         DEBUG(3,
812                               ("Allowing access to %s with null password\n",
813                                this_user));
814                         return (True);
815                 }
816         }
817
818 #endif /* WITH_PAM */
819
820         /* try it as it came to us */
821         if (password_check(password)) {
822                 if (fn)
823                         fn(user, password);
824                 return (True);
825         }
826
827         /* if the password was given to us with mixed case then we don't
828            need to proceed as we know it hasn't been case modified by the
829            client */
830         if (strhasupper(password) && strhaslower(password)) {
831                 return (False);
832         }
833
834         /* make a copy of it */
835         StrnCpy(pass2, password, sizeof(pstring) - 1);
836
837         /* try all lowercase if it's currently all uppercase */
838         if (strhasupper(password)) {
839                 strlower(password);
840                 if (password_check(password)) {
841                         if (fn)
842                                 fn(user, password);
843                         return (True);
844                 }
845         }
846
847         /* give up? */
848         if (level < 1) {
849                 /* restore it */
850                 fstrcpy(password, pass2);
851                 return (False);
852         }
853
854         /* last chance - all combinations of up to level chars upper! */
855         strlower(password);
856
857         if (string_combinations(password, password_check, level)) {
858                 if (fn)
859                         fn(user, password);
860                 return (True);
861         }
862
863         /* restore it */
864         fstrcpy(password, pass2);
865
866         return (False);
867 }