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