~ubuntu-branches/ubuntu/oneiric/likewise-open/oneiric

« back to all changes in this revision

Viewing changes to winbindd/source/auth/pampass.c

  • Committer: Bazaar Package Importer
  • Author(s): Rick Clark
  • Date: 2008-02-14 13:53:05 UTC
  • Revision ID: james.westby@ubuntu.com-20080214135305-cf45nar4lz1wgpz3
Tags: upstream-4.0.4
ImportĀ upstreamĀ versionĀ 4.0.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
   PAM Password checking
 
4
   Copyright (C) Andrew Tridgell 1992-2001
 
5
   Copyright (C) John H Terpsta 1999-2001
 
6
   Copyright (C) Andrew Bartlett 2001
 
7
   Copyright (C) Jeremy Allison 2001
 
8
   
 
9
   This program is free software; you can redistribute it and/or modify
 
10
   it under the terms of the GNU General Public License as published by
 
11
   the Free Software Foundation; either version 3 of the License, or
 
12
   (at your option) any later version.
 
13
   
 
14
   This program is distributed in the hope that it will be useful,
 
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
   GNU General Public License for more details.
 
18
   
 
19
   You should have received a copy of the GNU General Public License
 
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
*/
 
22
 
 
23
/*
 
24
 * This module provides PAM based functions for validation of
 
25
 * username/password pairs, account managment, session and access control.
 
26
 * Note: SMB password checking is done in smbpass.c
 
27
 */
 
28
 
 
29
#include "includes.h"
 
30
 
 
31
#undef DBGC_CLASS
 
32
#define DBGC_CLASS DBGC_AUTH
 
33
 
 
34
#ifdef WITH_PAM
 
35
 
 
36
/*******************************************************************
 
37
 * Handle PAM authentication 
 
38
 *      - Access, Authentication, Session, Password
 
39
 *   Note: See PAM Documentation and refer to local system PAM implementation
 
40
 *   which determines what actions/limitations/allowances become affected.
 
41
 *********************************************************************/
 
42
 
 
43
#if defined(HAVE_SECURITY_PAM_APPL_H)
 
44
#include <security/pam_appl.h>
 
45
#elif defined(HAVE_PAM_PAM_APPL_H)
 
46
#include <pam/pam_appl.h>
 
47
#endif
 
48
 
 
49
/*
 
50
 * Structure used to communicate between the conversation function
 
51
 * and the server_login/change password functions.
 
52
 */
 
53
 
 
54
struct smb_pam_userdata {
 
55
        const char *PAM_username;
 
56
        const char *PAM_password;
 
57
        const char *PAM_newpassword;
 
58
};
 
59
 
 
60
typedef int (*smb_pam_conv_fn)(int, const struct pam_message **, struct pam_response **, void *appdata_ptr);
 
61
 
 
62
/*
 
63
 *  Macros to help make life easy
 
64
 */
 
65
#define COPY_STRING(s) (s) ? SMB_STRDUP(s) : NULL
 
66
 
 
67
/*******************************************************************
 
68
 PAM error handler.
 
69
 *********************************************************************/
 
70
 
 
71
static bool smb_pam_error_handler(pam_handle_t *pamh, int pam_error, const char *msg, int dbglvl)
 
72
{
 
73
 
 
74
        if( pam_error != PAM_SUCCESS) {
 
75
                DEBUG(dbglvl, ("smb_pam_error_handler: PAM: %s : %s\n",
 
76
                                msg, pam_strerror(pamh, pam_error)));
 
77
                
 
78
                return False;
 
79
        }
 
80
        return True;
 
81
}
 
82
 
 
83
/*******************************************************************
 
84
 This function is a sanity check, to make sure that we NEVER report
 
85
 failure as sucess.
 
86
*********************************************************************/
 
87
 
 
88
static bool smb_pam_nt_status_error_handler(pam_handle_t *pamh, int pam_error,
 
89
                                            const char *msg, int dbglvl, 
 
90
                                            NTSTATUS *nt_status)
 
