r12627: This magic comment keeps minimal_includes.pl from suggesting the
[kai/samba-autobuild/.git] / source4 / auth / auth_unix.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Password and authentication handling
4    Copyright (C) Andrew Bartlett                2001
5    Copyright (C) Jeremy Allison                 2001
6    Copyright (C) Simo Sorce                     2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "auth/auth.h"
25 #include "system/passwd.h" /* needed by some systems for struct passwd */
26
27 /* TODO: look at how to best fill in parms retrieveing a struct passwd info
28  * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set
29  */
30 static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx,
31                                           const struct auth_usersupplied_info *user_info,
32                                           struct auth_serversupplied_info **_server_info)
33 {
34         struct auth_serversupplied_info *server_info;
35
36         server_info = talloc(mem_ctx, struct auth_serversupplied_info);
37         NT_STATUS_HAVE_NO_MEMORY(server_info);
38
39         server_info->authenticated = True;
40
41         server_info->account_name = talloc_strdup(server_info, talloc_strdup(mem_ctx, user_info->mapped.account_name));
42         NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
43
44         server_info->domain_name = talloc_strdup(server_info, talloc_strdup(mem_ctx, "unix"));
45         NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
46
47
48         /* is this correct? */
49         server_info->account_sid = NULL;
50         server_info->primary_group_sid = NULL;
51         server_info->n_domain_groups = 0;
52         server_info->domain_groups = NULL;
53         server_info->user_session_key = data_blob(NULL,0);
54         server_info->lm_session_key = data_blob(NULL,0);
55
56         server_info->full_name = talloc_strdup(server_info, "");
57         NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
58         server_info->logon_script = talloc_strdup(server_info, "");
59         NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
60         server_info->profile_path = talloc_strdup(server_info, "");
61         NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
62         server_info->home_directory = talloc_strdup(server_info, "");
63         NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
64         server_info->home_drive = talloc_strdup(server_info, "");
65         NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
66
67         server_info->last_logon = 0;
68         server_info->last_logoff = 0;
69         server_info->acct_expiry = 0;
70         server_info->last_password_change = 0;
71         server_info->allow_password_change = 0;
72         server_info->force_password_change = 0;
73         server_info->logon_count = 0;
74         server_info->bad_password_count = 0;
75         server_info->acct_flags = 0;
76
77         *_server_info = server_info;
78
79         return NT_STATUS_OK;
80 }
81
82 #ifdef HAVE_SECURITY_PAM_APPL_H
83 #include <security/pam_appl.h>
84
85 struct smb_pam_user_info {
86         const char *account_name;
87         const char *plaintext_password;
88 };
89
90 #define COPY_STRING(s) (s) ? strdup(s) : NULL
91
92 /* 
93  * Check user password
94  * Currently it uses PAM only and fails on systems without PAM
95  * Samba3 code located in pass_check.c is to ugly to be used directly it will
96  * need major rework that's why pass_check.c is still there.
97 */
98
99 static int smb_pam_conv(int num_msg, const struct pam_message **msg,
100                          struct pam_response **reply, void *appdata_ptr)
101 {
102         struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr;
103         int num;
104
105         if (num_msg <= 0) {
106                 *reply = NULL;
107                 return PAM_CONV_ERR;
108         }
109         
110         /*
111          * Apparantly HPUX has a buggy PAM that doesn't support the
112          * data pointer. Fail if this is the case. JRA.
113          */
114
115         if (info == NULL) {
116                 *reply = NULL;
117                 return PAM_CONV_ERR;
118         }
119
120         /*
121          * PAM frees memory in reply messages by itself
122          * so use malloc instead of talloc here.
123          */
124         *reply = malloc_array_p(struct pam_response, num_msg);
125         if (*reply == NULL) {
126                 return PAM_CONV_ERR;
127         }
128
129         for (num = 0; num < num_msg; num++) {
130                 switch  (msg[num]->msg_style) {
131                         case PAM_PROMPT_ECHO_ON:
132                                 (*reply)[num].resp_retcode = PAM_SUCCESS;
133                                 (*reply)[num].resp = COPY_STRING(info->account_name);
134                                 break;
135
136                         case PAM_PROMPT_ECHO_OFF:
137                                 (*reply)[num].resp_retcode = PAM_SUCCESS;
138                                 (*reply)[num].resp = COPY_STRING(info->plaintext_password);
139                                 break;
140
141                         case PAM_TEXT_INFO:
142                                 (*reply)[num].resp_retcode = PAM_SUCCESS;
143                                 (*reply)[num].resp = NULL;
144                                 DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg)));
145
146                         case PAM_ERROR_MSG:
147                                 (*reply)[num].resp_retcode = PAM_SUCCESS;
148                                 (*reply)[num].resp = NULL;
149                                 DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg)));
150                                 break;
151
152                         default:
153                                 SAFE_FREE(*reply);
154                                 *reply = NULL;
155                                 DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n"));
156                                 return PAM_CONV_ERR;
157                 }
158         }
159
160         return PAM_SUCCESS;
161 }
162
163 /*
164  * Start PAM authentication for specified account
165  */
166
167 static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv)
168 {
169         int pam_error;
170
171         if (account_name == NULL || remote_host == NULL) {
172                 return NT_STATUS_INVALID_PARAMETER;
173         }
174
175         DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name));
176
177         pam_error = pam_start("samba", account_name, pconv, pamh);
178         if (pam_error != PAM_SUCCESS) {
179                 /* no vaild pamh here, can we reliably call pam_strerror ? */
180                 DEBUG(4,("smb_pam_start: pam_start failed!\n"));
181                 return NT_STATUS_UNSUCCESSFUL;
182         }
183
184 #ifdef PAM_RHOST
185         DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host));
186         pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host);
187         if (pam_error != PAM_SUCCESS) {
188                 NTSTATUS nt_status;
189
190                 DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n",
191                          pam_strerror(*pamh, pam_error)));
192                 nt_status = pam_to_nt_status(pam_error);
193
194                 pam_error = pam_end(*pamh, 0);
195                 if (pam_error != PAM_SUCCESS) {
196                         /* no vaild pamh here, can we reliably call pam_strerror ? */
197                         DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
198                                  pam_error));
199                         return pam_to_nt_status(pam_error);
200                 }
201                 return nt_status;
202         }
203 #endif
204 #ifdef PAM_TTY
205         DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
206         pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
207         if (pam_error != PAM_SUCCESS) {
208                 NTSTATUS nt_status;
209
210                 DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
211                          pam_strerror(*pamh, pam_error)));
212                 nt_status = pam_to_nt_status(pam_error);
213
214                 pam_error = pam_end(*pamh, 0);
215                 if (pam_error != PAM_SUCCESS) {
216                         /* no vaild pamh here, can we reliably call pam_strerror ? */
217                         DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
218                                  pam_error));
219                         return pam_to_nt_status(pam_error);
220                 }
221                 return nt_status;
222         }
223 #endif
224         DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name));
225
226         return NT_STATUS_OK;
227 }
228
229 static NTSTATUS smb_pam_end(pam_handle_t *pamh)
230 {
231         int pam_error;
232
233         if (pamh != NULL) {
234                 pam_error = pam_end(pamh, 0);
235                 if (pam_error != PAM_SUCCESS) {
236                         /* no vaild pamh here, can we reliably call pam_strerror ? */
237                         DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
238                                  pam_error));
239                         return pam_to_nt_status(pam_error);
240                 }
241                 return NT_STATUS_OK;
242         }
243
244         DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n"));
245         return NT_STATUS_UNSUCCESSFUL;
246 }
247
248 /*
249  * PAM Authentication Handler
250  */
251 static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user)
252 {
253         int pam_error;
254
255         /*
256          * To enable debugging set in /etc/pam.d/samba:
257          *      auth required /lib/security/pam_pwdb.so nullok shadow audit
258          */
259         
260         DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
261
262         pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
263         switch( pam_error ){
264                 case PAM_AUTH_ERR:
265                         DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
266                         break;
267                 case PAM_CRED_INSUFFICIENT:
268                         DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
269                         break;
270                 case PAM_AUTHINFO_UNAVAIL:
271                         DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
272                         break;
273                 case PAM_USER_UNKNOWN:
274                         DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
275                         break;
276                 case PAM_MAXTRIES:
277                         DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
278                         break;
279                 case PAM_ABORT:
280                         DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
281                         break;
282                 case PAM_SUCCESS:
283                         DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
284                         break;
285                 default:
286                         DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
287                         break;
288         }
289
290         return pam_to_nt_status(pam_error);
291 }
292
293 /* 
294  * PAM Account Handler
295  */
296 static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
297 {
298         int pam_error;
299
300         DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
301
302         pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
303         switch( pam_error ) {
304                 case PAM_AUTHTOK_EXPIRED:
305                         DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
306                         break;
307                 case PAM_ACCT_EXPIRED:
308                         DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
309                         break;
310                 case PAM_AUTH_ERR:
311                         DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
312                         break;
313                 case PAM_PERM_DENIED:
314                         DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
315                         break;
316                 case PAM_USER_UNKNOWN:
317                         DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
318                         break;
319                 case PAM_SUCCESS:
320                         DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
321                         break;
322                 default:
323                         DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
324                         break;
325         }
326
327         return pam_to_nt_status(pam_error);
328 }
329
330 /*
331  * PAM Credential Setting
332  */
333
334 static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
335 {
336         int pam_error;
337
338         /*
339          * This will allow samba to aquire a kerberos token. And, when
340          * exporting an AFS cell, be able to /write/ to this cell.
341          */
342
343         DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
344
345         pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT)); 
346         switch( pam_error ) {
347                 case PAM_CRED_UNAVAIL:
348                         DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
349                         break;
350                 case PAM_CRED_EXPIRED:
351                         DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
352                         break;
353                 case PAM_USER_UNKNOWN:
354                         DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
355                         break;
356                 case PAM_CRED_ERR:
357                         DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
358                         break;
359                 case PAM_SUCCESS:
360                         DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
361                         break;
362                 default:
363                         DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
364                         break;
365         }
366
367         return pam_to_nt_status(pam_error);
368 }
369
370 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
371 {
372         struct smb_pam_user_info *info;
373         struct pam_conv *pamconv;
374         pam_handle_t *pamh;
375         NTSTATUS nt_status;
376
377         info = talloc(ctx, struct smb_pam_user_info);
378         if (info == NULL) {
379                 return NT_STATUS_NO_MEMORY;
380         }
381
382         info->account_name = user_info->mapped.account_name;
383         info->plaintext_password = user_info->password.plaintext;
384
385         pamconv = talloc(ctx, struct pam_conv);
386         if (pamconv == NULL) {
387                 return NT_STATUS_NO_MEMORY;
388         }
389
390         pamconv->conv = smb_pam_conv;
391         pamconv->appdata_ptr = (void *)info;
392
393         /* TODO:
394          * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME
395          * if true set up a crack name routine.
396          */
397
398         nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host, pamconv);
399         if (!NT_STATUS_IS_OK(nt_status)) {
400                 smb_pam_end(pamh);
401                 return nt_status;
402         }
403
404         nt_status = smb_pam_auth(pamh, user_info->mapped.account_name);
405         if (!NT_STATUS_IS_OK(nt_status)) {
406                 smb_pam_end(pamh);
407                 return nt_status;
408         }
409
410         if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
411
412                 nt_status = smb_pam_account(pamh, user_info->mapped.account_name);
413                 if (!NT_STATUS_IS_OK(nt_status)) {
414                         smb_pam_end(pamh);
415                         return nt_status;
416                 }
417
418                 nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name);
419                 if (!NT_STATUS_IS_OK(nt_status)) {
420                         smb_pam_end(pamh);
421                         return nt_status;
422                 }
423         }
424
425         smb_pam_end(pamh);
426         return NT_STATUS_OK;    
427 }
428
429 #else
430
431 static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, char *username, struct passwd **pws)
432 {
433         struct passwd *ret;
434         struct passwd *from;
435
436         *pws = NULL;
437
438         ret = talloc(ctx, struct passwd);
439         NT_STATUS_HAVE_NO_MEMORY(ret);
440
441         from = getpwnam(username);
442         if (!from) {
443                 return NT_STATUS_NO_SUCH_USER;
444         }
445
446         ret->pw_name = talloc_strdup(ctx, from->pw_name);
447         NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
448
449         ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
450         NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
451
452         ret->pw_uid = from->pw_uid;
453         ret->pw_gid = from->pw_gid;
454         ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
455         NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
456
457         ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
458         NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
459
460         ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
461         NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
462
463         *pws = ret;
464
465         return NT_STATUS_OK;
466 }
467
468
469 /****************************************************************************
470 core of password checking routine
471 ****************************************************************************/
472 static NTSTATUS password_check(const char *username, const char *password,
473                                         const char *crypted, const char *salt)
474 {
475         BOOL ret;
476
477 #ifdef WITH_AFS
478         if (afs_auth(username, password))
479                 return NT_STATUS_OK;
480 #endif /* WITH_AFS */
481
482 #ifdef WITH_DFS
483         if (dfs_auth(username, password))
484                 return NT_STATUS_OK;
485 #endif /* WITH_DFS */
486
487 #ifdef OSF1_ENH_SEC
488         
489         ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
490
491         if (!ret) {
492                 DEBUG(2,
493                       ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
494                 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
495         }
496         if (ret) {
497                 return NT_STATUS_OK;
498         } else {
499                 return NT_STATUS_WRONG_PASSWORD;
500         }
501         
502 #endif /* OSF1_ENH_SEC */
503         
504 #ifdef ULTRIX_AUTH
505         ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
506         if (ret) {
507                 return NT_STATUS_OK;
508         } else {
509                 return NT_STATUS_WRONG_PASSWORD;
510         }
511         
512 #endif /* ULTRIX_AUTH */
513         
514 #ifdef LINUX_BIGCRYPT
515         ret = (linux_bigcrypt(password, salt, crypted));
516         if (ret) {
517                 return NT_STATUS_OK;
518         } else {
519                 return NT_STATUS_WRONG_PASSWORD;
520         }
521 #endif /* LINUX_BIGCRYPT */
522         
523 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
524         
525         /*
526          * Some systems have bigcrypt in the C library but might not
527          * actually use it for the password hashes (HPUX 10.20) is
528          * a noteable example. So we try bigcrypt first, followed
529          * by crypt.
530          */
531
532         if (strcmp(bigcrypt(password, salt), crypted) == 0)
533                 return NT_STATUS_OK;
534         else
535                 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
536         if (ret) {
537                 return NT_STATUS_OK;
538         } else {
539                 return NT_STATUS_WRONG_PASSWORD;
540         }
541 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
542         
543 #ifdef HAVE_BIGCRYPT
544         ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
545         if (ret) {
546                 return NT_STATUS_OK;
547         } else {
548                 return NT_STATUS_WRONG_PASSWORD;
549         }
550 #endif /* HAVE_BIGCRYPT */
551         
552 #ifndef HAVE_CRYPT
553         DEBUG(1, ("Warning - no crypt available\n"));
554         return NT_STATUS_LOGON_FAILURE;
555 #else /* HAVE_CRYPT */
556         ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
557         if (ret) {
558                 return NT_STATUS_OK;
559         } else {
560                 return NT_STATUS_WRONG_PASSWORD;
561         }
562 #endif /* HAVE_CRYPT */
563 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
564 }
565
566 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
567 {
568         char *username;
569         char *password;
570         char *pwcopy;
571         char *salt;
572         char *crypted;
573         struct passwd *pws;
574         NTSTATUS nt_status;
575         int level = lp_passwordlevel();
576
577         username = talloc_strdup(ctx, user_info->mapped.account_name);
578         password = talloc_strdup(ctx, user_info->password.plaintext);
579
580         nt_status = talloc_getpwnam(ctx, username, &pws);
581         if (!NT_STATUS_IS_OK(nt_status)) {
582                 return nt_status;
583         }
584
585         crypted = pws->pw_passwd;
586         salt = pws->pw_passwd;
587
588 #ifdef HAVE_GETSPNAM
589         {
590                 struct spwd *spass;
591
592                 /* many shadow systems require you to be root to get
593                    the password, in most cases this should already be
594                    the case when this function is called, except
595                    perhaps for IPC password changing requests */
596
597                 spass = getspnam(pws->pw_name);
598                 if (spass && spass->sp_pwdp) {
599                         crypted = talloc_strdup(ctx, spass->sp_pwdp);
600                         NT_STATUS_HAVE_NO_MEMORY(crypted);
601                         salt = talloc_strdup(ctx, spass->sp_pwdp);
602                         NT_STATUS_HAVE_NO_MEMORY(salt);
603                 }
604         }
605 #elif defined(IA_UINFO)
606         {
607                 char *ia_password;
608                 /* Need to get password with SVR4.2's ia_ functions
609                    instead of get{sp,pw}ent functions. Required by
610                    UnixWare 2.x, tested on version
611                    2.1. (tangent@cyberport.com) */
612                 uinfo_t uinfo;
613                 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
614                         ia_get_logpwd(uinfo, &ia_password);
615                         crypted = talloc_strdup(ctx, ia_password);
616                         NT_STATUS_HAVE_NO_MEMORY(crypted);
617                 }
618         }
619 #endif
620
621 #ifdef HAVE_GETPRPWNAM
622         {
623                 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
624                 if (pr_pw && pr_pw->ufld.fd_encrypt) {
625                         crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
626                         NT_STATUS_HAVE_NO_MEMORY(crypted);
627                 }
628         }
629 #endif
630
631 #ifdef HAVE_GETPWANAM
632         {
633                 struct passwd_adjunct *pwret;
634                 pwret = getpwanam(s);
635                 if (pwret && pwret->pwa_passwd) {
636                         crypted = talloc_strdup(ctx, pwret->pwa_passwd);
637                         NT_STATUS_HAVE_NO_MEMORY(crypted);
638                 }
639         }
640 #endif
641
642 #ifdef OSF1_ENH_SEC
643         {
644                 struct pr_passwd *mypasswd;
645                 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
646                 mypasswd = getprpwnam(username);
647                 if (mypasswd) {
648                         username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
649                         NT_STATUS_HAVE_NO_MEMORY(username);
650                         crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
651                         NT_STATUS_HAVE_NO_MEMORY(crypted);
652                 } else {
653                         DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
654                 }
655         }
656 #endif
657
658 #ifdef ULTRIX_AUTH
659         {
660                 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
661                 if (ap) {
662                         crypted = talloc_strdup(ctx, ap->a_password);
663                         endauthent();
664                         NT_STATUS_HAVE_NO_MEMORY(crypted);
665                 }
666         }
667 #endif
668
669 #if defined(HAVE_TRUNCATED_SALT)
670         /* crypt on some platforms (HPUX in particular)
671            won't work with more than 2 salt characters. */
672         salt[2] = 0;
673 #endif
674
675         if (crypted[0] == '\0') {
676                 if (!lp_null_passwords()) {
677                         DEBUG(2, ("Disallowing %s with null password\n", username));
678                         return NT_STATUS_LOGON_FAILURE;
679                 }
680                 if (password == NULL) {
681                         DEBUG(3, ("Allowing access to %s with null password\n", username));
682                         return NT_STATUS_OK;
683                 }
684         }
685
686         /* try it as it came to us */
687         nt_status = password_check(username, password, crypted, salt);
688         if NT_STATUS_IS_OK(nt_status) {
689                 return nt_status;
690         }
691         else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
692                 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
693                 return nt_status;
694         }
695
696         if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) {
697                 return nt_status;
698         }
699
700         /* if the password was given to us with mixed case then we don't
701          * need to proceed as we know it hasn't been case modified by the
702          * client */
703         if (strhasupper(password) && strhaslower(password)) {
704                 return nt_status;
705         }
706
707         /* make a copy of it */
708         pwcopy = talloc_strdup(ctx, password);
709         if (!pwcopy)
710                 return NT_STATUS_NO_MEMORY;
711
712         /* try all lowercase if it's currently all uppercase */
713         if (strhasupper(pwcopy)) {
714                 strlower(pwcopy);
715                 nt_status = password_check(username, pwcopy, crypted, salt);
716                 if NT_STATUS_IS_OK(nt_status) {
717                         return nt_status;
718                 }
719         }
720
721         /* give up? */
722         if (level < 1) {
723                 return NT_STATUS_WRONG_PASSWORD;
724         }
725
726         /* last chance - all combinations of up to level chars upper! */
727         strlower(pwcopy);
728
729 #if 0
730         if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
731                 return nt_status;
732         }
733 #endif   
734         return NT_STATUS_WRONG_PASSWORD;
735 }
736
737 #endif
738
739 /** Check a plaintext username/password
740  *
741  **/
742
743 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
744                                         TALLOC_CTX *mem_ctx,
745                                         const struct auth_usersupplied_info *user_info,
746                                         struct  auth_serversupplied_info **server_info)
747 {
748         TALLOC_CTX *check_ctx;
749         NTSTATUS nt_status;
750
751         if (! user_info->mapped.account_name || ! *user_info->mapped.account_name) {
752                 /* 'not for me' */
753                 return NT_STATUS_NOT_IMPLEMENTED;
754         }
755
756         if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
757                 return NT_STATUS_INVALID_PARAMETER;
758         }
759
760         check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
761         if (check_ctx == NULL) {
762                 return NT_STATUS_NO_MEMORY;
763         }
764
765         nt_status = check_unix_password(check_ctx, user_info);
766         if ( ! NT_STATUS_IS_OK(nt_status)) {
767                 talloc_free(check_ctx);
768                 return nt_status;
769         }
770
771         nt_status = authunix_make_server_info(mem_ctx, user_info, server_info);
772         if ( ! NT_STATUS_IS_OK(nt_status)) {
773                 talloc_free(check_ctx);
774                 return nt_status;
775         }
776
777         talloc_free(check_ctx);
778         return NT_STATUS_OK;
779 }
780
781 static const struct auth_operations unix_ops = {
782         .name           = "unix",
783         .get_challenge  = auth_get_challenge_not_implemented,
784         .check_password = authunix_check_password
785 };
786
787 NTSTATUS auth_unix_init(void)
788 {
789         NTSTATUS ret;
790
791         ret = auth_register(&unix_ops);
792         if (!NT_STATUS_IS_OK(ret)) {
793                 DEBUG(0,("Failed to register unix auth backend!\n"));
794                 return ret;
795         }
796
797         return ret;
798 }