Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / lib / libpam / pam_framework.c
blob4bc7afea27029aa60b27b5358e4643bf297fcfda
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
26 * Copyright 2016 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
29 #include <syslog.h>
30 #include <dlfcn.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <stdlib.h>
34 #include <strings.h>
35 #include <malloc.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <errno.h>
40 #include <security/pam_appl.h>
41 #include <security/pam_modules.h>
42 #include <sys/mman.h>
44 #include <libintl.h>
46 #include "pam_impl.h"
48 static char *pam_snames [PAM_NUM_MODULE_TYPES] = {
49 PAM_ACCOUNT_NAME,
50 PAM_AUTH_NAME,
51 PAM_PASSWORD_NAME,
52 PAM_SESSION_NAME
55 static char *pam_inames [PAM_MAX_ITEMS] = {
56 /* NONE */ NULL,
57 /* PAM_SERVICE */ "service",
58 /* PAM_USER */ "user",
59 /* PAM_TTY */ "tty",
60 /* PAM_RHOST */ "rhost",
61 /* PAM_CONV */ "conv",
62 /* PAM_AUTHTOK */ "authtok",
63 /* PAM_OLDAUTHTOK */ "oldauthtok",
64 /* PAM_RUSER */ "ruser",
65 /* PAM_USER_PROMPT */ "user_prompt",
66 /* PAM_REPOSITORY */ "repository",
67 /* PAM_RESOURCE */ "resource",
68 /* PAM_AUSER */ "auser",
69 /* Undefined Items */
72 /* functions to dynamically load modules */
73 static int load_modules(pam_handle_t *, int, char *, pamtab_t *);
74 static void *open_module(pam_handle_t *, char *);
75 static int load_function(void *, char *, int (**func)());
77 /* functions to read and store the pam.conf configuration file */
78 static int open_pam_conf(struct pam_fh **, pam_handle_t *, char *, int);
79 static void close_pam_conf(struct pam_fh *);
80 static int read_pam_conf(pam_handle_t *, char *, char *);
81 static int get_pam_conf_entry(struct pam_fh *, pam_handle_t *,
82 pamtab_t **, char *, int);
83 static char *read_next_token(char **);
84 static char *nextline(struct pam_fh *, pam_handle_t *, int *);
85 static int verify_pam_conf(pamtab_t *, char *);
87 /* functions to clean up and free memory */
88 static void clean_up(pam_handle_t *);
89 static void free_pamconf(pamtab_t *);
90 static void free_pam_conf_info(pam_handle_t *);
91 static void free_env(env_list *);
93 /* convenience functions for I18N/L10N communication */
95 static void free_resp(int, struct pam_response *);
96 static int do_conv(pam_handle_t *, int, int,
97 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *,
98 struct pam_response **);
100 static int log_priority; /* pam_trace syslog priority & facility */
101 static int pam_debug = 0;
103 static char *
104 pam_trace_iname(int item_type, char *iname_buf)
106 char *name;
108 if (item_type <= 0 ||
109 item_type >= PAM_MAX_ITEMS ||
110 (name = pam_inames[item_type]) == NULL) {
111 (void) sprintf(iname_buf, "%d", item_type);
112 return (iname_buf);
114 return (name);
117 static char *
118 pam_trace_fname(int flag)
120 if (flag & PAM_BINDING)
121 return (PAM_BINDING_NAME);
122 if (flag & PAM_INCLUDE)
123 return (PAM_INCLUDE_NAME);
124 if (flag & PAM_OPTIONAL)
125 return (PAM_OPTIONAL_NAME);
126 if (flag & PAM_REQUIRED)
127 return (PAM_REQUIRED_NAME);
128 if (flag & PAM_REQUISITE)
129 return (PAM_REQUISITE_NAME);
130 if (flag & PAM_SUFFICIENT)
131 return (PAM_SUFFICIENT_NAME);
132 return ("bad flag name");
135 static char *
136 pam_trace_cname(pam_handle_t *pamh)
138 if (pamh->pam_conf_name[pamh->include_depth] == NULL)
139 return ("NULL");
140 return (pamh->pam_conf_name[pamh->include_depth]);
143 #include <deflt.h>
144 #include <stdarg.h>
146 * pam_settrace - setup configuration for pam tracing
148 * turn on PAM debug if "magic" file exists
149 * if exists (original), pam_debug = PAM_DEBUG_DEFAULT,
150 * log_priority = LOG_DEBUG(7) and log_facility = LOG_AUTH(4).
152 * if has contents, keywork=value pairs:
154 * "log_priority=" 0-7, the pam_trace syslog priority to use
155 * (see sys/syslog.h)
156 * "log_facility=" 0-23, the pam_trace syslog facility to use
157 * (see sys/syslog.h)
158 * "debug_flags=" PAM_DEBUG_DEFAULT (0x0001), log traditional
159 * (original) debugging.
160 * Plus the logical or of:
161 * PAM_DEBUG_ITEM (0x0002), log item values and
162 * pam_get_item.
163 * PAM_DEBUG_MODULE (0x0004), log module return status.
164 * PAM_DEBUG_CONF (0x0008), log pam.conf parsing.
165 * PAM_DEBUG_DATA (0x0010), get/set_data.
166 * PAM_DEBUG_CONV (0x0020), conversation/response.
168 * If compiled with DEBUG:
169 * PAM_DEBUG_AUTHTOK (0x8000), display AUTHTOK value if
170 * PAM_DEBUG_ITEM is set and results from
171 * PAM_PROMPT_ECHO_OFF responses.
172 * USE CAREFULLY, THIS EXPOSES THE USER'S PASSWORDS.
174 * or set to 0 and off even if PAM_DEBUG file exists.
176 * Output has the general form:
177 * <whatever was set syslog> PAM[<pid>]: <interface>(<handle> and other info)
178 * <whatever was set syslog> PAM[<pid>]: details requested for <interface> call
179 * Where: <pid> is the process ID of the calling process.
180 * <handle> is the Hex value of the pam_handle associated with the
181 * call.
184 static void
185 pam_settrace()
187 void *defp;
189 if ((defp = defopen_r(PAM_DEBUG)) != NULL) {
190 char *arg;
191 int code;
192 int facility = LOG_AUTH;
194 pam_debug = PAM_DEBUG_DEFAULT;
195 log_priority = LOG_DEBUG;
197 (void) defcntl_r(DC_SETFLAGS, DC_CASE, defp);
198 if ((arg = defread_r(LOG_PRIORITY, defp)) != NULL) {
199 code = (int)strtol(arg, NULL, 10);
200 if ((code & ~LOG_PRIMASK) == 0) {
201 log_priority = code;
204 if ((arg = defread_r(LOG_FACILITY, defp)) != NULL) {
205 code = (int)strtol(arg, NULL, 10);
206 if (code < LOG_NFACILITIES) {
207 facility = code << 3;
210 if ((arg = defread_r(DEBUG_FLAGS, defp)) != NULL) {
211 pam_debug = (int)strtol(arg, NULL, 0);
213 defclose_r(defp);
215 log_priority |= facility;
220 * pam_trace - logs tracing messages
222 * flag = debug_flags from /etc/pam_debug
223 * format and args = message to print (PAM[<pid>]: is prepended).
225 * global log_priority = pam_trace syslog (log_priority | log_facility)
226 * from /etc/pam_debug
228 /*PRINTFLIKE2*/
229 static void
230 pam_trace(int flag, char *format, ...)
232 va_list args;
233 char message[1024];
234 int savemask;
236 if ((pam_debug & flag) == 0)
237 return;
239 savemask = setlogmask(LOG_MASK(log_priority & LOG_PRIMASK));
240 (void) snprintf(message, sizeof (message), "PAM[%ld]: %s",
241 (long)getpid(), format);
242 va_start(args, format);
243 (void) vsyslog(log_priority, message, args);
244 va_end(args);
245 (void) setlogmask(savemask);
249 * __pam_log - logs PAM syslog messages
251 * priority = message priority
252 * format and args = message to log
254 /*PRINTFLIKE2*/
255 void
256 __pam_log(int priority, const char *format, ...)
258 va_list args;
259 int savemask = setlogmask(LOG_MASK(priority & LOG_PRIMASK));
261 va_start(args, format);
262 (void) vsyslog(priority, format, args);
263 va_end(args);
264 (void) setlogmask(savemask);
269 * pam_XXXXX routines
271 * These are the entry points to the authentication switch
275 * pam_start - initiate an authentication transaction and
276 * set parameter values to be used during the
277 * transaction
281 pam_start(const char *service, const char *user,
282 const struct pam_conv *pam_conv, pam_handle_t **pamh)
284 int err;
286 *pamh = calloc(1, sizeof (struct pam_handle));
288 pam_settrace();
289 pam_trace(PAM_DEBUG_DEFAULT,
290 "pam_start(%s,%s,%p:%p) - debug = %x",
291 service ? service : "NULL", user ? user : "NULL", (void *)pam_conv,
292 (void *)*pamh, pam_debug);
294 if (*pamh == NULL)
295 return (PAM_BUF_ERR);
297 (*pamh)->pam_inmodule = RO_OK; /* OK to set RO items */
298 if ((err = pam_set_item(*pamh, PAM_SERVICE, (void *)service))
299 != PAM_SUCCESS) {
300 clean_up(*pamh);
301 *pamh = NULL;
302 return (err);
305 if ((err = pam_set_item(*pamh, PAM_USER, (void *)user))
306 != PAM_SUCCESS) {
307 clean_up(*pamh);
308 *pamh = NULL;
309 return (err);
312 if ((err = pam_set_item(*pamh, PAM_CONV, (void *)pam_conv))
313 != PAM_SUCCESS) {
314 clean_up(*pamh);
315 *pamh = NULL;
316 return (err);
319 (*pamh)->pam_inmodule = RW_OK;
320 return (PAM_SUCCESS);
324 * pam_end - terminate an authentication transaction
328 pam_end(pam_handle_t *pamh, int pam_status)
330 struct pam_module_data *psd, *p;
331 fd_list *expired;
332 fd_list *traverse;
333 env_list *env_expired;
334 env_list *env_traverse;
336 pam_trace(PAM_DEBUG_DEFAULT,
337 "pam_end(%p): status = %s", (void *)pamh,
338 pam_strerror(pamh, pam_status));
340 if (pamh == NULL)
341 return (PAM_SYSTEM_ERR);
343 /* call the cleanup routines for module specific data */
345 psd = pamh->ssd;
346 while (psd) {
347 if (psd->cleanup) {
348 psd->cleanup(pamh, psd->data, pam_status);
350 p = psd;
351 psd = p->next;
352 free(p->module_data_name);
353 free(p);
355 pamh->ssd = NULL;
357 /* dlclose all module fds */
358 traverse = pamh->fd;
359 while (traverse) {
360 expired = traverse;
361 traverse = traverse->next;
362 (void) dlclose(expired->mh);
363 free(expired);
365 pamh->fd = 0;
367 /* remove all environment variables */
368 env_traverse = pamh->pam_env;
369 while (env_traverse) {
370 env_expired = env_traverse;
371 env_traverse = env_traverse->next;
372 free_env(env_expired);
375 clean_up(pamh);
376 return (PAM_SUCCESS);
380 * pam_set_item - set the value of a parameter that can be
381 * retrieved via a call to pam_get_item()
385 pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
387 struct pam_item *pip;
388 int size;
389 char iname_buf[PAM_MAX_MSG_SIZE];
391 if (((pam_debug & PAM_DEBUG_ITEM) == 0) || (pamh == NULL)) {
392 pam_trace(PAM_DEBUG_DEFAULT,
393 "pam_set_item(%p:%s)", (void *)pamh,
394 pam_trace_iname(item_type, iname_buf));
397 if (pamh == NULL)
398 return (PAM_SYSTEM_ERR);
400 /* check read only items */
401 if ((item_type == PAM_SERVICE) && (pamh->pam_inmodule != RO_OK))
402 return (PAM_PERM_DENIED);
405 * Check that item_type is within valid range
408 if (item_type <= 0 || item_type >= PAM_MAX_ITEMS)
409 return (PAM_SYMBOL_ERR);
411 pip = &(pamh->ps_item[item_type]);
413 switch (item_type) {
414 case PAM_AUTHTOK:
415 case PAM_OLDAUTHTOK:
416 if (pip->pi_addr != NULL)
417 (void) memset(pip->pi_addr, 0, pip->pi_size);
418 /*FALLTHROUGH*/
419 case PAM_SERVICE:
420 case PAM_USER:
421 case PAM_TTY:
422 case PAM_RHOST:
423 case PAM_RUSER:
424 case PAM_USER_PROMPT:
425 case PAM_RESOURCE:
426 case PAM_AUSER:
427 if (pip->pi_addr != NULL) {
428 free(pip->pi_addr);
431 if (item == NULL) {
432 pip->pi_addr = NULL;
433 pip->pi_size = 0;
434 } else {
435 pip->pi_addr = strdup((char *)item);
436 if (pip->pi_addr == NULL) {
437 pip->pi_size = 0;
438 return (PAM_BUF_ERR);
440 pip->pi_size = strlen(pip->pi_addr);
442 break;
443 case PAM_CONV:
444 free(pip->pi_addr);
445 size = sizeof (struct pam_conv);
446 if ((pip->pi_addr = calloc(1, size)) == NULL)
447 return (PAM_BUF_ERR);
448 if (item != NULL)
449 (void) memcpy(pip->pi_addr, item, (unsigned int) size);
450 else
451 (void) memset(pip->pi_addr, 0, size);
452 pip->pi_size = size;
453 break;
454 case PAM_REPOSITORY:
455 if (pip->pi_addr != NULL) {
456 pam_repository_t *auth_rep;
458 auth_rep = (pam_repository_t *)pip->pi_addr;
459 free(auth_rep->type);
460 free(auth_rep->scope);
461 free(auth_rep);
463 if (item != NULL) {
464 pam_repository_t *s, *d;
466 size = sizeof (struct pam_repository);
467 pip->pi_addr = calloc(1, size);
468 if (pip->pi_addr == NULL)
469 return (PAM_BUF_ERR);
471 s = (struct pam_repository *)item;
472 d = (struct pam_repository *)pip->pi_addr;
474 d->type = strdup(s->type);
475 if (d->type == NULL)
476 return (PAM_BUF_ERR);
477 d->scope = malloc(s->scope_len);
478 if (d->scope == NULL)
479 return (PAM_BUF_ERR);
480 (void) memcpy(d->scope, s->scope, s->scope_len);
481 d->scope_len = s->scope_len;
483 pip->pi_size = size;
484 break;
485 default:
486 return (PAM_SYMBOL_ERR);
488 switch (item_type) {
489 case PAM_CONV:
490 pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%p",
491 (void *)pamh,
492 pam_trace_iname(item_type, iname_buf),
493 item ? (void *)((struct pam_conv *)item)->conv :
494 NULL);
495 break;
496 case PAM_REPOSITORY:
497 pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%s",
498 (void *)pamh,
499 pam_trace_iname(item_type, iname_buf),
500 item ? (((struct pam_repository *)item)->type ?
501 ((struct pam_repository *)item)->type : "NULL") :
502 "NULL");
503 break;
504 case PAM_AUTHTOK:
505 case PAM_OLDAUTHTOK:
506 #ifdef DEBUG
507 if (pam_debug & PAM_DEBUG_AUTHTOK)
508 pam_trace(PAM_DEBUG_ITEM,
509 "pam_set_item(%p:%s)=%s", (void *)pamh,
510 pam_trace_iname(item_type, iname_buf),
511 item ? (char *)item : "NULL");
512 else
513 #endif /* DEBUG */
514 pam_trace(PAM_DEBUG_ITEM,
515 "pam_set_item(%p:%s)=%s", (void *)pamh,
516 pam_trace_iname(item_type, iname_buf),
517 item ? "********" : "NULL");
518 break;
519 default:
520 pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%s",
521 (void *)pamh,
522 pam_trace_iname(item_type, iname_buf),
523 item ? (char *)item : "NULL");
526 return (PAM_SUCCESS);
530 * pam_get_item - read the value of a parameter specified in
531 * the call to pam_set_item()
535 pam_get_item(const pam_handle_t *pamh, int item_type, void **item)
537 struct pam_item *pip;
538 char iname_buf[PAM_MAX_MSG_SIZE];
540 if (((pam_debug & PAM_DEBUG_ITEM) == 0) || (pamh == NULL)) {
541 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)",
542 (void *)pamh, pam_trace_iname(item_type, iname_buf));
545 if (pamh == NULL)
546 return (PAM_SYSTEM_ERR);
548 if (item_type <= 0 || item_type >= PAM_MAX_ITEMS)
549 return (PAM_SYMBOL_ERR);
551 if ((pamh->pam_inmodule != WO_OK) &&
552 ((item_type == PAM_AUTHTOK || item_type == PAM_OLDAUTHTOK))) {
553 __pam_log(LOG_AUTH | LOG_NOTICE, "pam_get_item(%s) called from "
554 "a non module context",
555 pam_trace_iname(item_type, iname_buf));
556 return (PAM_PERM_DENIED);
559 pip = (struct pam_item *)&(pamh->ps_item[item_type]);
561 *item = pip->pi_addr;
562 switch (item_type) {
563 case PAM_CONV:
564 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%p",
565 (void *)pamh,
566 pam_trace_iname(item_type, iname_buf),
567 (void *)((struct pam_conv *)*item)->conv);
568 break;
569 case PAM_REPOSITORY:
570 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%s",
571 (void *)pamh,
572 pam_trace_iname(item_type, iname_buf),
573 *item ? (((struct pam_repository *)*item)->type ?
574 ((struct pam_repository *)*item)->type : "NULL") :
575 "NULL");
576 break;
577 case PAM_AUTHTOK:
578 case PAM_OLDAUTHTOK:
579 #ifdef DEBUG
580 if (pam_debug & PAM_DEBUG_AUTHTOK)
581 pam_trace(PAM_DEBUG_ITEM,
582 "pam_get_item(%p:%s)=%s", (void *)pamh,
583 pam_trace_iname(item_type, iname_buf),
584 *item ? *(char **)item : "NULL");
585 else
586 #endif /* DEBUG */
587 pam_trace(PAM_DEBUG_ITEM,
588 "pam_get_item(%p:%s)=%s", (void *)pamh,
589 pam_trace_iname(item_type, iname_buf),
590 *item ? "********" : "NULL");
591 break;
592 default:
593 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%s",
594 (void *)pamh,
595 pam_trace_iname(item_type, iname_buf),
596 *item ? *(char **)item : "NULL");
599 return (PAM_SUCCESS);
603 * parse_user_name - process the user response: ignore
604 * '\t' or ' ' before or after a user name.
605 * user_input is a null terminated string.
606 * *ret_username will be the user name.
609 static int
610 parse_user_name(char *user_input, char **ret_username)
612 register char *ptr;
613 register int index = 0;
614 char username[PAM_MAX_RESP_SIZE];
616 /* Set the default value for *ret_username */
617 *ret_username = NULL;
620 * Set the initial value for username - this is a buffer holds
621 * the user name.
623 bzero((void *)username, PAM_MAX_RESP_SIZE);
626 * The user_input is guaranteed to be terminated by a null character.
628 ptr = user_input;
630 /* Skip all the leading whitespaces if there are any. */
631 while ((*ptr == ' ') || (*ptr == '\t'))
632 ptr++;
634 if (*ptr == '\0') {
636 * We should never get here since the user_input we got
637 * in pam_get_user() is not all whitespaces nor just "\0".
639 return (PAM_BUF_ERR);
643 * username will be the first string we get from user_input
644 * - we skip leading whitespaces and ignore trailing whitespaces
646 while (*ptr != '\0') {
647 if ((*ptr == ' ') || (*ptr == '\t'))
648 break;
649 else {
650 username[index] = *ptr;
651 index++;
652 ptr++;
656 /* ret_username will be freed in pam_get_user(). */
657 if ((*ret_username = malloc(index + 1)) == NULL)
658 return (PAM_BUF_ERR);
659 (void) strcpy(*ret_username, username);
660 return (PAM_SUCCESS);
664 * Get the value of PAM_USER. If not set, then use the convenience function
665 * to prompt for the user. Use prompt if specified, else use PAM_USER_PROMPT
666 * if it is set, else use default.
668 #define WHITESPACE 0
669 #define USERNAME 1
672 pam_get_user(pam_handle_t *pamh, char **user, const char *prompt_override)
674 int status;
675 char *prompt = NULL;
676 char *real_username;
677 struct pam_response *ret_resp = NULL;
678 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
680 pam_trace(PAM_DEBUG_DEFAULT,
681 "pam_get_user(%p, %p, %s)", (void *)pamh, (void *)*user,
682 prompt_override ? prompt_override : "NULL");
683 if (pamh == NULL)
684 return (PAM_SYSTEM_ERR);
686 if ((status = pam_get_item(pamh, PAM_USER, (void **)user))
687 != PAM_SUCCESS) {
688 return (status);
691 /* if the user is set, return it */
693 if (*user != NULL && *user[0] != '\0') {
694 return (PAM_SUCCESS);
698 * if the module is requesting a special prompt, use it.
699 * else use PAM_USER_PROMPT.
702 if (prompt_override != NULL) {
703 prompt = (char *)prompt_override;
704 } else {
705 status = pam_get_item(pamh, PAM_USER_PROMPT, (void**)&prompt);
706 if (status != PAM_SUCCESS) {
707 return (status);
711 /* if the prompt is not set, use default */
713 if (prompt == NULL || prompt[0] == '\0') {
714 prompt = dgettext(TEXT_DOMAIN, "Please enter user name: ");
717 /* prompt for the user */
719 (void) strncpy(messages[0], prompt, sizeof (messages[0]));
721 for (;;) {
722 int state = WHITESPACE;
724 status = do_conv(pamh, PAM_PROMPT_ECHO_ON, 1, messages,
725 NULL, &ret_resp);
727 if (status != PAM_SUCCESS) {
728 return (status);
731 if (ret_resp->resp && ret_resp->resp[0] != '\0') {
732 int len = strlen(ret_resp->resp);
733 int i;
735 for (i = 0; i < len; i++) {
736 if ((ret_resp->resp[i] != ' ') &&
737 (ret_resp->resp[i] != '\t')) {
738 state = USERNAME;
739 break;
743 if (state == USERNAME)
744 break;
746 /* essentially empty response, try again */
747 free_resp(1, ret_resp);
748 ret_resp = NULL;
751 /* set PAM_USER */
752 /* Parse the user input to get the user name. */
753 status = parse_user_name(ret_resp->resp, &real_username);
755 if (status != PAM_SUCCESS) {
756 free(real_username);
757 free_resp(1, ret_resp);
758 return (status);
761 status = pam_set_item(pamh, PAM_USER, real_username);
763 free(real_username);
765 free_resp(1, ret_resp);
766 if (status != PAM_SUCCESS) {
767 return (status);
771 * finally, get PAM_USER. We have to call pam_get_item to get
772 * the value of user because pam_set_item mallocs the memory.
775 status = pam_get_item(pamh, PAM_USER, (void**)user);
776 return (status);
780 * Set module specific data
784 pam_set_data(pam_handle_t *pamh, const char *module_data_name, void *data,
785 void (*cleanup)(pam_handle_t *pamh, void *data, int pam_end_status))
787 struct pam_module_data *psd;
789 pam_trace(PAM_DEBUG_DATA,
790 "pam_set_data(%p:%s:%d)=%p", (void *)pamh,
791 module_data_name ? module_data_name : "NULL", pamh->pam_inmodule,
792 data);
793 if (pamh == NULL || (pamh->pam_inmodule != WO_OK) ||
794 module_data_name == NULL) {
795 return (PAM_SYSTEM_ERR);
798 /* check if module data already exists */
800 for (psd = pamh->ssd; psd; psd = psd->next) {
801 if (strcmp(psd->module_data_name, module_data_name) == 0) {
802 /* clean up original data before setting the new data */
803 if (psd->cleanup) {
804 psd->cleanup(pamh, psd->data, PAM_SUCCESS);
806 psd->data = (void *)data;
807 psd->cleanup = cleanup;
808 return (PAM_SUCCESS);
812 psd = malloc(sizeof (struct pam_module_data));
813 if (psd == NULL)
814 return (PAM_BUF_ERR);
816 psd->module_data_name = strdup(module_data_name);
817 if (psd->module_data_name == NULL) {
818 free(psd);
819 return (PAM_BUF_ERR);
822 psd->data = (void *)data;
823 psd->cleanup = cleanup;
824 psd->next = pamh->ssd;
825 pamh->ssd = psd;
826 return (PAM_SUCCESS);
830 * get module specific data
834 pam_get_data(const pam_handle_t *pamh, const char *module_data_name,
835 const void **data)
837 struct pam_module_data *psd;
839 if (pamh == NULL || (pamh->pam_inmodule != WO_OK) ||
840 module_data_name == NULL) {
841 pam_trace(PAM_DEBUG_DATA,
842 "pam_get_data(%p:%s:%d)=%p", (void *)pamh,
843 module_data_name ? module_data_name : "NULL",
844 pamh->pam_inmodule, *data);
845 return (PAM_SYSTEM_ERR);
848 for (psd = pamh->ssd; psd; psd = psd->next) {
849 if (strcmp(psd->module_data_name, module_data_name) == 0) {
850 *data = psd->data;
851 pam_trace(PAM_DEBUG_DATA,
852 "pam_get_data(%p:%s)=%p", (void *)pamh,
853 module_data_name, *data);
854 return (PAM_SUCCESS);
857 pam_trace(PAM_DEBUG_DATA,
858 "pam_get_data(%p:%s)=%s", (void *)pamh, module_data_name,
859 "PAM_NO_MODULE_DATA");
861 return (PAM_NO_MODULE_DATA);
865 * PAM equivalent to strerror()
867 /* ARGSUSED */
868 const char *
869 pam_strerror(pam_handle_t *pamh, int errnum)
871 switch (errnum) {
872 case PAM_SUCCESS:
873 return (dgettext(TEXT_DOMAIN, "Success"));
874 case PAM_OPEN_ERR:
875 return (dgettext(TEXT_DOMAIN, "Dlopen failure"));
876 case PAM_SYMBOL_ERR:
877 return (dgettext(TEXT_DOMAIN, "Symbol not found"));
878 case PAM_SERVICE_ERR:
879 return (dgettext(TEXT_DOMAIN,
880 "Error in underlying service module"));
881 case PAM_SYSTEM_ERR:
882 return (dgettext(TEXT_DOMAIN, "System error"));
883 case PAM_BUF_ERR:
884 return (dgettext(TEXT_DOMAIN, "Memory buffer error"));
885 case PAM_CONV_ERR:
886 return (dgettext(TEXT_DOMAIN, "Conversation failure"));
887 case PAM_PERM_DENIED:
888 return (dgettext(TEXT_DOMAIN, "Permission denied"));
889 case PAM_MAXTRIES:
890 return (dgettext(TEXT_DOMAIN,
891 "Maximum number of attempts exceeded"));
892 case PAM_AUTH_ERR:
893 return (dgettext(TEXT_DOMAIN, "Authentication failed"));
894 case PAM_NEW_AUTHTOK_REQD:
895 return (dgettext(TEXT_DOMAIN, "Get new authentication token"));
896 case PAM_CRED_INSUFFICIENT:
897 return (dgettext(TEXT_DOMAIN, "Insufficient credentials"));
898 case PAM_AUTHINFO_UNAVAIL:
899 return (dgettext(TEXT_DOMAIN,
900 "Can not retrieve authentication info"));
901 case PAM_USER_UNKNOWN:
902 return (dgettext(TEXT_DOMAIN, "No account present for user"));
903 case PAM_CRED_UNAVAIL:
904 return (dgettext(TEXT_DOMAIN,
905 "Can not retrieve user credentials"));
906 case PAM_CRED_EXPIRED:
907 return (dgettext(TEXT_DOMAIN,
908 "User credentials have expired"));
909 case PAM_CRED_ERR:
910 return (dgettext(TEXT_DOMAIN,
911 "Failure setting user credentials"));
912 case PAM_ACCT_EXPIRED:
913 return (dgettext(TEXT_DOMAIN, "User account has expired"));
914 case PAM_AUTHTOK_EXPIRED:
915 return (dgettext(TEXT_DOMAIN, "User password has expired"));
916 case PAM_SESSION_ERR:
917 return (dgettext(TEXT_DOMAIN,
918 "Can not make/remove entry for session"));
919 case PAM_AUTHTOK_ERR:
920 return (dgettext(TEXT_DOMAIN,
921 "Authentication token manipulation error"));
922 case PAM_AUTHTOK_RECOVERY_ERR:
923 return (dgettext(TEXT_DOMAIN,
924 "Authentication token can not be recovered"));
925 case PAM_AUTHTOK_LOCK_BUSY:
926 return (dgettext(TEXT_DOMAIN,
927 "Authentication token lock busy"));
928 case PAM_AUTHTOK_DISABLE_AGING:
929 return (dgettext(TEXT_DOMAIN,
930 "Authentication token aging disabled"));
931 case PAM_NO_MODULE_DATA:
932 return (dgettext(TEXT_DOMAIN,
933 "Module specific data not found"));
934 case PAM_IGNORE:
935 return (dgettext(TEXT_DOMAIN, "Ignore module"));
936 case PAM_ABORT:
937 return (dgettext(TEXT_DOMAIN, "General PAM failure "));
938 case PAM_TRY_AGAIN:
939 return (dgettext(TEXT_DOMAIN,
940 "Unable to complete operation. Try again"));
941 default:
942 return (dgettext(TEXT_DOMAIN, "Unknown error"));
946 static void *
947 sm_name(int ind)
949 switch (ind) {
950 case PAM_AUTHENTICATE:
951 return (PAM_SM_AUTHENTICATE);
952 case PAM_SETCRED:
953 return (PAM_SM_SETCRED);
954 case PAM_ACCT_MGMT:
955 return (PAM_SM_ACCT_MGMT);
956 case PAM_OPEN_SESSION:
957 return (PAM_SM_OPEN_SESSION);
958 case PAM_CLOSE_SESSION:
959 return (PAM_SM_CLOSE_SESSION);
960 case PAM_CHAUTHTOK:
961 return (PAM_SM_CHAUTHTOK);
963 return (NULL);
966 static int
967 (*func(pamtab_t *modulep, int ind))()
969 void *funcp;
971 if ((funcp = modulep->function_ptr) == NULL)
972 return (NULL);
974 switch (ind) {
975 case PAM_AUTHENTICATE:
976 return (((struct auth_module *)funcp)->pam_sm_authenticate);
977 case PAM_SETCRED:
978 return (((struct auth_module *)funcp)->pam_sm_setcred);
979 case PAM_ACCT_MGMT:
980 return (((struct account_module *)funcp)->pam_sm_acct_mgmt);
981 case PAM_OPEN_SESSION:
982 return (((struct session_module *)funcp)->pam_sm_open_session);
983 case PAM_CLOSE_SESSION:
984 return (((struct session_module *)funcp)->pam_sm_close_session);
985 case PAM_CHAUTHTOK:
986 return (((struct password_module *)funcp)->pam_sm_chauthtok);
988 return (NULL);
992 * Run through the PAM service module stack for the given module type.
994 static int
995 run_stack(pam_handle_t *pamh, int flags, int type, int def_err, int ind,
996 char *function_name)
998 int err = PAM_SYSTEM_ERR; /* preset */
999 int optional_error = 0;
1000 int required_error = 0;
1001 int success = 0;
1002 pamtab_t *modulep;
1003 int (*sm_func)();
1004 char *service;
1005 char *service_file;
1007 if (pamh == NULL)
1008 return (PAM_SYSTEM_ERR);
1010 (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service);
1011 if (service == NULL || *service == '\0') {
1012 __pam_log(LOG_AUTH | LOG_ERR, "No service name");
1013 return (PAM_SYSTEM_ERR);
1016 /* read initial entries from /etc/pam.d/<service> */
1017 if (asprintf(&service_file, "%s%s", PAM_CONFIG_DIR, service) < 0)
1018 return (PAM_SYSTEM_ERR);
1019 if ((err = read_pam_conf(pamh, service_file, service))
1020 != PAM_SUCCESS) {
1021 pam_trace(PAM_DEBUG_CONF, "run_stack[%d]: can't read "
1022 "service-specific conf %s", pamh->include_depth,
1023 pam_trace_cname(pamh), service_file);
1025 free(service_file);
1026 service_file = NULL;
1028 if ((modulep =
1029 pamh->pam_conf_info[pamh->include_depth][type]) == NULL) {
1030 __pam_log(LOG_AUTH | LOG_ERR, "%s no initial module present",
1031 pam_trace_cname(pamh));
1032 goto exit_return;
1035 pamh->pam_inmodule = WO_OK; /* OK to get AUTHTOK */
1036 include:
1037 pam_trace(PAM_DEBUG_MODULE,
1038 "[%d:%s]:run_stack:%s(%p, %x): %s", pamh->include_depth,
1039 pam_trace_cname(pamh), function_name, (void *)pamh, flags,
1040 modulep ? modulep->module_path : "NULL");
1042 while (modulep != NULL) {
1043 if (modulep->pam_flag & PAM_INCLUDE) {
1044 /* save the return location */
1045 pamh->pam_conf_modulep[pamh->include_depth] =
1046 modulep->next;
1047 pam_trace(PAM_DEBUG_MODULE,
1048 "setting for include[%d:%p]",
1049 pamh->include_depth, (void *)modulep->next);
1050 if (pamh->include_depth++ >= PAM_MAX_INCLUDE) {
1051 __pam_log(LOG_AUTH | LOG_ERR,
1052 "run_stack: includes too deep %d "
1053 "found trying to include %s from %s, %d "
1054 "allowed", pamh->include_depth,
1055 modulep->module_path, pamh->pam_conf_name
1056 [PAM_MAX_INCLUDE] == NULL ? "NULL" :
1057 pamh->pam_conf_name[PAM_MAX_INCLUDE],
1058 PAM_MAX_INCLUDE);
1059 goto exit_return;
1061 err = read_pam_conf(pamh, modulep->module_path, service);
1062 if (err != PAM_SUCCESS) {
1063 __pam_log(LOG_AUTH | LOG_ERR,
1064 "run_stack[%d:%s]: can't read included "
1065 "conf %s", pamh->include_depth,
1066 pam_trace_cname(pamh),
1067 modulep->module_path);
1068 goto exit_return;
1070 if ((modulep = pamh->pam_conf_info
1071 [pamh->include_depth][type]) == NULL) {
1072 __pam_log(LOG_AUTH | LOG_ERR,
1073 "run_stack[%d:%s]: no include module "
1074 "present %s", pamh->include_depth,
1075 pam_trace_cname(pamh), function_name);
1076 goto exit_return;
1078 if (modulep->pam_flag & PAM_INCLUDE) {
1079 /* first line another include */
1080 goto include;
1082 pam_trace(PAM_DEBUG_DEFAULT, "include[%d:%s]"
1083 "(%p, %s)=%s", pamh->include_depth,
1084 pam_trace_cname(pamh), (void *)pamh,
1085 function_name, modulep->module_path);
1086 if ((err = load_modules(pamh, type, sm_name(ind),
1087 pamh->pam_conf_info
1088 [pamh->include_depth][type])) != PAM_SUCCESS) {
1089 pam_trace(PAM_DEBUG_DEFAULT,
1090 "[%d:%s]:%s(%p, %x): load_modules failed",
1091 pamh->include_depth, pam_trace_cname(pamh),
1092 function_name, (void *)pamh, flags);
1093 goto exit_return;
1095 if ((modulep = pamh->pam_conf_info
1096 [pamh->include_depth][type]) == NULL) {
1097 __pam_log(LOG_AUTH | LOG_ERR,
1098 "%s no initial module present",
1099 pam_trace_cname(pamh));
1100 goto exit_return;
1102 } else if ((err = load_modules(pamh, type, sm_name(ind),
1103 modulep)) != PAM_SUCCESS) {
1104 pam_trace(PAM_DEBUG_DEFAULT,
1105 "[%d:%s]:%s(%p, %x): load_modules failed",
1106 pamh->include_depth, pam_trace_cname(pamh),
1107 function_name, (void *)pamh, flags);
1108 goto exit_return;
1109 } /* PAM_INCLUDE */
1110 sm_func = func(modulep, ind);
1111 if (sm_func) {
1112 err = sm_func(pamh, flags, modulep->module_argc,
1113 (const char **)modulep->module_argv);
1115 pam_trace(PAM_DEBUG_MODULE,
1116 "[%d:%s]:%s(%p, %x): %s returned %s",
1117 pamh->include_depth, pam_trace_cname(pamh),
1118 function_name, (void *)pamh, flags,
1119 modulep->module_path, pam_strerror(pamh, err));
1121 switch (err) {
1122 case PAM_IGNORE:
1123 /* do nothing */
1124 break;
1125 case PAM_SUCCESS:
1126 if ((modulep->pam_flag & PAM_SUFFI_BIND) &&
1127 !required_error) {
1128 pamh->pam_inmodule = RW_OK;
1129 pam_trace(PAM_DEBUG_MODULE,
1130 "[%d:%s]:%s(%p, %x): %s: success",
1131 pamh->include_depth,
1132 pam_trace_cname(pamh),
1133 function_name, (void *)pamh, flags,
1134 (modulep->pam_flag & PAM_BINDING) ?
1135 PAM_BINDING_NAME :
1136 PAM_SUFFICIENT_NAME);
1137 goto exit_return;
1139 success = 1;
1140 break;
1141 case PAM_TRY_AGAIN:
1143 * We need to return immediately, and
1144 * we shouldn't reset the AUTHTOK item
1145 * since it is not an error per-se.
1147 pamh->pam_inmodule = RW_OK;
1148 pam_trace(PAM_DEBUG_MODULE,
1149 "[%d:%s]:%s(%p, %x): TRY_AGAIN: %s",
1150 pamh->include_depth, pam_trace_cname(pamh),
1151 function_name, (void *)pamh, flags,
1152 pam_strerror(pamh, required_error ?
1153 required_error : err));
1154 err = required_error ? required_error : err;
1155 goto exit_return;
1156 default:
1157 if (modulep->pam_flag & PAM_REQUISITE) {
1158 pamh->pam_inmodule = RW_OK;
1159 pam_trace(PAM_DEBUG_MODULE,
1160 "[%d:%s]:%s(%p, %x): requisite: %s",
1161 pamh->include_depth,
1162 pam_trace_cname(pamh),
1163 function_name, (void *)pamh, flags,
1164 pam_strerror(pamh,
1165 required_error ? required_error :
1166 err));
1167 err = required_error ?
1168 required_error : err;
1169 goto exit_return;
1170 } else if (modulep->pam_flag & PAM_REQRD_BIND) {
1171 if (!required_error)
1172 required_error = err;
1173 } else {
1174 if (!optional_error)
1175 optional_error = err;
1177 pam_trace(PAM_DEBUG_DEFAULT,
1178 "[%d:%s]:%s(%p, %x): error %s",
1179 pamh->include_depth, pam_trace_cname(pamh),
1180 function_name, (void *)pamh, flags,
1181 pam_strerror(pamh, err));
1182 break;
1185 modulep = modulep->next;
1188 pam_trace(PAM_DEBUG_MODULE, "[%d:%s]:stack_end:%s(%p, %x): %s %s: %s",
1189 pamh->include_depth, pam_trace_cname(pamh), function_name,
1190 (void *)pamh, flags, pamh->include_depth ? "included" : "final",
1191 required_error ? "required" : success ? "success" :
1192 optional_error ? "optional" : "default",
1193 pam_strerror(pamh, required_error ? required_error :
1194 success ? PAM_SUCCESS : optional_error ? optional_error : def_err));
1195 if (pamh->include_depth > 0) {
1196 free_pam_conf_info(pamh);
1197 pamh->include_depth--;
1198 /* continue at next entry */
1199 modulep = pamh->pam_conf_modulep[pamh->include_depth];
1200 pam_trace(PAM_DEBUG_MODULE, "looping for include[%d:%p]",
1201 pamh->include_depth, (void *)modulep);
1202 goto include;
1204 free_pam_conf_info(pamh);
1205 pamh->pam_inmodule = RW_OK;
1206 if (required_error != 0)
1207 return (required_error);
1208 else if (success != 0)
1209 return (PAM_SUCCESS);
1210 else if (optional_error != 0)
1211 return (optional_error);
1212 else
1213 return (def_err);
1215 exit_return:
1217 * All done at whatever depth we're at.
1218 * Go back to not having read /etc/pam.conf
1220 while (pamh->include_depth > 0) {
1221 free_pam_conf_info(pamh);
1222 pamh->include_depth--;
1224 free_pam_conf_info(pamh);
1225 pamh->pam_inmodule = RW_OK;
1226 return (err);
1230 * pam_authenticate - authenticate a user
1234 pam_authenticate(pam_handle_t *pamh, int flags)
1236 int retval;
1238 retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_AUTH_ERR,
1239 PAM_AUTHENTICATE, "pam_authenticate");
1241 if (retval != PAM_SUCCESS)
1242 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1243 return (retval);
1247 * pam_setcred - modify or retrieve user credentials
1251 pam_setcred(pam_handle_t *pamh, int flags)
1253 int retval;
1255 retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_CRED_ERR,
1256 PAM_SETCRED, "pam_setcred");
1258 if (retval != PAM_SUCCESS)
1259 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1260 return (retval);
1264 * pam_acct_mgmt - check password aging, account expiration
1268 pam_acct_mgmt(pam_handle_t *pamh, int flags)
1270 int retval;
1272 retval = run_stack(pamh, flags, PAM_ACCOUNT_MODULE, PAM_ACCT_EXPIRED,
1273 PAM_ACCT_MGMT, "pam_acct_mgmt");
1275 if (retval != PAM_SUCCESS &&
1276 retval != PAM_NEW_AUTHTOK_REQD) {
1277 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1279 return (retval);
1283 * pam_open_session - begin session management
1287 pam_open_session(pam_handle_t *pamh, int flags)
1289 int retval;
1291 retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR,
1292 PAM_OPEN_SESSION, "pam_open_session");
1294 if (retval != PAM_SUCCESS)
1295 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1296 return (retval);
1300 * pam_close_session - terminate session management
1304 pam_close_session(pam_handle_t *pamh, int flags)
1306 int retval;
1308 retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR,
1309 PAM_CLOSE_SESSION, "pam_close_session");
1311 if (retval != PAM_SUCCESS)
1312 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1313 return (retval);
1317 * pam_chauthtok - change user authentication token
1321 pam_chauthtok(pam_handle_t *pamh, int flags)
1323 int retval;
1325 /* do not let apps use PAM_PRELIM_CHECK or PAM_UPDATE_AUTHTOK */
1326 if (flags & (PAM_PRELIM_CHECK | PAM_UPDATE_AUTHTOK)) {
1327 pam_trace(PAM_DEBUG_DEFAULT,
1328 "pam_chauthtok(%p, %x): %s", (void *)pamh, flags,
1329 pam_strerror(pamh, PAM_SYMBOL_ERR));
1330 return (PAM_SYMBOL_ERR);
1333 /* 1st pass: PRELIM CHECK */
1334 retval = run_stack(pamh, flags | PAM_PRELIM_CHECK, PAM_PASSWORD_MODULE,
1335 PAM_AUTHTOK_ERR, PAM_CHAUTHTOK, "pam_chauthtok-prelim");
1337 if (retval == PAM_TRY_AGAIN)
1338 return (retval);
1340 if (retval != PAM_SUCCESS) {
1341 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1342 return (retval);
1345 /* 2nd pass: UPDATE AUTHTOK */
1346 retval = run_stack(pamh, flags | PAM_UPDATE_AUTHTOK,
1347 PAM_PASSWORD_MODULE, PAM_AUTHTOK_ERR, PAM_CHAUTHTOK,
1348 "pam_chauthtok-update");
1350 if (retval != PAM_SUCCESS)
1351 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1353 return (retval);
1357 * pam_putenv - add an environment variable to the PAM handle
1358 * if name_value == 'NAME=VALUE' then set variable to the value
1359 * if name_value == 'NAME=' then set variable to an empty value
1360 * if name_value == 'NAME' then delete the variable
1364 pam_putenv(pam_handle_t *pamh, const char *name_value)
1366 int error = PAM_SYSTEM_ERR;
1367 char *equal_sign = 0;
1368 char *name = NULL, *value = NULL, *tmp_value = NULL;
1369 env_list *traverse = NULL, *trail;
1371 pam_trace(PAM_DEBUG_DEFAULT,
1372 "pam_putenv(%p, %s)", (void *)pamh,
1373 name_value ? name_value : "NULL");
1375 if (pamh == NULL || name_value == NULL)
1376 goto out;
1378 /* see if we were passed 'NAME=VALUE', 'NAME=', or 'NAME' */
1379 if ((equal_sign = strchr(name_value, '=')) != 0) {
1380 if ((name = calloc(equal_sign - name_value + 1,
1381 sizeof (char))) == 0) {
1382 error = PAM_BUF_ERR;
1383 goto out;
1385 (void) strncpy(name, name_value, equal_sign - name_value);
1386 if ((value = strdup(++equal_sign)) == 0) {
1387 error = PAM_BUF_ERR;
1388 goto out;
1390 } else {
1391 if ((name = strdup(name_value)) == 0) {
1392 error = PAM_BUF_ERR;
1393 goto out;
1397 /* check to see if we already have this variable in the PAM handle */
1398 traverse = pamh->pam_env;
1399 trail = traverse;
1400 while (traverse && strncmp(traverse->name, name, strlen(name))) {
1401 trail = traverse;
1402 traverse = traverse->next;
1405 if (traverse) {
1406 /* found a match */
1407 if (value == 0) {
1408 /* remove the env variable */
1409 if (pamh->pam_env == traverse)
1410 pamh->pam_env = traverse->next;
1411 else
1412 trail->next = traverse->next;
1413 free_env(traverse);
1414 } else if (strlen(value) == 0) {
1415 /* set env variable to empty value */
1416 if ((tmp_value = strdup("")) == 0) {
1417 error = PAM_SYSTEM_ERR;
1418 goto out;
1420 free(traverse->value);
1421 traverse->value = tmp_value;
1422 } else {
1423 /* set the new value */
1424 if ((tmp_value = strdup(value)) == 0) {
1425 error = PAM_SYSTEM_ERR;
1426 goto out;
1428 free(traverse->value);
1429 traverse->value = tmp_value;
1432 } else if (traverse == 0 && value) {
1434 * could not find a match in the PAM handle.
1435 * add the new value if there is one
1437 if ((traverse = calloc(1, sizeof (env_list))) == 0) {
1438 error = PAM_BUF_ERR;
1439 goto out;
1441 if ((traverse->name = strdup(name)) == 0) {
1442 free_env(traverse);
1443 error = PAM_BUF_ERR;
1444 goto out;
1446 if ((traverse->value = strdup(value)) == 0) {
1447 free_env(traverse);
1448 error = PAM_BUF_ERR;
1449 goto out;
1451 if (trail == 0) {
1452 /* new head of list */
1453 pamh->pam_env = traverse;
1454 } else {
1455 /* adding to end of list */
1456 trail->next = traverse;
1460 error = PAM_SUCCESS;
1461 out:
1462 if (error != PAM_SUCCESS) {
1463 if (traverse) {
1464 free(traverse->name);
1465 free(traverse->value);
1466 free(traverse);
1469 free(name);
1470 free(value);
1471 return (error);
1475 * pam_getenv - retrieve an environment variable from the PAM handle
1477 char *
1478 pam_getenv(pam_handle_t *pamh, const char *name)
1480 int error = PAM_SYSTEM_ERR;
1481 env_list *traverse;
1483 pam_trace(PAM_DEBUG_DEFAULT,
1484 "pam_getenv(%p, %p)", (void *)pamh, (void *)name);
1486 if (pamh == NULL || name == NULL)
1487 goto out;
1489 /* check to see if we already have this variable in the PAM handle */
1490 traverse = pamh->pam_env;
1491 while (traverse && strncmp(traverse->name, name, strlen(name))) {
1492 traverse = traverse->next;
1494 error = (traverse ? PAM_SUCCESS : PAM_SYSTEM_ERR);
1495 pam_trace(PAM_DEBUG_DEFAULT,
1496 "pam_getenv(%p, %s)=%s", (void *)pamh, name,
1497 traverse ? traverse->value : "NULL");
1498 out:
1499 return (error ? NULL : strdup(traverse->value));
1503 * pam_getenvlist - retrieve all environment variables from the PAM handle
1504 * in a NULL terminated array. On error, return NULL.
1506 char **
1507 pam_getenvlist(pam_handle_t *pamh)
1509 int error = PAM_SYSTEM_ERR;
1510 char **list = 0;
1511 int length = 0;
1512 env_list *traverse;
1513 char *tenv;
1514 size_t tenv_size;
1516 pam_trace(PAM_DEBUG_DEFAULT,
1517 "pam_getenvlist(%p)", (void *)pamh);
1519 if (pamh == NULL)
1520 goto out;
1522 /* find out how many environment variables we have */
1523 traverse = pamh->pam_env;
1524 while (traverse) {
1525 length++;
1526 traverse = traverse->next;
1529 /* allocate the array we will return to the caller */
1530 if ((list = calloc(length + 1, sizeof (char *))) == NULL) {
1531 error = PAM_BUF_ERR;
1532 goto out;
1535 /* add the variables one by one */
1536 length = 0;
1537 traverse = pamh->pam_env;
1538 while (traverse != NULL) {
1539 tenv_size = strlen(traverse->name) +
1540 strlen(traverse->value) + 2; /* name=val\0 */
1541 if ((tenv = malloc(tenv_size)) == NULL) {
1542 error = PAM_BUF_ERR;
1543 goto out;
1545 /*LINTED*/
1546 (void) sprintf(tenv, "%s=%s", traverse->name, traverse->value);
1547 list[length++] = tenv;
1548 traverse = traverse->next;
1550 list[length] = NULL;
1552 error = PAM_SUCCESS;
1553 out:
1554 if (error != PAM_SUCCESS) {
1555 /* free the partially constructed list */
1556 if (list) {
1557 length = 0;
1558 while (list[length] != NULL) {
1559 free(list[length]);
1560 length++;
1562 free(list);
1565 return (error ? NULL : list);
1569 * Routines to load a requested module on demand
1573 * load_modules - load the requested module.
1574 * if the dlopen or dlsym fail, then
1575 * the module is ignored.
1578 static int
1579 load_modules(pam_handle_t *pamh, int type, char *function_name,
1580 pamtab_t *pam_entry)
1582 void *mh;
1583 struct auth_module *authp;
1584 struct account_module *accountp;
1585 struct session_module *sessionp;
1586 struct password_module *passwdp;
1587 int loading_functions = 0; /* are we currently loading functions? */
1589 pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=%s:%s",
1590 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
1591 function_name, pam_trace_fname(pam_entry->pam_flag),
1592 pam_entry->module_path);
1594 while (pam_entry != NULL) {
1595 pam_trace(PAM_DEBUG_DEFAULT,
1596 "while load_modules[%d:%s](%p, %s)=%s",
1597 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
1598 function_name, pam_entry->module_path);
1600 if (pam_entry->pam_flag & PAM_INCLUDE) {
1601 pam_trace(PAM_DEBUG_DEFAULT,
1602 "done load_modules[%d:%s](%p, %s)=%s",
1603 pamh->include_depth, pam_trace_cname(pamh),
1604 (void *)pamh, function_name,
1605 pam_entry->module_path);
1606 return (PAM_SUCCESS);
1608 switch (type) {
1609 case PAM_AUTH_MODULE:
1611 /* if the function has already been loaded, return */
1612 authp = pam_entry->function_ptr;
1613 if (!loading_functions &&
1614 (((strcmp(function_name, PAM_SM_AUTHENTICATE)
1615 == 0) && authp && authp->pam_sm_authenticate) ||
1616 ((strcmp(function_name, PAM_SM_SETCRED) == 0) &&
1617 authp && authp->pam_sm_setcred))) {
1618 return (PAM_SUCCESS);
1621 /* function has not been loaded yet */
1622 loading_functions = 1;
1623 if (authp == NULL) {
1624 authp = calloc(1, sizeof (struct auth_module));
1625 if (authp == NULL)
1626 return (PAM_BUF_ERR);
1629 /* if open_module fails, return error */
1630 if ((mh = open_module(pamh,
1631 pam_entry->module_path)) == NULL) {
1632 __pam_log(LOG_AUTH | LOG_ERR,
1633 "load_modules[%d:%s]: can not open module "
1634 "%s", pamh->include_depth,
1635 pam_trace_cname(pamh),
1636 pam_entry->module_path);
1637 free(authp);
1638 return (PAM_OPEN_ERR);
1641 /* load the authentication function */
1642 if (strcmp(function_name, PAM_SM_AUTHENTICATE) == 0) {
1643 if (load_function(mh, PAM_SM_AUTHENTICATE,
1644 &authp->pam_sm_authenticate)
1645 != PAM_SUCCESS) {
1646 /* return error if dlsym fails */
1647 free(authp);
1648 return (PAM_SYMBOL_ERR);
1651 /* load the setcred function */
1652 } else if (strcmp(function_name, PAM_SM_SETCRED) == 0) {
1653 if (load_function(mh, PAM_SM_SETCRED,
1654 &authp->pam_sm_setcred) != PAM_SUCCESS) {
1655 /* return error if dlsym fails */
1656 free(authp);
1657 return (PAM_SYMBOL_ERR);
1660 pam_entry->function_ptr = authp;
1661 break;
1662 case PAM_ACCOUNT_MODULE:
1663 accountp = pam_entry->function_ptr;
1664 if (!loading_functions &&
1665 (strcmp(function_name, PAM_SM_ACCT_MGMT) == 0) &&
1666 accountp && accountp->pam_sm_acct_mgmt) {
1667 return (PAM_SUCCESS);
1671 * If functions are added to the account module,
1672 * verify that one of the other functions hasn't
1673 * already loaded it. See PAM_AUTH_MODULE code.
1675 loading_functions = 1;
1676 accountp = calloc(1, sizeof (struct account_module));
1677 if (accountp == NULL)
1678 return (PAM_BUF_ERR);
1680 /* if open_module fails, return error */
1681 if ((mh = open_module(pamh,
1682 pam_entry->module_path)) == NULL) {
1683 __pam_log(LOG_AUTH | LOG_ERR,
1684 "load_modules[%d:%s]: can not open module "
1685 "%s", pamh->include_depth,
1686 pam_trace_cname(pamh),
1687 pam_entry->module_path);
1688 free(accountp);
1689 return (PAM_OPEN_ERR);
1692 if (load_function(mh, PAM_SM_ACCT_MGMT,
1693 &accountp->pam_sm_acct_mgmt) != PAM_SUCCESS) {
1694 __pam_log(LOG_AUTH | LOG_ERR,
1695 "load_modules[%d:%s]: pam_sm_acct_mgmt() "
1696 "missing", pamh->include_depth,
1697 pam_trace_cname(pamh));
1698 free(accountp);
1699 return (PAM_SYMBOL_ERR);
1701 pam_entry->function_ptr = accountp;
1702 break;
1703 case PAM_SESSION_MODULE:
1704 sessionp = pam_entry->function_ptr;
1705 if (!loading_functions &&
1706 (((strcmp(function_name,
1707 PAM_SM_OPEN_SESSION) == 0) &&
1708 sessionp && sessionp->pam_sm_open_session) ||
1709 ((strcmp(function_name,
1710 PAM_SM_CLOSE_SESSION) == 0) &&
1711 sessionp && sessionp->pam_sm_close_session))) {
1712 return (PAM_SUCCESS);
1715 loading_functions = 1;
1716 if (sessionp == NULL) {
1717 sessionp = calloc(1,
1718 sizeof (struct session_module));
1719 if (sessionp == NULL)
1720 return (PAM_BUF_ERR);
1723 /* if open_module fails, return error */
1724 if ((mh = open_module(pamh,
1725 pam_entry->module_path)) == NULL) {
1726 __pam_log(LOG_AUTH | LOG_ERR,
1727 "load_modules[%d:%s]: can not open module "
1728 "%s", pamh->include_depth,
1729 pam_trace_cname(pamh),
1730 pam_entry->module_path);
1731 free(sessionp);
1732 return (PAM_OPEN_ERR);
1735 if ((strcmp(function_name, PAM_SM_OPEN_SESSION) == 0) &&
1736 load_function(mh, PAM_SM_OPEN_SESSION,
1737 &sessionp->pam_sm_open_session) != PAM_SUCCESS) {
1738 free(sessionp);
1739 return (PAM_SYMBOL_ERR);
1740 } else if ((strcmp(function_name,
1741 PAM_SM_CLOSE_SESSION) == 0) &&
1742 load_function(mh, PAM_SM_CLOSE_SESSION,
1743 &sessionp->pam_sm_close_session) != PAM_SUCCESS) {
1744 free(sessionp);
1745 return (PAM_SYMBOL_ERR);
1747 pam_entry->function_ptr = sessionp;
1748 break;
1749 case PAM_PASSWORD_MODULE:
1750 passwdp = pam_entry->function_ptr;
1751 if (!loading_functions &&
1752 (strcmp(function_name, PAM_SM_CHAUTHTOK) == 0) &&
1753 passwdp && passwdp->pam_sm_chauthtok) {
1754 return (PAM_SUCCESS);
1758 * If functions are added to the password module,
1759 * verify that one of the other functions hasn't
1760 * already loaded it. See PAM_AUTH_MODULE code.
1762 loading_functions = 1;
1763 passwdp = calloc(1, sizeof (struct password_module));
1764 if (passwdp == NULL)
1765 return (PAM_BUF_ERR);
1767 /* if open_module fails, continue */
1768 if ((mh = open_module(pamh,
1769 pam_entry->module_path)) == NULL) {
1770 __pam_log(LOG_AUTH | LOG_ERR,
1771 "load_modules[%d:%s]: can not open module "
1772 "%s", pamh->include_depth,
1773 pam_trace_cname(pamh),
1774 pam_entry->module_path);
1775 free(passwdp);
1776 return (PAM_OPEN_ERR);
1779 if (load_function(mh, PAM_SM_CHAUTHTOK,
1780 &passwdp->pam_sm_chauthtok) != PAM_SUCCESS) {
1781 free(passwdp);
1782 return (PAM_SYMBOL_ERR);
1784 pam_entry->function_ptr = passwdp;
1785 break;
1786 default:
1787 pam_trace(PAM_DEBUG_DEFAULT,
1788 "load_modules[%d:%s](%p, %s): unsupported type %d",
1789 pamh->include_depth, pam_trace_cname(pamh),
1790 (void *)pamh, function_name, type);
1791 break;
1794 pam_entry = pam_entry->next;
1795 } /* while */
1797 pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=done",
1798 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
1799 function_name);
1801 return (PAM_SUCCESS);
1805 * open_module - Open the module first checking for
1806 * propers modes and ownerships on the file.
1809 static void *
1810 open_module(pam_handle_t *pamh, char *module_so)
1812 struct stat stb;
1813 char *errmsg;
1814 void *lfd;
1815 fd_list *module_fds = 0;
1816 fd_list *trail = 0;
1817 fd_list *traverse = 0;
1819 /* Check the ownership and file modes */
1820 if (stat(module_so, &stb) < 0) {
1821 __pam_log(LOG_AUTH | LOG_ERR,
1822 "open_module[%d:%s]: stat(%s) failed: %s",
1823 pamh->include_depth, pam_trace_cname(pamh), module_so,
1824 strerror(errno));
1825 return (NULL);
1827 if (stb.st_uid != (uid_t)0) {
1828 __pam_log(LOG_AUTH | LOG_ALERT,
1829 "open_module[%d:%s]: Owner of the module %s is not root",
1830 pamh->include_depth, pam_trace_cname(pamh), module_so);
1831 return (NULL);
1833 if (stb.st_mode & S_IWGRP) {
1834 __pam_log(LOG_AUTH | LOG_ALERT,
1835 "open_module[%d:%s]: module %s writable by group",
1836 pamh->include_depth, pam_trace_cname(pamh), module_so);
1837 return (NULL);
1839 if (stb.st_mode & S_IWOTH) {
1840 __pam_log(LOG_AUTH | LOG_ALERT,
1841 "open_module[%d:%s]: module %s writable by world",
1842 pamh->include_depth, pam_trace_cname(pamh), module_so);
1843 return (NULL);
1847 * Perform the dlopen()
1849 lfd = (void *)dlopen(module_so, RTLD_LAZY);
1851 if (lfd == NULL) {
1852 errmsg = dlerror();
1853 __pam_log(LOG_AUTH | LOG_ERR, "open_module[%d:%s]: %s "
1854 "failed: %s", pamh->include_depth, pam_trace_cname(pamh),
1855 module_so, errmsg != NULL ? errmsg : "Unknown error");
1856 return (NULL);
1857 } else {
1858 /* add this fd to the pam handle */
1859 if ((module_fds = calloc(1, sizeof (fd_list))) == 0) {
1860 (void) dlclose(lfd);
1861 lfd = 0;
1862 return (NULL);
1864 module_fds->mh = lfd;
1866 if (pamh->fd == 0) {
1867 /* adding new head of list */
1868 pamh->fd = module_fds;
1869 } else {
1870 /* appending to end of list */
1871 traverse = pamh->fd;
1872 while (traverse) {
1873 trail = traverse;
1874 traverse = traverse->next;
1876 trail->next = module_fds;
1880 return (lfd);
1884 * load_function - call dlsym() to resolve the function address
1886 static int
1887 load_function(void *lfd, char *name, int (**func)())
1889 char *errmsg = NULL;
1891 if (lfd == NULL)
1892 return (PAM_SYMBOL_ERR);
1894 *func = (int (*)())dlsym(lfd, name);
1895 if (*func == NULL) {
1896 errmsg = dlerror();
1897 __pam_log(LOG_AUTH | LOG_ERR, "dlsym failed %s: error %s",
1898 name, errmsg != NULL ? errmsg : "Unknown error");
1899 return (PAM_SYMBOL_ERR);
1902 pam_trace(PAM_DEBUG_DEFAULT,
1903 "load_function: successful load of %s", name);
1904 return (PAM_SUCCESS);
1908 * Routines to read the pam.conf configuration file
1912 * open_pam_conf - open the pam.conf config file
1915 static int
1916 open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config,
1917 int shardfile)
1919 struct stat stb;
1920 int fd;
1922 if ((fd = open(config, O_RDONLY)) == -1) {
1923 if (!shardfile)
1924 __pam_log(LOG_AUTH | LOG_ALERT,
1925 "open_pam_conf[%d:%s]: open(%s) failed: %s",
1926 pamh->include_depth, pam_trace_cname(pamh), config,
1927 strerror(errno));
1928 return (0);
1930 /* Check the ownership and file modes */
1931 if (fstat(fd, &stb) < 0) {
1932 __pam_log(LOG_AUTH | LOG_ALERT,
1933 "open_pam_conf[%d:%s]: stat(%s) failed: %s",
1934 pamh->include_depth, pam_trace_cname(pamh), config,
1935 strerror(errno));
1936 (void) close(fd);
1937 return (0);
1939 if (stb.st_uid != (uid_t)0) {
1940 __pam_log(LOG_AUTH | LOG_ALERT,
1941 "open_pam_conf[%d:%s]: Owner of %s is not root",
1942 pamh->include_depth, pam_trace_cname(pamh), config);
1943 (void) close(fd);
1944 return (0);
1946 if (stb.st_mode & S_IWGRP) {
1947 __pam_log(LOG_AUTH | LOG_ALERT,
1948 "open_pam_conf[%d:%s]: %s writable by group",
1949 pamh->include_depth, pam_trace_cname(pamh), config);
1950 (void) close(fd);
1951 return (0);
1953 if (stb.st_mode & S_IWOTH) {
1954 __pam_log(LOG_AUTH | LOG_ALERT,
1955 "open_pam_conf[%d:%s]: %s writable by world",
1956 pamh->include_depth, pam_trace_cname(pamh), config);
1957 (void) close(fd);
1958 return (0);
1960 if ((*pam_fh = calloc(1, sizeof (struct pam_fh))) == NULL) {
1961 (void) close(fd);
1962 return (0);
1964 (*pam_fh)->fconfig = fd;
1965 (*pam_fh)->bufsize = (size_t)stb.st_size;
1966 if (((*pam_fh)->data = mmap(NULL, (*pam_fh)->bufsize, PROT_READ,
1967 MAP_PRIVATE, (*pam_fh)->fconfig, 0)) == MAP_FAILED) {
1968 (void) close(fd);
1969 free (*pam_fh);
1970 return (0);
1972 (*pam_fh)->bufferp = (*pam_fh)->data;
1974 return (1);
1978 * close_pam_conf - close pam.conf
1981 static void
1982 close_pam_conf(struct pam_fh *pam_fh)
1984 (void) munmap(pam_fh->data, pam_fh->bufsize);
1985 (void) close(pam_fh->fconfig);
1986 free(pam_fh);
1990 * read_pam_conf - read in each entry in pam.conf and store info
1991 * under the pam handle.
1994 static int
1995 read_pam_conf(pam_handle_t *pamh, char *config, char *service)
1997 struct pam_fh *pam_fh;
1998 pamtab_t *pamentp;
1999 pamtab_t *tpament;
2000 int error;
2001 int i = pamh->include_depth; /* include depth */
2002 int j;
2003 int shardfile = 1;
2005 * service types:
2006 * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3)
2008 int service_found[PAM_NUM_MODULE_TYPES+1] = {0, 0, 0, 0, 0};
2010 pamh->pam_conf_name[i] = strdup(config);
2011 pam_trace(PAM_DEBUG_CONF, "read_pam_conf[%d:%s](%p) open(%s)",
2012 i, pam_trace_cname(pamh), (void *)pamh, config);
2013 if (open_pam_conf(&pam_fh, pamh, config, 1) == 0) {
2014 /* fall back to /etc/pam.conf */
2015 config = PAM_CONFIG;
2016 shardfile = 0;
2018 pam_trace(PAM_DEBUG_CONF, "read_pam_conf[%d:%s](%p) open(%s)",
2019 i, pam_trace_cname(pamh), (void *)pamh, PAM_CONFIG);
2020 if (open_pam_conf(&pam_fh, pamh, config, 0) == 0)
2021 return (PAM_SYSTEM_ERR);
2024 while ((error =
2025 get_pam_conf_entry(pam_fh, pamh, &pamentp, service, shardfile))
2026 == PAM_SUCCESS && pamentp) {
2028 /* See if entry is this service and valid */
2029 if (verify_pam_conf(pamentp, service)) {
2030 pam_trace(PAM_DEBUG_CONF,
2031 "read_pam_conf[%d:%s](%p): bad entry error %s",
2032 i, pam_trace_cname(pamh), (void *)pamh, service);
2034 error = PAM_SYSTEM_ERR;
2035 free_pamconf(pamentp);
2036 goto out;
2038 if (strcasecmp(pamentp->pam_service, service) == 0) {
2039 pam_trace(PAM_DEBUG_CONF,
2040 "read_pam_conf[%d:%s](%p): processing %s",
2041 i, pam_trace_cname(pamh), (void *)pamh, service);
2042 /* process first service entry */
2043 if (service_found[pamentp->pam_type + 1] == 0) {
2044 /* purge "other" entries */
2045 while ((tpament = pamh->pam_conf_info[i]
2046 [pamentp->pam_type]) != NULL) {
2047 pam_trace(PAM_DEBUG_CONF,
2048 "read_pam_conf(%p): purging "
2049 "\"other\"[%d:%s][%s]",
2050 (void *)pamh, i,
2051 pam_trace_cname(pamh),
2052 pam_snames[pamentp->pam_type]);
2053 pamh->pam_conf_info[i]
2054 [pamentp->pam_type] = tpament->next;
2055 free_pamconf(tpament);
2057 /* add first service entry */
2058 pam_trace(PAM_DEBUG_CONF,
2059 "read_pam_conf(%p): adding 1st "
2060 "%s[%d:%s][%s]",
2061 (void *)pamh, service, i,
2062 pam_trace_cname(pamh),
2063 pam_snames[pamentp->pam_type]);
2064 pamh->pam_conf_info[i][pamentp->pam_type] =
2065 pamentp;
2066 service_found[pamentp->pam_type + 1] = 1;
2067 } else {
2068 /* append more service entries */
2069 pam_trace(PAM_DEBUG_CONF,
2070 "read_pam_conf(%p): adding more "
2071 "%s[%d:%s][%s]",
2072 (void *)pamh, service, i,
2073 pam_trace_cname(pamh),
2074 pam_snames[pamentp->pam_type]);
2075 tpament =
2076 pamh->pam_conf_info[i][pamentp->pam_type];
2077 while (tpament->next != NULL) {
2078 tpament = tpament->next;
2080 tpament->next = pamentp;
2082 } else if (service_found[pamentp->pam_type + 1] == 0) {
2083 /* See if "other" entry available and valid */
2084 if (verify_pam_conf(pamentp, "other")) {
2085 pam_trace(PAM_DEBUG_CONF,
2086 "read_pam_conf(%p): bad entry error %s "
2087 "\"other\"[%d:%s]",
2088 (void *)pamh, service, i,
2089 pam_trace_cname(pamh));
2090 error = PAM_SYSTEM_ERR;
2091 free_pamconf(pamentp);
2092 goto out;
2094 if (strcasecmp(pamentp->pam_service, "other") == 0) {
2095 pam_trace(PAM_DEBUG_CONF,
2096 "read_pam_conf(%p): processing "
2097 "\"other\"[%d:%s]", (void *)pamh, i,
2098 pam_trace_cname(pamh));
2099 if ((tpament = pamh->pam_conf_info[i]
2100 [pamentp->pam_type]) == NULL) {
2101 /* add first "other" entry */
2102 pam_trace(PAM_DEBUG_CONF,
2103 "read_pam_conf(%p): adding 1st "
2104 "other[%d:%s][%s]", (void *)pamh, i,
2105 pam_trace_cname(pamh),
2106 pam_snames[pamentp->pam_type]);
2107 pamh->pam_conf_info[i]
2108 [pamentp->pam_type] = pamentp;
2109 } else {
2110 /* append more "other" entries */
2111 pam_trace(PAM_DEBUG_CONF,
2112 "read_pam_conf(%p): adding more "
2113 "other[%d:%s][%s]", (void *)pamh, i,
2114 pam_trace_cname(pamh),
2115 pam_snames[pamentp->pam_type]);
2116 while (tpament->next != NULL) {
2117 tpament = tpament->next;
2119 tpament->next = pamentp;
2121 } else {
2122 /* irrelevant entry */
2123 free_pamconf(pamentp);
2125 } else {
2126 /* irrelevant entry */
2127 free_pamconf(pamentp);
2132 * If we have no entries for this module type (e.g. "account"), then
2133 * generate a single "include" rule for the shard file "other" as a
2134 * fallback.
2136 if (strcasecmp(service, "other") == 0)
2137 goto out;
2139 for (j = 0; j < PAM_NUM_MODULE_TYPES; j++) {
2140 pamtab_t *pe;
2142 if (service_found[j + 1] != 0 ||
2143 pamh->pam_conf_info[i][j] != NULL)
2144 continue;
2146 pe = calloc(1, sizeof (pamtab_t));
2148 pam_trace(PAM_DEBUG_CONF, "read_pam_conf(%p): falling back to "
2149 "\"other\" for module type \"%s\" in service \"%s\"",
2150 (void *)pamh, pam_snames[j], service);
2151 if (pe == NULL) {
2152 error = PAM_SYSTEM_ERR;
2153 __pam_log(LOG_AUTH | LOG_ERR, "calloc: out of memory");
2154 goto out;
2157 pe->pam_service = strdup(service);
2158 pe->pam_type = j;
2159 pe->pam_flag = PAM_INCLUDE;
2160 if (asprintf(&pe->module_path, "%s%s", PAM_CONFIG_DIR,
2161 "other") < 0) {
2162 free(pe);
2163 error = PAM_SYSTEM_ERR;
2164 __pam_log(LOG_AUTH | LOG_ERR, "asprintf: out of memory");
2165 goto out;
2168 pamh->pam_conf_info[i][j] = pe;
2171 out:
2172 (void) close_pam_conf(pam_fh);
2173 if (error != PAM_SUCCESS)
2174 free_pam_conf_info(pamh);
2175 return (error);
2179 * get_pam_conf_entry - get a pam.conf entry
2182 static int
2183 get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam,
2184 char *service, int shardfile)
2186 char *cp, *arg;
2187 int argc;
2188 char *tmp, *tmp_free;
2189 int i;
2190 char *current_line = NULL;
2191 int error = PAM_SYSTEM_ERR; /* preset to error */
2192 int err;
2194 /* get the next line from pam.conf */
2195 if ((cp = nextline(pam_fh, pamh, &err)) == NULL) {
2196 /* no more lines in pam.conf ==> return */
2197 error = PAM_SUCCESS;
2198 *pam = NULL;
2199 goto out;
2202 if ((*pam = calloc(1, sizeof (pamtab_t))) == NULL) {
2203 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2204 goto out;
2207 /* copy full line for error reporting */
2208 if ((current_line = strdup(cp)) == NULL) {
2209 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2210 goto out;
2213 pam_trace(PAM_DEBUG_CONF,
2214 "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh), current_line);
2216 if (shardfile) {
2218 * If this is an /etc/pam.d shard file, then the service name
2219 * comes from the file name of the shard.
2221 if (((*pam)->pam_service = strdup(service)) == 0) {
2222 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2223 goto out;
2225 } else {
2226 /* get service name (e.g. login, su, passwd) */
2227 if ((arg = read_next_token(&cp)) == 0) {
2228 __pam_log(LOG_AUTH | LOG_CRIT,
2229 "illegal pam.conf[%s] entry: %s: missing SERVICE "
2230 "NAME", pam_trace_cname(pamh), current_line);
2231 goto out;
2233 if (((*pam)->pam_service = strdup(arg)) == 0) {
2234 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2235 goto out;
2239 /* get module type (e.g. authentication, acct mgmt) */
2240 if ((arg = read_next_token(&cp)) == 0) {
2241 __pam_log(LOG_AUTH | LOG_CRIT,
2242 "illegal pam.conf[%s] entry: %s: missing MODULE TYPE",
2243 pam_trace_cname(pamh), current_line);
2244 (*pam)->pam_type = -1; /* 0 is a valid value */
2245 goto getflag;
2247 if (strcasecmp(arg, PAM_AUTH_NAME) == 0) {
2248 (*pam)->pam_type = PAM_AUTH_MODULE;
2249 } else if (strcasecmp(arg, PAM_ACCOUNT_NAME) == 0) {
2250 (*pam)->pam_type = PAM_ACCOUNT_MODULE;
2251 } else if (strcasecmp(arg, PAM_SESSION_NAME) == 0) {
2252 (*pam)->pam_type = PAM_SESSION_MODULE;
2253 } else if (strcasecmp(arg, PAM_PASSWORD_NAME) == 0) {
2254 (*pam)->pam_type = PAM_PASSWORD_MODULE;
2255 } else {
2256 /* error */
2257 __pam_log(LOG_AUTH | LOG_CRIT,
2258 "illegal pam.conf[%s] entry: %s: invalid module "
2259 "type: %s", pam_trace_cname(pamh), current_line, arg);
2260 (*pam)->pam_type = -1; /* 0 is a valid value */
2263 getflag:
2264 /* get pam flag (e.g., requisite, required, sufficient, optional) */
2265 if ((arg = read_next_token(&cp)) == 0) {
2266 __pam_log(LOG_AUTH | LOG_CRIT,
2267 "illegal pam.conf[%s] entry: %s: missing CONTROL FLAG",
2268 pam_trace_cname(pamh), current_line);
2269 goto getpath;
2271 if (strcasecmp(arg, PAM_BINDING_NAME) == 0) {
2272 (*pam)->pam_flag = PAM_BINDING;
2273 } else if (strcasecmp(arg, PAM_INCLUDE_NAME) == 0) {
2274 (*pam)->pam_flag = PAM_INCLUDE;
2275 } else if (strcasecmp(arg, PAM_OPTIONAL_NAME) == 0) {
2276 (*pam)->pam_flag = PAM_OPTIONAL;
2277 } else if (strcasecmp(arg, PAM_REQUIRED_NAME) == 0) {
2278 (*pam)->pam_flag = PAM_REQUIRED;
2279 } else if (strcasecmp(arg, PAM_REQUISITE_NAME) == 0) {
2280 (*pam)->pam_flag = PAM_REQUISITE;
2281 } else if (strcasecmp(arg, PAM_SUFFICIENT_NAME) == 0) {
2282 (*pam)->pam_flag = PAM_SUFFICIENT;
2283 } else {
2284 /* error */
2285 __pam_log(LOG_AUTH | LOG_CRIT,
2286 "illegal pam.conf[%s] entry: %s",
2287 pam_trace_cname(pamh), current_line);
2288 __pam_log(LOG_AUTH | LOG_CRIT,
2289 "\tinvalid control flag: %s", arg);
2292 getpath:
2293 /* get module path (e.g. /usr/lib/security/pam_unix_auth.so.1) */
2294 if ((arg = read_next_token(&cp)) == 0) {
2295 __pam_log(LOG_AUTH | LOG_CRIT,
2296 "illegal pam.conf[%s] entry: %s: missing MODULE PATH",
2297 pam_trace_cname(pamh), current_line);
2298 error = PAM_SUCCESS; /* success */
2299 goto out;
2301 if (arg[0] != '/') {
2302 int ret;
2304 * If module path does not start with "/", then
2305 * prepend PAM_LIB_DIR (/usr/lib/security/).
2307 if ((*pam)->pam_flag & PAM_INCLUDE) {
2309 * If this is an /etc/pam.d shard, we want to get
2310 * included files from /etc/pam.d rather than
2311 * /usr/lib/security.
2313 ret = asprintf(&(*pam)->module_path, "%s%s",
2314 (shardfile ? PAM_CONFIG_DIR : PAM_LIB_DIR), arg);
2315 } else {
2316 ret = asprintf(&(*pam)->module_path, "%s%s%s",
2317 PAM_LIB_DIR, PAM_ISA_DIR, arg);
2319 if (ret < 0) {
2320 __pam_log(LOG_AUTH | LOG_ERR,
2321 "asprintf: out of memory");
2322 goto out;
2324 } else {
2325 /* Full path provided for module */
2326 char *isa;
2328 /* Check for Instruction Set Architecture indicator */
2329 if ((isa = strstr(arg, PAM_ISA)) != NULL) {
2330 size_t len;
2331 len = strlen(arg) - (sizeof (PAM_ISA)-1) +
2332 sizeof (PAM_ISA_DIR);
2334 /* substitute the architecture dependent path */
2335 if (((*pam)->module_path = malloc(len)) == NULL) {
2336 __pam_log(LOG_AUTH | LOG_ERR,
2337 "strdup: out of memory");
2338 goto out;
2340 *isa = '\000';
2341 isa += strlen(PAM_ISA);
2342 (void) snprintf((*pam)->module_path, len, "%s%s%s",
2343 arg, PAM_ISA_DIR, isa);
2344 } else if (((*pam)->module_path = strdup(arg)) == 0) {
2345 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2346 goto out;
2350 /* count the number of module-specific options first */
2351 argc = 0;
2352 if ((tmp = strdup(cp)) == NULL) {
2353 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2354 goto out;
2356 tmp_free = tmp;
2357 for (arg = read_next_token(&tmp); arg; arg = read_next_token(&tmp))
2358 argc++;
2359 free(tmp_free);
2361 /* allocate array for the module-specific options */
2362 if (argc > 0) {
2363 if (((*pam)->module_argv =
2364 calloc(argc+1, sizeof (char *))) == 0) {
2365 __pam_log(LOG_AUTH | LOG_ERR, "calloc: out of memory");
2366 goto out;
2368 i = 0;
2369 for (arg = read_next_token(&cp); arg;
2370 arg = read_next_token(&cp)) {
2371 (*pam)->module_argv[i] = strdup(arg);
2372 if ((*pam)->module_argv[i] == NULL) {
2373 __pam_log(LOG_AUTH | LOG_ERR, "strdup failed");
2374 goto out;
2376 i++;
2378 (*pam)->module_argv[argc] = NULL;
2380 (*pam)->module_argc = argc;
2382 error = PAM_SUCCESS; /* success */
2383 (*pam)->pam_err = err; /* was the line truncated */
2385 out:
2386 free(current_line);
2387 if (error != PAM_SUCCESS) {
2388 /* on error free this */
2389 if (*pam)
2390 free_pamconf(*pam);
2392 return (error);
2397 * read_next_token - skip tab and space characters and return the next token
2400 static char *
2401 read_next_token(char **cpp)
2403 register char *cp = *cpp;
2404 char *start;
2406 if (cp == NULL) {
2407 *cpp = NULL;
2408 return (NULL);
2410 while (*cp == ' ' || *cp == '\t')
2411 cp++;
2412 if (*cp == '\0') {
2413 *cpp = NULL;
2414 return (NULL);
2416 start = cp;
2417 while (*cp && *cp != ' ' && *cp != '\t')
2418 cp++;
2419 if (*cp != '\0')
2420 *cp++ = '\0';
2421 *cpp = cp;
2422 return (start);
2425 static char *
2426 pam_conf_strnchr(char *sp, int c, intptr_t count)
2428 while (count) {
2429 if (*sp == (char)c)
2430 return ((char *)sp);
2431 else {
2432 sp++;
2433 count--;
2436 return (NULL);
2440 * nextline - skip all blank lines and comments
2443 static char *
2444 nextline(struct pam_fh *pam_fh, pam_handle_t *pamh, int *err)
2446 char *ll;
2447 int find_a_line = 0;
2448 char *data = pam_fh->data;
2449 char *bufferp = pam_fh->bufferp;
2450 char *bufferendp = &data[pam_fh->bufsize];
2451 size_t input_len;
2454 * Skip the blank line, comment line
2456 while (!find_a_line) {
2457 /* if we are at the end of the buffer, there is no next line */
2458 if (bufferp == bufferendp)
2459 return (NULL);
2461 /* skip blank line */
2462 while (*bufferp == '\n') {
2464 * If we are at the end of the buffer, there is
2465 * no next line.
2467 if (++bufferp == bufferendp) {
2468 return (NULL);
2470 /* else we check *bufferp again */
2473 /* skip comment line */
2474 while (*bufferp == '#') {
2475 if ((ll = pam_conf_strnchr(bufferp, '\n',
2476 bufferendp - bufferp)) != NULL) {
2477 bufferp = ll;
2478 } else {
2480 * this comment line the last line.
2481 * no next line
2483 return (NULL);
2487 * If we are at the end of the buffer, there is
2488 * no next line.
2490 if (bufferp == bufferendp) {
2491 return (NULL);
2495 if ((*bufferp != '\n') && (*bufferp != '#')) {
2496 find_a_line = 1;
2500 *err = PAM_SUCCESS;
2501 /* now we find one line */
2502 if ((ll = pam_conf_strnchr(bufferp, '\n', bufferendp - bufferp))
2503 != NULL) {
2504 if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) {
2505 __pam_log(LOG_AUTH | LOG_ERR,
2506 "nextline[%d:%s]: pam.conf line too long %.256s",
2507 pamh->include_depth, pam_trace_cname(pamh),
2508 bufferp);
2509 input_len = sizeof (pam_fh->line) - 1;
2510 *err = PAM_SERVICE_ERR;
2512 (void) strncpy(pam_fh->line, bufferp, input_len);
2513 pam_fh->line[input_len] = '\0';
2514 pam_fh->bufferp = ll++;
2515 } else {
2516 ll = bufferendp;
2517 if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) {
2518 __pam_log(LOG_AUTH | LOG_ERR,
2519 "nextline[%d:%s]: pam.conf line too long %.256s",
2520 pamh->include_depth, pam_trace_cname(pamh),
2521 bufferp);
2522 input_len = sizeof (pam_fh->line) - 1;
2523 *err = PAM_SERVICE_ERR;
2525 (void) strncpy(pam_fh->line, bufferp, input_len);
2526 pam_fh->line[input_len] = '\0';
2527 pam_fh->bufferp = ll;
2530 return (pam_fh->line);
2534 * verify_pam_conf - verify that the pam_conf entry is filled in.
2536 * True = Error if there is no service.
2537 * True = Error if there is a service and it matches the requested service
2538 * but, the type, flag, line overflow, or path is in error.
2541 static int
2542 verify_pam_conf(pamtab_t *pam, char *service)
2544 return ((pam->pam_service == NULL) ||
2545 ((strcasecmp(pam->pam_service, service) == 0) &&
2546 ((pam->pam_type == -1) ||
2547 (pam->pam_flag == 0) ||
2548 (pam->pam_err != PAM_SUCCESS) ||
2549 (pam->module_path == NULL))));
2553 * Routines to free allocated storage
2557 * clean_up - free allocated storage in the pam handle
2560 static void
2561 clean_up(pam_handle_t *pamh)
2563 int i;
2564 pam_repository_t *auth_rep;
2566 if (pamh) {
2567 while (pamh->include_depth >= 0) {
2568 free_pam_conf_info(pamh);
2569 pamh->include_depth--;
2572 /* Cleanup PAM_REPOSITORY structure */
2573 auth_rep = pamh->ps_item[PAM_REPOSITORY].pi_addr;
2574 if (auth_rep != NULL) {
2575 free(auth_rep->type);
2576 free(auth_rep->scope);
2579 for (i = 0; i < PAM_MAX_ITEMS; i++) {
2580 if (pamh->ps_item[i].pi_addr != NULL) {
2581 if (i == PAM_AUTHTOK || i == PAM_OLDAUTHTOK) {
2582 (void) memset(pamh->ps_item[i].pi_addr,
2583 0, pamh->ps_item[i].pi_size);
2585 free(pamh->ps_item[i].pi_addr);
2588 free(pamh);
2593 * free_pamconf - free memory used to store pam.conf entry
2596 static void
2597 free_pamconf(pamtab_t *cp)
2599 int i;
2601 if (cp) {
2602 free(cp->pam_service);
2603 free(cp->module_path);
2604 for (i = 0; i < cp->module_argc; i++) {
2605 free(cp->module_argv[i]);
2607 if (cp->module_argc > 0)
2608 free(cp->module_argv);
2609 free(cp->function_ptr);
2611 free(cp);
2616 * free_pam_conf_info - free memory used to store all pam.conf info
2617 * under the pam handle
2620 static void
2621 free_pam_conf_info(pam_handle_t *pamh)
2623 pamtab_t *pamentp;
2624 pamtab_t *pament_trail;
2625 int i = pamh->include_depth;
2626 int j;
2628 for (j = 0; j < PAM_NUM_MODULE_TYPES; j++) {
2629 pamentp = pamh->pam_conf_info[i][j];
2630 pamh->pam_conf_info[i][j] = NULL;
2631 pament_trail = pamentp;
2632 while (pamentp) {
2633 pamentp = pamentp->next;
2634 free_pamconf(pament_trail);
2635 pament_trail = pamentp;
2638 if (pamh->pam_conf_name[i] != NULL) {
2639 free(pamh->pam_conf_name[i]);
2640 pamh->pam_conf_name[i] = NULL;
2644 static void
2645 free_env(env_list *pam_env)
2647 if (pam_env) {
2648 free(pam_env->name);
2649 free(pam_env->value);
2650 free(pam_env);
2655 * Internal convenience functions for Solaris PAM service modules.
2658 #include <libintl.h>
2659 #include <nl_types.h>
2660 #include <synch.h>
2661 #include <locale.h>
2662 #include <thread.h>
2664 typedef struct pam_msg_data {
2665 nl_catd fd;
2666 } pam_msg_data_t;
2669 * free_resp():
2670 * free storage for responses used in the call back "pam_conv" functions
2673 void
2674 free_resp(int num_msg, struct pam_response *resp)
2676 int i;
2677 struct pam_response *r;
2679 if (resp) {
2680 r = resp;
2681 for (i = 0; i < num_msg; i++, r++) {
2682 if (r->resp) {
2683 /* clear before freeing -- may be a password */
2684 bzero(r->resp, strlen(r->resp));
2685 free(r->resp);
2686 r->resp = NULL;
2689 free(resp);
2693 static int
2694 do_conv(pam_handle_t *pamh, int msg_style, int num_msg,
2695 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp,
2696 struct pam_response *ret_respp[])
2698 struct pam_message *msg;
2699 struct pam_message *m;
2700 int i;
2701 int k;
2702 int retcode;
2703 struct pam_conv *pam_convp;
2705 if ((retcode = pam_get_item(pamh, PAM_CONV,
2706 (void **)&pam_convp)) != PAM_SUCCESS) {
2707 return (retcode);
2711 * When pam_set_item() is called to set PAM_CONV and the
2712 * item is NULL, memset(pip->pi_addr, 0, size) is called.
2713 * So at this point, we should check whether pam_convp->conv
2714 * is NULL or not.
2716 if ((pam_convp == NULL) || (pam_convp->conv == NULL))
2717 return (PAM_SYSTEM_ERR);
2719 i = 0;
2720 k = num_msg;
2722 msg = calloc(num_msg, sizeof (struct pam_message));
2723 if (msg == NULL) {
2724 return (PAM_BUF_ERR);
2726 m = msg;
2728 while (k--) {
2730 * fill out the message structure to display prompt message
2732 m->msg_style = msg_style;
2733 m->msg = messages[i];
2734 pam_trace(PAM_DEBUG_CONV,
2735 "pam_conv_msg(%p:%d[%d]=%s)",
2736 (void *)pamh, msg_style, i, messages[i]);
2737 m++;
2738 i++;
2742 * The UNIX pam modules always calls __pam_get_authtok() and
2743 * __pam_display_msg() with a NULL pointer as the conv_apdp.
2744 * In case the conv_apdp is NULL and the pam_convp->appdata_ptr
2745 * is not NULL, we should pass the pam_convp->appdata_ptr
2746 * to the conversation function.
2748 if (conv_apdp == NULL && pam_convp->appdata_ptr != NULL)
2749 conv_apdp = pam_convp->appdata_ptr;
2752 * Call conv function to display the prompt.
2754 retcode = (pam_convp->conv)(num_msg, &msg, ret_respp, conv_apdp);
2755 pam_trace(PAM_DEBUG_CONV,
2756 "pam_conv_resp(%p pam_conv = %s) ret_respp = %p",
2757 (void *)pamh, pam_strerror(pamh, retcode), (void *)ret_respp);
2758 if (*ret_respp == NULL) {
2759 pam_trace(PAM_DEBUG_CONV,
2760 "pam_conv_resp(%p No response requested)", (void *)pamh);
2761 } else if ((pam_debug & (PAM_DEBUG_CONV | PAM_DEBUG_AUTHTOK)) != 0) {
2762 struct pam_response *r = *ret_respp;
2764 for (i = 0; i < num_msg; i++, r++) {
2765 if (r->resp == NULL) {
2766 pam_trace(PAM_DEBUG_CONV,
2767 "pam_conv_resp(%p:"
2768 "[%d] NULL response string)",
2769 (void *)pamh, i);
2770 } else {
2771 if (msg_style == PAM_PROMPT_ECHO_OFF) {
2772 #ifdef DEBUG
2773 pam_trace(PAM_DEBUG_AUTHTOK,
2774 "pam_conv_resp(%p:[%d]=%s, "
2775 "code=%d)",
2776 (void *)pamh, i, r->resp,
2777 r->resp_retcode);
2778 #endif /* DEBUG */
2779 pam_trace(PAM_DEBUG_CONV,
2780 "pam_conv_resp(%p:[%d] len=%lu, "
2781 "code=%d)",
2782 (void *)pamh, i,
2783 (ulong_t)strlen(r->resp),
2784 r->resp_retcode);
2785 } else {
2786 pam_trace(PAM_DEBUG_CONV,
2787 "pam_conv_resp(%p:[%d]=%s, "
2788 "code=%d)",
2789 (void *)pamh, i, r->resp,
2790 r->resp_retcode);
2796 free(msg);
2797 return (retcode);
2801 * __pam_display_msg():
2802 * display message by calling the call back functions
2803 * provided by the application through "pam_conv" structure
2807 __pam_display_msg(pam_handle_t *pamh, int msg_style, int num_msg,
2808 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp)
2810 struct pam_response *ret_respp = NULL;
2811 int ret;
2813 ret = do_conv(pamh, msg_style, num_msg, messages,
2814 conv_apdp, &ret_respp);
2816 if (ret_respp != NULL)
2817 free_resp(num_msg, ret_respp);
2819 return (ret);
2823 * __pam_get_authtok()
2824 * retrieves a password of at most PASS_MAX length from the pam
2825 * handle (pam_get_item) or from the input stream (do_conv).
2827 * This function allocates memory for the new authtok.
2828 * Applications calling this function are responsible for
2829 * freeing this memory.
2831 * If "source" is
2832 * PAM_HANDLE
2833 * and "type" is:
2834 * PAM_AUTHTOK - password is taken from pam handle (PAM_AUTHTOK)
2835 * PAM_OLDAUTHTOK - password is taken from pam handle (PAM_OLDAUTHTOK)
2837 * If "source" is
2838 * PAM_PROMPT
2839 * and "type" is:
2840 * 0: Prompt for new passwd, do not even attempt
2841 * to store it in the pam handle.
2842 * PAM_AUTHTOK: Prompt for new passwd, store in pam handle as
2843 * PAM_AUTHTOK item if this value is not already set.
2844 * PAM_OLDAUTHTOK: Prompt for new passwd, store in pam handle as
2845 * PAM_OLDAUTHTOK item if this value is not
2846 * already set.
2849 __pam_get_authtok(pam_handle_t *pamh, int source, int type, char *prompt,
2850 char **authtok)
2852 int error = PAM_SYSTEM_ERR;
2853 char *new_password = NULL;
2854 struct pam_response *ret_resp = NULL;
2855 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
2857 if ((*authtok = calloc(PASS_MAX+1, sizeof (char))) == NULL)
2858 return (PAM_BUF_ERR);
2860 if (prompt == NULL)
2861 prompt = dgettext(TEXT_DOMAIN, "password: ");
2863 switch (source) {
2864 case PAM_HANDLE:
2866 /* get password from pam handle item list */
2868 switch (type) {
2869 case PAM_AUTHTOK:
2870 case PAM_OLDAUTHTOK:
2872 if ((error = pam_get_item(pamh, type,
2873 (void **)&new_password)) != PAM_SUCCESS)
2874 goto err_ret;
2876 if (new_password == NULL || new_password[0] == '\0') {
2877 free(*authtok);
2878 *authtok = NULL;
2879 } else {
2880 (void) strlcpy(*authtok, new_password,
2881 PASS_MAX+1);
2883 break;
2884 default:
2885 __pam_log(LOG_AUTH | LOG_ERR,
2886 "__pam_get_authtok() invalid type: %d", type);
2887 error = PAM_SYMBOL_ERR;
2888 goto err_ret;
2890 break;
2891 case PAM_PROMPT:
2894 * Prompt for new password and save in pam handle item list
2895 * if the that item is not already set.
2898 (void) strncpy(messages[0], prompt, sizeof (messages[0]));
2899 if ((error = do_conv(pamh, PAM_PROMPT_ECHO_OFF, 1, messages,
2900 NULL, &ret_resp)) != PAM_SUCCESS)
2901 goto err_ret;
2903 if (ret_resp->resp == NULL) {
2904 /* getpass didn't return anything */
2905 error = PAM_SYSTEM_ERR;
2906 goto err_ret;
2909 /* save the new password if this item was NULL */
2910 if (type) {
2911 if ((error = pam_get_item(pamh, type,
2912 (void **)&new_password)) != PAM_SUCCESS) {
2913 free_resp(1, ret_resp);
2914 goto err_ret;
2916 if (new_password == NULL)
2917 (void) pam_set_item(pamh, type, ret_resp->resp);
2920 (void) strlcpy(*authtok, ret_resp->resp, PASS_MAX+1);
2921 free_resp(1, ret_resp);
2922 break;
2923 default:
2924 __pam_log(LOG_AUTH | LOG_ERR,
2925 "__pam_get_authtok() invalid source: %d", source);
2926 error = PAM_SYMBOL_ERR;
2927 goto err_ret;
2930 return (PAM_SUCCESS);
2932 err_ret:
2933 bzero(*authtok, PASS_MAX+1);
2934 free(*authtok);
2935 *authtok = NULL;
2936 return (error);