91
{
 
92
        *nt_status = pam_to_nt_status(pam_error);
 
93
 
 
94
        if (smb_pam_error_handler(pamh, pam_error, msg, dbglvl))
 
95
                return True;
 
96
 
 
97
        if (NT_STATUS_IS_OK(*nt_status)) {
 
98
                /* Complain LOUDLY */
 
99
                DEBUG(0, ("smb_pam_nt_status_error_handler: PAM: BUG: PAM and NT_STATUS \
 
100
error MISMATCH, forcing to NT_STATUS_LOGON_FAILURE"));
 
101
                *nt_status = NT_STATUS_LOGON_FAILURE;
 
102
        }
 
103
        return False;
 
104
}
 
105
 
 
106
/*
 
107
 * PAM conversation function
 
108
 * Here we assume (for now, at least) that echo on means login name, and
 
109
 * echo off means password.
 
110
 */
 
111
 
 
112
static int smb_pam_conv(int num_msg,
 
113
                    const struct pam_message **msg,
 
114
                    struct pam_response **resp,
 
115
                    void *appdata_ptr)
 
116
{
 
117
        int replies = 0;
 
118
        struct pam_response *reply = NULL;
 
119
        struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
 
120
 
 
121
        *resp = NULL;
 
122
 
 
123
        if (num_msg <= 0)
 
124
                return PAM_CONV_ERR;
 
125
 
 
126
        /*
 
127
         * Apparantly HPUX has a buggy PAM that doesn't support the
 
128
         * appdata_ptr. Fail if this is the case. JRA.
 
129
         */
 
130
 
 
131
        if (udp == NULL) {
 
132
                DEBUG(0,("smb_pam_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));
 
133
                return PAM_CONV_ERR;
 
134
        }
 
135
 
 
136
        reply = SMB_MALLOC_ARRAY(struct pam_response, num_msg);
 
137
        if (!reply)
 
138
                return PAM_CONV_ERR;
 
139
 
 
140
        memset(reply, '\0', sizeof(struct pam_response) * num_msg);
 
141
 
 
142
        for (replies = 0; replies < num_msg; replies++) {
 
143
                switch (msg[replies]->msg_style) {
 
144
                        case PAM_PROMPT_ECHO_ON:
 
145
                                reply[replies].resp_retcode = PAM_SUCCESS;
 
146
                                reply[replies].resp = COPY_STRING(udp->PAM_username);
 
147
                                /* PAM frees resp */
 
148
                                break;
 
149
 
 
150
                        case PAM_PROMPT_ECHO_OFF:
 
151
                                reply[replies].resp_retcode = PAM_SUCCESS;
 
152
                                reply[replies].resp = COPY_STRING(udp->PAM_password);
 
153
                                /* PAM frees resp */
 
154
                                break;
 
155
 
 
156
                        case PAM_TEXT_INFO:
 
157
                                /* fall through */
 
158
 
 
159
                        case PAM_ERROR_MSG:
 
160
                                /* ignore it... */
 
161
                                reply[replies].resp_retcode = PAM_SUCCESS;
 
162
                                reply[replies].resp = NULL;
 
163
                                break;
 
164
 
 
165
                        default:
 
166
                                /* Must be an error of some sort... */
 
167
                                SAFE_FREE(reply);
 
168
                                return PAM_CONV_ERR;
 
169
                }
 
170
        }
 
171
        if (reply)
 
172
                *resp = reply;
 
173
        return PAM_SUCCESS;
 
174
}
 
175
 
 
176
/*
 
177
 * PAM password change conversation function
 
178
 * Here we assume (for now, at least) that echo on means login name, and
 
179
 * echo off means password.
 
180
 */
 
181
 
 
182
static void special_char_sub(char *buf)
 
183
{
 
184
        all_string_sub(buf, "\\n", "", 0);
 
185
        all_string_sub(buf, "\\r", "", 0);
 
186
        all_string_sub(buf, "\\s", " ", 0);
 
187
        all_string_sub(buf, "\\t", "\t", 0);
 
188
}
 
189
 
 
190
static void pwd_sub(char *buf, const char *username, const char *oldpass, const char *newpass)
 
191
{
 
192
        fstring_sub(buf, "%u", username);
 
193
        all_string_sub(buf, "%o", oldpass, sizeof(fstring));
 
194
        all_string_sub(buf, "%n", newpass, sizeof(fstring));
 
195
}
 
196
 
 
197
 
 
198
struct chat_struct {
 
199
        struct chat_struct *next, *prev;
 
200
        fstring prompt;
 
201
        fstring reply;
 
202
};
 
203
 
 
204
/**************************************************************
 
205
 Create a linked list containing chat data.
 
206
***************************************************************/
 
207
 
 
208
static struct chat_struct *make_pw_chat(const char *p) 
 
209
{
 
210
        char *prompt;
 
211
        char *reply;
 
212
        struct chat_struct *list = NULL;
 
213
        struct chat_struct *t;
 
214
        TALLOC_CTX *frame = talloc_stackframe();
 
215
 
 
216
        while (1) {
 
217
                t = SMB_MALLOC_P(struct chat_struct);
 
218
                if (!t) {
 
219
                        DEBUG(0,("make_pw_chat: malloc failed!\n"));
 
220
                        TALLOC_FREE(frame);
 
221
                        return NULL;
 
222
                }
 
223
 
 
224
                ZERO_STRUCTP(t);
 
225
 
 
226
                DLIST_ADD_END(list, t, struct chat_struct*);
 
227
 
 
228
                if (!next_token_talloc(frame, &p, &prompt, NULL)) {
 
229
                        break;
 
230
                }
 
231
 
 
232
                if (strequal(prompt,".")) {
 
233
                        fstrcpy(prompt,"*");
 
234
                }
 
235
 
 
236
                special_char_sub(prompt);
 
237
                fstrcpy(t->prompt, prompt);
 
238
                strlower_m(t->prompt);
 
239
                trim_char(t->prompt, ' ', ' ');
 
240
 
 
241
                if (!next_token_talloc(frame, &p, &reply, NULL)) {
 
242
                        break;
 
243
                }
 
244
 
 
245
                if (strequal(reply,".")) {
 
246
                        fstrcpy(reply,"");
 
247
                }
 
248
 
 
249
                special_char_sub(reply);
 
250
                fstrcpy(t->reply, reply);
 
251
                strlower_m(t->reply);
 
252
                trim_char(t->reply, ' ', ' ');
 
253
 
 
254
        }
 
255
        TALLOC_FREE(frame);
 
256
        return list;
 
257
}
 
258
 
 
259
static void free_pw_chat(struct chat_struct *list)
 
260
{
 
261
    while (list) {
 
262
        struct chat_struct *old_head = list;
 
263
        DLIST_REMOVE(list, list);
 
264
        SAFE_FREE(old_head);
 
265
    }
 
266
}
 
267
 
 
268
static int smb_pam_passchange_conv(int num_msg,
 
269
                                const struct pam_message **msg,
 
270
                                struct pam_response **resp,
 
271
                                void *appdata_ptr)
 
272
{
 
273
        int replies = 0;
 
274
        struct pam_response *reply = NULL;
 
275
        fstring current_prompt;
 
276
        fstring current_reply;
 
277
        struct smb_pam_userdata *udp = (struct smb_pam_userdata *)appdata_ptr;
 
278
        struct chat_struct *pw_chat= make_pw_chat(lp_passwd_chat());
 
279
        struct chat_struct *t;
 
280
        bool found; 
 
281
        *resp = NULL;
 
282
        
 
283
        DEBUG(10,("smb_pam_passchange_conv: starting converstation for %d messages\n", num_msg));
 
284
 
 
285
        if (num_msg <= 0)
 
286
                return PAM_CONV_ERR;
 
287
 
 
288
        if (pw_chat == NULL)
 
289
                return PAM_CONV_ERR;
 
290
 
 
291
        /*
 
292
         * Apparantly HPUX has a buggy PAM that doesn't support the
 
293
         * appdata_ptr. Fail if this is the case. JRA.
 
294
         */
 
295
 
 
296
        if (udp == NULL) {
 
297
                DEBUG(0,("smb_pam_passchange_conv: PAM on this system is broken - appdata_ptr == NULL !\n"));
 
298
                free_pw_chat(pw_chat);
 
299
                return PAM_CONV_ERR;
 
300
        }
 
301
 
 
302
        reply = SMB_MALLOC_ARRAY(struct pam_response, num_msg);
 
303
        if (!reply) {
 
304
                DEBUG(0,("smb_pam_passchange_conv: malloc for reply failed!\n"));
 
305
                free_pw_chat(pw_chat);
 
306
                return PAM_CONV_ERR;
 
307
        }
 
308
 
 
309
        for (replies = 0; replies < num_msg; replies++) {
 
310
                found = False;
 
311
                DEBUG(10,("smb_pam_passchange_conv: Processing message %d\n", replies));
 
312
                switch (msg[replies]->msg_style) {
 
313
                case PAM_PROMPT_ECHO_ON:
 
314
                        DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: PAM said: %s\n", msg[replies]->msg));
 
315
                        fstrcpy(current_prompt, msg[replies]->msg);
 
316
                        trim_char(current_prompt, ' ', ' ');
 
317
                        for (t=pw_chat; t; t=t->next) {
 
318
 
 
319
                                DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: trying to match |%s| to |%s|\n",
 
320
                                                t->prompt, current_prompt ));
 
321
 
 
322
                                if (unix_wild_match(t->prompt, current_prompt)) {
 
323
                                        fstrcpy(current_reply, t->reply);
 
324
                                        DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We sent: %s\n", current_reply));
 
325
                                        pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
 
326
#ifdef DEBUG_PASSWORD
 
327
                                        DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We actualy sent: %s\n", current_reply));
 
328
#endif
 
329
                                        reply[replies].resp_retcode = PAM_SUCCESS;
 
330
                                        reply[replies].resp = COPY_STRING(current_reply);
 
331
                                        found = True;
 
332
                                        break;
 
333
                                }
 
334
                        }
 
335
                        /* PAM frees resp */
 
336
                        if (!found) {
 
337
                                DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
 
338
                                free_pw_chat(pw_chat);
 
339
                                SAFE_FREE(reply);
 
340
                                return PAM_CONV_ERR;
 
341
                        }
 
342
                        break;
 
343
 
 
344
                case PAM_PROMPT_ECHO_OFF:
 
345
                        DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: PAM said: %s\n", msg[replies]->msg));
 
346
                        fstrcpy(current_prompt, msg[replies]->msg);
 
347
                        trim_char(current_prompt, ' ', ' ');
 
348
                        for (t=pw_chat; t; t=t->next) {
 
349
 
 
350
                                DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: trying to match |%s| to |%s|\n",
 
351
                                                t->prompt, current_prompt ));
 
352
 
 
353
                                if (unix_wild_match(t->prompt, current_prompt)) {
 
354
                                        fstrcpy(current_reply, t->reply);
 
355
                                        DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We sent: %s\n", current_reply));
 
356
                                        pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
 
357
                                        reply[replies].resp_retcode = PAM_SUCCESS;
 
358
                                        reply[replies].resp = COPY_STRING(current_reply);
 
359
#ifdef DEBUG_PASSWORD
 
360
                                        DEBUG(100,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We actualy sent: %s\n", current_reply));
 
361
#endif
 
362
                                        found = True;
 
363
                                        break;
 
364
                                }
 
365
                        }
 
366
                        /* PAM frees resp */
 
367
                        
 
368
                        if (!found) {
 
369
                                DEBUG(3,("smb_pam_passchange_conv: Could not find reply for PAM prompt: %s\n",msg[replies]->msg));
 
370
                                free_pw_chat(pw_chat);
 
371
                                SAFE_FREE(reply);
 
372
                                return PAM_CONV_ERR;
 
373
                        }
 
374
                        break;
 
375
 
 
376
                case PAM_TEXT_INFO:
 
377
                        /* fall through */
 
378
 
 
379
                case PAM_ERROR_MSG:
 
380
                        /* ignore it... */
 
381
                        reply[replies].resp_retcode = PAM_SUCCESS;
 
382
                        reply[replies].resp = NULL;
 
383
                        break;
 
384
                        
 
385
                default:
 
386
                        /* Must be an error of some sort... */
 
387
                        free_pw_chat(pw_chat);
 
388
                        SAFE_FREE(reply);
 
389
                        return PAM_CONV_ERR;
 
390
                }
 
391
        }
 
392
                
 
393
        free_pw_chat(pw_chat);
 
394
        if (reply)
 
395
                *resp = reply;
 
396
        return PAM_SUCCESS;
 
397
}
 
398
 
 
399
/***************************************************************************
 
400
 Free up a malloced pam_conv struct.
 
401
****************************************************************************/
 
402
 
 
403
static void smb_free_pam_conv(struct pam_conv *pconv)
 
404
{
 
405
        if (pconv)
 
406
                SAFE_FREE(pconv->appdata_ptr);
 
407
 
 
408
        SAFE_FREE(pconv);
 
409
}
 
410
 
 
411
/***************************************************************************
 
412
 Allocate a pam_conv struct.
 
413
****************************************************************************/
 
414
 
 
415
static struct pam_conv *smb_setup_pam_conv(smb_pam_conv_fn smb_pam_conv_fnptr, const char *user,
 
416
                                        const char *passwd, const char *newpass)
 
417
{
 
418
        struct pam_conv *pconv = SMB_MALLOC_P(struct pam_conv);
 
419
        struct smb_pam_userdata *udp = SMB_MALLOC_P(struct smb_pam_userdata);
 
420
 
 
421
        if (pconv == NULL || udp == NULL) {
 
422
                SAFE_FREE(pconv);
 
423
                SAFE_FREE(udp);
 
424
                return NULL;
 
425
        }
 
426
 
 
427
        udp->PAM_username = user;
 
428
        udp->PAM_password = passwd;
 
429
        udp->PAM_newpassword = newpass;
 
430
 
 
431
        pconv->conv = smb_pam_conv_fnptr;
 
432
        pconv->appdata_ptr = (void *)udp;
 
433
        return pconv;
 
434
}
 
435
 
 
436
/* 
 
437
 * PAM Closing out cleanup handler
 
438
 */
 
439
 
 
440
static bool smb_pam_end(pam_handle_t *pamh, struct pam_conv *smb_pam_conv_ptr)
 
441
{
 
442
        int pam_error;
 
443
 
 
444
        smb_free_pam_conv(smb_pam_conv_ptr);
 
445
       
 
446
        if( pamh != NULL ) {
 
447
                pam_error = pam_end(pamh, 0);
 
448
                if(smb_pam_error_handler(pamh, pam_error, "End Cleanup Failed", 2) == True) {
 
449
                        DEBUG(4, ("smb_pam_end: PAM: PAM_END OK.\n"));
 
450
                        return True;
 
451
                }
 
452
        }
 
453
        DEBUG(2,("smb_pam_end: PAM: not initialised"));
 
454
        return False;
 
455
}
 
456
 
 
457
/*
 
458
 * Start PAM authentication for specified account
 
459
 */
 
460
 
 
461
static bool smb_pam_start(pam_handle_t **pamh, const char *user, const char *rhost, struct pam_conv *pconv)
 
462
{
 
463
        int pam_error;
 
464
        const char *our_rhost;
 
465
        char addr[INET6_ADDRSTRLEN];
 
466
 
 
467
        *pamh = (pam_handle_t *)NULL;
 
468
 
 
469
        DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", user));
 
470
 
 
471
        pam_error = pam_start("samba", user, pconv, pamh);
 
472
        if( !smb_pam_error_handler(*pamh, pam_error, "Init Failed", 0)) {
 
473
                *pamh = (pam_handle_t *)NULL;
 
474
                return False;
 
475
        }
 
476
 
 
477
        if (rhost == NULL) {
 
478
                our_rhost = client_name(get_client_fd());
 
479
                if (strequal(our_rhost,"UNKNOWN"))
 
480
                        our_rhost = client_addr(get_client_fd(),addr,sizeof(addr));
 
481
        } else {
 
482
                our_rhost = rhost;
 
483
        }
 
484
 
 
485
#ifdef PAM_RHOST
 
486
        DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", our_rhost));
 
487
        pam_error = pam_set_item(*pamh, PAM_RHOST, our_rhost);
 
488
        if(!smb_pam_error_handler(*pamh, pam_error, "set rhost failed", 0)) {
 
489
                smb_pam_end(*pamh, pconv);
 
490
                *pamh = (pam_handle_t *)NULL;
 
491
                return False;
 
492
        }
 
493
#endif
 
494
#ifdef PAM_TTY
 
495
        DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
 
496
        pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
 
497
        if (!smb_pam_error_handler(*pamh, pam_error, "set tty failed", 0)) {
 
498
                smb_pam_end(*pamh, pconv);
 
499
                *pamh = (pam_handle_t *)NULL;
 
500
                return False;
 
501
        }
 
502
#endif
 
503
        DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", user));
 
504
        return True;
 
505
}
 
506
 
 
507
/*
 
508
 * PAM Authentication Handler
 
509
 */
 
510
static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user)
 
