s4:auth/ntlm/auth_unix.c - remove unused variables
[mdw/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 #ifdef WITH_AFS
517         if (afs_auth(username, password))
518                 return NT_STATUS_OK;
519 #endif /* WITH_AFS */
520
521 #ifdef WITH_DFS
522         if (dfs_auth(username, password))
523                 return NT_STATUS_OK;
524 #endif /* WITH_DFS */
525
526 #ifdef OSF1_ENH_SEC
527         
528         ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
529
530         if (!ret) {
531                 DEBUG(2,
532                       ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
533                 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
534         }
535         if (ret) {
536                 return NT_STATUS_OK;
537         } else {
538                 return NT_STATUS_WRONG_PASSWORD;
539         }
540         
541 #endif /* OSF1_ENH_SEC */
542         
543 #ifdef ULTRIX_AUTH
544         ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
545         if (ret) {
546                 return NT_STATUS_OK;
547         } else {
548                 return NT_STATUS_WRONG_PASSWORD;
549         }
550         
551 #endif /* ULTRIX_AUTH */
552         
553 #ifdef LINUX_BIGCRYPT
554         ret = (linux_bigcrypt(password, salt, crypted));
555         if (ret) {
556                 return NT_STATUS_OK;
557         } else {
558                 return NT_STATUS_WRONG_PASSWORD;
559         }
560 #endif /* LINUX_BIGCRYPT */
561         
562 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
563         
564         /*
565          * Some systems have bigcrypt in the C library but might not
566          * actually use it for the password hashes (HPUX 10.20) is
567          * a noteable example. So we try bigcrypt first, followed
568          * by crypt.
569          */
570
571         if (strcmp(bigcrypt(password, salt), crypted) == 0)
572                 return NT_STATUS_OK;
573         else
574                 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
575         if (ret) {
576                 return NT_STATUS_OK;
577         } else {
578                 return NT_STATUS_WRONG_PASSWORD;
579         }
580 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
581         
582 #ifdef HAVE_BIGCRYPT
583         ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
584         if (ret) {
585                 return NT_STATUS_OK;
586         } else {
587                 return NT_STATUS_WRONG_PASSWORD;
588         }
589 #endif /* HAVE_BIGCRYPT */
590         
591 #ifndef HAVE_CRYPT
592         DEBUG(1, ("Warning - no crypt available\n"));
593         return NT_STATUS_LOGON_FAILURE;
594 #else /* HAVE_CRYPT */
595         ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
596         if (ret) {
597                 return NT_STATUS_OK;
598         } else {
599                 return NT_STATUS_WRONG_PASSWORD;
600         }
601 #endif /* HAVE_CRYPT */
602 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
603 }
604
605 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx,
606                                     const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd)
607 {
608         char *username;
609         char *password;
610         char *salt;
611         char *crypted;
612         struct passwd *pws;
613         NTSTATUS nt_status;
614
615         *ret_passwd = NULL;
616
617         username = talloc_strdup(ctx, user_info->mapped.account_name);
618         password = talloc_strdup(ctx, user_info->password.plaintext);
619
620         nt_status = talloc_getpwnam(ctx, username, &pws);
621         if (!NT_STATUS_IS_OK(nt_status)) {
622                 return nt_status;
623         }
624
625         crypted = pws->pw_passwd;
626         salt = pws->pw_passwd;
627
628 #ifdef HAVE_GETSPNAM
629         {
630                 struct spwd *spass;
631
632                 /* many shadow systems require you to be root to get
633                    the password, in most cases this should already be
634                    the case when this function is called, except
635                    perhaps for IPC password changing requests */
636
637                 spass = getspnam(pws->pw_name);
638                 if (spass && spass->sp_pwdp) {
639                         crypted = talloc_strdup(ctx, spass->sp_pwdp);
640                         NT_STATUS_HAVE_NO_MEMORY(crypted);
641                         salt = talloc_strdup(ctx, spass->sp_pwdp);
642                         NT_STATUS_HAVE_NO_MEMORY(salt);
643                 }
644         }
645 #elif defined(IA_UINFO)
646         {
647                 char *ia_password;
648                 /* Need to get password with SVR4.2's ia_ functions
649                    instead of get{sp,pw}ent functions. Required by
650                    UnixWare 2.x, tested on version
651                    2.1. (tangent@cyberport.com) */
652                 uinfo_t uinfo;
653                 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
654                         ia_get_logpwd(uinfo, &ia_password);
655                         crypted = talloc_strdup(ctx, ia_password);
656                         NT_STATUS_HAVE_NO_MEMORY(crypted);
657                 }
658         }
659 #endif
660
661 #ifdef HAVE_GETPRPWNAM
662         {
663                 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
664                 if (pr_pw && pr_pw->ufld.fd_encrypt) {
665                         crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
666                         NT_STATUS_HAVE_NO_MEMORY(crypted);
667                 }
668         }
669 #endif
670
671 #ifdef HAVE_GETPWANAM
672         {
673                 struct passwd_adjunct *pwret;
674                 pwret = getpwanam(s);
675                 if (pwret && pwret->pwa_passwd) {
676                         crypted = talloc_strdup(ctx, pwret->pwa_passwd);
677                         NT_STATUS_HAVE_NO_MEMORY(crypted);
678                 }
679         }
680 #endif
681
682 #ifdef OSF1_ENH_SEC
683         {
684                 struct pr_passwd *mypasswd;
685                 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
686                 mypasswd = getprpwnam(username);
687                 if (mypasswd) {
688                         username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
689                         NT_STATUS_HAVE_NO_MEMORY(username);
690                         crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
691                         NT_STATUS_HAVE_NO_MEMORY(crypted);
692                 } else {
693                         DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
694                 }
695         }
696 #endif
697
698 #ifdef ULTRIX_AUTH
699         {
700                 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
701                 if (ap) {
702                         crypted = talloc_strdup(ctx, ap->a_password);
703                         endauthent();
704                         NT_STATUS_HAVE_NO_MEMORY(crypted);
705                 }
706         }
707 #endif
708
709 #if defined(HAVE_TRUNCATED_SALT)
710         /* crypt on some platforms (HPUX in particular)
711            won't work with more than 2 salt characters. */
712         salt[2] = 0;
713 #endif
714
715         if (crypted[0] == '\0') {
716                 if (!lpcfg_null_passwords(lp_ctx)) {
717                         DEBUG(2, ("Disallowing %s with null password\n", username));
718                         return NT_STATUS_LOGON_FAILURE;
719                 }
720                 if (password == NULL) {
721                         DEBUG(3, ("Allowing access to %s with null password\n", username));
722                         *ret_passwd = pws;
723                         return NT_STATUS_OK;
724                 }
725         }
726
727         /* try it as it came to us */
728         nt_status = password_check(username, password, crypted, salt);
729         if (NT_STATUS_IS_OK(nt_status)) {
730                 *ret_passwd = pws;
731                 return nt_status;
732         }
733         else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
734                 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
735                 return nt_status;
736         }
737
738         /* we no longer try different case combinations here. The use
739          * of this code is now web auth, where trying different case
740          * combinations makes no sense
741          */
742
743         return NT_STATUS_WRONG_PASSWORD;
744 }
745
746 #endif
747
748 /** Check a plaintext username/password
749  *
750  **/
751
752 static NTSTATUS authunix_want_check(struct auth_method_context *ctx,
753                                     TALLOC_CTX *mem_ctx,
754                                     const struct auth_usersupplied_info *user_info)
755 {
756         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
757                 return NT_STATUS_NOT_IMPLEMENTED;
758         }
759
760         return NT_STATUS_OK;
761 }
762
763 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
764                                         TALLOC_CTX *mem_ctx,
765                                         const struct auth_usersupplied_info *user_info,
766                                         struct auth_user_info_dc **user_info_dc)
767 {
768         TALLOC_CTX *check_ctx;
769         NTSTATUS nt_status;
770         struct passwd *pwd;
771
772         if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
773                 return NT_STATUS_INVALID_PARAMETER;
774         }
775
776         check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
777         if (check_ctx == NULL) {
778                 return NT_STATUS_NO_MEMORY;
779         }
780
781         nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd);
782         if (!NT_STATUS_IS_OK(nt_status)) {
783                 talloc_free(check_ctx);
784                 return nt_status;
785         }
786
787         nt_status = authunix_make_user_info_dc(mem_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx),
788                                               user_info, pwd, user_info_dc);
789         if (!NT_STATUS_IS_OK(nt_status)) {
790                 talloc_free(check_ctx);
791                 return nt_status;
792         }
793
794         talloc_free(check_ctx);
795         return NT_STATUS_OK;
796 }
797
798 static const struct auth_operations unix_ops = {
799         .name           = "unix",
800         .get_challenge  = auth_get_challenge_not_implemented,
801         .want_check     = authunix_want_check,
802         .check_password = authunix_check_password
803 };
804
805 _PUBLIC_ NTSTATUS auth4_unix_init(void)
806 {
807         NTSTATUS ret;
808
809         ret = auth_register(&unix_ops);
810         if (!NT_STATUS_IS_OK(ret)) {
811                 DEBUG(0,("Failed to register unix auth backend!\n"));
812                 return ret;
813         }
814
815         return ret;
816 }