~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/pam_smbpass/support.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Unix NT password database implementation, version 0.6.
 
2
 *
 
3
 * This program is free software; you can redistribute it and/or modify it under
 
4
 * the terms of the GNU General Public License as published by the Free
 
5
 * Software Foundation; either version 3 of the License, or (at your option)
 
6
 * any later version.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
 
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
10
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
11
 * more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along with
 
14
 * this program; if not, see <http://www.gnu.org/licenses/>.
 
15
 */
 
16
 
 
17
#include "config.h"
 
18
#include "includes.h"
 
19
#include "general.h"
 
20
 
 
21
#include "support.h"
 
22
 
 
23
#if defined(HAVE_SECURITY_PAM_EXT_H)
 
24
#include <security/pam_ext.h>
 
25
#elif defined(HAVE_PAM_PAM_EXT_H)
 
26
#include <pam/pam_ext.h>
 
27
#endif
 
28
 
 
29
#if defined(HAVE_SECURITY__PAM_MACROS_H)
 
30
#include <security/_pam_macros.h>
 
31
#elif defined(HAVE_PAM__PAM_MACROS_H)
 
32
#include <pam/_pam_macros.h>
 
33
#endif
 
34
 
 
35
#ifdef HAVE_SYSLOG_H
 
36
#include <syslog.h>
 
37
#endif
 
38
 
 
39
#define _pam_overwrite(x)        \
 
40
do {                             \
 
41
     register char *__xx__;      \
 
42
     if ((__xx__=(x)))           \
 
43
          while (*__xx__)        \
 
44
               *__xx__++ = '\0'; \
 
45
} while (0)
 
46
 
 
47
/*
 
48
 * Don't just free it, forget it too.
 
49
 */
 
50
 
 
51
#define _pam_drop(X) \
 
52
do {                 \
 
53
    if (X) {         \
 
54
        free(X);     \
 
55
        X=NULL;      \
 
56
    }                \
 
57
} while (0)
 
58
 
 
59
#define _pam_drop_reply(/* struct pam_response * */ reply, /* int */ replies) \
 
60
do {                                              \
 
61
    int reply_i;                                  \
 
62
                                                  \
 
63
    for (reply_i=0; reply_i<replies; ++reply_i) { \
 
64
        if (reply[reply_i].resp) {                \
 
65
            _pam_overwrite(reply[reply_i].resp);  \
 
66
            free(reply[reply_i].resp);            \
 
67
        }                                         \
 
68
    }                                             \
 
69
    if (reply)                                    \
 
70
        free(reply);                              \
 
71
} while (0)
 
72
 
 
73
 
 
74
int converse(pam_handle_t *, int, int, struct pam_message **,
 
75
                         struct pam_response **);
 
76
int make_remark(pam_handle_t *, unsigned int, int, const char *);
 
77
void _cleanup(pam_handle_t *, void *, int);
 
78
char *_pam_delete(register char *);
 
79
 
 
80
/* syslogging function for errors and other information */
 
81
#ifdef HAVE_PAM_VSYSLOG
 
82
void _log_err( pam_handle_t *pamh, int err, const char *format, ... )
 
83
{
 
84
        va_list args;
 
85
 
 
86
        va_start(args, format);
 
87
        pam_vsyslog(pamh, err, format, args);
 
88
        va_end(args);
 
89
}
 
90
#else
 
91
void _log_err( pam_handle_t *pamh, int err, const char *format, ... )
 
92
{
 
93
        va_list args;
 
94
        const char tag[] = "(pam_smbpass) ";
 
95
        char *mod_format;
 
96
 
 
97
        mod_format = SMB_MALLOC_ARRAY(char, sizeof(tag) + strlen(format));
 
98
        /* try really, really hard to log something, since this may have
 
99
           been a message about a malloc() failure... */
 
100
        if (mod_format == NULL) {
 
101
                va_start(args, format);
 
102
                vsyslog(err | LOG_AUTH, format, args);
 
103
                va_end(args);
 
104
                return;
 
105
        }
 
106
 
 
107
        strncpy(mod_format, tag, strlen(tag)+1);
 
108
        strlcat(mod_format, format, strlen(format)+1);
 
109
 
 
110
        va_start(args, format);
 
111
        vsyslog(err | LOG_AUTH, mod_format, args);
 
112
        va_end(args);
 
113
 
 
114
        free(mod_format);
 
115
}
 