511
{
 
512
        int pam_error;
 
513
        NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
 
514
 
 
515
        /*
 
516
         * To enable debugging set in /etc/pam.d/samba:
 
517
         *      auth required /lib/security/pam_pwdb.so nullok shadow audit
 
518
         */
 
519
        
 
520
        DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
 
521
        pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
 
522
        switch( pam_error ){
 
523
                case PAM_AUTH_ERR:
 
524
                        DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user));
 
525
                        break;
 
526
                case PAM_CRED_INSUFFICIENT:
 
527
                        DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
 
528
                        break;
 
529
                case PAM_AUTHINFO_UNAVAIL:
 
530
                        DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
 
531
                        break;
 
532
                case PAM_USER_UNKNOWN:
 
533
                        DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
 
534
                        break;
 
535
                case PAM_MAXTRIES:
 
536
                        DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
 
537
                        break;
 
538
                case PAM_ABORT:
 
539
                        DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
 
540
                        break;
 
541
                case PAM_SUCCESS:
 
542
                        DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
 
543
                        break;
 
544
                default:
 
545
                        DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
 
546
                        break;
 
547
        }
 
548
 
 
549
        smb_pam_nt_status_error_handler(pamh, pam_error, "Authentication Failure", 2, &nt_status);
 
550
        return nt_status;
 
