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