116
#endif
 
117
 
 
118
/* this is a front-end for module-application conversations */
 
119
 
 
120
int converse( pam_handle_t * pamh, int ctrl, int nargs
 
121
              , struct pam_message **message
 
122
              , struct pam_response **response )
 
123
{
 
124
        int retval;
 
125
        struct pam_conv *conv;
 
126
 
 
127
        retval = _pam_get_item(pamh, PAM_CONV, &conv);
 
128
        if (retval == PAM_SUCCESS) {
 
129
 
 
130
                retval = conv->conv(nargs, (const struct pam_message **) message
 
131
                                                        ,response, conv->appdata_ptr);
 
132
 
 
133
                if (retval != PAM_SUCCESS && on(SMB_DEBUG, ctrl)) {
 
134
                        _log_err(pamh, LOG_DEBUG, "conversation failure [%s]"
 
135
                                         ,pam_strerror(pamh, retval));
 
136
                }
 
137
        } else {
 
138
                _log_err(pamh, LOG_ERR, "couldn't obtain coversation function [%s]"
 
139
                                 ,pam_strerror(pamh, retval));
 
140
        }
 
141
 
 
142
        return retval;                          /* propagate error status */
 
143
}
 
144
 
 
145
int make_remark( pam_handle_t * pamh, unsigned int ctrl
 
146
                 , int type, const char *text )
 
147
{
 
148
        if (off(SMB__QUIET, ctrl)) {
 
149
                struct pam_message *pmsg[1], msg[1];
 
150
                struct pam_response *resp;
 
151
 
 
152
                pmsg[0] = &msg[0];
 
153
                msg[0].msg = CONST_DISCARD(char *, text);
 
154
                msg[0].msg_style = type;
 
155
                resp = NULL;
 
156
 
 
157
                return converse(pamh, ctrl, 1, pmsg, &resp);
 
158
        }
 
159
        return PAM_SUCCESS;
 
160
}
 
161
 
 
162
 
 
163
/* set the control flags for the SMB module. */
 
164
 
 
165
int set_ctrl( pam_handle_t *pamh, int flags, int argc, const char **argv )
 
166
{
 
167
    int i = 0;
 
168
    const char *service_file = NULL;
 
169
    unsigned int ctrl;
 
170
 
 
171
    ctrl = SMB_DEFAULTS;        /* the default selection of options */
 
172
 
 
173
    /* set some flags manually */
 
174
 
 
175
    /* A good, sane default (matches Samba's behavior). */
 
176
    set( SMB__NONULL, ctrl );
 
177
 
 
178
    /* initialize service file location */
 
179
    service_file=get_dyn_CONFIGFILE();
 
180
 
 
181
    if (flags & PAM_SILENT) {
 
182
        set( SMB__QUIET, ctrl );
 
183
    }
 
184
 
 
185
    /* Run through the arguments once, looking for an alternate smb config
 
186
       file location */
 
187
    while (i < argc) {
 
188
        int j;
 
189
 
 
190
        for (j = 0; j < SMB_CTRLS_; ++j) {
 
191
            if (smb_args[j].token
 
192
                && !strncmp(argv[i], smb_args[j].token, strlen(smb_args[j].token)))
 
193
            {
 
194
                break;
 
195
            }
 
196
        }
 
197
 
 
198
        if (j == SMB_CONF_FILE) {
 
199
            service_file = argv[i] + 8;
 
200
        }
 
201
        i++;
 
202
    }
 
203
 
 
204
    /* Read some options from the Samba config. Can be overridden by
 
205
       the PAM config. */
 
206
    if(lp_load(service_file,True,False,False,True) == False) {
 
207
        _log_err(pamh, LOG_ERR, "Error loading service file %s", service_file);
 
208
    }
 
209
 
 
210
    secrets_init();
 
211
 
 
212
    if (lp_null_passwords()) {
 
213
        set( SMB__NULLOK, ctrl );
 
214
    }
 
215
 
 
216
    /* now parse the rest of the arguments to this module */
 
217
 
 
218
    while (argc-- > 0) {
 
219
        int j;
 
220
 
 
221
        for (j = 0; j < SMB_CTRLS_; ++j) {
 
222
            if (smb_args[j].token
 
223
                && !strncmp(*argv, smb_args[j].token, strlen(smb_args[j].token)))
 
224
            {
 
225
                break;
 
226
            }
 
227
        }
 
228
 
 
229
        if (j >= SMB_CTRLS_) {
 
230
            _log_err(pamh, LOG_ERR, "unrecognized option [%s]", *argv);
 
231
        } else {
 
232
            ctrl &= smb_args[j].mask;   /* for turning things off */
 
233
            ctrl |= smb_args[j].flag;   /* for turning things on  */
 
234
        }
 
235
 
 
236
        ++argv;                         /* step to next argument */
 
237
    }
 
238
 
 
239
    /* auditing is a more sensitive version of debug */
 
240
 
 
241
    if (on( SMB_AUDIT, ctrl )) {
 
242
        set( SMB_DEBUG, ctrl );
 
243
    }
 
244
    /* return the set of flags */
 
245
 
 
246
    return ctrl;
 
247
}
 
