~ubuntu-branches/ubuntu/breezy/pam/breezy

« back to all changes in this revision

Viewing changes to Linux-PAM/modules/pam_stress/pam_stress.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2004-06-28 14:28:08 UTC
  • mfrom: (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20040628142808-adikk7vtfg3pzcjw
Tags: 0.76-22
* Add uploaders
* Document location of repository
* Fix options containing arguments in pam_unix, Closes: #254904

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* pam_stress module */
 
2
 
 
3
/* $Id: pam_stress.c,v 1.1 2001/04/29 04:17:34 hartmans Exp $
 
4
 *
 
5
 * created by Andrew Morgan <morgan@linux.kernel.org> 1996/3/12
 
6
 */
 
7
 
 
8
#include <security/_pam_aconf.h>
 
9
 
 
10
#include <stdlib.h>
 
11
#include <stdio.h>
 
12
 
 
13
#define __USE_BSD
 
14
#include <syslog.h>
 
15
 
 
16
#include <stdarg.h>
 
17
#include <string.h>
 
18
#include <unistd.h>
 
19
 
 
20
/*
 
21
 * here, we make definitions for the externally accessible functions
 
22
 * in this file (these definitions are required for static modules
 
23
 * but strongly encouraged generally) they are used to instruct the
 
24
 * modules include file to define their prototypes.
 
25
 */
 
26
 
 
27
#define PAM_SM_AUTH
 
28
#define PAM_SM_ACCOUNT
 
29
#define PAM_SM_SESSION
 
30
#define PAM_SM_PASSWORD
 
31
 
 
32
#include <security/pam_modules.h>
 
33
#include <security/_pam_macros.h>
 
34
 
 
35
static char *_strdup(const char *x)
 
36
{
 
37
     char *new;
 
38
     new = malloc(strlen(x)+1);
 
39
     strcpy(new,x);
 
40
     return new;
 
41
}
 
42
 
 
43
/* log errors */
 
44
 
 
45
static void _pam_log(int err, const char *format, ...)
 
46
{
 
47
    va_list args;
 
48
 
 
49
    va_start(args, format);
 
50
    openlog("PAM-stress", LOG_CONS|LOG_PID, LOG_AUTH);
 
51
    vsyslog(err, format, args);
 
52
    va_end(args);
 
53
    closelog();
 
54
}
 
55
 
 
56
/* ---------- */
 
57
 
 
58
/* an internal function to turn all possible test arguments into bits
 
59
   of a ctrl number */
 
60
 
 
61
/* generic options */
 
62
 
 
63
#define PAM_ST_DEBUG         01
 
64
#define PAM_ST_NO_WARN       02
 
65
#define PAM_ST_USE_PASS1     04
 
66
#define PAM_ST_TRY_PASS1    010
 
67
#define PAM_ST_ROOTOK       020
 
68
 
 
69
/* simulation options */
 
70
 
 
71
#define PAM_ST_EXPIRED       040
 
72
#define PAM_ST_FAIL_1       0100
 
73
#define PAM_ST_FAIL_2       0200
 
74
#define PAM_ST_PRELIM       0400
 
75
#define PAM_ST_REQUIRE_PWD 01000
 
76
 
 
77
/* some syslogging */
 
78
 
 
79
static void _pam_report(int ctrl, const char *name, int flags,
 
80
                 int argc, const char **argv)
 
81
{
 
82
     if (ctrl & PAM_ST_DEBUG) {
 
83
          _pam_log(LOG_DEBUG, "CALLED: %s", name);
 
84
          _pam_log(LOG_DEBUG, "FLAGS : 0%o%s", flags,
 
85
                   (flags & PAM_SILENT) ? " (silent)":"");
 
86
          _pam_log(LOG_DEBUG, "CTRL  = 0%o",ctrl);
 
87
          _pam_log(LOG_DEBUG, "ARGV  :");
 
88
          while (argc--) {
 
89
               _pam_log(LOG_DEBUG, " \"%s\"", *argv++);
 
90
          }
 
91
     }
 
92
}
 
93
 
 
94
static int _pam_parse(int argc, const char **argv)
 
95
{
 
96
     int ctrl=0;
 
97
 
 
98
     /* step through arguments */
 
99
     for (ctrl=0; argc-- > 0; ++argv) {
 
100
 
 
101
          /* generic options */
 
102
 
 
103
          if (!strcmp(*argv,"debug"))
 
104
               ctrl |= PAM_ST_DEBUG;
 
105
          else if (!strcmp(*argv,"no_warn"))
 
106
               ctrl |= PAM_ST_NO_WARN;
 
107
          else if (!strcmp(*argv,"use_first_pass"))
 
108
               ctrl |= PAM_ST_USE_PASS1;
 
109
          else if (!strcmp(*argv,"try_first_pass"))
 
110
               ctrl |= PAM_ST_TRY_PASS1;
 
111
          else if (!strcmp(*argv,"rootok"))
 
112
               ctrl |= PAM_ST_ROOTOK;
 
113
 
 
114
          /* simulation options */
 
115
 
 
116
          else if (!strcmp(*argv,"expired"))   /* signal password needs
 
117
                                                  renewal */
 
118
               ctrl |= PAM_ST_EXPIRED;
 
119
          else if (!strcmp(*argv,"fail_1"))    /* instruct fn 1 to fail */
 
120
               ctrl |= PAM_ST_FAIL_1;
 
121
          else if (!strcmp(*argv,"fail_2"))    /* instruct fn 2 to fail */
 
122
               ctrl |= PAM_ST_FAIL_2;
 
123
          else if (!strcmp(*argv,"prelim"))    /* instruct pam_sm_setcred
 
124
                                                  to fail on first call */
 
125
               ctrl |= PAM_ST_PRELIM;
 
126
          else if (!strcmp(*argv,"required"))  /* module is fussy about the
 
127
                                                  user being authenticated */
 
128
               ctrl |= PAM_ST_REQUIRE_PWD;
 
129
 
 
130
          else {
 
131
               _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
 
132
          }
 
133
     }
 
134
 
 
135
     return ctrl;
 
136
}
 
137
 
 
138
static int converse(pam_handle_t *pamh, int nargs
 
139
                    , struct pam_message **message
 
140
                    , struct pam_response **response)
 
141
{
 
142
     int retval;
 
143
     struct pam_conv *conv;
 
144
 
 
145
     if ((retval = pam_get_item(pamh,PAM_CONV,(const void **)&conv))
 
146
         == PAM_SUCCESS) {
 
147
          retval = conv->conv(nargs, (const struct pam_message **) message
 
148
                              , response, conv->appdata_ptr);
 
149
          if (retval != PAM_SUCCESS) {
 
150
               _pam_log(LOG_ERR,"(pam_stress) converse returned %d",retval);
 
151
               _pam_log(LOG_ERR,"that is: %s",pam_strerror(pamh, retval));
 
152
          }
 
153
     } else {
 
154
          _pam_log(LOG_ERR,"(pam_stress) converse failed to get pam_conv");
 
155
     }
 
156
 
 
157
     return retval;
 
158
}
 
159
 
 
160
/* authentication management functions */
 
161
 
 
162
static int stress_get_password(pam_handle_t *pamh, int flags
 
163
                               , int ctrl, char **password)
 
164
{
 
165
     char *pass;
 
166
 
 
167
     if ( (ctrl & (PAM_ST_TRY_PASS1|PAM_ST_USE_PASS1))
 
168
         && (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass)
 
169
             == PAM_SUCCESS)
 
170
         && (pass != NULL) ) {
 
171
          pass = _strdup(pass);
 
172
     } else if ((ctrl & PAM_ST_USE_PASS1)) {
 
173
          _pam_log(LOG_WARNING, "pam_stress: no forwarded password");
 
174
          return PAM_PERM_DENIED;
 
175
     } else {                                /* we will have to get one */
 
176
          struct pam_message msg[1],*pmsg[1];
 
177
          struct pam_response *resp;
 
178
          int retval;
 
179
 
 
180
          /* set up conversation call */
 
181
 
 
182
          pmsg[0] = &msg[0];
 
183
          msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
 
184
          msg[0].msg = "STRESS Password: ";
 
185
          resp = NULL;
 
186
 
 
187
          if ((retval = converse(pamh,1,pmsg,&resp)) != PAM_SUCCESS) {
 
188
               return retval;
 
189
          }
 
190
 
 
191
          if (resp) {
 
192
               if ((resp[0].resp == NULL) && (ctrl & PAM_ST_DEBUG)) {
 
193
                    _pam_log(LOG_DEBUG,
 
194
                             "pam_sm_authenticate: NULL authtok given");
 
195
               }
 
196
               if ((flags & PAM_DISALLOW_NULL_AUTHTOK)
 
197
                   && resp[0].resp == NULL) {
 
198
                    free(resp);
 
199
                    return PAM_AUTH_ERR;
 
200
               }
 
201
 
 
202
               pass = resp[0].resp;          /* remember this! */
 
203
 
 
204
               resp[0].resp = NULL;
 
205
          } else if (ctrl & PAM_ST_DEBUG) {
 
206
               _pam_log(LOG_DEBUG,"pam_sm_authenticate: no error reported");
 
207
               _pam_log(LOG_DEBUG,"getting password, but NULL returned!?");
 
208
               return PAM_CONV_ERR;
 
209
          }
 
210
          free(resp);
 
211
     }
 
212
 
 
213
     *password = pass;             /* this *MUST* be free()'d by this module */
 
214
 
 
215
     return PAM_SUCCESS;
 
216
}
 