551
}
 
552
 
 
553
/* 
 
554
 * PAM Account Handler
 
555
 */
 
556
static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
 
557
{
 
558
        int pam_error;
 
559
        NTSTATUS nt_status = NT_STATUS_ACCOUNT_DISABLED;
 
560
 
 
561
        DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
 
562
        pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
 
563
        switch( pam_error ) {
 
564
                case PAM_AUTHTOK_EXPIRED:
 
565
                        DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
 
566
                        break;
 
567
                case PAM_ACCT_EXPIRED:
 
568
                        DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
 
569
                        break;
 
570
                case PAM_AUTH_ERR:
 
571
                        DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
 
572
                        break;
 
573
                case PAM_PERM_DENIED:
 
574
                        DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
 
575
                        break;
 
576
                case PAM_USER_UNKNOWN:
 
577
                        DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
 
578
                        break;
 
579
                case PAM_SUCCESS:
 
580
                        DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
 
581
                        break;
 
582
                default:
 
583
                        DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
 
584
                        break;
 
585
        }
 
586
 
 
587
        smb_pam_nt_status_error_handler(pamh, pam_error, "Account Check Failed", 2, &nt_status);
 
588
        return nt_status;
 
589
}
 
590
 
 
591
/*
 
592
 * PAM Credential Setting
 
593
 */
 