248
 
 
249
/* use this to free strings. ESPECIALLY password strings */
 
250
 
 
251
char * _pam_delete( register char *xx )
 
252
{
 
253
    _pam_overwrite( xx );
 
254
    _pam_drop( xx );
 
255
    return NULL;
 
256
}
 
257
 
 
258
void _cleanup( pam_handle_t * pamh, void *x, int error_status )
 
259
{
 
260
    x = _pam_delete( (char *) x );
 
261
}
 
262
 
 
263
/* JHT
 
264
 *
 
265
 * Safe duplication of character strings. "Paranoid"; don't leave
 
266
 * evidence of old token around for later stack analysis.
 
267
 *
 
268
 */
 
269
char * smbpXstrDup( pam_handle_t *pamh, const char *x )
 
270
{
 
271
    register char *newstr = NULL;
 
272
 
 
273
    if (x != NULL) {
 
274
        register int i;
 
275
 
 
276
        for (i = 0; x[i]; ++i); /* length of string */
 
277
        if ((newstr = SMB_MALLOC_ARRAY(char, ++i)) == NULL) {
 
278
            i = 0;
 
279
            _log_err(pamh, LOG_CRIT, "out of memory in smbpXstrDup");
 
280
        } else {
 
281
            while (i-- > 0) {
 
282
                newstr[i] = x[i];
 
283
            }
 
284
        }
 
285
        x = NULL;
 
286
    }
 
287
    return newstr;                      /* return the duplicate or NULL on error */
 
288
}
 
289
 
 
290
/* ************************************************************** *
 
291
 * Useful non-trivial functions                                   *
 
292
 * ************************************************************** */
 
293
 
 
294
void _cleanup_failures( pam_handle_t * pamh, void *fl, int err )
 
