1
/* pam_stress module */
3
/* $Id: pam_stress.c,v 1.1 2001/04/29 04:17:34 hartmans Exp $
5
* created by Andrew Morgan <morgan@linux.kernel.org> 1996/3/12
8
#include <security/_pam_aconf.h>
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.
28
#define PAM_SM_ACCOUNT
29
#define PAM_SM_SESSION
30
#define PAM_SM_PASSWORD
32
#include <security/pam_modules.h>
33
#include <security/_pam_macros.h>
35
static char *_strdup(const char *x)
38
new = malloc(strlen(x)+1);
45
static void _pam_log(int err, const char *format, ...)
49
va_start(args, format);
50
openlog("PAM-stress", LOG_CONS|LOG_PID, LOG_AUTH);
51
vsyslog(err, format, args);
58
/* an internal function to turn all possible test arguments into bits
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
69
/* simulation options */
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
79
static void _pam_report(int ctrl, const char *name, int flags,
80
int argc, const char **argv)
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 :");
89
_pam_log(LOG_DEBUG, " \"%s\"", *argv++);
94
static int _pam_parse(int argc, const char **argv)
98
/* step through arguments */
99
for (ctrl=0; argc-- > 0; ++argv) {
101
/* generic options */
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;
114
/* simulation options */
116
else if (!strcmp(*argv,"expired")) /* signal password needs
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;
131
_pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
138
static int converse(pam_handle_t *pamh, int nargs
139
, struct pam_message **message
140
, struct pam_response **response)
143
struct pam_conv *conv;
145
if ((retval = pam_get_item(pamh,PAM_CONV,(const void **)&conv))
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));
154
_pam_log(LOG_ERR,"(pam_stress) converse failed to get pam_conv");
160
/* authentication management functions */
162
static int stress_get_password(pam_handle_t *pamh, int flags
163
, int ctrl, char **password)
167
if ( (ctrl & (PAM_ST_TRY_PASS1|PAM_ST_USE_PASS1))
168
&& (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass)
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;
180
/* set up conversation call */
183
msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
184
msg[0].msg = "STRESS Password: ";
187
if ((retval = converse(pamh,1,pmsg,&resp)) != PAM_SUCCESS) {
192
if ((resp[0].resp == NULL) && (ctrl & PAM_ST_DEBUG)) {
194
"pam_sm_authenticate: NULL authtok given");
196
if ((flags & PAM_DISALLOW_NULL_AUTHTOK)
197
&& resp[0].resp == NULL) {
202
pass = resp[0].resp; /* remember this! */
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!?");
213
*password = pass; /* this *MUST* be free()'d by this module */
218
/* function to clean up data items */
220
static void wipe_up(pam_handle_t *pamh, void *data, int error)
226
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
227
int argc, const char **argv)
229
const char *username;
230
int retval=PAM_SUCCESS;
236
ctrl = _pam_parse(argc,argv);
237
_pam_report(ctrl, "pam_sm_authenticate", flags, argc, argv);
239
/* try to get the username */
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");
249
/* now get the password */
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");
258
/* try to set password item */
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);
269
/* clean up local copy of password */
271
_pam_overwrite(pass);
275
/* if we are debugging then we print the password */
277
if (ctrl & PAM_ST_DEBUG) {
278
(void) pam_get_item(pamh,PAM_AUTHTOK,(const void **)&pass);
280
"pam_st_authenticate: password entered is: [%s]\n",pass);
284
/* if we signal a fail for this function then fail */
286
if ((ctrl & PAM_ST_FAIL_1) && retval == PAM_SUCCESS)
287
return PAM_PERM_DENIED;
293
int pam_sm_setcred(pam_handle_t *pamh, int flags,
294
int argc, const char **argv)
296
int ctrl = _pam_parse(argc,argv);
298
D(("called. [post parsing]"));
300
_pam_report(ctrl, "pam_sm_setcred", flags, argc, argv);
302
if (ctrl & PAM_ST_FAIL_2)
308
/* account management functions */
311
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
312
int argc, const char **argv)
314
int ctrl = _pam_parse(argc,argv);
316
D(("called. [post parsing]"));
318
_pam_report(ctrl,"pam_sm_acct_mgmt", flags, argc, argv);
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);
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");
329
return PAM_NEW_AUTHTOK_REQD;
336
int pam_sm_open_session(pam_handle_t *pamh, int flags,
337
int argc, const char **argv)
339
char *username,*service;
340
int ctrl = _pam_parse(argc,argv);
342
D(("called. [post parsing]"));
344
_pam_report(ctrl,"pam_sm_open_session", flags, argc, argv);
346
if ((pam_get_item(pamh, PAM_USER, (const void **) &username)
348
|| (pam_get_item(pamh, PAM_SERVICE, (const void **) &service)
350
_pam_log(LOG_WARNING,"pam_sm_open_session: for whom?");
351
return PAM_SESSION_ERR;
354
_pam_log(LOG_NOTICE,"pam_stress: opened [%s] session for user [%s]"
355
, service, username);
357
if (ctrl & PAM_ST_FAIL_1)
358
return PAM_SESSION_ERR;
364
int pam_sm_close_session(pam_handle_t *pamh, int flags,
365
int argc, const char **argv)
367
const char *username,*service;
368
int ctrl = _pam_parse(argc,argv);
370
D(("called. [post parsing]"));
372
_pam_report(ctrl,"pam_sm_close_session", flags, argc, argv);
374
if ((pam_get_item(pamh, PAM_USER, (const void **)&username)
376
|| (pam_get_item(pamh, PAM_SERVICE, (const void **)&service)
378
_pam_log(LOG_WARNING,"pam_sm_close_session: for whom?");
379
return PAM_SESSION_ERR;
382
_pam_log(LOG_NOTICE,"pam_stress: closed [%s] session for user [%s]"
383
, service, username);
385
if (ctrl & PAM_ST_FAIL_2)
386
return PAM_SESSION_ERR;
392
int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
393
int argc, const char **argv)
396
int ctrl = _pam_parse(argc,argv);
398
D(("called. [post parsing]"));
400
_pam_report(ctrl,"pam_sm_chauthtok", flags, argc, argv);
402
/* this function should be called twice by the Linux-PAM library */
404
if (flags & PAM_PRELIM_CHECK) { /* first call */
405
if (ctrl & PAM_ST_DEBUG) {
406
_pam_log(LOG_DEBUG,"pam_sm_chauthtok: prelim check");
408
if (ctrl & PAM_ST_PRELIM)
409
return PAM_TRY_AGAIN;
412
} else if (flags & PAM_UPDATE_AUTHTOK) { /* second call */
413
struct pam_message msg[3],*pmsg[3];
414
struct pam_response *resp;
419
if (ctrl & PAM_ST_DEBUG) {
420
_pam_log(LOG_DEBUG,"pam_sm_chauthtok: alter password");
423
if (ctrl & PAM_ST_FAIL_1)
424
return PAM_AUTHTOK_LOCK_BUSY;
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 */
433
/* the password should be changed */
435
if ((ctrl & PAM_ST_REQUIRE_PWD)
436
&& !(getuid() == 0 && (ctrl & PAM_ST_ROOTOK))
437
) { /* first get old one? */
440
if (ctrl & PAM_ST_DEBUG) {
442
,"pam_sm_chauthtok: getting old password");
444
retval = stress_get_password(pamh,flags,ctrl,&pass);
445
if (retval != PAM_SUCCESS) {
447
,"pam_sm_chauthtok: no password obtained");
450
retval = pam_set_item(pamh, PAM_OLDAUTHTOK, pass);
451
if (retval != PAM_SUCCESS) {
453
,"pam_sm_chauthtok: could not set OLDAUTHTOK");
454
_pam_overwrite(pass);
458
_pam_overwrite(pass);
462
/* set up for conversation */
464
if (!(flags & PAM_SILENT)) {
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;
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);
487
msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
488
msg[i++].msg = "Enter new STRESS password: ";
490
msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
491
msg[i++].msg = "Retype new STRESS password: ";
494
retval = converse(pamh,i,pmsg,&resp);
497
txt = NULL; /* clean up */
499
if (retval != PAM_SUCCESS) {
504
_pam_log(LOG_ERR, "pam_sm_chauthtok: no response from conv");
508
/* store the password */
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 */
514
_pam_drop_reply(resp, i);
516
if (!(flags & PAM_SILENT) && !(ctrl & PAM_ST_NO_WARN)) {
518
msg[0].msg_style = PAM_ERROR_MSG;
519
msg[0].msg = "Verification mis-typed; "
522
(void) converse(pamh,1,pmsg,&resp);
524
_pam_drop_reply(resp, 1);
527
return PAM_AUTHTOK_ERR;
530
if (pam_get_item(pamh,PAM_AUTHTOK,(const void **)&text)
532
(void) pam_set_item(pamh,PAM_OLDAUTHTOK,text);
535
(void) pam_set_item(pamh,PAM_AUTHTOK,resp[0].resp);
537
_pam_log(LOG_DEBUG,"pam_sm_chauthtok: problem with resp");
538
retval = PAM_SYSTEM_ERR;
541
_pam_drop_reply(resp, i); /* clean up the passwords */
543
_pam_log(LOG_ERR,"pam_sm_chauthtok: this must be a Linux-PAM error");
544
return PAM_SYSTEM_ERR;
553
/* static module data */
555
struct pam_module _pam_stress_modstruct = {
561
pam_sm_close_session,