s4-auth Rename auth -> auth4 to avoid conflict with s3 auth
[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 *pwcopy;
611         char *salt;
612         char *crypted;
613         struct passwd *pws;
614         NTSTATUS nt_status;
615         int level = lpcfg_passwordlevel(lp_ctx);
616
617         *ret_passwd = NULL;
618
619         username = talloc_strdup(ctx, user_info->mapped.account_name);
620         password = talloc_strdup(ctx, user_info->password.plaintext);
621
622         nt_status = talloc_getpwnam(ctx, username, &pws);
623         if (!NT_STATUS_IS_OK(nt_status)) {
624                 return nt_status;
625         }
626
627         crypted = pws->pw_passwd;
628         salt = pws->pw_passwd;
629
630 #ifdef HAVE_GETSPNAM
631         {
632                 struct spwd *spass;
633
634                 /* many shadow systems require you to be root to get
635                    the password, in most cases this should already be
636                    the case when this function is called, except
637                    perhaps for IPC password changing requests */
638
639                 spass = getspnam(pws->pw_name);
640                 if (spass && spass->sp_pwdp) {
641                         crypted = talloc_strdup(ctx, spass->sp_pwdp);
642                         NT_STATUS_HAVE_NO_MEMORY(crypted);
643                         salt = talloc_strdup(ctx, spass->sp_pwdp);
644                         NT_STATUS_HAVE_NO_MEMORY(salt);
645                 }
646         }
647 #elif defined(IA_UINFO)
648         {
649                 char *ia_password;
650                 /* Need to get password with SVR4.2's ia_ functions
651                    instead of get{sp,pw}ent functions. Required by
652                    UnixWare 2.x, tested on version
653                    2.1. (tangent@cyberport.com) */
654                 uinfo_t uinfo;
655                 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
656                         ia_get_logpwd(uinfo, &ia_password);
657                         crypted = talloc_strdup(ctx, ia_password);
658                         NT_STATUS_HAVE_NO_MEMORY(crypted);
659                 }
660         }
661 #endif
662
663 #ifdef HAVE_GETPRPWNAM
664         {
665                 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
666                 if (pr_pw && pr_pw->ufld.fd_encrypt) {
667                         crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
668                         NT_STATUS_HAVE_NO_MEMORY(crypted);
669                 }
670         }
671 #endif
672
673 #ifdef HAVE_GETPWANAM
674         {
675                 struct passwd_adjunct *pwret;
676                 pwret = getpwanam(s);
677                 if (pwret && pwret->pwa_passwd) {
678                         crypted = talloc_strdup(ctx, pwret->pwa_passwd);
679                         NT_STATUS_HAVE_NO_MEMORY(crypted);
680                 }
681         }
682 #endif
683
684 #ifdef OSF1_ENH_SEC
685         {
686                 struct pr_passwd *mypasswd;
687                 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
688                 mypasswd = getprpwnam(username);
689                 if (mypasswd) {
690                         username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
691                         NT_STATUS_HAVE_NO_MEMORY(username);
692                         crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
693                         NT_STATUS_HAVE_NO_MEMORY(crypted);
694                 } else {
695                         DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
696                 }
697         }
698 #endif
699
700 #ifdef ULTRIX_AUTH
701         {
702                 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
703                 if (ap) {
704                         crypted = talloc_strdup(ctx, ap->a_password);
705                         endauthent();
706                         NT_STATUS_HAVE_NO_MEMORY(crypted);
707                 }
708         }
709 #endif
710
711 #if defined(HAVE_TRUNCATED_SALT)
712         /* crypt on some platforms (HPUX in particular)
713            won't work with more than 2 salt characters. */
714         salt[2] = 0;
715 #endif
716
717         if (crypted[0] == '\0') {
718                 if (!lpcfg_null_passwords(lp_ctx)) {
719                         DEBUG(2, ("Disallowing %s with null password\n", username));
720                         return NT_STATUS_LOGON_FAILURE;
721                 }
722                 if (password == NULL) {
723                         DEBUG(3, ("Allowing access to %s with null password\n", username));
724                         *ret_passwd = pws;
725                         return NT_STATUS_OK;
726                 }
727         }
728
729         /* try it as it came to us */
730         nt_status = password_check(username, password, crypted, salt);
731         if (NT_STATUS_IS_OK(nt_status)) {
732                 *ret_passwd = pws;
733                 return nt_status;
734         }
735         else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
736                 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
737                 return nt_status;
738         }
739
740         /* we no longer try different case combinations here. The use
741          * of this code is now web auth, where trying different case
742          * combinations makes no sense
743          */
744
745         return NT_STATUS_WRONG_PASSWORD;
746 }
747
748 #endif
749
750 /** Check a plaintext username/password
751  *
752  **/
753
754 static NTSTATUS authunix_want_check(struct auth_method_context *ctx,
755                                     TALLOC_CTX *mem_ctx,
756                                     const struct auth_usersupplied_info *user_info)
757 {
758         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
759                 return NT_STATUS_NOT_IMPLEMENTED;
760         }
761
762         return NT_STATUS_OK;
763 }
764
765 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
766                                         TALLOC_CTX *mem_ctx,
767                                         const struct auth_usersupplied_info *user_info,
768                                         struct auth_user_info_dc **user_info_dc)
769 {
770         TALLOC_CTX *check_ctx;
771         NTSTATUS nt_status;
772         struct passwd *pwd;
773
774         if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
775                 return NT_STATUS_INVALID_PARAMETER;
776         }
777
778         check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
779         if (check_ctx == NULL) {
780                 return NT_STATUS_NO_MEMORY;
781         }
782
783         nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd);
784         if (!NT_STATUS_IS_OK(nt_status)) {
785                 talloc_free(check_ctx);
786                 return nt_status;
787         }
788
789         nt_status = authunix_make_user_info_dc(mem_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx),
790                                               user_info, pwd, user_info_dc);
791         if (!NT_STATUS_IS_OK(nt_status)) {
792                 talloc_free(check_ctx);
793                 return nt_status;
794         }
795
796         talloc_free(check_ctx);
797         return NT_STATUS_OK;
798 }
799
800 static const struct auth_operations unix_ops = {
801         .name           = "unix",
802         .get_challenge  = auth_get_challenge_not_implemented,
803         .want_check     = authunix_want_check,
804         .check_password = authunix_check_password
805 };
806
807 _PUBLIC_ NTSTATUS auth4_unix_init(void)
808 {
809         NTSTATUS ret;
810
811         ret = auth_register(&unix_ops);
812         if (!NT_STATUS_IS_OK(ret)) {
813                 DEBUG(0,("Failed to register unix auth backend!\n"));
814                 return ret;
815         }
816
817         return ret;
818 }