594
 
 
595
static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
 
596
{
 
597
        int pam_error;
 
598
        NTSTATUS nt_status = NT_STATUS_NO_TOKEN;
 
599
 
 
600
        /*
 
601
         * This will allow samba to aquire a kerberos token. And, when
 
602
         * exporting an AFS cell, be able to /write/ to this cell.
 
603
         */
 
604
 
 
605
        DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
 
606
        pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT)); 
 
607
        switch( pam_error ) {
 
608
                case PAM_CRED_UNAVAIL:
 
609
                        DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
 
610
                        break;
 
611
                case PAM_CRED_EXPIRED:
 
612
                        DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
 
613
                        break;
 
614
                case PAM_USER_UNKNOWN:
 
615
                        DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
 
616
                        break;
 
617
                case PAM_CRED_ERR:
 
618
                        DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
 
619
                        break;
 
620
                case PAM_SUCCESS:
 
621
                        DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
 
622
                        break;
 
623
                default:
 
624
                        DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
 
625
                        break;
 
626
        }
 
627
 
 
628
        smb_pam_nt_status_error_handler(pamh, pam_error, "Set Credential Failure", 2, &nt_status);
 
629
        return nt_status;
 
630
}
 
631
 
 
632
/*
 
633
 * PAM Internal Session Handler
 
634
 */
 
