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