5fb8b4f5dde61b42069312d4d7d2bfc97d0878aa
[garming/samba-autobuild/.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(TALLOC_CTX *);
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 valid 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 valid 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 valid 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         
546         
547 #ifdef HAVE_BIGCRYPT
548         ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
549         if (ret) {
550                 return NT_STATUS_OK;
551         } else {
552                 return NT_STATUS_WRONG_PASSWORD;
553         }
554 #endif /* HAVE_BIGCRYPT */
555         
556 #ifndef HAVE_CRYPT
557         DEBUG(1, ("Warning - no crypt available\n"));
558         return NT_STATUS_LOGON_FAILURE;
559 #else /* HAVE_CRYPT */
560         ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
561         if (ret) {
562                 return NT_STATUS_OK;
563         } else {
564                 return NT_STATUS_WRONG_PASSWORD;
565         }
566 #endif /* HAVE_CRYPT */
567 }
568
569 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx,
570                                     const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd)
571 {
572         char *username;
573         char *password;
574         char *salt;
575         char *crypted;
576         struct passwd *pws;
577         NTSTATUS nt_status;
578
579         *ret_passwd = NULL;
580
581         username = talloc_strdup(ctx, user_info->mapped.account_name);
582         password = talloc_strdup(ctx, user_info->password.plaintext);
583
584         nt_status = talloc_getpwnam(ctx, username, &pws);
585         if (!NT_STATUS_IS_OK(nt_status)) {
586                 return nt_status;
587         }
588
589         crypted = pws->pw_passwd;
590         salt = pws->pw_passwd;
591
592 #ifdef HAVE_GETSPNAM
593         {
594                 struct spwd *spass;
595
596                 /* many shadow systems require you to be root to get
597                    the password, in most cases this should already be
598                    the case when this function is called, except
599                    perhaps for IPC password changing requests */
600
601                 spass = getspnam(pws->pw_name);
602                 if (spass && spass->sp_pwdp) {
603                         crypted = talloc_strdup(ctx, spass->sp_pwdp);
604                         NT_STATUS_HAVE_NO_MEMORY(crypted);
605                         salt = talloc_strdup(ctx, spass->sp_pwdp);
606                         NT_STATUS_HAVE_NO_MEMORY(salt);
607                 }
608         }
609 #elif defined(IA_UINFO)
610         {
611                 char *ia_password;
612                 /* Need to get password with SVR4.2's ia_ functions
613                    instead of get{sp,pw}ent functions. Required by
614                    UnixWare 2.x, tested on version
615                    2.1. (tangent@cyberport.com) */
616                 uinfo_t uinfo;
617                 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
618                         ia_get_logpwd(uinfo, &ia_password);
619                         crypted = talloc_strdup(ctx, ia_password);
620                         NT_STATUS_HAVE_NO_MEMORY(crypted);
621                 }
622         }
623 #endif
624
625
626 #ifdef HAVE_GETPWANAM
627         {
628                 struct passwd_adjunct *pwret;
629                 pwret = getpwanam(s);
630                 if (pwret && pwret->pwa_passwd) {
631                         crypted = talloc_strdup(ctx, pwret->pwa_passwd);
632                         NT_STATUS_HAVE_NO_MEMORY(crypted);
633                 }
634         }
635 #endif
636
637 #ifdef OSF1_ENH_SEC
638         {
639                 struct pr_passwd *mypasswd;
640                 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
641                 mypasswd = getprpwnam(username);
642                 if (mypasswd) {
643                         username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
644                         NT_STATUS_HAVE_NO_MEMORY(username);
645                         crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
646                         NT_STATUS_HAVE_NO_MEMORY(crypted);
647                 } else {
648                         DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
649                 }
650         }
651 #endif
652
653 #ifdef ULTRIX_AUTH
654         {
655                 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
656                 if (ap) {
657                         crypted = talloc_strdup(ctx, ap->a_password);
658                         endauthent();
659                         NT_STATUS_HAVE_NO_MEMORY(crypted);
660                 }
661         }
662 #endif
663
664
665         if (crypted[0] == '\0') {
666                 if (!lpcfg_null_passwords(lp_ctx)) {
667                         DEBUG(2, ("Disallowing %s with null password\n", username));
668                         return NT_STATUS_LOGON_FAILURE;
669                 }
670                 if (password == NULL) {
671                         DEBUG(3, ("Allowing access to %s with null password\n", username));
672                         *ret_passwd = pws;
673                         return NT_STATUS_OK;
674                 }
675         }
676
677         /* try it as it came to us */
678         nt_status = password_check(username, password, crypted, salt);
679         if (NT_STATUS_IS_OK(nt_status)) {
680                 *ret_passwd = pws;
681                 return nt_status;
682         }
683         else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
684                 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
685                 return nt_status;
686         }
687
688         /* we no longer try different case combinations here. The use
689          * of this code is now web auth, where trying different case
690          * combinations makes no sense
691          */
692
693         return NT_STATUS_WRONG_PASSWORD;
694 }
695
696 #endif
697
698 /** Check a plaintext username/password
699  *
700  **/
701
702 static NTSTATUS authunix_want_check(struct auth_method_context *ctx,
703                                     TALLOC_CTX *mem_ctx,
704                                     const struct auth_usersupplied_info *user_info)
705 {
706         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
707                 return NT_STATUS_NOT_IMPLEMENTED;
708         }
709
710         return NT_STATUS_OK;
711 }
712
713 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
714                                         TALLOC_CTX *mem_ctx,
715                                         const struct auth_usersupplied_info *user_info,
716                                         struct auth_user_info_dc **user_info_dc)
717 {
718         TALLOC_CTX *check_ctx;
719         NTSTATUS nt_status;
720         struct passwd *pwd;
721
722         if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
723                 return NT_STATUS_INVALID_PARAMETER;
724         }
725
726         check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
727         if (check_ctx == NULL) {
728                 return NT_STATUS_NO_MEMORY;
729         }
730
731         nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd);
732         if (!NT_STATUS_IS_OK(nt_status)) {
733                 talloc_free(check_ctx);
734                 return nt_status;
735         }
736
737         nt_status = authunix_make_user_info_dc(mem_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx),
738                                               user_info, pwd, user_info_dc);
739         if (!NT_STATUS_IS_OK(nt_status)) {
740                 talloc_free(check_ctx);
741                 return nt_status;
742         }
743
744         talloc_free(check_ctx);
745         return NT_STATUS_OK;
746 }
747
748 static const struct auth_operations unix_ops = {
749         .name           = "unix",
750         .want_check     = authunix_want_check,
751         .check_password = authunix_check_password
752 };
753
754 _PUBLIC_ NTSTATUS auth4_unix_init(TALLOC_CTX *ctx)
755 {
756         NTSTATUS ret;
757
758         ret = auth_register(&unix_ops);
759         if (!NT_STATUS_IS_OK(ret)) {
760                 DEBUG(0,("Failed to register unix auth backend!\n"));
761                 return ret;
762         }
763
764         return ret;
765 }