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