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