295
{
 
296
    int quiet;
 
297
    const char *service = NULL;
 
298
    struct _pam_failed_auth *failure;
 
299
 
 
300
#ifdef PAM_DATA_SILENT
 
301
    quiet = err & PAM_DATA_SILENT;      /* should we log something? */
 
302
#else
 
303
    quiet = 0;
 
304
#endif
 
305
#ifdef PAM_DATA_REPLACE
 
306
    err &= PAM_DATA_REPLACE;    /* are we just replacing data? */
 
307
#endif
 
308
    failure = (struct _pam_failed_auth *) fl;
 
309
 
 
310
    if (failure != NULL) {
 
311
 
 
312
#ifdef PAM_DATA_SILENT
 
313
        if (!quiet && !err) {   /* under advisement from Sun,may go away */
 
314
#else
 
315
        if (!quiet) {   /* under advisement from Sun,may go away */
 
316
#endif
 
317
 
 
318
            /* log the number of authentication failures */
 
319
            if (failure->count != 0) {
 
320
                _pam_get_item( pamh, PAM_SERVICE, &service );
 
321
                _log_err(pamh, LOG_NOTICE
 
322
                          , "%d authentication %s "
 
323
                            "from %s for service %s as %s(%d)"
 
324
                          , failure->count
 
325
                          , failure->count == 1 ? "failure" : "failures"
 
326
                          , failure->agent
 
327
                          , service == NULL ? "**unknown**" : service 
 
328
                          , failure->user, failure->id );
 
329
                if (failure->count > SMB_MAX_RETRIES) {
 
330
                    _log_err(pamh, LOG_ALERT
 
331
                              , "service(%s) ignoring max retries; %d > %d"
 
332
                              , service == NULL ? "**unknown**" : service
 
333
                              , failure->count
 
334
                              , SMB_MAX_RETRIES );
 
335
                }
 
336
            }
 
337
        }
 
338
        _pam_delete( failure->agent );  /* tidy up */
 
339
        _pam_delete( failure->user );   /* tidy up */
 
340
        SAFE_FREE( failure );
 
341
    }
 
342
}
 
343
 
 
344
int _smb_verify_password( pam_handle_t * pamh, struct samu *sampass,
 
345
                          const char *p, unsigned int ctrl )
 
346
{
 
347
    uchar lm_pw[16];
 
348
    uchar nt_pw[16];
 
349
    int retval = PAM_AUTH_ERR;
 
350
    char *data_name;
 
351
    const char *name;
 
352
 
 
353
    if (!sampass)
 
354
        return PAM_ABORT;
 
355
 
 
356
    name = pdb_get_username(sampass);
 
357
 
 
358
#ifdef HAVE_PAM_FAIL_DELAY
 
359
    if (off( SMB_NODELAY, ctrl )) {
 
360
        (void) pam_fail_delay( pamh, 1000000 ); /* 1 sec delay for on failure */
 
361
    }
 
362
#endif
 
363
 
 
364
    if (!pdb_get_nt_passwd(sampass))
 
365
    {
 
366
        _log_err(pamh, LOG_DEBUG, "user %s has null SMB password", name);
 
367
 
 
368
        if (off( SMB__NONULL, ctrl )
 
369
            && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ))
 
370
        { /* this means we've succeeded */
 
371
            return PAM_SUCCESS;
 
372
        } else {
 
373
            const char *service;
 
374
 
 
375
            _pam_get_item( pamh, PAM_SERVICE, &service );
 
376
            _log_err(pamh, LOG_NOTICE, "failed auth request by %s for service %s as %s",
 
377
                      uidtoname(getuid()), service ? service : "**unknown**", name);
 
378
            return PAM_AUTH_ERR;
 
379
        }
 
380
    }
 
381
 
 
382
    data_name = SMB_MALLOC_ARRAY(char, sizeof(FAIL_PREFIX) + strlen( name ));
 
383
    if (data_name == NULL) {
 
384
        _log_err(pamh, LOG_CRIT, "no memory for data-name" );
 
385
        return PAM_AUTH_ERR;
 
386
    }
 
387
    strncpy( data_name, FAIL_PREFIX, sizeof(FAIL_PREFIX) );
 
388
    strncpy( data_name + sizeof(FAIL_PREFIX) - 1, name, strlen( name ) + 1 );
 
389
 
 
390
    /*
 
391
     * The password we were given wasn't an encrypted password, or it
 
392
     * didn't match the one we have.  We encrypt the password now and try
 
393
     * again.
 
394
     */
 
395
 
 
396
    nt_lm_owf_gen(p, nt_pw, lm_pw);
 
397
 
 
398
    /* the moment of truth -- do we agree with the password? */
 
399
 
 
400
    if (!memcmp( nt_pw, pdb_get_nt_passwd(sampass), 16 )) {
 
401
 
 
402
        retval = PAM_SUCCESS;
 
403
        if (data_name) {                /* reset failures */
 
404
            pam_set_data(pamh, data_name, NULL, _cleanup_failures);
 
405
        }
 
406
    } else {
 
407
 
 
408
        const char *service;
 
409
 
 
410
        _pam_get_item( pamh, PAM_SERVICE, &service );
 
411
 
 
412
        if (data_name != NULL) {
 
413
            struct _pam_failed_auth *newauth = NULL;
 
414
            const struct _pam_failed_auth *old = NULL;
 
415
 
 
416
            /* get a failure recorder */
 
417
 
 
418
            newauth = SMB_MALLOC_P( struct _pam_failed_auth );
 
419
 
 
420
            if (newauth != NULL) {
 
421
 
 
422
                /* any previous failures for this user ? */
 
423
                _pam_get_data(pamh, data_name, &old);
 
424
 
 
425
                if (old != NULL) {
 
426
                    newauth->count = old->count + 1;
 
427
                    if (newauth->count >= SMB_MAX_RETRIES) {
 
428
                        retval = PAM_MAXTRIES;
 
429
                    }
 
430
                } else {
 
431
                    _log_err(pamh, LOG_NOTICE,
 
432
                      "failed auth request by %s for service %s as %s",
 
433
                      uidtoname(getuid()),
 
434
                      service ? service : "**unknown**", name);
 
435
                    newauth->count = 1;
 
436
                }
 
437
                if (!sid_to_uid(pdb_get_user_sid(sampass), &(newauth->id))) {
 
438
                    _log_err(pamh, LOG_NOTICE,
 
439
                      "failed auth request by %s for service %s as %s",
 
440
                      uidtoname(getuid()),
 
441
                      service ? service : "**unknown**", name);
 
442
                }               
 
443
                newauth->user = smbpXstrDup( pamh, name );
 
444
                newauth->agent = smbpXstrDup( pamh, uidtoname( getuid() ) );
 
445
                pam_set_data( pamh, data_name, newauth, _cleanup_failures );
 
446
 
 
447
            } else {
 
448
                _log_err(pamh, LOG_CRIT, "no memory for failure recorder" );
 
449
                _log_err(pamh, LOG_NOTICE,
 
450
                      "failed auth request by %s for service %s as %s(%d)",
 
451
                      uidtoname(getuid()),
 
452
                      service ? service : "**unknown**", name);
 
453
            }
 
454
        }
 
455
        _log_err(pamh, LOG_NOTICE,
 
456
                  "failed auth request by %s for service %s as %s(%d)",
 
457
                  uidtoname(getuid()),
 
458
                  service ? service : "**unknown**", name);
 
459
        retval = PAM_AUTH_ERR;
 
460
    }
 
461
 
 
462
    _pam_delete( data_name );
 
463
 
 
464
    return retval;
 
465
}
 
