4 * created by Andrew Morgan <morgan@linux.kernel.org> 1996/3/12
19 * here, we make definitions for the externally accessible functions
20 * in this file (these definitions are required for static modules
21 * but strongly encouraged generally) they are used to instruct the
22 * modules include file to define their prototypes.
26 #define PAM_SM_ACCOUNT
27 #define PAM_SM_SESSION
28 #define PAM_SM_PASSWORD
30 #include <security/pam_modules.h>
31 #include <security/_pam_macros.h>
32 #include <security/pam_ext.h>
36 /* an internal function to turn all possible test arguments into bits
41 #define PAM_ST_DEBUG 01
42 #define PAM_ST_NO_WARN 02
43 #define PAM_ST_USE_PASS1 04
44 #define PAM_ST_TRY_PASS1 010
45 #define PAM_ST_ROOTOK 020
47 /* simulation options */
49 #define PAM_ST_EXPIRED 040
50 #define PAM_ST_FAIL_1 0100
51 #define PAM_ST_FAIL_2 0200
52 #define PAM_ST_PRELIM 0400
53 #define PAM_ST_REQUIRE_PWD 01000
58 _pam_report (const pam_handle_t *pamh, int ctrl, const char *name,
59 int flags, int argc, const char **argv)
61 if (ctrl & PAM_ST_DEBUG) {
62 pam_syslog(pamh, LOG_DEBUG, "CALLED: %s", name);
63 pam_syslog(pamh, LOG_DEBUG, "FLAGS : 0%o%s",
64 flags, (flags & PAM_SILENT) ? " (silent)":"");
65 pam_syslog(pamh, LOG_DEBUG, "CTRL = 0%o", ctrl);
66 pam_syslog(pamh, LOG_DEBUG, "ARGV :");
68 pam_syslog(pamh, LOG_DEBUG, " \"%s\"", *argv++);
74 _pam_parse (const pam_handle_t *pamh, int argc, const char **argv)
78 /* step through arguments */
79 for (ctrl=0; argc-- > 0; ++argv) {
83 if (!strcmp(*argv,"debug"))
85 else if (!strcmp(*argv,"no_warn"))
86 ctrl |= PAM_ST_NO_WARN;
87 else if (!strcmp(*argv,"use_first_pass"))
88 ctrl |= PAM_ST_USE_PASS1;
89 else if (!strcmp(*argv,"try_first_pass"))
90 ctrl |= PAM_ST_TRY_PASS1;
91 else if (!strcmp(*argv,"rootok"))
92 ctrl |= PAM_ST_ROOTOK;
94 /* simulation options */
96 else if (!strcmp(*argv,"expired")) /* signal password needs
98 ctrl |= PAM_ST_EXPIRED;
99 else if (!strcmp(*argv,"fail_1")) /* instruct fn 1 to fail */
100 ctrl |= PAM_ST_FAIL_1;
101 else if (!strcmp(*argv,"fail_2")) /* instruct fn 2 to fail */
102 ctrl |= PAM_ST_FAIL_2;
103 else if (!strcmp(*argv,"prelim")) /* instruct pam_sm_setcred
104 to fail on first call */
105 ctrl |= PAM_ST_PRELIM;
106 else if (!strcmp(*argv,"required")) /* module is fussy about the
107 user being authenticated */
108 ctrl |= PAM_ST_REQUIRE_PWD;
111 pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
118 static int converse(pam_handle_t *pamh, int nargs
119 , const struct pam_message **message
120 , struct pam_response **response)
123 const void *void_conv;
124 const struct pam_conv *conv;
126 retval = pam_get_item(pamh,PAM_CONV,&void_conv);
128 if (retval == PAM_SUCCESS && conv) {
129 retval = conv->conv(nargs, message, response, conv->appdata_ptr);
130 if (retval != PAM_SUCCESS) {
131 pam_syslog(pamh, LOG_ERR, "converse returned %d: %s",
132 retval, pam_strerror(pamh, retval));
135 pam_syslog(pamh, LOG_ERR, "converse failed to get pam_conv");
136 if (retval == PAM_SUCCESS)
137 retval = PAM_BAD_ITEM; /* conv was null */
143 /* authentication management functions */
145 static int stress_get_password(pam_handle_t *pamh, int flags
146 , int ctrl, char **password)
148 const void *pam_pass;
151 if ( (ctrl & (PAM_ST_TRY_PASS1|PAM_ST_USE_PASS1))
152 && (pam_get_item(pamh,PAM_AUTHTOK,&pam_pass)
154 && (pam_pass != NULL) ) {
155 if ((pass = strdup(pam_pass)) == NULL)
157 } else if ((ctrl & PAM_ST_USE_PASS1)) {
158 pam_syslog(pamh, LOG_WARNING, "no forwarded password");
159 return PAM_PERM_DENIED;
160 } else { /* we will have to get one */
161 struct pam_message msg[1];
162 const struct pam_message *pmsg[1];
163 struct pam_response *resp;
166 /* set up conversation call */
169 msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
170 msg[0].msg = "STRESS Password: ";
173 if ((retval = converse(pamh,1,pmsg,&resp)) != PAM_SUCCESS) {
178 if ((resp[0].resp == NULL) && (ctrl & PAM_ST_DEBUG)) {
179 pam_syslog(pamh, LOG_DEBUG,
180 "pam_sm_authenticate: NULL authtok given");
182 if ((flags & PAM_DISALLOW_NULL_AUTHTOK)
183 && resp[0].resp == NULL) {
188 pass = resp[0].resp; /* remember this! */
192 if (ctrl & PAM_ST_DEBUG) {
193 pam_syslog(pamh, LOG_DEBUG,
194 "pam_sm_authenticate: no error reported");
195 pam_syslog(pamh, LOG_DEBUG,
196 "getting password, but NULL returned!?");
203 *password = pass; /* this *MUST* be free()'d by this module */
208 /* function to clean up data items */
211 wipe_up (pam_handle_t *pamh UNUSED, void *data, int error UNUSED)
217 int pam_sm_authenticate(pam_handle_t *pamh, int flags,
218 int argc, const char **argv)
220 const char *username;
221 int retval=PAM_SUCCESS;
227 ctrl = _pam_parse(pamh, argc, argv);
228 _pam_report(pamh, ctrl, "pam_sm_authenticate", flags, argc, argv);
230 /* try to get the username */
232 retval = pam_get_user(pamh, &username, "username: ");
233 if (retval != PAM_SUCCESS || !username) {
234 pam_syslog(pamh, LOG_WARNING,
235 "pam_sm_authenticate: failed to get username");
236 if (retval == PAM_SUCCESS)
237 retval = PAM_USER_UNKNOWN; /* username was null */
240 else if (ctrl & PAM_ST_DEBUG) {
241 pam_syslog(pamh, LOG_DEBUG,
242 "pam_sm_authenticate: username = %s", username);
245 /* now get the password */
247 retval = stress_get_password(pamh,flags,ctrl,&pass);
248 if (retval != PAM_SUCCESS) {
249 pam_syslog(pamh, LOG_WARNING,
250 "pam_sm_authenticate: failed to get a password");
254 /* try to set password item */
256 retval = pam_set_item(pamh,PAM_AUTHTOK,pass);
257 _pam_overwrite(pass); /* clean up local copy of password */
260 if (retval != PAM_SUCCESS) {
261 pam_syslog(pamh, LOG_WARNING,
262 "pam_sm_authenticate: failed to store new password");
266 /* if we are debugging then we print the password */
268 if (ctrl & PAM_ST_DEBUG) {
269 const void *pam_pass;
270 (void) pam_get_item(pamh,PAM_AUTHTOK,&pam_pass);
271 pam_syslog(pamh, LOG_DEBUG,
272 "pam_st_authenticate: password entered is: [%s]",
273 (const char *)pam_pass);
276 /* if we signal a fail for this function then fail */
278 if ((ctrl & PAM_ST_FAIL_1) && retval == PAM_SUCCESS)
279 return PAM_PERM_DENIED;
285 int pam_sm_setcred(pam_handle_t *pamh, int flags,
286 int argc, const char **argv)
288 int ctrl = _pam_parse(pamh, argc, argv);
290 D(("called. [post parsing]"));
292 _pam_report(pamh, ctrl, "pam_sm_setcred", flags, argc, argv);
294 if (ctrl & PAM_ST_FAIL_2)
300 /* account management functions */
303 int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
304 int argc, const char **argv)
306 int ctrl = _pam_parse(pamh, argc, argv);
308 D(("called. [post parsing]"));
310 _pam_report(pamh, ctrl,"pam_sm_acct_mgmt", flags, argc, argv);
312 if (ctrl & PAM_ST_FAIL_1)
313 return PAM_PERM_DENIED;
314 else if (ctrl & PAM_ST_EXPIRED) {
316 void *text = strdup("yes");
319 retval = pam_set_data(pamh,"stress_new_pwd",text,wipe_up);
320 if (retval != PAM_SUCCESS) {
321 pam_syslog(pamh, LOG_DEBUG,
322 "pam_sm_acct_mgmt: failed setting stress_new_pwd");
327 if (ctrl & PAM_ST_DEBUG) {
328 pam_syslog(pamh, LOG_DEBUG,
329 "pam_sm_acct_mgmt: need a new password");
331 return PAM_NEW_AUTHTOK_REQD;
338 int pam_sm_open_session(pam_handle_t *pamh, int flags,
339 int argc, const char **argv)
341 const void *username, *service;
342 int ctrl = _pam_parse(pamh, argc, argv);
344 D(("called. [post parsing]"));
346 _pam_report(pamh, ctrl,"pam_sm_open_session", flags, argc, argv);
348 if ((pam_get_item(pamh, PAM_USER, &username)
349 != PAM_SUCCESS || !username)
350 || (pam_get_item(pamh, PAM_SERVICE, &service)
351 != PAM_SUCCESS || !service)) {
352 pam_syslog(pamh, LOG_WARNING, "pam_sm_open_session: for whom?");
353 return PAM_SESSION_ERR;
356 pam_syslog(pamh, LOG_NOTICE, "opened [%s] session for user [%s]",
357 (const char *)service, (const char *)username);
359 if (ctrl & PAM_ST_FAIL_1)
360 return PAM_SESSION_ERR;
366 int pam_sm_close_session(pam_handle_t *pamh, int flags,
367 int argc, const char **argv)
369 const void *username, *service;
370 int ctrl = _pam_parse(pamh, argc, argv);
372 D(("called. [post parsing]"));
374 _pam_report(pamh, ctrl,"pam_sm_close_session", flags, argc, argv);
376 if ((pam_get_item(pamh, PAM_USER, &username)
377 != PAM_SUCCESS || !username)
378 || (pam_get_item(pamh, PAM_SERVICE, &service)
379 != PAM_SUCCESS || !service)) {
380 pam_syslog(pamh, LOG_WARNING, "pam_sm_close_session: for whom?");
381 return PAM_SESSION_ERR;
384 pam_syslog(pamh, LOG_NOTICE, "closed [%s] session for user [%s]",
385 (const char *)service, (const char *)username);
387 if (ctrl & PAM_ST_FAIL_2)
388 return PAM_SESSION_ERR;
394 int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
395 int argc, const char **argv)
398 int ctrl = _pam_parse(pamh, argc, argv);
400 D(("called. [post parsing]"));
402 _pam_report(pamh, ctrl,"pam_sm_chauthtok", flags, argc, argv);
404 /* this function should be called twice by the Linux-PAM library */
406 if (flags & PAM_PRELIM_CHECK) { /* first call */
407 if (ctrl & PAM_ST_DEBUG) {
408 pam_syslog(pamh, LOG_DEBUG, "pam_sm_chauthtok: prelim check");
410 if (ctrl & PAM_ST_PRELIM)
411 return PAM_TRY_AGAIN;
414 } else if (flags & PAM_UPDATE_AUTHTOK) { /* second call */
415 struct pam_message msg[3];
416 const struct pam_message *pmsg[3];
417 struct pam_response *resp;
422 if (ctrl & PAM_ST_DEBUG) {
423 pam_syslog(pamh, LOG_DEBUG, "pam_sm_chauthtok: alter password");
426 if (ctrl & PAM_ST_FAIL_1)
427 return PAM_AUTHTOK_LOCK_BUSY;
429 if ( !(ctrl & PAM_ST_EXPIRED)
430 && (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
431 && (pam_get_data(pamh,"stress_new_pwd", &text)
432 != PAM_SUCCESS || strcmp(text,"yes"))) {
433 return PAM_SUCCESS; /* the token has not expired */
436 /* the password should be changed */
438 if ((ctrl & PAM_ST_REQUIRE_PWD)
439 && !(getuid() == 0 && (ctrl & PAM_ST_ROOTOK))
440 ) { /* first get old one? */
443 if (ctrl & PAM_ST_DEBUG) {
444 pam_syslog(pamh, LOG_DEBUG,
445 "pam_sm_chauthtok: getting old password");
447 retval = stress_get_password(pamh,flags,ctrl,&pass);
448 if (retval != PAM_SUCCESS) {
449 pam_syslog(pamh, LOG_DEBUG,
450 "pam_sm_chauthtok: no password obtained");
453 retval = pam_set_item(pamh, PAM_OLDAUTHTOK, pass);
454 _pam_overwrite(pass);
457 if (retval != PAM_SUCCESS) {
458 pam_syslog(pamh, LOG_DEBUG,
459 "pam_sm_chauthtok: could not set OLDAUTHTOK");
464 /* set up for conversation */
466 if (!(flags & PAM_SILENT)) {
467 const void *username;
469 if ( pam_get_item(pamh, PAM_USER, &username)
470 || username == NULL ) {
471 pam_syslog(pamh, LOG_ERR, "no username set");
472 return PAM_USER_UNKNOWN;
475 msg[0].msg_style = PAM_TEXT_INFO;
476 if (asprintf(&txt, _("Changing STRESS password for %s."),
477 (const char *)username) < 0) {
478 pam_syslog(pamh, LOG_CRIT, "out of memory");
489 msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
490 msg[i++].msg = _("Enter new STRESS password: ");
492 msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
493 msg[i++].msg = _("Retype new STRESS password: ");
496 retval = converse(pamh,i,pmsg,&resp);
499 txt = NULL; /* clean up */
501 if (retval != PAM_SUCCESS) {
506 pam_syslog(pamh, LOG_ERR,
507 "pam_sm_chauthtok: no response from conv");
511 /* store the password */
513 if (resp[i-2].resp && resp[i-1].resp) {
514 if (strcmp(resp[i-2].resp,resp[i-1].resp)) {
515 /* passwords are not the same; forget and return error */
517 _pam_drop_reply(resp, i);
519 if (!(flags & PAM_SILENT) && !(ctrl & PAM_ST_NO_WARN)) {
521 msg[0].msg_style = PAM_ERROR_MSG;
522 msg[0].msg = _("Verification mis-typed; "
523 "password unchanged");
525 (void) converse(pamh,1,pmsg,&resp);
527 _pam_drop_reply(resp, 1);
530 return PAM_AUTHTOK_ERR;
533 if (pam_get_item(pamh,PAM_AUTHTOK,&text)
535 (void) pam_set_item(pamh,PAM_OLDAUTHTOK,text);
538 (void) pam_set_item(pamh,PAM_AUTHTOK,resp[0].resp);
540 pam_syslog(pamh, LOG_DEBUG,
541 "pam_sm_chauthtok: problem with resp");
542 retval = PAM_SYSTEM_ERR;
545 _pam_drop_reply(resp, i); /* clean up the passwords */
547 pam_syslog(pamh, LOG_ERR,
548 "pam_sm_chauthtok: this must be a Linux-PAM error");
549 return PAM_SYSTEM_ERR;
558 /* static module data */
560 struct pam_module _pam_stress_modstruct = {
566 pam_sm_close_session,