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