635
static bool smb_internal_pam_session(pam_handle_t *pamh, const char *user, const char *tty, bool flag)
 
636
{
 
637
        int pam_error;
 
638
 
 
639
#ifdef PAM_TTY
 
640
        DEBUG(4,("smb_internal_pam_session: PAM: tty set to: %s\n", tty));
 
641
        pam_error = pam_set_item(pamh, PAM_TTY, tty);
 
642
        if (!smb_pam_error_handler(pamh, pam_error, "set tty failed", 0))
 
643
                return False;
 
644
#endif
 
645
 
 
646
        if (flag) {
 
647
                pam_error = pam_open_session(pamh, PAM_SILENT);
 
648
                if (!smb_pam_error_handler(pamh, pam_error, "session setup failed", 0))
 
649
                        return False;
 
650
        } else {
 
651
                pam_setcred(pamh, (PAM_DELETE_CRED|PAM_SILENT)); /* We don't care if this fails */
 
652
                pam_error = pam_close_session(pamh, PAM_SILENT); /* This will probably pick up the error anyway */
 
653
                if (!smb_pam_error_handler(pamh, pam_error, "session close failed", 0))
 
654
                        return False;
 
655
        }
 
656
        return (True);
 
657
}
 
658
 
 
659
/*
 
660
 * Internal PAM Password Changer.
 
661
 */
 
662
 
 
663
static bool smb_pam_chauthtok(pam_handle_t *pamh, const char * user)
 
