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