217
 
 
218
/* function to clean up data items */
 
219
 
 
220
static void wipe_up(pam_handle_t *pamh, void *data, int error)
 
221
{
 
222
     free(data);
 
223
}
 
224
 
 
225
PAM_EXTERN
 
226
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
 
227
                        int argc, const char **argv)
 
228
{
 
229
     const char *username;
 
230
     int retval=PAM_SUCCESS;
 
231
     char *pass;
 
232
     int ctrl;
 
233
 
 
234
     D(("called."));
 
235
 
 
236
     ctrl = _pam_parse(argc,argv);
 
237
     _pam_report(ctrl, "pam_sm_authenticate", flags, argc, argv);
 
238
 
 
239
     /* try to get the username */
 
240
 
 
241
     retval = pam_get_user(pamh, &username, "username: ");
 
242
     if ((ctrl & PAM_ST_DEBUG) && (retval == PAM_SUCCESS)) {
 
243
          _pam_log(LOG_DEBUG, "pam_sm_authenticate: username = %s", username);
 
244
     } else if (retval != PAM_SUCCESS) {
 
245
          _pam_log(LOG_WARNING, "pam_sm_authenticate: failed to get username");
 
246
          return retval;
 
247
     }
 
248
 
 
249
     /* now get the password */
 
250
 
 
251
     retval = stress_get_password(pamh,flags,ctrl,&pass);
 
252
     if (retval != PAM_SUCCESS) {
 
253
          _pam_log(LOG_WARNING, "pam_sm_authenticate: "
 
254
                   "failed to get a password");
 
255
          return retval;
 
256
     }
 
257
 
 
258
     /* try to set password item */
 
259
 
 
260
     retval = pam_set_item(pamh,PAM_AUTHTOK,pass);
 
261
     if (retval != PAM_SUCCESS) {
 
262
          _pam_log(LOG_WARNING, "pam_sm_authenticate: "
 
263
                   "failed to store new password");
 
264
          _pam_overwrite(pass);
 
265
          free(pass);
 
266
          return retval;
 
267
     }
 
268
 
 
269
     /* clean up local copy of password */
 
270
 
 
271
     _pam_overwrite(pass);
 
272
     free(pass);
 
273
     pass = NULL;
 
274
 
 
275
     /* if we are debugging then we print the password */
 
276
 
 
277
     if (ctrl & PAM_ST_DEBUG) {
 
278
          (void) pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass);
 
279
          _pam_log(LOG_DEBUG,
 
280
                   "pam_st_authenticate: password entered is: [%s]\n",pass);
 
281
          pass = NULL;
 
282
     }
 
