indent update to make t easier to see setuid mods in TNG. some
[samba.git] / source3 / auth / pass_check.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Password checking
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /* this module is for checking a username/password against a system
23    password database. The SMB encrypted password support is elsewhere */
24
25 #include "includes.h"
26
27 extern int DEBUGLEVEL;
28
29 /* these are kept here to keep the string_combinations function simple */
30 static 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         if (set_effective_gid(pw->pw_gid) != 0)
357         {
358                 DEBUG(0, ("Can't set egid to %d (%s)\n",
359                           pw->pw_gid, strerror(errno)));
360                 return False;
361         }
362
363         if (set_effective_uid(pw->pw_uid) != 0)
364         {
365                 set_effective_gid(egid);
366                 DEBUG(0, ("Can't set euid to %d (%s)\n",
367                           pw->pw_uid, strerror(errno)));
368                 return False;
369         }
370
371         if (sec_login_setup_identity((unsigned char *)user,
372                                      sec_login_no_flags,
373                                      &my_dce_sec_context, &err) == 0)
374         {
375                 dce_error_inq_text(err, dce_errstr, &err2);
376                 DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
377                           user, dce_errstr));
378                 goto err;
379         }
380
381         sec_login_get_pwent(my_dce_sec_context,
382                             (sec_login_passwd_t *) & pw, &err);
383         if (err != error_status_ok)
384         {
385                 dce_error_inq_text(err, dce_errstr, &err2);
386                 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
387                 goto err;
388         }
389
390         passwd_rec.version_number = sec_passwd_c_version_none;
391         passwd_rec.pepper = NULL;
392         passwd_rec.key.key_type = sec_passwd_plain;
393         passwd_rec.key.tagged_union.plain = (idl_char *) password;
394
395         sec_login_validate_identity(my_dce_sec_context,
396                                     &passwd_rec, &password_reset,
397                                     &auth_src, &err);
398         if (err != error_status_ok)
399         {
400                 dce_error_inq_text(err, dce_errstr, &err2);
401                 DEBUG(0,
402                       ("DCE Identity Validation failed for principal %s: %s\n",
403                        user, dce_errstr));
404                 goto err;
405         }
406
407         sec_login_certify_identity(my_dce_sec_context, &err);
408         if (err != error_status_ok)
409         {
410                 dce_error_inq_text(err, dce_errstr, &err2);
411                 DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
412                 goto err;
413         }
414
415         if (auth_src != sec_login_auth_src_network)
416         {
417                 DEBUG(0, ("DCE context has no network credentials.\n"));
418         }
419
420         sec_login_set_context(my_dce_sec_context, &err);
421         if (err != error_status_ok)
422         {
423                 dce_error_inq_text(err, dce_errstr, &err2);
424                 DEBUG(0,
425                       ("DCE login failed for principal %s, cant set context: %s\n",
426                        user, dce_errstr));
427
428                 sec_login_purge_context(&my_dce_sec_context, &err);
429                 goto err;
430         }
431
432         sec_login_get_pwent(my_dce_sec_context,
433                             (sec_login_passwd_t *) & pw, &err);
434         if (err != error_status_ok)
435         {
436                 dce_error_inq_text(err, dce_errstr, &err2);
437                 DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
438                 goto err;
439         }
440
441         DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
442                   user, getpid()));
443
444         DEBUG(3, ("DCE principal: %s\n"
445                   "          uid: %d\n"
446                   "          gid: %d\n",
447                   pw->pw_name, pw->pw_uid, pw->pw_gid));
448         DEBUG(3, ("         info: %s\n"
449                   "          dir: %s\n"
450                   "        shell: %s\n",
451                   pw->pw_gecos, pw->pw_dir, pw->pw_shell));
452
453         sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
454         if (err != error_status_ok)
455         {
456                 dce_error_inq_text(err, dce_errstr, &err2);
457                 DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
458                 goto err;
459         }
460
461         set_effective_uid(0);
462         set_effective_gid(0);
463
464         DEBUG(0,
465               ("DCE context expires: %s", asctime(localtime(&expire_time))));
466
467         dcelogin_atmost_once = 1;
468         return (True);
469
470       err:
471
472         /* Go back to root, JRA. */
473         set_effective_uid(0);
474         set_effective_gid(egid);
475         return (False);
476 }
477
478 void dfs_unlogin(void)
479 {
480         error_status_t err;
481         int err2;
482         unsigned char dce_errstr[dce_c_error_string_len];
483
484         sec_login_purge_context(&my_dce_sec_context, &err);
485         if (err != error_status_ok)
486         {
487                 dce_error_inq_text(err, dce_errstr, &err2);
488                 DEBUG(0,
489                       ("DCE purge login context failed for server instance %d: %s\n",
490                        getpid(), dce_errstr));
491         }
492 }
493 #endif
494
495 #ifdef KRB5_AUTH
496
497 #include <krb5.h>
498
499 /*******************************************************************
500 check on Kerberos authentication
501 ********************************************************************/
502 static BOOL krb5_auth(char *user, char *password)
503 {
504         krb5_data tgtname = {
505                 0,
506                 KRB5_TGS_NAME_SIZE,
507                 KRB5_TGS_NAME
508         };
509         krb5_context kcontext;
510         krb5_principal kprinc;
511         krb5_principal server;
512         krb5_creds kcreds;
513         int options = 0;
514         krb5_address **addrs = (krb5_address **) 0;
515         krb5_preauthtype *preauth = NULL;
516         krb5_keytab keytab = NULL;
517         krb5_timestamp now;
518         krb5_ccache ccache = NULL;
519         int retval;
520         char *name;
521
522         if (retval = krb5_init_context(&kcontext))
523         {
524                 return (False);
525         }
526
527         if (retval = krb5_timeofday(kcontext, &now))
528         {
529                 return (False);
530         }
531
532         if (retval = krb5_cc_default(kcontext, &ccache))
533         {
534                 return (False);
535         }
536
537         if (retval = krb5_parse_name(kcontext, user, &kprinc))
538         {
539                 return (False);
540         }
541
542         ZERO_STRUCT(kcreds);
543
544         kcreds.client = kprinc;
545
546         if ((retval = krb5_build_principal_ext(kcontext, &server,
547                                                krb5_princ_realm(kcontext,
548                                                                 kprinc)->
549                                                length,
550                                                krb5_princ_realm(kcontext,
551                                                                 kprinc)->data,
552                                                tgtname.length, tgtname.data,
553                                                krb5_princ_realm(kcontext,
554                                                                 kprinc)->
555                                                length,
556                                                krb5_princ_realm(kcontext,
557                                                                 kprinc)->data,
558                                                0)))
559         {
560                 return (False);
561         }
562
563         kcreds.server = server;
564
565         retval = krb5_get_in_tkt_with_password(kcontext,
566                                                options,
567                                                addrs,
568                                                NULL,
569                                                preauth,
570                                                password, 0, &kcreds, 0);
571
572         if (retval)
573         {
574                 return (False);
575         }
576
577         return (True);
578 }
579 #endif /* KRB5_AUTH */
580
581 #ifdef KRB4_AUTH
582 #include <krb.h>
583
584 /*******************************************************************
585 check on Kerberos authentication
586 ********************************************************************/
587 static BOOL krb4_auth(char *user, char *password)
588 {
589         char realm[REALM_SZ];
590         char tkfile[MAXPATHLEN];
591
592         if (krb_get_lrealm(realm, 1) != KSUCCESS)
593         {
594                 (void)safe_strcpy(realm, KRB_REALM, sizeof(realm) - 1);
595         }
596
597         (void)slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d",
598                        (int)getpid());
599
600         krb_set_tkt_string(tkfile);
601         if (krb_verify_user(user, "", realm, password, 0, "rmcd") == KSUCCESS)
602         {
603                 unlink(tkfile);
604                 return 1;
605         }
606         unlink(tkfile);
607         return 0;
608 }
609 #endif /* KRB4_AUTH */
610
611 #ifdef LINUX_BIGCRYPT
612 /****************************************************************************
613 an enhanced crypt for Linux to handle password longer than 8 characters
614 ****************************************************************************/
615 static int linux_bigcrypt(char *password, char *salt1, char *crypted)
616 {
617 #define LINUX_PASSWORD_SEG_CHARS 8
618         char salt[3];
619         int i;
620
621         StrnCpy(salt, salt1, 2);
622         crypted += 2;
623
624         for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS)
625         {
626                 char *p = crypt(password, salt) + 2;
627                 if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
628                         return (0);
629                 password += LINUX_PASSWORD_SEG_CHARS;
630                 crypted += strlen(p);
631         }
632
633         return (1);
634 }
635 #endif
636
637 #ifdef OSF1_ENH_SEC
638 /****************************************************************************
639 an enhanced crypt for OSF1
640 ****************************************************************************/
641 static char *osf1_bigcrypt(char *password, char *salt1)
642 {
643         static char result[AUTH_MAX_PASSWD_LENGTH] = "";
644         char *p1;
645         char *p2 = password;
646         char salt[3];
647         int i;
648         int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
649         if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
650         {
651                 parts++;
652         }
653
654         StrnCpy(salt, salt1, 2);
655         StrnCpy(result, salt1, 2);
656         result[2] = '\0';
657
658         for (i = 0; i < parts; i++)
659         {
660                 p1 = crypt(p2, salt);
661                 strncat(result, p1 + 2,
662                         AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
663                 StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
664                 p2 += AUTH_CLEARTEXT_SEG_CHARS;
665         }
666
667         return (result);
668 }
669 #endif
670
671
672 /****************************************************************************
673 apply a function to upper/lower case combinations
674 of a string and return true if one of them returns true.
675 try all combinations with N uppercase letters.
676 offset is the first char to try and change (start with 0)
677 it assumes the string starts lowercased
678 ****************************************************************************/
679 static BOOL string_combinations2(char *s, int offset, BOOL (*fn) (char *),
680                                  int N)
681 {
682         int len = strlen(s);
683         int i;
684
685 #ifdef PASSWORD_LENGTH
686         len = MIN(len, PASSWORD_LENGTH);
687 #endif
688
689         if (N <= 0 || offset >= len)
690         {
691                 return (fn(s));
692         }
693
694         for (i = offset; i < (len - (N - 1)); i++)
695         {
696                 char c = s[i];
697                 if (!islower(c))
698                         continue;
699                 s[i] = toupper(c);
700                 if (string_combinations2(s, i + 1, fn, N - 1))
701                         return (True);
702                 s[i] = c;
703         }
704         return (False);
705 }
706
707 /****************************************************************************
708 apply a function to upper/lower case combinations
709 of a string and return true if one of them returns true.
710 try all combinations with up to N uppercase letters.
711 offset is the first char to try and change (start with 0)
712 it assumes the string starts lowercased
713 ****************************************************************************/
714 static BOOL string_combinations(char *s, BOOL (*fn) (char *), int N)
715 {
716         int n;
717         for (n = 1; n <= N; n++)
718                 if (string_combinations2(s, 0, fn, n))
719                         return (True);
720         return (False);
721 }
722
723
724 /****************************************************************************
725 core of password checking routine
726 ****************************************************************************/
727 static BOOL password_check(char *password)
728 {
729
730 #ifdef WITH_PAM
731         /* This falls through if the password check fails
732            - if HAVE_CRYPT is not defined this causes an error msg
733            saying Warning - no crypt available
734            - if HAVE_CRYPT is defined this is a potential security hole
735            as it may authenticate via the crypt call when PAM
736            settings say it should fail.
737            if (pam_auth(user,password)) return(True);
738            Hence we make a direct return to avoid a second chance!!!
739          */
740         return (pam_auth(this_user, password));
741 #endif /* WITH_PAM */
742
743 #ifdef WITH_AFS
744         if (afs_auth(this_user, password))
745                 return (True);
746 #endif /* WITH_AFS */
747
748 #ifdef WITH_DFS
749         if (dfs_auth(this_user, password))
750                 return (True);
751 #endif /* WITH_DFS */
752
753 #ifdef KRB5_AUTH
754         if (krb5_auth(this_user, password))
755                 return (True);
756 #endif /* KRB5_AUTH */
757
758 #ifdef KRB4_AUTH
759         if (krb4_auth(this_user, password))
760                 return (True);
761 #endif /* KRB4_AUTH */
762
763 #ifdef OSF1_ENH_SEC
764         {
765                 BOOL ret =
766                         (strcmp
767                          (osf1_bigcrypt(password, this_salt),
768                           this_crypted) == 0);
769                 if (!ret)
770                 {
771                         DEBUG(2,
772                               ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
773                         ret =
774                                 (strcmp
775                                ((char *)crypt(password, this_salt),
776                                 this_crypted) == 0);
777                 }
778                 return ret;
779         }
780 #endif /* OSF1_ENH_SEC */
781
782 #ifdef ULTRIX_AUTH
783         return (strcmp((char *)crypt16(password, this_salt), this_crypted) ==
784                 0);
785 #endif /* ULTRIX_AUTH */
786
787 #ifdef LINUX_BIGCRYPT
788         return (linux_bigcrypt(password, this_salt, this_crypted));
789 #endif /* LINUX_BIGCRYPT */
790
791 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
792
793         /*
794          * Some systems have bigcrypt in the C library but might not
795          * actually use it for the password hashes (HPUX 10.20) is
796          * a noteable example. So we try bigcrypt first, followed
797          * by crypt.
798          */
799
800         if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
801                 return True;
802         else
803                 return (strcmp
804                         ((char *)crypt(password, this_salt),
805                          this_crypted) == 0);
806 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
807
808 #ifdef HAVE_BIGCRYPT
809         return (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
810 #endif /* HAVE_BIGCRYPT */
811
812 #ifndef HAVE_CRYPT
813         DEBUG(1, ("Warning - no crypt available\n"));
814         return (False);
815 #else /* HAVE_CRYPT */
816         return (strcmp((char *)crypt(password, this_salt), this_crypted) ==
817                 0);
818 #endif /* HAVE_CRYPT */
819 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
820 }
821
822
823
824 /****************************************************************************
825 check if a username/password is OK
826 the function pointer fn() points to a function to call when a successful
827 match is found and is used to update the encrypted password file 
828 return True on correct match, False otherwise
829 ****************************************************************************/
830 BOOL pass_check(char *user, char *password, int pwlen, struct passwd *pwd,
831                 BOOL (*fn) (char *, char *))
832 {
833         pstring pass2;
834         int level = lp_passwordlevel();
835         struct passwd *pass;
836
837         if (password)
838                 password[pwlen] = 0;
839
840 #if DEBUG_PASSWORD
841         DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
842 #endif
843
844         if (!password)
845         {
846                 return (False);
847         }
848
849         if (((!*password) || (!pwlen)) && !lp_null_passwords())
850         {
851                 return (False);
852         }
853
854         if (pwd && !user)
855         {
856                 pass = (struct passwd *)pwd;
857                 user = pass->pw_name;
858         }
859         else
860         {
861                 pass = Get_Pwnam(user, True);
862         }
863
864
865         DEBUG(4, ("Checking password for user %s (l=%d)\n", user, pwlen));
866
867         if (!pass)
868         {
869                 DEBUG(3, ("Couldn't find user %s\n", user));
870                 return (False);
871         }
872
873 #ifdef HAVE_GETSPNAM
874         {
875                 struct spwd *spass;
876
877                 /* many shadow systems require you to be root to get
878                    the password, in most cases this should already be
879                    the case when this function is called, except
880                    perhaps for IPC password changing requests */
881
882                 spass = getspnam(pass->pw_name);
883                 if (spass && spass->sp_pwdp)
884                 {
885                         pstrcpy(pass->pw_passwd, spass->sp_pwdp);
886                 }
887         }
888 #elif defined(IA_UINFO)
889         {
890                 /* Need to get password with SVR4.2's ia_ functions
891                    instead of get{sp,pw}ent functions. Required by
892                    UnixWare 2.x, tested on version
893                    2.1. (tangent@cyberport.com) */
894                 uinfo_t uinfo;
895                 if (ia_openinfo(pass->pw_name, &uinfo) != -1)
896                 {
897                         ia_get_logpwd(uinfo, &(pass->pw_passwd));
898                 }
899         }
900 #endif
901
902 #ifdef HAVE_GETPRPWNAM
903         {
904                 struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
905                 if (pr_pw && pr_pw->ufld.fd_encrypt)
906                         pstrcpy(pass->pw_passwd, pr_pw->ufld.fd_encrypt);
907         }
908 #endif
909
910 #ifdef OSF1_ENH_SEC
911         {
912                 struct pr_passwd *mypasswd;
913                 DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
914                           user));
915                 mypasswd = getprpwnam(user);
916                 if (mypasswd)
917                 {
918                         fstrcpy(pass->pw_name, mypasswd->ufld.fd_name);
919                         fstrcpy(pass->pw_passwd, mypasswd->ufld.fd_encrypt);
920                 }
921                 else
922                 {
923                         DEBUG(5,
924                               ("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
925                                user));
926                 }
927         }
928 #endif
929
930 #ifdef ULTRIX_AUTH
931         {
932                 AUTHORIZATION *ap = getauthuid(pass->pw_uid);
933                 if (ap)
934                 {
935                         fstrcpy(pass->pw_passwd, ap->a_password);
936                         endauthent();
937                 }
938         }
939 #endif
940
941         /* extract relevant info */
942         fstrcpy(this_user, pass->pw_name);
943         fstrcpy(this_salt, pass->pw_passwd);
944
945 #if defined(HAVE_TRUNCATED_SALT)
946         /* crypt on some platforms (HPUX in particular)
947            won't work with more than 2 salt characters. */
948         this_salt[2] = 0;
949 #endif
950
951         fstrcpy(this_crypted, pass->pw_passwd);
952
953         if (!*this_crypted)
954         {
955                 if (!lp_null_passwords())
956                 {
957                         DEBUG(2, ("Disallowing %s with null password\n",
958                                   this_user));
959                         return (False);
960                 }
961                 if (!*password)
962                 {
963                         DEBUG(3,
964                               ("Allowing access to %s with null password\n",
965                                this_user));
966                         return (True);
967                 }
968         }
969
970         /* try it as it came to us */
971         if (password_check(password))
972         {
973                 if (fn)
974                         fn(user, password);
975                 return (True);
976         }
977
978         /* if the password was given to us with mixed case then we don't
979            need to proceed as we know it hasn't been case modified by the
980            client */
981         if (strhasupper(password) && strhaslower(password))
982         {
983                 return (False);
984         }
985
986         /* make a copy of it */
987         StrnCpy(pass2, password, sizeof(pstring) - 1);
988
989         /* try all lowercase */
990         strlower(password);
991         if (password_check(password))
992         {
993                 if (fn)
994                         fn(user, password);
995                 return (True);
996         }
997
998         /* give up? */
999         if (level < 1)
1000         {
1001
1002                 /* restore it */
1003                 fstrcpy(password, pass2);
1004
1005                 return (False);
1006         }
1007
1008         /* last chance - all combinations of up to level chars upper! */
1009         strlower(password);
1010
1011         if (string_combinations(password, password_check, level))
1012         {
1013                 if (fn)
1014                         fn(user, password);
1015                 return (True);
1016         }
1017
1018         /* restore it */
1019         fstrcpy(password, pass2);
1020
1021         return (False);
1022 }