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