283
 
 
284
     /* if we signal a fail for this function then fail */
 
285
 
 
286
     if ((ctrl & PAM_ST_FAIL_1) && retval == PAM_SUCCESS)
 
287
          return PAM_PERM_DENIED;
 
288
 
 
289
     return retval;
 
290
}
 
291
 
 
292
PAM_EXTERN
 
293
int pam_sm_setcred(pam_handle_t *pamh, int flags,
 
294
                   int argc, const char **argv)
 
295
{
 
296
     int ctrl = _pam_parse(argc,argv);
 
297
 
 
298
     D(("called. [post parsing]"));
 
299
 
 
300
     _pam_report(ctrl, "pam_sm_setcred", flags, argc, argv);
 
301
 
 
302
     if (ctrl & PAM_ST_FAIL_2)
 
303
          return PAM_CRED_ERR;
 
304
 
 
305
     return PAM_SUCCESS;
 
306
}
 
307
 
 
308
/* account management functions */
 
309
 
 
310
PAM_EXTERN
 
311
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
 
312
                     int argc, const char **argv)
 
313
{
 
314
     int ctrl = _pam_parse(argc,argv);
 
315
 
 
316
     D(("called. [post parsing]"));
 
317
 
 
318
     _pam_report(ctrl,"pam_sm_acct_mgmt", flags, argc, argv);
 
319
 
 
320
     if (ctrl & PAM_ST_FAIL_1)
 
321
          return PAM_PERM_DENIED;
 
322
     else if (ctrl & PAM_ST_EXPIRED) {
 
323
          void *text = malloc(sizeof("yes")+1);
 
324
          strcpy(text,"yes");
 
325
          pam_set_data(pamh,"stress_new_pwd",text,wipe_up);
 
326
          if (ctrl & PAM_ST_DEBUG) {
 
327
               _pam_log(LOG_DEBUG,"pam_sm_acct_mgmt: need a new password");
 
328
          }
 
329
          return PAM_NEW_AUTHTOK_REQD;
 
330
     }
 
331
 
 
332
     return PAM_SUCCESS;
 
333
}
 
