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