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