Fix from Paul Green to set correct lengths.
[samba.git] / source3 / auth / 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 fstring this_user[100] = "";
31 static fstring this_salt[100] = "";
32 static fstring 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_OK);
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, 
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         pass = Get_Pwnam(user, True);
706
707 #ifdef WITH_PAM
708
709         /*
710          * If we're using PAM we want to short-circuit all the 
711          * checks below and dive straight into the PAM code.
712          */
713
714         fstrcpy(this_user, user);
715
716         DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user, pwlen));
717
718 #else /* Not using PAM */
719
720         DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user, pwlen));
721
722         if (!pass) {
723                 DEBUG(3, ("Couldn't find user %s\n", user));
724                 return (False);
725         }
726
727 #ifdef HAVE_GETSPNAM
728         {
729                 struct spwd *spass;
730
731                 /* many shadow systems require you to be root to get
732                    the password, in most cases this should already be
733                    the case when this function is called, except
734                    perhaps for IPC password changing requests */
735
736                 spass = getspnam(pass->pw_name);
737                 if (spass && spass->sp_pwdp)
738                         pstrcpy(pass->pw_passwd, spass->sp_pwdp);
739         }
740 #elif defined(IA_UINFO)
741         {
742                 /* Need to get password with SVR4.2's ia_ functions
743                    instead of get{sp,pw}ent functions. Required by
744                    UnixWare 2.x, tested on version
745                    2.1. (tangent@cyberport.com) */
746                 uinfo_t uinfo;
747                 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
748                         ia_get_logpwd(uinfo, &(pass->pw_passwd));
749         }
750 #endif
751
752 #ifdef HAVE_GETPRPWNAM
753         {
754                 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
755                 if (pr_pw && pr_pw->ufld.fd_encrypt)
756                         pstrcpy(pass->pw_passwd, pr_pw->ufld.fd_encrypt);
757         }
758 #endif
759
760 #ifdef OSF1_ENH_SEC
761         {
762                 struct pr_passwd *mypasswd;
763                 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
764                           user));
765                 mypasswd = getprpwnam(user);
766                 if (mypasswd) {
767                         fstrcpy(pass->pw_name, mypasswd->ufld.fd_name);
768                         fstrcpy(pass->pw_passwd, mypasswd->ufld.fd_encrypt);
769                 } else {
770                         DEBUG(5,
771                               ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
772                                user));
773                 }
774         }
775 #endif
776
777 #ifdef ULTRIX_AUTH
778         {
779                 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
780                 if (ap) {
781                         fstrcpy(pass->pw_passwd, ap->a_password);
782                         endauthent();
783                 }
784         }
785 #endif
786
787         /* extract relevant info */
788         fstrcpy(this_user, pass->pw_name);
789         fstrcpy(this_salt, pass->pw_passwd);
790
791 #if defined(HAVE_TRUNCATED_SALT)
792         /* crypt on some platforms (HPUX in particular)
793            won't work with more than 2 salt characters. */
794         this_salt[2] = 0;
795 #endif
796
797         fstrcpy(this_crypted, pass->pw_passwd);
798
799         if (!*this_crypted) {
800                 if (!lp_null_passwords()) {
801                         DEBUG(2, ("Disallowing %s with null password\n",
802                                   this_user));
803                         return (False);
804                 }
805                 if (!*password) {
806                         DEBUG(3,
807                               ("Allowing access to %s with null password\n",
808                                this_user));
809                         return (True);
810                 }
811         }
812
813 #endif /* WITH_PAM */
814
815         /* try it as it came to us */
816         if (password_check(password)) {
817                 if (fn)
818                         fn(user, password);
819                 return (True);
820         }
821
822         /* if the password was given to us with mixed case then we don't
823            need to proceed as we know it hasn't been case modified by the
824            client */
825         if (strhasupper(password) && strhaslower(password)) {
826                 return (False);
827         }
828
829         /* make a copy of it */
830         StrnCpy(pass2, password, sizeof(pstring) - 1);
831
832         /* try all lowercase if it's currently all uppercase */
833         if (strhasupper(password)) {
834                 strlower(password);
835                 if (password_check(password)) {
836                         if (fn)
837                                 fn(user, password);
838                         return (True);
839                 }
840         }
841
842         /* give up? */
843         if (level < 1) {
844                 /* restore it */
845                 fstrcpy(password, pass2);
846                 return (False);
847         }
848
849         /* last chance - all combinations of up to level chars upper! */
850         strlower(password);
851
852         if (string_combinations(password, password_check, level)) {
853                 if (fn)
854                         fn(user, password);
855                 return (True);
856         }
857
858         /* restore it */
859         fstrcpy(password, pass2);
860
861         return (False);
862 }