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