r8251: fixed a couple of valgrind errors in the unix auth code. Simo, can you
[kai/samba.git] / source4 / auth / auth_unix.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Password and authentication handling
4    Copyright (C) Andrew Bartlett                2001
5    Copyright (C) Jeremy Allison                 2001
6    Copyright (C) Simo Sorce                     2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 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->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         NTSTATUS nt_status;
170         int pam_error;
171
172         if (account_name == NULL || remote_host == NULL) {
173                 return NT_STATUS_INVALID_PARAMETER;
174         }
175
176         DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name));
177
178         pam_error = pam_start("samba", account_name, pconv, pamh);
179         if (pam_error != PAM_SUCCESS) {
180                 /* no vaild pamh here, can we reliably call pam_strerror ? */
181                 DEBUG(4,("smb_pam_start: pam_start failed!\n"));
182                 return NT_STATUS_UNSUCCESSFUL;
183         }
184
185 #ifdef PAM_RHOST
186         DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host));
187         pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host);
188         if (pam_error != PAM_SUCCESS) {
189                 DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n",
190                          pam_strerror(*pamh, pam_error)));
191                 nt_status = pam_to_nt_status(pam_error);
192
193                 pam_error = pam_end(*pamh, 0);
194                 if (pam_error != PAM_SUCCESS) {
195                         /* no vaild pamh here, can we reliably call pam_strerror ? */
196                         DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
197                                  pam_error));
198                         return pam_to_nt_status(pam_error);
199                 }
200                 return nt_status;
201         }
202 #endif
203 #ifdef PAM_TTY
204         DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
205         pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
206         if (pam_error != PAM_SUCCESS) {
207                 DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
208                          pam_strerror(*pamh, pam_error)));
209                 nt_status = pam_to_nt_status(pam_error);
210
211                 pam_error = pam_end(*pamh, 0);
212                 if (pam_error != PAM_SUCCESS) {
213                         /* no vaild pamh here, can we reliably call pam_strerror ? */
214                         DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
215                                  pam_error));
216                         return pam_to_nt_status(pam_error);
217                 }
218                 return nt_status;
219         }
220 #endif
221         DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name));
222
223         return NT_STATUS_OK;
224 }
225
226 static NTSTATUS smb_pam_end(pam_handle_t *pamh)
227 {
228         int pam_error;
229
230         if (pamh != NULL) {
231                 pam_error = pam_end(pamh, 0);
232                 if (pam_error != PAM_SUCCESS) {
233                         /* no vaild pamh here, can we reliably call pam_strerror ? */
234                         DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
235                                  pam_error));
236                         return pam_to_nt_status(pam_error);
237                 }
238                 return NT_STATUS_OK;
239         }
240
241         DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n"));
242         return NT_STATUS_UNSUCCESSFUL;
243 }
244
245 /*
246  * PAM Authentication Handler
247  */
248 static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user)
249 {
250         int pam_error;
251
252         /*
253          * To enable debugging set in /etc/pam.d/samba:
254          *      auth required /lib/security/pam_pwdb.so nullok shadow audit
255          */
256         
257         DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
258
259         pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
260         switch( pam_error ){
261                 case PAM_AUTH_ERR:
262                         DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
263                         break;
264                 case PAM_CRED_INSUFFICIENT:
265                         DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
266                         break;
267                 case PAM_AUTHINFO_UNAVAIL:
268                         DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
269                         break;
270                 case PAM_USER_UNKNOWN:
271                         DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
272                         break;
273                 case PAM_MAXTRIES:
274                         DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
275                         break;
276                 case PAM_ABORT:
277                         DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
278                         break;
279                 case PAM_SUCCESS:
280                         DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
281                         break;
282                 default:
283                         DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
284                         break;
285         }
286
287         return pam_to_nt_status(pam_error);
288 }
289
290 /* 
291  * PAM Account Handler
292  */
293 static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
294 {
295         int pam_error;
296
297         DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
298
299         pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
300         switch( pam_error ) {
301                 case PAM_AUTHTOK_EXPIRED:
302                         DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
303                         break;
304                 case PAM_ACCT_EXPIRED:
305                         DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
306                         break;
307                 case PAM_AUTH_ERR:
308                         DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
309                         break;
310                 case PAM_PERM_DENIED:
311                         DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
312                         break;
313                 case PAM_USER_UNKNOWN:
314                         DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
315                         break;
316                 case PAM_SUCCESS:
317                         DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
318                         break;
319                 default:
320                         DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
321                         break;
322         }
323
324         return pam_to_nt_status(pam_error);
325 }
326
327 /*
328  * PAM Credential Setting
329  */
330
331 static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
332 {
333         int pam_error;
334
335         /*
336          * This will allow samba to aquire a kerberos token. And, when
337          * exporting an AFS cell, be able to /write/ to this cell.
338          */
339
340         DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
341
342         pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT)); 
343         switch( pam_error ) {
344                 case PAM_CRED_UNAVAIL:
345                         DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
346                         break;
347                 case PAM_CRED_EXPIRED:
348                         DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
349                         break;
350                 case PAM_USER_UNKNOWN:
351                         DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
352                         break;
353                 case PAM_CRED_ERR:
354                         DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
355                         break;
356                 case PAM_SUCCESS:
357                         DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
358                         break;
359                 default:
360                         DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
361                         break;
362         }
363
364         return pam_to_nt_status(pam_error);
365 }
366
367 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
368 {
369         struct smb_pam_user_info *info;
370         struct pam_conv *pamconv;
371         pam_handle_t *pamh;
372         NTSTATUS nt_status;
373
374         info = talloc(ctx, struct smb_pam_user_info);
375         if (info == NULL) {
376                 return NT_STATUS_NO_MEMORY;
377         }
378
379         info->account_name = user_info->account_name;
380         info->plaintext_password = (char *)(user_info->plaintext_password.data);
381
382         pamconv = talloc(ctx, struct pam_conv);
383         if (pamconv == NULL) {
384                 return NT_STATUS_NO_MEMORY;
385         }
386
387         pamconv->conv = smb_pam_conv;
388         pamconv->appdata_ptr = (void *)info;
389
390         /* TODO:
391          * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME
392          * if true set up a crack name routine.
393          */
394
395         nt_status = smb_pam_start(&pamh, user_info->account_name, user_info->remote_host, pamconv);
396         if (!NT_STATUS_IS_OK(nt_status)) {
397                 smb_pam_end(pamh);
398                 return nt_status;
399         }
400
401         nt_status = smb_pam_auth(pamh, user_info->account_name);
402         if (!NT_STATUS_IS_OK(nt_status)) {
403                 smb_pam_end(pamh);
404                 return nt_status;
405         }
406
407         if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
408
409                 nt_status = smb_pam_account(pamh, user_info->account_name);
410                 if (!NT_STATUS_IS_OK(nt_status)) {
411                         smb_pam_end(pamh);
412                         return nt_status;
413                 }
414
415                 nt_status = smb_pam_setcred(pamh, user_info->account_name);
416                 if (!NT_STATUS_IS_OK(nt_status)) {
417                         smb_pam_end(pamh);
418                         return nt_status;
419                 }
420         }
421
422         smb_pam_end(pamh);
423         return NT_STATUS_OK;    
424 }
425
426 #else
427
428 static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, char *username, struct passwd **pws)
429 {
430         struct passwd *ret;
431         struct passwd *from;
432
433         *pws = NULL;
434
435         ret = talloc(ctx, struct passwd);
436         NT_STATUS_HAVE_NO_MEMORY(ret);
437
438         from = getpwnam(username);
439         if (!from) {
440                 return NT_STATUS_NO_SUCH_USER;
441         }
442
443         ret->pw_name = talloc_strdup(ctx, from->pw_name);
444         NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
445
446         ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
447         NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
448
449         ret->pw_uid = from->pw_uid;
450         ret->pw_gid = from->pw_gid;
451         ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
452         NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
453
454         ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
455         NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
456
457         ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
458         NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
459
460         *pws = ret;
461
462         return NT_STATUS_OK;
463 }
464
465
466 /****************************************************************************
467 core of password checking routine
468 ****************************************************************************/
469 static NTSTATUS password_check(const char *username, const char *password,
470                                         const char *crypted, const char *salt)
471 {
472         BOOL ret;
473
474 #ifdef WITH_AFS
475         if (afs_auth(username, password))
476                 return NT_STATUS_OK;
477 #endif /* WITH_AFS */
478
479 #ifdef WITH_DFS
480         if (dfs_auth(username, password))
481                 return NT_STATUS_OK;
482 #endif /* WITH_DFS */
483
484 #ifdef OSF1_ENH_SEC
485         
486         ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
487
488         if (!ret) {
489                 DEBUG(2,
490                       ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
491                 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
492         }
493         if (ret) {
494                 return NT_STATUS_OK;
495         } else {
496                 return NT_STATUS_WRONG_PASSWORD;
497         }
498         
499 #endif /* OSF1_ENH_SEC */
500         
501 #ifdef ULTRIX_AUTH
502         ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
503         if (ret) {
504                 return NT_STATUS_OK;
505         } else {
506                 return NT_STATUS_WRONG_PASSWORD;
507         }
508         
509 #endif /* ULTRIX_AUTH */
510         
511 #ifdef LINUX_BIGCRYPT
512         ret = (linux_bigcrypt(password, salt, crypted));
513         if (ret) {
514                 return NT_STATUS_OK;
515         } else {
516                 return NT_STATUS_WRONG_PASSWORD;
517         }
518 #endif /* LINUX_BIGCRYPT */
519         
520 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
521         
522         /*
523          * Some systems have bigcrypt in the C library but might not
524          * actually use it for the password hashes (HPUX 10.20) is
525          * a noteable example. So we try bigcrypt first, followed
526          * by crypt.
527          */
528
529         if (strcmp(bigcrypt(password, salt), crypted) == 0)
530                 return NT_STATUS_OK;
531         else
532                 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
533         if (ret) {
534                 return NT_STATUS_OK;
535         } else {
536                 return NT_STATUS_WRONG_PASSWORD;
537         }
538 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
539         
540 #ifdef HAVE_BIGCRYPT
541         ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
542         if (ret) {
543                 return NT_STATUS_OK;
544         } else {
545                 return NT_STATUS_WRONG_PASSWORD;
546         }
547 #endif /* HAVE_BIGCRYPT */
548         
549 #ifndef HAVE_CRYPT
550         DEBUG(1, ("Warning - no crypt available\n"));
551         return NT_STATUS_LOGON_FAILURE;
552 #else /* HAVE_CRYPT */
553         ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
554         if (ret) {
555                 return NT_STATUS_OK;
556         } else {
557                 return NT_STATUS_WRONG_PASSWORD;
558         }
559 #endif /* HAVE_CRYPT */
560 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
561 }
562
563 /**
564  Does a string have any lowercase chars in it?
565 **/
566 static BOOL strhaslower(const char *s)
567 {
568         while (*s) {
569                 if (islower(*s)) return True;
570                 s++;
571         }
572         return False;
573 }
574
575 /**
576  Does a string have any uppercase chars in it?
577 **/
578 static BOOL strhasupper(const char *s)
579 {
580         while (*s) {
581                 if (isupper(*s)) return True;
582                 s++;
583         }
584         return False;
585 }
586
587 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
588 {
589         char *username;
590         char *password;
591         char *pwcopy;
592         char *salt;
593         char *crypted;
594         struct passwd *pws;
595         NTSTATUS nt_status;
596         int level = lp_passwordlevel();
597
598         username = talloc_strdup(ctx, user_info->account_name);
599         password = talloc_strdup(ctx, user_info->plaintext_password.data);
600
601         nt_status = talloc_getpwnam(ctx, username, &pws);
602         if (!NT_STATUS_IS_OK(nt_status)) {
603                 return nt_status;
604         }
605
606         crypted = pws->pw_passwd;
607         salt = pws->pw_passwd;
608
609 #ifdef HAVE_GETSPNAM
610         {
611                 struct spwd *spass;
612
613                 /* many shadow systems require you to be root to get
614                    the password, in most cases this should already be
615                    the case when this function is called, except
616                    perhaps for IPC password changing requests */
617
618                 spass = getspnam(pws->pw_name);
619                 if (spass && spass->sp_pwdp) {
620                         crypted = talloc_strdup(ctx, spass->sp_pwdp);
621                         NT_STATUS_HAVE_NO_MEMORY(crypted);
622                         salt = talloc_strdup(ctx, spass->sp_pwdp);
623                         NT_STATUS_HAVE_NO_MEMORY(salt);
624                 }
625         }
626 #elif defined(IA_UINFO)
627         {
628                 char *ia_password;
629                 /* Need to get password with SVR4.2's ia_ functions
630                    instead of get{sp,pw}ent functions. Required by
631                    UnixWare 2.x, tested on version
632                    2.1. (tangent@cyberport.com) */
633                 uinfo_t uinfo;
634                 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
635                         ia_get_logpwd(uinfo, &ia_password);
636                         crypted = talloc_strdup(ctx, ia_password);
637                         NT_STATUS_HAVE_NO_MEMORY(crypted);
638                 }
639         }
640 #endif
641
642 #ifdef HAVE_GETPRPWNAM
643         {
644                 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
645                 if (pr_pw && pr_pw->ufld.fd_encrypt) {
646                         crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
647                         NT_STATUS_HAVE_NO_MEMORY(crypted);
648                 }
649         }
650 #endif
651
652 #ifdef HAVE_GETPWANAM
653         {
654                 struct passwd_adjunct *pwret;
655                 pwret = getpwanam(s);
656                 if (pwret && pwret->pwa_passwd) {
657                         crypted = talloc_strdup(ctx, pwret->pwa_passwd);
658                         NT_STATUS_HAVE_NO_MEMORY(crypted);
659                 }
660         }
661 #endif
662
663 #ifdef OSF1_ENH_SEC
664         {
665                 struct pr_passwd *mypasswd;
666                 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
667                 mypasswd = getprpwnam(username);
668                 if (mypasswd) {
669                         username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
670                         NT_STATUS_HAVE_NO_MEMORY(username);
671                         crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
672                         NT_STATUS_HAVE_NO_MEMORY(crypted);
673                 } else {
674                         DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
675                 }
676         }
677 #endif
678
679 #ifdef ULTRIX_AUTH
680         {
681                 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
682                 if (ap) {
683                         crypted = talloc_strdup(ctx, ap->a_password);
684                         endauthent();
685                         NT_STATUS_HAVE_NO_MEMORY(crypted);
686                 }
687         }
688 #endif
689
690 #if defined(HAVE_TRUNCATED_SALT)
691         /* crypt on some platforms (HPUX in particular)
692            won't work with more than 2 salt characters. */
693         salt[2] = 0;
694 #endif
695
696         if (crypted[0] == '\0') {
697                 if (!lp_null_passwords()) {
698                         DEBUG(2, ("Disallowing %s with null password\n", username));
699                         return NT_STATUS_LOGON_FAILURE;
700                 }
701                 if (password == NULL) {
702                         DEBUG(3, ("Allowing access to %s with null password\n", username));
703                         return NT_STATUS_OK;
704                 }
705         }
706
707         /* try it as it came to us */
708         nt_status = password_check(username, password, crypted, salt);
709         if NT_STATUS_IS_OK(nt_status) {
710                 return nt_status;
711         }
712         else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
713                 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
714                 return nt_status;
715         }
716
717         if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) {
718                 return nt_status;
719         }
720
721         /* if the password was given to us with mixed case then we don't
722          * need to proceed as we know it hasn't been case modified by the
723          * client */
724         if (strhasupper(password) && strhaslower(password)) {
725                 return nt_status;
726         }
727
728         /* make a copy of it */
729         pwcopy = talloc_strdup(ctx, password);
730         if (!pwcopy)
731                 return NT_STATUS_NO_MEMORY;
732
733         /* try all lowercase if it's currently all uppercase */
734         if (strhasupper(pwcopy)) {
735                 strlower(pwcopy);
736                 nt_status = password_check(username, pwcopy, crypted, salt);
737                 if NT_STATUS_IS_OK(nt_status) {
738                         return nt_status;
739                 }
740         }
741
742         /* give up? */
743         if (level < 1) {
744                 return NT_STATUS_WRONG_PASSWORD;
745         }
746
747         /* last chance - all combinations of up to level chars upper! */
748         strlower(pwcopy);
749
750 #if 0
751         if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
752                 return nt_status;
753         }
754 #endif   
755         return NT_STATUS_WRONG_PASSWORD;
756 }
757
758 #endif
759
760 /** Check a plaintext username/password
761  *
762  **/
763
764 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
765                                         TALLOC_CTX *mem_ctx,
766                                         const struct auth_usersupplied_info *user_info,
767                                         struct  auth_serversupplied_info **server_info)
768 {
769         TALLOC_CTX *check_ctx;
770         NTSTATUS nt_status;
771
772         if (! user_info->account_name && ! *user_info->account_name) {
773                 return NT_STATUS_INVALID_PARAMETER;
774         }
775
776         check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
777         if (check_ctx == NULL) {
778                 return NT_STATUS_NO_MEMORY;
779         }
780
781         nt_status = check_unix_password(check_ctx, user_info);
782         if ( ! NT_STATUS_IS_OK(nt_status)) {
783                 talloc_free(check_ctx);
784                 return nt_status;
785         }
786
787         nt_status = authunix_make_server_info(mem_ctx, user_info, server_info);
788         if ( ! NT_STATUS_IS_OK(nt_status)) {
789                 talloc_free(check_ctx);
790                 return nt_status;
791         }
792
793         talloc_free(check_ctx);
794         return NT_STATUS_OK;
795 }
796
797 static const struct auth_operations unix_ops = {
798         .name           = "unix",
799         .get_challenge  = auth_get_challenge_not_implemented,
800         .check_password = authunix_check_password
801 };
802
803 NTSTATUS auth_unix_init(void)
804 {
805         NTSTATUS ret;
806
807         ret = auth_register(&unix_ops);
808         if (!NT_STATUS_IS_OK(ret)) {
809                 DEBUG(0,("Failed to register unix auth backend!\n"));
810                 return ret;
811         }
812
813         return ret;
814 }