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