334
 
 
335
PAM_EXTERN
 
336
int pam_sm_open_session(pam_handle_t *pamh, int flags,
 
337
                        int argc, const char **argv)
 
338
{
 
339
     char *username,*service;
 
340
     int ctrl = _pam_parse(argc,argv);
 
341
 
 
342
     D(("called. [post parsing]"));
 
343
 
 
344
     _pam_report(ctrl,"pam_sm_open_session", flags, argc, argv);
 
345
 
 
346
     if ((pam_get_item(pamh, PAM_USER, (const void **) &username)
 
347
          != PAM_SUCCESS)
 
348
         || (pam_get_item(pamh, PAM_SERVICE, (const void **) &service)
 
349
             != PAM_SUCCESS)) {
 
350
          _pam_log(LOG_WARNING,"pam_sm_open_session: for whom?");
 
351
          return PAM_SESSION_ERR;
 
352
     }
 
353
 
 
354
     _pam_log(LOG_NOTICE,"pam_stress: opened [%s] session for user [%s]"
 
355
              , service, username);
 
356
 
 
357
     if (ctrl & PAM_ST_FAIL_1)
 
358
          return PAM_SESSION_ERR;
 
359
 
 
360
     return PAM_SUCCESS;
 
361
}
 
362
 
 
363
PAM_EXTERN
 
364
int pam_sm_close_session(pam_handle_t *pamh, int flags,
 
365
                         int argc, const char **argv)
 
366
{
 
367
     const char *username,*service;
 
368
     int ctrl = _pam_parse(argc,argv);
 
369
 
 
370
     D(("called. [post parsing]"));
 
371
 
 
372
     _pam_report(ctrl,"pam_sm_close_session", flags, argc, argv);
 
373
 
 
374
     if ((pam_get_item(pamh, PAM_USER, (const void **)&username)
 
375
          != PAM_SUCCESS)
 
376
         || (pam_get_item(pamh, PAM_SERVICE, (const void **)&service)
 
377
             != PAM_SUCCESS)) {
 
378
          _pam_log(LOG_WARNING,"pam_sm_close_session: for whom?");
 
379
          return PAM_SESSION_ERR;
 
380
     }
 
381
 
 
382
     _pam_log(LOG_NOTICE,"pam_stress: closed [%s] session for user [%s]"
 
383
              , service, username);
 
384
 
 
385
     if (ctrl & PAM_ST_FAIL_2)
 
386
          return PAM_SESSION_ERR;
 
387
 
 
388
     return PAM_SUCCESS;
 
389
}
 
