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