466
 
 
467
 
 
468
/*
 
469
 * _smb_blankpasswd() is a quick check for a blank password
 
470
 *
 
471
 * returns TRUE if user does not have a password
 
472
 * - to avoid prompting for one in such cases (CG)
 
473
 */
 
474
 
 
475
int _smb_blankpasswd( unsigned int ctrl, struct samu *sampass )
 
476
{
 
477
        int retval;
 
478
 
 
479
        /*
 
480
         * This function does not have to be too smart if something goes
 
481
         * wrong, return FALSE and let this case to be treated somewhere
 
482
         * else (CG)
 
483
         */
 
484
 
 
485
        if (on( SMB__NONULL, ctrl ))
 
486
                return 0;               /* will fail but don't let on yet */
 
487
 
 
488
        if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ))
 
489
                return 0;
 
490
 
 
491
        if (pdb_get_nt_passwd(sampass) == NULL)
 
492
                retval = 1;
 
493
        else
 
494
                retval = 0;
 
495
 
 
496
        return retval;
 
497
}
 
498
 
 
499
/*
 
500
 * obtain a password from the user
 
501
 */
 
502
 
 
503
int _smb_read_password( pam_handle_t * pamh, unsigned int ctrl,
 
504
                        const char *comment, const char *prompt1,
 
505
                        const char *prompt2, const char *data_name, char **pass )
 