664
{
 
665
        int pam_error;
 
666
 
 
667
        DEBUG(4,("smb_pam_chauthtok: PAM: Password Change for User: %s\n", user));
 
668
 
 
669
        pam_error = pam_chauthtok(pamh, PAM_SILENT); /* Change Password */
 
670
 
 
671
        switch( pam_error ) {
 
672
        case PAM_AUTHTOK_ERR:
 
673
                DEBUG(2, ("PAM: unable to obtain the new authentication token - is password to weak?\n"));
 
674
                break;
 
675
 
 
676
        /* This doesn't seem to be defined on Solaris. JRA */
 
677
#ifdef PAM_AUTHTOK_RECOVER_ERR
 
678
        case PAM_AUTHTOK_RECOVER_ERR:
 
679
                DEBUG(2, ("PAM: unable to obtain the old authentication token - was the old password wrong?.\n"));
 
680
                break;
 
681
#endif
 
682
 
 
683
        case PAM_AUTHTOK_LOCK_BUSY:
 
684
                DEBUG(2, ("PAM: unable to change the authentication token since it is currently locked.\n"));
 
685
                break;
 
686
        case PAM_AUTHTOK_DISABLE_AGING:
 
687
                DEBUG(2, ("PAM: Authentication token aging has been disabled.\n"));
 
688
                break;
 
689
        case PAM_PERM_DENIED:
 
690
                DEBUG(0, ("PAM: Permission denied.\n"));
 
691
                break;
 
692
        case PAM_TRY_AGAIN:
 
693
                DEBUG(0, ("PAM: Could not update all authentication token(s). No authentication tokens were updated.\n"));
 
694
                break;
 
695
        case PAM_USER_UNKNOWN:
 
696
                DEBUG(0, ("PAM: User not known to PAM\n"));
 
697
                break;
 
698
        case PAM_SUCCESS:
 
699
                DEBUG(4, ("PAM: Account OK for User: %s\n", user));
 
700
                break;
 
701
        default:
 
702
                DEBUG(0, ("PAM: UNKNOWN PAM ERROR (%d) for User: %s\n", pam_error, user));
 
703
        }
 
704
 
 
705
        if(!smb_pam_error_handler(pamh, pam_error, "Password Change Failed", 2)) {
 
706
                return False;
 
707
        }
 
708
 
 
709
        /* If this point is reached, the password has changed. */
 
710
        return True;
 
711
}
 
712
 
 
713
/*
 
714
 * PAM Externally accessible Session handler
 
715
 */
 
716
 
 
717
bool smb_pam_claim_session(char *user, char *tty, char *rhost)
 
718
{
 
719
        pam_handle_t *pamh = NULL;
 
720
        struct pam_conv *pconv = NULL;
 
721
 
 
722
        /* Ignore PAM if told to. */
 
723
 
 
724
        if (!lp_obey_pam_restrictions())
 
725
                return True;
 
726
 
 
727
        if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
 
728
                return False;
 
729
 
 
730
        if (!smb_pam_start(&pamh, user, rhost, pconv))
 
731
                return False;
 
732
 
 
733
        if (!smb_internal_pam_session(pamh, user, tty, True)) {
 
734
                smb_pam_end(pamh, pconv);
 
735
                return False;
 
736
        }
 
737
 
 
738
        return smb_pam_end(pamh, pconv);
 
739
}
 
740
 
 
741
/*
 
742
 * PAM Externally accessible Session handler
 
743
 */
 
744
 
 
745
bool smb_pam_close_session(char *user, char *tty, char *rhost)
 
746
{
 
747
        pam_handle_t *pamh = NULL;
 
748
        struct pam_conv *pconv = NULL;
 
749
 
 
750
        /* Ignore PAM if told to. */
 
751
 
 
752
        if (!lp_obey_pam_restrictions())
 
753
                return True;
 
754
 
 
755
        if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
 
756
                return False;
 
757
 
 
758
        if (!smb_pam_start(&pamh, user, rhost, pconv))
 
759
                return False;
 
760
 
 
761
        if (!smb_internal_pam_session(pamh, user, tty, False)) {
 
762
                smb_pam_end(pamh, pconv);
 
763
                return False;
 
764
        }
 
765
 
 
766
        return smb_pam_end(pamh, pconv);
 
767
}
 
768
 
 
769
/*
 
770
 * PAM Externally accessible Account handler
 
771
 */
 
772
 
 
773
NTSTATUS smb_pam_accountcheck(const char * user)
 
774
{
 
775
        NTSTATUS nt_status = NT_STATUS_ACCOUNT_DISABLED;
 
776
        pam_handle_t *pamh = NULL;
 
777
        struct pam_conv *pconv = NULL;
 
778
 
 
779
        /* Ignore PAM if told to. */
 
780
 
 
781
        if (!lp_obey_pam_restrictions())
 
782
                return NT_STATUS_OK;
 
783
 
 
784
        if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, NULL, NULL)) == NULL)
 