390
 
 
391
PAM_EXTERN
 
392
int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
 
393
                     int argc, const char **argv)
 
394
{
 
395
     int retval;
 
396
     int ctrl = _pam_parse(argc,argv);
 
397
 
 
398
     D(("called. [post parsing]"));
 
399
 
 
400
     _pam_report(ctrl,"pam_sm_chauthtok", flags, argc, argv);
 
401
 
 
402
     /* this function should be called twice by the Linux-PAM library */
 
403
 
 
404
     if (flags & PAM_PRELIM_CHECK) {           /* first call */
 
405
          if (ctrl & PAM_ST_DEBUG) {
 
406
               _pam_log(LOG_DEBUG,"pam_sm_chauthtok: prelim check");
 
407
          }
 
408
          if (ctrl & PAM_ST_PRELIM)
 
409
               return PAM_TRY_AGAIN;
 
410
 
 
411
          return PAM_SUCCESS;
 
412
     } else if (flags & PAM_UPDATE_AUTHTOK) {  /* second call */
 
413
          struct pam_message msg[3],*pmsg[3];
 
414
          struct pam_response *resp;
 
415
          const char *text;
 
416
          char *txt=NULL;
 
417
          int i;
 
418
 
 
419
          if (ctrl & PAM_ST_DEBUG) {
 
420
               _pam_log(LOG_DEBUG,"pam_sm_chauthtok: alter password");
 
421
          }
 
422
 
 
423
          if (ctrl & PAM_ST_FAIL_1)
 
424
               return PAM_AUTHTOK_LOCK_BUSY;
 
425
 
 
426
          if ( !(ctrl && PAM_ST_EXPIRED)
 
427
               && (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
 
428
               && (pam_get_data(pamh,"stress_new_pwd",(const void **)&text)
 
429
                      != PAM_SUCCESS || strcmp(text,"yes"))) {
 
430
               return PAM_SUCCESS;          /* the token has not expired */
 
431
          }
 
432
 
 
433
          /* the password should be changed */
 
434
 
 
435
          if ((ctrl & PAM_ST_REQUIRE_PWD)
 
436
              && !(getuid() == 0 && (ctrl & PAM_ST_ROOTOK))
 
437
               ) {                       /* first get old one? */
 
438
               char *pass;
 
439
 
 
440
               if (ctrl & PAM_ST_DEBUG) {
 
441
                    _pam_log(LOG_DEBUG
 
442
                             ,"pam_sm_chauthtok: getting old password");
 
443
               }
 
444
               retval = stress_get_password(pamh,flags,ctrl,&pass);
 
445
               if (retval != PAM_SUCCESS) {
 
446
                    _pam_log(LOG_DEBUG
 
447
                             ,"pam_sm_chauthtok: no password obtained");
 
448
                    return retval;
 
449
               }
 
450
               retval = pam_set_item(pamh, PAM_OLDAUTHTOK, pass);
 
451
               if (retval != PAM_SUCCESS) {
 
452
                    _pam_log(LOG_DEBUG
 
453
                             ,"pam_sm_chauthtok: could not set OLDAUTHTOK");
 
454
                    _pam_overwrite(pass);
 
455
                    free(pass);
 
456
                    return retval;
 
457
               }
 
458
               _pam_overwrite(pass);
 
459
               free(pass);
 
460
          }
 
461
 
 
462
          /* set up for conversation */
 
463
 
 
464
          if (!(flags & PAM_SILENT)) {
 
465
               char *username;
 
466
 
 
467
               if ( pam_get_item(pamh, PAM_USER, (const void **)&username)
 
468
                    || username == NULL ) {
 
469
                    _pam_log(LOG_ERR,"no username set");
 
470
                    return PAM_USER_UNKNOWN;
 
471
               }
 
472
               pmsg[0] = &msg[0];
 
473
               msg[0].msg_style = PAM_TEXT_INFO;
 
474
#define _LOCAL_STRESS_COMMENT "Changing STRESS password for "
 
475
               txt = (char *) malloc(sizeof(_LOCAL_STRESS_COMMENT)
 
476
                                     +strlen(username)+1);
 
477
               strcpy(txt, _LOCAL_STRESS_COMMENT);
 
478
#undef _LOCAL_STRESS_COMMENT
 
479
               strcat(txt, username);
 
480
               msg[0].msg = txt;
 
481
               i = 1;
 
482
          } else {
 
483
               i = 0;
 
484
          }
 
485
 
 
486
          pmsg[i] = &msg[i];
 
487
          msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
 
488
          msg[i++].msg = "Enter new STRESS password: ";
 
489
          pmsg[i] = &msg[i];
 
490
          msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
 
491
          msg[i++].msg = "Retype new STRESS password: ";
 
492
          resp = NULL;
 
493
 
 
494
          retval = converse(pamh,i,pmsg,&resp);
 
495
          if (txt) {
 
496
               free(txt);
 
497
               txt = NULL;               /* clean up */
 
498
          }
 
499
          if (retval != PAM_SUCCESS) {
 
500
               return retval;
 
501
          }
 
502
 
 
503
          if (resp == NULL) {
 
504
               _pam_log(LOG_ERR, "pam_sm_chauthtok: no response from conv");
 
505
               return PAM_CONV_ERR;
 
506
          }
 
507
 
 
508
          /* store the password */
 
509
 
 
510
          if (resp[i-2].resp && resp[i-1].resp) {
 
511
               if (strcmp(resp[i-2].resp,resp[i-1].resp)) {
 
512
                    /* passwords are not the same; forget and return error */
 
513
 
 
514
                    _pam_drop_reply(resp, i);
 
515
 
 
516
                    if (!(flags & PAM_SILENT) && !(ctrl & PAM_ST_NO_WARN)) {
 
517
                         pmsg[0] = &msg[0];
 
518
                         msg[0].msg_style = PAM_ERROR_MSG;
 
519
                         msg[0].msg = "Verification mis-typed; "
 
520
                              "password unchaged";
 
521
                         resp = NULL;
 
522
                         (void) converse(pamh,1,pmsg,&resp);
 
523
                         if (resp) {
 
524
                             _pam_drop_reply(resp, 1);
 
525
                         }
 
526
                    }
 
527
                    return PAM_AUTHTOK_ERR;
 
528
               }
 
529
 
 
530
               if (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&text)
 
531
                   == PAM_SUCCESS) {
 
532
                    (void) pam_set_item(pamh,PAM_OLDAUTHTOK,text);
 
533
                    text = NULL;
 
534
               }
 
535
               (void) pam_set_item(pamh,PAM_AUTHTOK,resp[0].resp);
 
536
          } else {
 
537
               _pam_log(LOG_DEBUG,"pam_sm_chauthtok: problem with resp");
 
538
               retval = PAM_SYSTEM_ERR;
 
539
          }
 
540
 
 
541
          _pam_drop_reply(resp, i);      /* clean up the passwords */
 
542
     } else {
 
543
          _pam_log(LOG_ERR,"pam_sm_chauthtok: this must be a Linux-PAM error");
 
544
          return PAM_SYSTEM_ERR;
 
545
     }
 
546
 
 
547
     return retval;
 
548
}
 
549
 
 
550
 
 
551
#ifdef PAM_STATIC
 
552
 
 
553
/* static module data */
 
554
 
 
555
struct pam_module _pam_stress_modstruct = {
 
556
    "pam_stress",
 
557
    pam_sm_authenticate,
 
558
    pam_sm_setcred,
 
559
    pam_sm_acct_mgmt,
 
560
    pam_sm_open_session,
 
561
    pam_sm_close_session,
 
562
    pam_sm_chauthtok
 
563
};
 
564
 
 
565
#endif