506
{
 
507
    int authtok_flag;
 
508
    int retval;
 
509
    char *item = NULL;
 
510
    char *token;
 
511
 
 
512
    struct pam_message msg[3], *pmsg[3];
 
513
    struct pam_response *resp;
 
514
    int i, expect;
 
515
 
 
516
 
 
517
    /* make sure nothing inappropriate gets returned */
 
518
 
 
519
    *pass = token = NULL;
 
520
 
 
521
    /* which authentication token are we getting? */
 
522
 
 
523
    authtok_flag = on(SMB__OLD_PASSWD, ctrl) ? PAM_OLDAUTHTOK : PAM_AUTHTOK;
 
524
 
 
525
    /* should we obtain the password from a PAM item ? */
 
526
 
 
527
    if (on(SMB_TRY_FIRST_PASS, ctrl) || on(SMB_USE_FIRST_PASS, ctrl)) {
 
528
        retval = _pam_get_item( pamh, authtok_flag, &item );
 
529
        if (retval != PAM_SUCCESS) {
 
530
            /* very strange. */
 
531
            _log_err(pamh, LOG_ALERT,
 
532
                     "pam_get_item returned error to smb_read_password");
 
533
            return retval;
 
534
        } else if (item != NULL) {      /* we have a password! */
 
535
            *pass = item;
 
536
            item = NULL;
 
537
            return PAM_SUCCESS;
 
538
        } else if (on( SMB_USE_FIRST_PASS, ctrl )) {
 
539
            return PAM_AUTHTOK_RECOVER_ERR;             /* didn't work */
 
540
        } else if (on( SMB_USE_AUTHTOK, ctrl )
 
541
                   && off( SMB__OLD_PASSWD, ctrl ))
 
542
        {
 
543
            return PAM_AUTHTOK_RECOVER_ERR;
 
544
        }
 
545
    }
 
546
 
 
547
    /*
 
548
     * getting here implies we will have to get the password from the
 
549
     * user directly.
 
550
     */
 
551
 
 
552
    /* prepare to converse */
 
553
    if (comment != NULL && off(SMB__QUIET, ctrl)) {
 
554
        pmsg[0] = &msg[0];
 
555
        msg[0].msg_style = PAM_TEXT_INFO;
 
556
        msg[0].msg = CONST_DISCARD(char *, comment);
 
557
        i = 1;
 
558
    } else {
 
559
        i = 0;
 
560
    }
 
561
 
 
562
    pmsg[i] = &msg[i];
 
563
    msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
 
564
    msg[i++].msg = CONST_DISCARD(char *, prompt1);
 
565
 
 
566
    if (prompt2 != NULL) {
 
567
        pmsg[i] = &msg[i];
 
568
        msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
 
569
        msg[i++].msg = CONST_DISCARD(char *, prompt2);
 
570
        expect = 2;
 
571
    } else
 
572
        expect = 1;
 
573
 
 
574
    resp = NULL;
 
575
 
 
576
    retval = converse( pamh, ctrl, i, pmsg, &resp );
 
577
 
 
578
    if (resp != NULL) {
 
579
        int j = comment ? 1 : 0;
 
580
        /* interpret the response */
 
581
 
 
582
        if (retval == PAM_SUCCESS) {    /* a good conversation */
 
583
 
 
584
            token = smbpXstrDup(pamh, resp[j++].resp);
 
585
            if (token != NULL) {
 
586
                if (expect == 2) {
 
587
                    /* verify that password entered correctly */
 
588
                    if (!resp[j].resp || strcmp( token, resp[j].resp )) {
 
589
                        _pam_delete( token );
 
590
                        retval = PAM_AUTHTOK_RECOVER_ERR;
 
591
                        make_remark( pamh, ctrl, PAM_ERROR_MSG
 
592
                                     , MISTYPED_PASS );
 
593
                    }
 
594
                }
 
595
            } else {
 
596
                _log_err(pamh, LOG_NOTICE,
 
597
                         "could not recover authentication token");
 
598
            }
 
599
        }
 
600
 
 
601
        /* tidy up */
 
602
        _pam_drop_reply( resp, expect );
 
603
 
 
604
    } else {
 
605
        retval = (retval == PAM_SUCCESS) ? PAM_AUTHTOK_RECOVER_ERR : retval;
 
606
    }
 
607
 
 
608
    if (retval != PAM_SUCCESS) {
 
609
        if (on( SMB_DEBUG, ctrl ))
 
610
            _log_err(pamh, LOG_DEBUG, "unable to obtain a password");
 
611
        return retval;
 
612
    }
 
613
    /* 'token' is the entered password */
 
614
 
 
615
    if (off( SMB_NOT_SET_PASS, ctrl )) {
 
616
 
 
617
        /* we store this password as an item */
 
618
 
 
619
        retval = pam_set_item( pamh, authtok_flag, (const void *)token );
 
620
        _pam_delete( token );           /* clean it up */
 
621
        if (retval != PAM_SUCCESS
 
622
            || (retval = _pam_get_item( pamh, authtok_flag
 
623
                            ,&item )) != PAM_SUCCESS)
 
624
        {
 
625
            _log_err(pamh, LOG_CRIT, "error manipulating password");
 
626
            return retval;
 
627
        }
 
628
    } else {
 
629
        /*
 
630
         * then store it as data specific to this module. pam_end()
 
631
         * will arrange to clean it up.
 
632
         */
 
633
 
 
634
        retval = pam_set_data( pamh, data_name, (void *) token, _cleanup );
 
635
        if (retval != PAM_SUCCESS
 
636
            || (retval = _pam_get_data( pamh, data_name, &item ))
 
637
                             != PAM_SUCCESS)
 
638
        {
 
639
            _log_err(pamh, LOG_CRIT, "error manipulating password data [%s]",
 
640
                     pam_strerror( pamh, retval ));
 
641
            _pam_delete( token );
 
642
            item = NULL;
 
643
            return retval;
 
644
        }
 
645
        token = NULL;                   /* break link to password */
 
646
    }
 
647
 
 
648
    *pass = item;
 
649
    item = NULL;                        /* break link to password */
 
650
 
 
651
    return PAM_SUCCESS;
 
652
}
 
