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