785
                return NT_STATUS_NO_MEMORY;
 
786
 
 
787
        if (!smb_pam_start(&pamh, user, NULL, pconv))
 
788
                return NT_STATUS_ACCOUNT_DISABLED;
 
789
 
 
790
        if (!NT_STATUS_IS_OK(nt_status = smb_pam_account(pamh, user)))
 
791
                DEBUG(0, ("smb_pam_accountcheck: PAM: Account Validation Failed - Rejecting User %s!\n", user));
 
792
 
 
793
        smb_pam_end(pamh, pconv);
 
794
        return nt_status;
 
795
}
 
796
 
 
797
/*
 
798
 * PAM Password Validation Suite
 
799
 */
 
800
 
 
801
NTSTATUS smb_pam_passcheck(const char * user, const char * password)
 
802
{
 
803
        pam_handle_t *pamh = NULL;
 
804
        NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
 
805
        struct pam_conv *pconv = NULL;
 
806
 
 
807
        /*
 
808
         * Note we can't ignore PAM here as this is the only
 
809
         * way of doing auths on plaintext passwords when
 
810
         * compiled --with-pam.
 
811
         */
 
812
 
 
813
        if ((pconv = smb_setup_pam_conv(smb_pam_conv, user, password, NULL)) == NULL)
 
814
                return NT_STATUS_LOGON_FAILURE;
 
815
 
 
816
        if (!smb_pam_start(&pamh, user, NULL, pconv))
 
817
                return NT_STATUS_LOGON_FAILURE;
 
818
 
 
819
        if (!NT_STATUS_IS_OK(nt_status = smb_pam_auth(pamh, user))) {
 
820
                DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_auth failed - Rejecting User %s !\n", user));
 
821
                smb_pam_end(pamh, pconv);
 
822
                return nt_status;
 
823
        }
 
824
 
 
825
        if (!NT_STATUS_IS_OK(nt_status = smb_pam_account(pamh, user))) {
 
826
                DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_account failed - Rejecting User %s !\n", user));
 
827
                smb_pam_end(pamh, pconv);
 
828
                return nt_status;
 
829
        }
 
830
 
 
831
        if (!NT_STATUS_IS_OK(nt_status = smb_pam_setcred(pamh, user))) {
 
832
                DEBUG(0, ("smb_pam_passcheck: PAM: smb_pam_setcred failed - Rejecting User %s !\n", user));
 
833
                smb_pam_end(pamh, pconv);
 
834
                return nt_status;
 
835
        }
 
836
 
 
837
        smb_pam_end(pamh, pconv);
 
838
        return nt_status;
 
839
}
 
840
 
 
841
/*
 
842
 * PAM Password Change Suite
 
843
 */
 
844
 
 
845
bool smb_pam_passchange(const char * user, const char * oldpassword, const char * newpassword)
 
846
{
 
847
        /* Appropriate quantities of root should be obtained BEFORE calling this function */
 
848
        struct pam_conv *pconv = NULL;
 
849
        pam_handle_t *pamh = NULL;
 
850
 
 
851
        if ((pconv = smb_setup_pam_conv(smb_pam_passchange_conv, user, oldpassword, newpassword)) == NULL)
 
852
                return False;
 
853
 
 
854
        if(!smb_pam_start(&pamh, user, NULL, pconv))
 
855
                return False;
 
856
 
 
857
        if (!smb_pam_chauthtok(pamh, user)) {
 
858
                DEBUG(0, ("smb_pam_passchange: PAM: Password Change Failed for user %s!\n", user));
 
859
                smb_pam_end(pamh, pconv);
 
860
                return False;
 
861
        }
 
862
 
 
863
        return smb_pam_end(pamh, pconv);
 
864
}
 
865
 
 
866
#else
 
867
 
 
868
/* If PAM not used, no PAM restrictions on accounts. */
 
869
NTSTATUS smb_pam_accountcheck(const char * user)
 
870
{
 
871
        return NT_STATUS_OK;
 
872
}
 
873
 
 
874
/* If PAM not used, also no PAM restrictions on sessions. */
 
875
bool smb_pam_claim_session(char *user, char *tty, char *rhost)
 
876
{
 
877
        return True;
 
878
}
 
879
 
 
880
/* If PAM not used, also no PAM restrictions on sessions. */
 
881
bool smb_pam_close_session(char *in_user, char *tty, char *rhost)
 
882
{
 
883
        return True;
 
884
}
 
885
#endif /* WITH_PAM */