653
 
 
654
int _pam_smb_approve_pass(pam_handle_t * pamh,
 
655
                unsigned int ctrl,
 
656
                const char *pass_old,
 
657
                const char *pass_new )
 
658
{
 
659
 
 
660
    /* Further checks should be handled through module stacking. -SRL */
 
661
    if (pass_new == NULL || (pass_old && !strcmp( pass_old, pass_new )))
 
662
    {
 
663
        if (on(SMB_DEBUG, ctrl)) {
 
664
            _log_err(pamh, LOG_DEBUG,
 
665
                     "passwd: bad authentication token (null or unchanged)");
 
666
        }
 
667
        make_remark( pamh, ctrl, PAM_ERROR_MSG, pass_new == NULL ?
 
668
                                "No password supplied" : "Password unchanged" );
 
669
        return PAM_AUTHTOK_ERR;
 
670
    }
 
671
 
 
672
    return PAM_SUCCESS;
 
673
}
 
674
 
 
675
/*
 
676
 * Work around the pam API that has functions with void ** as parameters
 
677
 * These lead to strict aliasing warnings with gcc.
 
678
 */
 
679
int _pam_get_item(const pam_handle_t *pamh,
 
680
                  int item_type,
 
681
                  const void *_item)
 
682
{
 
683
        const void **item = (const void **)_item;
 
684
        return pam_get_item(pamh, item_type, item);
 
685
}
 
686
 
 
687
int _pam_get_data(const pam_handle_t *pamh,
 
688
                  const char *module_data_name,
 
689
                  const void *_data)
 
690
{
 
691
        const void **data = (const void **)_data;
 
692
        return pam_get_data(pamh, module_data_name, data);
 
693
}