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