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]
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>
31 #include <sys/types.h>
40 #include <security/pam_appl.h>
41 #include <security/pam_modules.h>
48 static char *pam_snames
[PAM_NUM_MODULE_TYPES
] = {
55 static char *pam_inames
[PAM_MAX_ITEMS
] = {
57 /* PAM_SERVICE */ "service",
58 /* PAM_USER */ "user",
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",
73 * This extra definition is needed in order to build this library
74 * on pre-64-bit-aware systems.
76 #if !defined(_LFS64_LARGEFILE)
78 #endif /* !defined(_LFS64_LARGEFILE) */
80 /* functions to dynamically load modules */
81 static int load_modules(pam_handle_t
*, int, char *, pamtab_t
*);
82 static void *open_module(pam_handle_t
*, char *);
83 static int load_function(void *, char *, int (**func
)());
85 /* functions to read and store the pam.conf configuration file */
86 static int open_pam_conf(struct pam_fh
**, pam_handle_t
*, char *, int);
87 static void close_pam_conf(struct pam_fh
*);
88 static int read_pam_conf(pam_handle_t
*, char *, char *);
89 static int get_pam_conf_entry(struct pam_fh
*, pam_handle_t
*,
90 pamtab_t
**, char *, int);
91 static char *read_next_token(char **);
92 static char *nextline(struct pam_fh
*, pam_handle_t
*, int *);
93 static int verify_pam_conf(pamtab_t
*, char *);
95 /* functions to clean up and free memory */
96 static void clean_up(pam_handle_t
*);
97 static void free_pamconf(pamtab_t
*);
98 static void free_pam_conf_info(pam_handle_t
*);
99 static void free_env(env_list
*);
101 /* convenience functions for I18N/L10N communication */
103 static void free_resp(int, struct pam_response
*);
104 static int do_conv(pam_handle_t
*, int, int,
105 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
], void *,
106 struct pam_response
**);
108 static int log_priority
; /* pam_trace syslog priority & facility */
109 static int pam_debug
= 0;
112 pam_trace_iname(int item_type
, char *iname_buf
)
116 if (item_type
<= 0 ||
117 item_type
>= PAM_MAX_ITEMS
||
118 (name
= pam_inames
[item_type
]) == NULL
) {
119 (void) sprintf(iname_buf
, "%d", item_type
);
126 pam_trace_fname(int flag
)
128 if (flag
& PAM_BINDING
)
129 return (PAM_BINDING_NAME
);
130 if (flag
& PAM_INCLUDE
)
131 return (PAM_INCLUDE_NAME
);
132 if (flag
& PAM_OPTIONAL
)
133 return (PAM_OPTIONAL_NAME
);
134 if (flag
& PAM_REQUIRED
)
135 return (PAM_REQUIRED_NAME
);
136 if (flag
& PAM_REQUISITE
)
137 return (PAM_REQUISITE_NAME
);
138 if (flag
& PAM_SUFFICIENT
)
139 return (PAM_SUFFICIENT_NAME
);
140 return ("bad flag name");
144 pam_trace_cname(pam_handle_t
*pamh
)
146 if (pamh
->pam_conf_name
[pamh
->include_depth
] == NULL
)
148 return (pamh
->pam_conf_name
[pamh
->include_depth
]);
154 * pam_settrace - setup configuration for pam tracing
156 * turn on PAM debug if "magic" file exists
157 * if exists (original), pam_debug = PAM_DEBUG_DEFAULT,
158 * log_priority = LOG_DEBUG(7) and log_facility = LOG_AUTH(4).
160 * if has contents, keywork=value pairs:
162 * "log_priority=" 0-7, the pam_trace syslog priority to use
164 * "log_facility=" 0-23, the pam_trace syslog facility to use
166 * "debug_flags=" PAM_DEBUG_DEFAULT (0x0001), log traditional
167 * (original) debugging.
168 * Plus the logical or of:
169 * PAM_DEBUG_ITEM (0x0002), log item values and
171 * PAM_DEBUG_MODULE (0x0004), log module return status.
172 * PAM_DEBUG_CONF (0x0008), log pam.conf parsing.
173 * PAM_DEBUG_DATA (0x0010), get/set_data.
174 * PAM_DEBUG_CONV (0x0020), conversation/response.
176 * If compiled with DEBUG:
177 * PAM_DEBUG_AUTHTOK (0x8000), display AUTHTOK value if
178 * PAM_DEBUG_ITEM is set and results from
179 * PAM_PROMPT_ECHO_OFF responses.
180 * USE CAREFULLY, THIS EXPOSES THE USER'S PASSWORDS.
182 * or set to 0 and off even if PAM_DEBUG file exists.
184 * Output has the general form:
185 * <whatever was set syslog> PAM[<pid>]: <interface>(<handle> and other info)
186 * <whatever was set syslog> PAM[<pid>]: details requested for <interface> call
187 * Where: <pid> is the process ID of the calling process.
188 * <handle> is the Hex value of the pam_handle associated with the
197 if ((defp
= defopen_r(PAM_DEBUG
)) != NULL
) {
200 int facility
= LOG_AUTH
;
202 pam_debug
= PAM_DEBUG_DEFAULT
;
203 log_priority
= LOG_DEBUG
;
205 (void) defcntl_r(DC_SETFLAGS
, DC_CASE
, defp
);
206 if ((arg
= defread_r(LOG_PRIORITY
, defp
)) != NULL
) {
207 code
= (int)strtol(arg
, NULL
, 10);
208 if ((code
& ~LOG_PRIMASK
) == 0) {
212 if ((arg
= defread_r(LOG_FACILITY
, defp
)) != NULL
) {
213 code
= (int)strtol(arg
, NULL
, 10);
214 if (code
< LOG_NFACILITIES
) {
215 facility
= code
<< 3;
218 if ((arg
= defread_r(DEBUG_FLAGS
, defp
)) != NULL
) {
219 pam_debug
= (int)strtol(arg
, NULL
, 0);
223 log_priority
|= facility
;
228 * pam_trace - logs tracing messages
230 * flag = debug_flags from /etc/pam_debug
231 * format and args = message to print (PAM[<pid>]: is prepended).
233 * global log_priority = pam_trace syslog (log_priority | log_facility)
234 * from /etc/pam_debug
238 pam_trace(int flag
, char *format
, ...)
244 if ((pam_debug
& flag
) == 0)
247 savemask
= setlogmask(LOG_MASK(log_priority
& LOG_PRIMASK
));
248 (void) snprintf(message
, sizeof (message
), "PAM[%ld]: %s",
249 (long)getpid(), format
);
250 va_start(args
, format
);
251 (void) vsyslog(log_priority
, message
, args
);
253 (void) setlogmask(savemask
);
257 * __pam_log - logs PAM syslog messages
259 * priority = message priority
260 * format and args = message to log
264 __pam_log(int priority
, const char *format
, ...)
267 int savemask
= setlogmask(LOG_MASK(priority
& LOG_PRIMASK
));
269 va_start(args
, format
);
270 (void) vsyslog(priority
, format
, args
);
272 (void) setlogmask(savemask
);
279 * These are the entry points to the authentication switch
283 * pam_start - initiate an authentication transaction and
284 * set parameter values to be used during the
289 pam_start(const char *service
, const char *user
,
290 const struct pam_conv
*pam_conv
, pam_handle_t
**pamh
)
294 *pamh
= calloc(1, sizeof (struct pam_handle
));
297 pam_trace(PAM_DEBUG_DEFAULT
,
298 "pam_start(%s,%s,%p:%p) - debug = %x",
299 service
? service
: "NULL", user
? user
: "NULL", (void *)pam_conv
,
300 (void *)*pamh
, pam_debug
);
303 return (PAM_BUF_ERR
);
305 (*pamh
)->pam_inmodule
= RO_OK
; /* OK to set RO items */
306 if ((err
= pam_set_item(*pamh
, PAM_SERVICE
, (void *)service
))
313 if ((err
= pam_set_item(*pamh
, PAM_USER
, (void *)user
))
320 if ((err
= pam_set_item(*pamh
, PAM_CONV
, (void *)pam_conv
))
327 (*pamh
)->pam_inmodule
= RW_OK
;
328 return (PAM_SUCCESS
);
332 * pam_end - terminate an authentication transaction
336 pam_end(pam_handle_t
*pamh
, int pam_status
)
338 struct pam_module_data
*psd
, *p
;
341 env_list
*env_expired
;
342 env_list
*env_traverse
;
344 pam_trace(PAM_DEBUG_DEFAULT
,
345 "pam_end(%p): status = %s", (void *)pamh
,
346 pam_strerror(pamh
, pam_status
));
349 return (PAM_SYSTEM_ERR
);
351 /* call the cleanup routines for module specific data */
356 psd
->cleanup(pamh
, psd
->data
, pam_status
);
360 free(p
->module_data_name
);
365 /* dlclose all module fds */
369 traverse
= traverse
->next
;
370 (void) dlclose(expired
->mh
);
375 /* remove all environment variables */
376 env_traverse
= pamh
->pam_env
;
377 while (env_traverse
) {
378 env_expired
= env_traverse
;
379 env_traverse
= env_traverse
->next
;
380 free_env(env_expired
);
384 return (PAM_SUCCESS
);
388 * pam_set_item - set the value of a parameter that can be
389 * retrieved via a call to pam_get_item()
393 pam_set_item(pam_handle_t
*pamh
, int item_type
, const void *item
)
395 struct pam_item
*pip
;
397 char iname_buf
[PAM_MAX_MSG_SIZE
];
399 if (((pam_debug
& PAM_DEBUG_ITEM
) == 0) || (pamh
== NULL
)) {
400 pam_trace(PAM_DEBUG_DEFAULT
,
401 "pam_set_item(%p:%s)", (void *)pamh
,
402 pam_trace_iname(item_type
, iname_buf
));
406 return (PAM_SYSTEM_ERR
);
408 /* check read only items */
409 if ((item_type
== PAM_SERVICE
) && (pamh
->pam_inmodule
!= RO_OK
))
410 return (PAM_PERM_DENIED
);
413 * Check that item_type is within valid range
416 if (item_type
<= 0 || item_type
>= PAM_MAX_ITEMS
)
417 return (PAM_SYMBOL_ERR
);
419 pip
= &(pamh
->ps_item
[item_type
]);
424 if (pip
->pi_addr
!= NULL
)
425 (void) memset(pip
->pi_addr
, 0, pip
->pi_size
);
432 case PAM_USER_PROMPT
:
435 if (pip
->pi_addr
!= NULL
) {
443 pip
->pi_addr
= strdup((char *)item
);
444 if (pip
->pi_addr
== NULL
) {
446 return (PAM_BUF_ERR
);
448 pip
->pi_size
= strlen(pip
->pi_addr
);
453 size
= sizeof (struct pam_conv
);
454 if ((pip
->pi_addr
= calloc(1, size
)) == NULL
)
455 return (PAM_BUF_ERR
);
457 (void) memcpy(pip
->pi_addr
, item
, (unsigned int) size
);
459 (void) memset(pip
->pi_addr
, 0, size
);
463 if (pip
->pi_addr
!= NULL
) {
464 pam_repository_t
*auth_rep
;
466 auth_rep
= (pam_repository_t
*)pip
->pi_addr
;
467 free(auth_rep
->type
);
468 free(auth_rep
->scope
);
472 pam_repository_t
*s
, *d
;
474 size
= sizeof (struct pam_repository
);
475 pip
->pi_addr
= calloc(1, size
);
476 if (pip
->pi_addr
== NULL
)
477 return (PAM_BUF_ERR
);
479 s
= (struct pam_repository
*)item
;
480 d
= (struct pam_repository
*)pip
->pi_addr
;
482 d
->type
= strdup(s
->type
);
484 return (PAM_BUF_ERR
);
485 d
->scope
= malloc(s
->scope_len
);
486 if (d
->scope
== NULL
)
487 return (PAM_BUF_ERR
);
488 (void) memcpy(d
->scope
, s
->scope
, s
->scope_len
);
489 d
->scope_len
= s
->scope_len
;
494 return (PAM_SYMBOL_ERR
);
498 pam_trace(PAM_DEBUG_ITEM
, "pam_set_item(%p:%s)=%p",
500 pam_trace_iname(item_type
, iname_buf
),
501 item
? (void *)((struct pam_conv
*)item
)->conv
:
505 pam_trace(PAM_DEBUG_ITEM
, "pam_set_item(%p:%s)=%s",
507 pam_trace_iname(item_type
, iname_buf
),
508 item
? (((struct pam_repository
*)item
)->type
?
509 ((struct pam_repository
*)item
)->type
: "NULL") :
515 if (pam_debug
& PAM_DEBUG_AUTHTOK
)
516 pam_trace(PAM_DEBUG_ITEM
,
517 "pam_set_item(%p:%s)=%s", (void *)pamh
,
518 pam_trace_iname(item_type
, iname_buf
),
519 item
? (char *)item
: "NULL");
522 pam_trace(PAM_DEBUG_ITEM
,
523 "pam_set_item(%p:%s)=%s", (void *)pamh
,
524 pam_trace_iname(item_type
, iname_buf
),
525 item
? "********" : "NULL");
528 pam_trace(PAM_DEBUG_ITEM
, "pam_set_item(%p:%s)=%s",
530 pam_trace_iname(item_type
, iname_buf
),
531 item
? (char *)item
: "NULL");
534 return (PAM_SUCCESS
);
538 * pam_get_item - read the value of a parameter specified in
539 * the call to pam_set_item()
543 pam_get_item(const pam_handle_t
*pamh
, int item_type
, void **item
)
545 struct pam_item
*pip
;
546 char iname_buf
[PAM_MAX_MSG_SIZE
];
548 if (((pam_debug
& PAM_DEBUG_ITEM
) == 0) || (pamh
== NULL
)) {
549 pam_trace(PAM_DEBUG_ITEM
, "pam_get_item(%p:%s)",
550 (void *)pamh
, pam_trace_iname(item_type
, iname_buf
));
554 return (PAM_SYSTEM_ERR
);
556 if (item_type
<= 0 || item_type
>= PAM_MAX_ITEMS
)
557 return (PAM_SYMBOL_ERR
);
559 if ((pamh
->pam_inmodule
!= WO_OK
) &&
560 ((item_type
== PAM_AUTHTOK
|| item_type
== PAM_OLDAUTHTOK
))) {
561 __pam_log(LOG_AUTH
| LOG_NOTICE
, "pam_get_item(%s) called from "
562 "a non module context",
563 pam_trace_iname(item_type
, iname_buf
));
564 return (PAM_PERM_DENIED
);
567 pip
= (struct pam_item
*)&(pamh
->ps_item
[item_type
]);
569 *item
= pip
->pi_addr
;
572 pam_trace(PAM_DEBUG_ITEM
, "pam_get_item(%p:%s)=%p",
574 pam_trace_iname(item_type
, iname_buf
),
575 (void *)((struct pam_conv
*)*item
)->conv
);
578 pam_trace(PAM_DEBUG_ITEM
, "pam_get_item(%p:%s)=%s",
580 pam_trace_iname(item_type
, iname_buf
),
581 *item
? (((struct pam_repository
*)*item
)->type
?
582 ((struct pam_repository
*)*item
)->type
: "NULL") :
588 if (pam_debug
& PAM_DEBUG_AUTHTOK
)
589 pam_trace(PAM_DEBUG_ITEM
,
590 "pam_get_item(%p:%s)=%s", (void *)pamh
,
591 pam_trace_iname(item_type
, iname_buf
),
592 *item
? *(char **)item
: "NULL");
595 pam_trace(PAM_DEBUG_ITEM
,
596 "pam_get_item(%p:%s)=%s", (void *)pamh
,
597 pam_trace_iname(item_type
, iname_buf
),
598 *item
? "********" : "NULL");
601 pam_trace(PAM_DEBUG_ITEM
, "pam_get_item(%p:%s)=%s",
603 pam_trace_iname(item_type
, iname_buf
),
604 *item
? *(char **)item
: "NULL");
607 return (PAM_SUCCESS
);
611 * parse_user_name - process the user response: ignore
612 * '\t' or ' ' before or after a user name.
613 * user_input is a null terminated string.
614 * *ret_username will be the user name.
618 parse_user_name(char *user_input
, char **ret_username
)
621 register int index
= 0;
622 char username
[PAM_MAX_RESP_SIZE
];
624 /* Set the default value for *ret_username */
625 *ret_username
= NULL
;
628 * Set the initial value for username - this is a buffer holds
631 bzero((void *)username
, PAM_MAX_RESP_SIZE
);
634 * The user_input is guaranteed to be terminated by a null character.
638 /* Skip all the leading whitespaces if there are any. */
639 while ((*ptr
== ' ') || (*ptr
== '\t'))
644 * We should never get here since the user_input we got
645 * in pam_get_user() is not all whitespaces nor just "\0".
647 return (PAM_BUF_ERR
);
651 * username will be the first string we get from user_input
652 * - we skip leading whitespaces and ignore trailing whitespaces
654 while (*ptr
!= '\0') {
655 if ((*ptr
== ' ') || (*ptr
== '\t'))
658 username
[index
] = *ptr
;
664 /* ret_username will be freed in pam_get_user(). */
665 if ((*ret_username
= malloc(index
+ 1)) == NULL
)
666 return (PAM_BUF_ERR
);
667 (void) strcpy(*ret_username
, username
);
668 return (PAM_SUCCESS
);
672 * Get the value of PAM_USER. If not set, then use the convenience function
673 * to prompt for the user. Use prompt if specified, else use PAM_USER_PROMPT
674 * if it is set, else use default.
680 pam_get_user(pam_handle_t
*pamh
, char **user
, const char *prompt_override
)
685 struct pam_response
*ret_resp
= NULL
;
686 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
];
688 pam_trace(PAM_DEBUG_DEFAULT
,
689 "pam_get_user(%p, %p, %s)", (void *)pamh
, (void *)*user
,
690 prompt_override
? prompt_override
: "NULL");
692 return (PAM_SYSTEM_ERR
);
694 if ((status
= pam_get_item(pamh
, PAM_USER
, (void **)user
))
699 /* if the user is set, return it */
701 if (*user
!= NULL
&& *user
[0] != '\0') {
702 return (PAM_SUCCESS
);
706 * if the module is requesting a special prompt, use it.
707 * else use PAM_USER_PROMPT.
710 if (prompt_override
!= NULL
) {
711 prompt
= (char *)prompt_override
;
713 status
= pam_get_item(pamh
, PAM_USER_PROMPT
, (void**)&prompt
);
714 if (status
!= PAM_SUCCESS
) {
719 /* if the prompt is not set, use default */
721 if (prompt
== NULL
|| prompt
[0] == '\0') {
722 prompt
= dgettext(TEXT_DOMAIN
, "Please enter user name: ");
725 /* prompt for the user */
727 (void) strncpy(messages
[0], prompt
, sizeof (messages
[0]));
730 int state
= WHITESPACE
;
732 status
= do_conv(pamh
, PAM_PROMPT_ECHO_ON
, 1, messages
,
735 if (status
!= PAM_SUCCESS
) {
739 if (ret_resp
->resp
&& ret_resp
->resp
[0] != '\0') {
740 int len
= strlen(ret_resp
->resp
);
743 for (i
= 0; i
< len
; i
++) {
744 if ((ret_resp
->resp
[i
] != ' ') &&
745 (ret_resp
->resp
[i
] != '\t')) {
751 if (state
== USERNAME
)
754 /* essentially empty response, try again */
755 free_resp(1, ret_resp
);
760 /* Parse the user input to get the user name. */
761 status
= parse_user_name(ret_resp
->resp
, &real_username
);
763 if (status
!= PAM_SUCCESS
) {
765 free_resp(1, ret_resp
);
769 status
= pam_set_item(pamh
, PAM_USER
, real_username
);
773 free_resp(1, ret_resp
);
774 if (status
!= PAM_SUCCESS
) {
779 * finally, get PAM_USER. We have to call pam_get_item to get
780 * the value of user because pam_set_item mallocs the memory.
783 status
= pam_get_item(pamh
, PAM_USER
, (void**)user
);
788 * Set module specific data
792 pam_set_data(pam_handle_t
*pamh
, const char *module_data_name
, void *data
,
793 void (*cleanup
)(pam_handle_t
*pamh
, void *data
, int pam_end_status
))
795 struct pam_module_data
*psd
;
797 pam_trace(PAM_DEBUG_DATA
,
798 "pam_set_data(%p:%s:%d)=%p", (void *)pamh
,
799 module_data_name
? module_data_name
: "NULL", pamh
->pam_inmodule
,
801 if (pamh
== NULL
|| (pamh
->pam_inmodule
!= WO_OK
) ||
802 module_data_name
== NULL
) {
803 return (PAM_SYSTEM_ERR
);
806 /* check if module data already exists */
808 for (psd
= pamh
->ssd
; psd
; psd
= psd
->next
) {
809 if (strcmp(psd
->module_data_name
, module_data_name
) == 0) {
810 /* clean up original data before setting the new data */
812 psd
->cleanup(pamh
, psd
->data
, PAM_SUCCESS
);
814 psd
->data
= (void *)data
;
815 psd
->cleanup
= cleanup
;
816 return (PAM_SUCCESS
);
820 psd
= malloc(sizeof (struct pam_module_data
));
822 return (PAM_BUF_ERR
);
824 psd
->module_data_name
= strdup(module_data_name
);
825 if (psd
->module_data_name
== NULL
) {
827 return (PAM_BUF_ERR
);
830 psd
->data
= (void *)data
;
831 psd
->cleanup
= cleanup
;
832 psd
->next
= pamh
->ssd
;
834 return (PAM_SUCCESS
);
838 * get module specific data
842 pam_get_data(const pam_handle_t
*pamh
, const char *module_data_name
,
845 struct pam_module_data
*psd
;
847 if (pamh
== NULL
|| (pamh
->pam_inmodule
!= WO_OK
) ||
848 module_data_name
== NULL
) {
849 pam_trace(PAM_DEBUG_DATA
,
850 "pam_get_data(%p:%s:%d)=%p", (void *)pamh
,
851 module_data_name
? module_data_name
: "NULL",
852 pamh
->pam_inmodule
, *data
);
853 return (PAM_SYSTEM_ERR
);
856 for (psd
= pamh
->ssd
; psd
; psd
= psd
->next
) {
857 if (strcmp(psd
->module_data_name
, module_data_name
) == 0) {
859 pam_trace(PAM_DEBUG_DATA
,
860 "pam_get_data(%p:%s)=%p", (void *)pamh
,
861 module_data_name
, *data
);
862 return (PAM_SUCCESS
);
865 pam_trace(PAM_DEBUG_DATA
,
866 "pam_get_data(%p:%s)=%s", (void *)pamh
, module_data_name
,
867 "PAM_NO_MODULE_DATA");
869 return (PAM_NO_MODULE_DATA
);
873 * PAM equivalent to strerror()
877 pam_strerror(pam_handle_t
*pamh
, int errnum
)
881 return (dgettext(TEXT_DOMAIN
, "Success"));
883 return (dgettext(TEXT_DOMAIN
, "Dlopen failure"));
885 return (dgettext(TEXT_DOMAIN
, "Symbol not found"));
886 case PAM_SERVICE_ERR
:
887 return (dgettext(TEXT_DOMAIN
,
888 "Error in underlying service module"));
890 return (dgettext(TEXT_DOMAIN
, "System error"));
892 return (dgettext(TEXT_DOMAIN
, "Memory buffer error"));
894 return (dgettext(TEXT_DOMAIN
, "Conversation failure"));
895 case PAM_PERM_DENIED
:
896 return (dgettext(TEXT_DOMAIN
, "Permission denied"));
898 return (dgettext(TEXT_DOMAIN
,
899 "Maximum number of attempts exceeded"));
901 return (dgettext(TEXT_DOMAIN
, "Authentication failed"));
902 case PAM_NEW_AUTHTOK_REQD
:
903 return (dgettext(TEXT_DOMAIN
, "Get new authentication token"));
904 case PAM_CRED_INSUFFICIENT
:
905 return (dgettext(TEXT_DOMAIN
, "Insufficient credentials"));
906 case PAM_AUTHINFO_UNAVAIL
:
907 return (dgettext(TEXT_DOMAIN
,
908 "Can not retrieve authentication info"));
909 case PAM_USER_UNKNOWN
:
910 return (dgettext(TEXT_DOMAIN
, "No account present for user"));
911 case PAM_CRED_UNAVAIL
:
912 return (dgettext(TEXT_DOMAIN
,
913 "Can not retrieve user credentials"));
914 case PAM_CRED_EXPIRED
:
915 return (dgettext(TEXT_DOMAIN
,
916 "User credentials have expired"));
918 return (dgettext(TEXT_DOMAIN
,
919 "Failure setting user credentials"));
920 case PAM_ACCT_EXPIRED
:
921 return (dgettext(TEXT_DOMAIN
, "User account has expired"));
922 case PAM_AUTHTOK_EXPIRED
:
923 return (dgettext(TEXT_DOMAIN
, "User password has expired"));
924 case PAM_SESSION_ERR
:
925 return (dgettext(TEXT_DOMAIN
,
926 "Can not make/remove entry for session"));
927 case PAM_AUTHTOK_ERR
:
928 return (dgettext(TEXT_DOMAIN
,
929 "Authentication token manipulation error"));
930 case PAM_AUTHTOK_RECOVERY_ERR
:
931 return (dgettext(TEXT_DOMAIN
,
932 "Authentication token can not be recovered"));
933 case PAM_AUTHTOK_LOCK_BUSY
:
934 return (dgettext(TEXT_DOMAIN
,
935 "Authentication token lock busy"));
936 case PAM_AUTHTOK_DISABLE_AGING
:
937 return (dgettext(TEXT_DOMAIN
,
938 "Authentication token aging disabled"));
939 case PAM_NO_MODULE_DATA
:
940 return (dgettext(TEXT_DOMAIN
,
941 "Module specific data not found"));
943 return (dgettext(TEXT_DOMAIN
, "Ignore module"));
945 return (dgettext(TEXT_DOMAIN
, "General PAM failure "));
947 return (dgettext(TEXT_DOMAIN
,
948 "Unable to complete operation. Try again"));
950 return (dgettext(TEXT_DOMAIN
, "Unknown error"));
958 case PAM_AUTHENTICATE
:
959 return (PAM_SM_AUTHENTICATE
);
961 return (PAM_SM_SETCRED
);
963 return (PAM_SM_ACCT_MGMT
);
964 case PAM_OPEN_SESSION
:
965 return (PAM_SM_OPEN_SESSION
);
966 case PAM_CLOSE_SESSION
:
967 return (PAM_SM_CLOSE_SESSION
);
969 return (PAM_SM_CHAUTHTOK
);
975 (*func(pamtab_t
*modulep
, int ind
))()
979 if ((funcp
= modulep
->function_ptr
) == NULL
)
983 case PAM_AUTHENTICATE
:
984 return (((struct auth_module
*)funcp
)->pam_sm_authenticate
);
986 return (((struct auth_module
*)funcp
)->pam_sm_setcred
);
988 return (((struct account_module
*)funcp
)->pam_sm_acct_mgmt
);
989 case PAM_OPEN_SESSION
:
990 return (((struct session_module
*)funcp
)->pam_sm_open_session
);
991 case PAM_CLOSE_SESSION
:
992 return (((struct session_module
*)funcp
)->pam_sm_close_session
);
994 return (((struct password_module
*)funcp
)->pam_sm_chauthtok
);
1000 * Run through the PAM service module stack for the given module type.
1003 run_stack(pam_handle_t
*pamh
, int flags
, int type
, int def_err
, int ind
,
1004 char *function_name
)
1006 int err
= PAM_SYSTEM_ERR
; /* preset */
1007 int optional_error
= 0;
1008 int required_error
= 0;
1016 return (PAM_SYSTEM_ERR
);
1018 (void) pam_get_item(pamh
, PAM_SERVICE
, (void **)&service
);
1019 if (service
== NULL
|| *service
== '\0') {
1020 __pam_log(LOG_AUTH
| LOG_ERR
, "No service name");
1021 return (PAM_SYSTEM_ERR
);
1024 /* read initial entries from /etc/pam.d/<service> */
1025 if (asprintf(&service_file
, "%s%s", PAM_CONFIG_DIR
, service
) < 0)
1026 return (PAM_SYSTEM_ERR
);
1027 if ((err
= read_pam_conf(pamh
, service_file
, service
))
1029 pam_trace(PAM_DEBUG_CONF
, "run_stack[%d:%s]: can't read "
1030 "service-specific conf %s", pamh
->include_depth
,
1031 pam_trace_cname(pamh
), modulep
->module_path
, service_file
);
1034 service_file
= NULL
;
1037 pamh
->pam_conf_info
[pamh
->include_depth
][type
]) == NULL
) {
1038 __pam_log(LOG_AUTH
| LOG_ERR
, "%s no initial module present",
1039 pam_trace_cname(pamh
));
1043 pamh
->pam_inmodule
= WO_OK
; /* OK to get AUTHTOK */
1045 pam_trace(PAM_DEBUG_MODULE
,
1046 "[%d:%s]:run_stack:%s(%p, %x): %s", pamh
->include_depth
,
1047 pam_trace_cname(pamh
), function_name
, (void *)pamh
, flags
,
1048 modulep
? modulep
->module_path
: "NULL");
1050 while (modulep
!= NULL
) {
1051 if (modulep
->pam_flag
& PAM_INCLUDE
) {
1052 /* save the return location */
1053 pamh
->pam_conf_modulep
[pamh
->include_depth
] =
1055 pam_trace(PAM_DEBUG_MODULE
,
1056 "setting for include[%d:%p]",
1057 pamh
->include_depth
, (void *)modulep
->next
);
1058 if (pamh
->include_depth
++ >= PAM_MAX_INCLUDE
) {
1059 __pam_log(LOG_AUTH
| LOG_ERR
,
1060 "run_stack: includes too deep %d "
1061 "found trying to include %s from %s, %d "
1062 "allowed", pamh
->include_depth
,
1063 modulep
->module_path
, pamh
->pam_conf_name
1064 [PAM_MAX_INCLUDE
] == NULL
? "NULL" :
1065 pamh
->pam_conf_name
[PAM_MAX_INCLUDE
],
1069 err
= read_pam_conf(pamh
, modulep
->module_path
, service
);
1070 if (err
!= PAM_SUCCESS
) {
1071 __pam_log(LOG_AUTH
| LOG_ERR
,
1072 "run_stack[%d:%s]: can't read included "
1073 "conf %s", pamh
->include_depth
,
1074 pam_trace_cname(pamh
),
1075 modulep
->module_path
);
1078 if ((modulep
= pamh
->pam_conf_info
1079 [pamh
->include_depth
][type
]) == NULL
) {
1080 __pam_log(LOG_AUTH
| LOG_ERR
,
1081 "run_stack[%d:%s]: no include module "
1082 "present %s", pamh
->include_depth
,
1083 pam_trace_cname(pamh
), function_name
);
1086 if (modulep
->pam_flag
& PAM_INCLUDE
) {
1087 /* first line another include */
1090 pam_trace(PAM_DEBUG_DEFAULT
, "include[%d:%s]"
1091 "(%p, %s)=%s", pamh
->include_depth
,
1092 pam_trace_cname(pamh
), (void *)pamh
,
1093 function_name
, modulep
->module_path
);
1094 if ((err
= load_modules(pamh
, type
, sm_name(ind
),
1096 [pamh
->include_depth
][type
])) != PAM_SUCCESS
) {
1097 pam_trace(PAM_DEBUG_DEFAULT
,
1098 "[%d:%s]:%s(%p, %x): load_modules failed",
1099 pamh
->include_depth
, pam_trace_cname(pamh
),
1100 function_name
, (void *)pamh
, flags
);
1103 if ((modulep
= pamh
->pam_conf_info
1104 [pamh
->include_depth
][type
]) == NULL
) {
1105 __pam_log(LOG_AUTH
| LOG_ERR
,
1106 "%s no initial module present",
1107 pam_trace_cname(pamh
));
1110 } else if ((err
= load_modules(pamh
, type
, sm_name(ind
),
1111 modulep
)) != PAM_SUCCESS
) {
1112 pam_trace(PAM_DEBUG_DEFAULT
,
1113 "[%d:%s]:%s(%p, %x): load_modules failed",
1114 pamh
->include_depth
, pam_trace_cname(pamh
),
1115 function_name
, (void *)pamh
, flags
);
1118 sm_func
= func(modulep
, ind
);
1120 err
= sm_func(pamh
, flags
, modulep
->module_argc
,
1121 (const char **)modulep
->module_argv
);
1123 pam_trace(PAM_DEBUG_MODULE
,
1124 "[%d:%s]:%s(%p, %x): %s returned %s",
1125 pamh
->include_depth
, pam_trace_cname(pamh
),
1126 function_name
, (void *)pamh
, flags
,
1127 modulep
->module_path
, pam_strerror(pamh
, err
));
1134 if ((modulep
->pam_flag
& PAM_SUFFI_BIND
) &&
1136 pamh
->pam_inmodule
= RW_OK
;
1137 pam_trace(PAM_DEBUG_MODULE
,
1138 "[%d:%s]:%s(%p, %x): %s: success",
1139 pamh
->include_depth
,
1140 pam_trace_cname(pamh
),
1141 function_name
, (void *)pamh
, flags
,
1142 (modulep
->pam_flag
& PAM_BINDING
) ?
1144 PAM_SUFFICIENT_NAME
);
1151 * We need to return immediately, and
1152 * we shouldn't reset the AUTHTOK item
1153 * since it is not an error per-se.
1155 pamh
->pam_inmodule
= RW_OK
;
1156 pam_trace(PAM_DEBUG_MODULE
,
1157 "[%d:%s]:%s(%p, %x): TRY_AGAIN: %s",
1158 pamh
->include_depth
, pam_trace_cname(pamh
),
1159 function_name
, (void *)pamh
, flags
,
1160 pam_strerror(pamh
, required_error
?
1161 required_error
: err
));
1162 err
= required_error
? required_error
: err
;
1165 if (modulep
->pam_flag
& PAM_REQUISITE
) {
1166 pamh
->pam_inmodule
= RW_OK
;
1167 pam_trace(PAM_DEBUG_MODULE
,
1168 "[%d:%s]:%s(%p, %x): requisite: %s",
1169 pamh
->include_depth
,
1170 pam_trace_cname(pamh
),
1171 function_name
, (void *)pamh
, flags
,
1173 required_error
? required_error
:
1175 err
= required_error
?
1176 required_error
: err
;
1178 } else if (modulep
->pam_flag
& PAM_REQRD_BIND
) {
1179 if (!required_error
)
1180 required_error
= err
;
1182 if (!optional_error
)
1183 optional_error
= err
;
1185 pam_trace(PAM_DEBUG_DEFAULT
,
1186 "[%d:%s]:%s(%p, %x): error %s",
1187 pamh
->include_depth
, pam_trace_cname(pamh
),
1188 function_name
, (void *)pamh
, flags
,
1189 pam_strerror(pamh
, err
));
1193 modulep
= modulep
->next
;
1196 pam_trace(PAM_DEBUG_MODULE
, "[%d:%s]:stack_end:%s(%p, %x): %s %s: %s",
1197 pamh
->include_depth
, pam_trace_cname(pamh
), function_name
,
1198 (void *)pamh
, flags
, pamh
->include_depth
? "included" : "final",
1199 required_error
? "required" : success
? "success" :
1200 optional_error
? "optional" : "default",
1201 pam_strerror(pamh
, required_error
? required_error
:
1202 success
? PAM_SUCCESS
: optional_error
? optional_error
: def_err
));
1203 if (pamh
->include_depth
> 0) {
1204 free_pam_conf_info(pamh
);
1205 pamh
->include_depth
--;
1206 /* continue at next entry */
1207 modulep
= pamh
->pam_conf_modulep
[pamh
->include_depth
];
1208 pam_trace(PAM_DEBUG_MODULE
, "looping for include[%d:%p]",
1209 pamh
->include_depth
, (void *)modulep
);
1212 free_pam_conf_info(pamh
);
1213 pamh
->pam_inmodule
= RW_OK
;
1214 if (required_error
!= 0)
1215 return (required_error
);
1216 else if (success
!= 0)
1217 return (PAM_SUCCESS
);
1218 else if (optional_error
!= 0)
1219 return (optional_error
);
1225 * All done at whatever depth we're at.
1226 * Go back to not having read /etc/pam.conf
1228 while (pamh
->include_depth
> 0) {
1229 free_pam_conf_info(pamh
);
1230 pamh
->include_depth
--;
1232 free_pam_conf_info(pamh
);
1233 pamh
->pam_inmodule
= RW_OK
;
1238 * pam_authenticate - authenticate a user
1242 pam_authenticate(pam_handle_t
*pamh
, int flags
)
1246 retval
= run_stack(pamh
, flags
, PAM_AUTH_MODULE
, PAM_AUTH_ERR
,
1247 PAM_AUTHENTICATE
, "pam_authenticate");
1249 if (retval
!= PAM_SUCCESS
)
1250 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1255 * pam_setcred - modify or retrieve user credentials
1259 pam_setcred(pam_handle_t
*pamh
, int flags
)
1263 retval
= run_stack(pamh
, flags
, PAM_AUTH_MODULE
, PAM_CRED_ERR
,
1264 PAM_SETCRED
, "pam_setcred");
1266 if (retval
!= PAM_SUCCESS
)
1267 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1272 * pam_acct_mgmt - check password aging, account expiration
1276 pam_acct_mgmt(pam_handle_t
*pamh
, int flags
)
1280 retval
= run_stack(pamh
, flags
, PAM_ACCOUNT_MODULE
, PAM_ACCT_EXPIRED
,
1281 PAM_ACCT_MGMT
, "pam_acct_mgmt");
1283 if (retval
!= PAM_SUCCESS
&&
1284 retval
!= PAM_NEW_AUTHTOK_REQD
) {
1285 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1291 * pam_open_session - begin session management
1295 pam_open_session(pam_handle_t
*pamh
, int flags
)
1299 retval
= run_stack(pamh
, flags
, PAM_SESSION_MODULE
, PAM_SESSION_ERR
,
1300 PAM_OPEN_SESSION
, "pam_open_session");
1302 if (retval
!= PAM_SUCCESS
)
1303 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1308 * pam_close_session - terminate session management
1312 pam_close_session(pam_handle_t
*pamh
, int flags
)
1316 retval
= run_stack(pamh
, flags
, PAM_SESSION_MODULE
, PAM_SESSION_ERR
,
1317 PAM_CLOSE_SESSION
, "pam_close_session");
1319 if (retval
!= PAM_SUCCESS
)
1320 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1325 * pam_chauthtok - change user authentication token
1329 pam_chauthtok(pam_handle_t
*pamh
, int flags
)
1333 /* do not let apps use PAM_PRELIM_CHECK or PAM_UPDATE_AUTHTOK */
1334 if (flags
& (PAM_PRELIM_CHECK
| PAM_UPDATE_AUTHTOK
)) {
1335 pam_trace(PAM_DEBUG_DEFAULT
,
1336 "pam_chauthtok(%p, %x): %s", (void *)pamh
, flags
,
1337 pam_strerror(pamh
, PAM_SYMBOL_ERR
));
1338 return (PAM_SYMBOL_ERR
);
1341 /* 1st pass: PRELIM CHECK */
1342 retval
= run_stack(pamh
, flags
| PAM_PRELIM_CHECK
, PAM_PASSWORD_MODULE
,
1343 PAM_AUTHTOK_ERR
, PAM_CHAUTHTOK
, "pam_chauthtok-prelim");
1345 if (retval
== PAM_TRY_AGAIN
)
1348 if (retval
!= PAM_SUCCESS
) {
1349 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1353 /* 2nd pass: UPDATE AUTHTOK */
1354 retval
= run_stack(pamh
, flags
| PAM_UPDATE_AUTHTOK
,
1355 PAM_PASSWORD_MODULE
, PAM_AUTHTOK_ERR
, PAM_CHAUTHTOK
,
1356 "pam_chauthtok-update");
1358 if (retval
!= PAM_SUCCESS
)
1359 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1365 * pam_putenv - add an environment variable to the PAM handle
1366 * if name_value == 'NAME=VALUE' then set variable to the value
1367 * if name_value == 'NAME=' then set variable to an empty value
1368 * if name_value == 'NAME' then delete the variable
1372 pam_putenv(pam_handle_t
*pamh
, const char *name_value
)
1374 int error
= PAM_SYSTEM_ERR
;
1375 char *equal_sign
= 0;
1376 char *name
= NULL
, *value
= NULL
, *tmp_value
= NULL
;
1377 env_list
*traverse
, *trail
;
1379 pam_trace(PAM_DEBUG_DEFAULT
,
1380 "pam_putenv(%p, %s)", (void *)pamh
,
1381 name_value
? name_value
: "NULL");
1383 if (pamh
== NULL
|| name_value
== NULL
)
1386 /* see if we were passed 'NAME=VALUE', 'NAME=', or 'NAME' */
1387 if ((equal_sign
= strchr(name_value
, '=')) != 0) {
1388 if ((name
= calloc(equal_sign
- name_value
+ 1,
1389 sizeof (char))) == 0) {
1390 error
= PAM_BUF_ERR
;
1393 (void) strncpy(name
, name_value
, equal_sign
- name_value
);
1394 if ((value
= strdup(++equal_sign
)) == 0) {
1395 error
= PAM_BUF_ERR
;
1399 if ((name
= strdup(name_value
)) == 0) {
1400 error
= PAM_BUF_ERR
;
1405 /* check to see if we already have this variable in the PAM handle */
1406 traverse
= pamh
->pam_env
;
1408 while (traverse
&& strncmp(traverse
->name
, name
, strlen(name
))) {
1410 traverse
= traverse
->next
;
1416 /* remove the env variable */
1417 if (pamh
->pam_env
== traverse
)
1418 pamh
->pam_env
= traverse
->next
;
1420 trail
->next
= traverse
->next
;
1422 } else if (strlen(value
) == 0) {
1423 /* set env variable to empty value */
1424 if ((tmp_value
= strdup("")) == 0) {
1425 error
= PAM_SYSTEM_ERR
;
1428 free(traverse
->value
);
1429 traverse
->value
= tmp_value
;
1431 /* set the new value */
1432 if ((tmp_value
= strdup(value
)) == 0) {
1433 error
= PAM_SYSTEM_ERR
;
1436 free(traverse
->value
);
1437 traverse
->value
= tmp_value
;
1440 } else if (traverse
== 0 && value
) {
1442 * could not find a match in the PAM handle.
1443 * add the new value if there is one
1445 if ((traverse
= calloc(1, sizeof (env_list
))) == 0) {
1446 error
= PAM_BUF_ERR
;
1449 if ((traverse
->name
= strdup(name
)) == 0) {
1451 error
= PAM_BUF_ERR
;
1454 if ((traverse
->value
= strdup(value
)) == 0) {
1456 error
= PAM_BUF_ERR
;
1460 /* new head of list */
1461 pamh
->pam_env
= traverse
;
1463 /* adding to end of list */
1464 trail
->next
= traverse
;
1468 error
= PAM_SUCCESS
;
1470 if (error
!= PAM_SUCCESS
) {
1472 free(traverse
->name
);
1473 free(traverse
->value
);
1483 * pam_getenv - retrieve an environment variable from the PAM handle
1486 pam_getenv(pam_handle_t
*pamh
, const char *name
)
1488 int error
= PAM_SYSTEM_ERR
;
1491 pam_trace(PAM_DEBUG_DEFAULT
,
1492 "pam_getenv(%p, %p)", (void *)pamh
, (void *)name
);
1494 if (pamh
== NULL
|| name
== NULL
)
1497 /* check to see if we already have this variable in the PAM handle */
1498 traverse
= pamh
->pam_env
;
1499 while (traverse
&& strncmp(traverse
->name
, name
, strlen(name
))) {
1500 traverse
= traverse
->next
;
1502 error
= (traverse
? PAM_SUCCESS
: PAM_SYSTEM_ERR
);
1503 pam_trace(PAM_DEBUG_DEFAULT
,
1504 "pam_getenv(%p, %s)=%s", (void *)pamh
, name
,
1505 traverse
? traverse
->value
: "NULL");
1507 return (error
? NULL
: strdup(traverse
->value
));
1511 * pam_getenvlist - retrieve all environment variables from the PAM handle
1512 * in a NULL terminated array. On error, return NULL.
1515 pam_getenvlist(pam_handle_t
*pamh
)
1517 int error
= PAM_SYSTEM_ERR
;
1524 pam_trace(PAM_DEBUG_DEFAULT
,
1525 "pam_getenvlist(%p)", (void *)pamh
);
1530 /* find out how many environment variables we have */
1531 traverse
= pamh
->pam_env
;
1534 traverse
= traverse
->next
;
1537 /* allocate the array we will return to the caller */
1538 if ((list
= calloc(length
+ 1, sizeof (char *))) == NULL
) {
1539 error
= PAM_BUF_ERR
;
1543 /* add the variables one by one */
1545 traverse
= pamh
->pam_env
;
1546 while (traverse
!= NULL
) {
1547 tenv_size
= strlen(traverse
->name
) +
1548 strlen(traverse
->value
) + 2; /* name=val\0 */
1549 if ((tenv
= malloc(tenv_size
)) == NULL
) {
1550 error
= PAM_BUF_ERR
;
1554 (void) sprintf(tenv
, "%s=%s", traverse
->name
, traverse
->value
);
1555 list
[length
++] = tenv
;
1556 traverse
= traverse
->next
;
1558 list
[length
] = NULL
;
1560 error
= PAM_SUCCESS
;
1562 if (error
!= PAM_SUCCESS
) {
1563 /* free the partially constructed list */
1566 while (list
[length
] != NULL
) {
1573 return (error
? NULL
: list
);
1577 * Routines to load a requested module on demand
1581 * load_modules - load the requested module.
1582 * if the dlopen or dlsym fail, then
1583 * the module is ignored.
1587 load_modules(pam_handle_t
*pamh
, int type
, char *function_name
,
1588 pamtab_t
*pam_entry
)
1591 struct auth_module
*authp
;
1592 struct account_module
*accountp
;
1593 struct session_module
*sessionp
;
1594 struct password_module
*passwdp
;
1595 int loading_functions
= 0; /* are we currently loading functions? */
1597 pam_trace(PAM_DEBUG_MODULE
, "load_modules[%d:%s](%p, %s)=%s:%s",
1598 pamh
->include_depth
, pam_trace_cname(pamh
), (void *)pamh
,
1599 function_name
, pam_trace_fname(pam_entry
->pam_flag
),
1600 pam_entry
->module_path
);
1602 while (pam_entry
!= NULL
) {
1603 pam_trace(PAM_DEBUG_DEFAULT
,
1604 "while load_modules[%d:%s](%p, %s)=%s",
1605 pamh
->include_depth
, pam_trace_cname(pamh
), (void *)pamh
,
1606 function_name
, pam_entry
->module_path
);
1608 if (pam_entry
->pam_flag
& PAM_INCLUDE
) {
1609 pam_trace(PAM_DEBUG_DEFAULT
,
1610 "done load_modules[%d:%s](%p, %s)=%s",
1611 pamh
->include_depth
, pam_trace_cname(pamh
),
1612 (void *)pamh
, function_name
,
1613 pam_entry
->module_path
);
1614 return (PAM_SUCCESS
);
1617 case PAM_AUTH_MODULE
:
1619 /* if the function has already been loaded, return */
1620 authp
= pam_entry
->function_ptr
;
1621 if (!loading_functions
&&
1622 (((strcmp(function_name
, PAM_SM_AUTHENTICATE
)
1623 == 0) && authp
&& authp
->pam_sm_authenticate
) ||
1624 ((strcmp(function_name
, PAM_SM_SETCRED
) == 0) &&
1625 authp
&& authp
->pam_sm_setcred
))) {
1626 return (PAM_SUCCESS
);
1629 /* function has not been loaded yet */
1630 loading_functions
= 1;
1631 if (authp
== NULL
) {
1632 authp
= calloc(1, sizeof (struct auth_module
));
1634 return (PAM_BUF_ERR
);
1637 /* if open_module fails, return error */
1638 if ((mh
= open_module(pamh
,
1639 pam_entry
->module_path
)) == NULL
) {
1640 __pam_log(LOG_AUTH
| LOG_ERR
,
1641 "load_modules[%d:%s]: can not open module "
1642 "%s", pamh
->include_depth
,
1643 pam_trace_cname(pamh
),
1644 pam_entry
->module_path
);
1646 return (PAM_OPEN_ERR
);
1649 /* load the authentication function */
1650 if (strcmp(function_name
, PAM_SM_AUTHENTICATE
) == 0) {
1651 if (load_function(mh
, PAM_SM_AUTHENTICATE
,
1652 &authp
->pam_sm_authenticate
)
1654 /* return error if dlsym fails */
1656 return (PAM_SYMBOL_ERR
);
1659 /* load the setcred function */
1660 } else if (strcmp(function_name
, PAM_SM_SETCRED
) == 0) {
1661 if (load_function(mh
, PAM_SM_SETCRED
,
1662 &authp
->pam_sm_setcred
) != PAM_SUCCESS
) {
1663 /* return error if dlsym fails */
1665 return (PAM_SYMBOL_ERR
);
1668 pam_entry
->function_ptr
= authp
;
1670 case PAM_ACCOUNT_MODULE
:
1671 accountp
= pam_entry
->function_ptr
;
1672 if (!loading_functions
&&
1673 (strcmp(function_name
, PAM_SM_ACCT_MGMT
) == 0) &&
1674 accountp
&& accountp
->pam_sm_acct_mgmt
) {
1675 return (PAM_SUCCESS
);
1679 * If functions are added to the account module,
1680 * verify that one of the other functions hasn't
1681 * already loaded it. See PAM_AUTH_MODULE code.
1683 loading_functions
= 1;
1684 accountp
= calloc(1, sizeof (struct account_module
));
1685 if (accountp
== NULL
)
1686 return (PAM_BUF_ERR
);
1688 /* if open_module fails, return error */
1689 if ((mh
= open_module(pamh
,
1690 pam_entry
->module_path
)) == NULL
) {
1691 __pam_log(LOG_AUTH
| LOG_ERR
,
1692 "load_modules[%d:%s]: can not open module "
1693 "%s", pamh
->include_depth
,
1694 pam_trace_cname(pamh
),
1695 pam_entry
->module_path
);
1697 return (PAM_OPEN_ERR
);
1700 if (load_function(mh
, PAM_SM_ACCT_MGMT
,
1701 &accountp
->pam_sm_acct_mgmt
) != PAM_SUCCESS
) {
1702 __pam_log(LOG_AUTH
| LOG_ERR
,
1703 "load_modules[%d:%s]: pam_sm_acct_mgmt() "
1704 "missing", pamh
->include_depth
,
1705 pam_trace_cname(pamh
));
1707 return (PAM_SYMBOL_ERR
);
1709 pam_entry
->function_ptr
= accountp
;
1711 case PAM_SESSION_MODULE
:
1712 sessionp
= pam_entry
->function_ptr
;
1713 if (!loading_functions
&&
1714 (((strcmp(function_name
,
1715 PAM_SM_OPEN_SESSION
) == 0) &&
1716 sessionp
&& sessionp
->pam_sm_open_session
) ||
1717 ((strcmp(function_name
,
1718 PAM_SM_CLOSE_SESSION
) == 0) &&
1719 sessionp
&& sessionp
->pam_sm_close_session
))) {
1720 return (PAM_SUCCESS
);
1723 loading_functions
= 1;
1724 if (sessionp
== NULL
) {
1725 sessionp
= calloc(1,
1726 sizeof (struct session_module
));
1727 if (sessionp
== NULL
)
1728 return (PAM_BUF_ERR
);
1731 /* if open_module fails, return error */
1732 if ((mh
= open_module(pamh
,
1733 pam_entry
->module_path
)) == NULL
) {
1734 __pam_log(LOG_AUTH
| LOG_ERR
,
1735 "load_modules[%d:%s]: can not open module "
1736 "%s", pamh
->include_depth
,
1737 pam_trace_cname(pamh
),
1738 pam_entry
->module_path
);
1740 return (PAM_OPEN_ERR
);
1743 if ((strcmp(function_name
, PAM_SM_OPEN_SESSION
) == 0) &&
1744 load_function(mh
, PAM_SM_OPEN_SESSION
,
1745 &sessionp
->pam_sm_open_session
) != PAM_SUCCESS
) {
1747 return (PAM_SYMBOL_ERR
);
1748 } else if ((strcmp(function_name
,
1749 PAM_SM_CLOSE_SESSION
) == 0) &&
1750 load_function(mh
, PAM_SM_CLOSE_SESSION
,
1751 &sessionp
->pam_sm_close_session
) != PAM_SUCCESS
) {
1753 return (PAM_SYMBOL_ERR
);
1755 pam_entry
->function_ptr
= sessionp
;
1757 case PAM_PASSWORD_MODULE
:
1758 passwdp
= pam_entry
->function_ptr
;
1759 if (!loading_functions
&&
1760 (strcmp(function_name
, PAM_SM_CHAUTHTOK
) == 0) &&
1761 passwdp
&& passwdp
->pam_sm_chauthtok
) {
1762 return (PAM_SUCCESS
);
1766 * If functions are added to the password module,
1767 * verify that one of the other functions hasn't
1768 * already loaded it. See PAM_AUTH_MODULE code.
1770 loading_functions
= 1;
1771 passwdp
= calloc(1, sizeof (struct password_module
));
1772 if (passwdp
== NULL
)
1773 return (PAM_BUF_ERR
);
1775 /* if open_module fails, continue */
1776 if ((mh
= open_module(pamh
,
1777 pam_entry
->module_path
)) == NULL
) {
1778 __pam_log(LOG_AUTH
| LOG_ERR
,
1779 "load_modules[%d:%s]: can not open module "
1780 "%s", pamh
->include_depth
,
1781 pam_trace_cname(pamh
),
1782 pam_entry
->module_path
);
1784 return (PAM_OPEN_ERR
);
1787 if (load_function(mh
, PAM_SM_CHAUTHTOK
,
1788 &passwdp
->pam_sm_chauthtok
) != PAM_SUCCESS
) {
1790 return (PAM_SYMBOL_ERR
);
1792 pam_entry
->function_ptr
= passwdp
;
1795 pam_trace(PAM_DEBUG_DEFAULT
,
1796 "load_modules[%d:%s](%p, %s): unsupported type %d",
1797 pamh
->include_depth
, pam_trace_cname(pamh
),
1798 (void *)pamh
, function_name
, type
);
1802 pam_entry
= pam_entry
->next
;
1805 pam_trace(PAM_DEBUG_MODULE
, "load_modules[%d:%s](%p, %s)=done",
1806 pamh
->include_depth
, pam_trace_cname(pamh
), (void *)pamh
,
1809 return (PAM_SUCCESS
);
1813 * open_module - Open the module first checking for
1814 * propers modes and ownerships on the file.
1818 open_module(pam_handle_t
*pamh
, char *module_so
)
1823 fd_list
*module_fds
= 0;
1825 fd_list
*traverse
= 0;
1827 /* Check the ownership and file modes */
1828 if (stat64(module_so
, &stb
) < 0) {
1829 __pam_log(LOG_AUTH
| LOG_ERR
,
1830 "open_module[%d:%s]: stat(%s) failed: %s",
1831 pamh
->include_depth
, pam_trace_cname(pamh
), module_so
,
1835 if (stb
.st_uid
!= (uid_t
)0) {
1836 __pam_log(LOG_AUTH
| LOG_ALERT
,
1837 "open_module[%d:%s]: Owner of the module %s is not root",
1838 pamh
->include_depth
, pam_trace_cname(pamh
), module_so
);
1841 if (stb
.st_mode
& S_IWGRP
) {
1842 __pam_log(LOG_AUTH
| LOG_ALERT
,
1843 "open_module[%d:%s]: module %s writable by group",
1844 pamh
->include_depth
, pam_trace_cname(pamh
), module_so
);
1847 if (stb
.st_mode
& S_IWOTH
) {
1848 __pam_log(LOG_AUTH
| LOG_ALERT
,
1849 "open_module[%d:%s]: module %s writable by world",
1850 pamh
->include_depth
, pam_trace_cname(pamh
), module_so
);
1855 * Perform the dlopen()
1857 lfd
= (void *)dlopen(module_so
, RTLD_LAZY
);
1861 __pam_log(LOG_AUTH
| LOG_ERR
, "open_module[%d:%s]: %s "
1862 "failed: %s", pamh
->include_depth
, pam_trace_cname(pamh
),
1863 module_so
, errmsg
!= NULL
? errmsg
: "Unknown error");
1866 /* add this fd to the pam handle */
1867 if ((module_fds
= calloc(1, sizeof (fd_list
))) == 0) {
1868 (void) dlclose(lfd
);
1872 module_fds
->mh
= lfd
;
1874 if (pamh
->fd
== 0) {
1875 /* adding new head of list */
1876 pamh
->fd
= module_fds
;
1878 /* appending to end of list */
1879 traverse
= pamh
->fd
;
1882 traverse
= traverse
->next
;
1884 trail
->next
= module_fds
;
1892 * load_function - call dlsym() to resolve the function address
1895 load_function(void *lfd
, char *name
, int (**func
)())
1897 char *errmsg
= NULL
;
1900 return (PAM_SYMBOL_ERR
);
1902 *func
= (int (*)())dlsym(lfd
, name
);
1903 if (*func
== NULL
) {
1905 __pam_log(LOG_AUTH
| LOG_ERR
, "dlsym failed %s: error %s",
1906 name
, errmsg
!= NULL
? errmsg
: "Unknown error");
1907 return (PAM_SYMBOL_ERR
);
1910 pam_trace(PAM_DEBUG_DEFAULT
,
1911 "load_function: successful load of %s", name
);
1912 return (PAM_SUCCESS
);
1916 * Routines to read the pam.conf configuration file
1920 * open_pam_conf - open the pam.conf config file
1924 open_pam_conf(struct pam_fh
**pam_fh
, pam_handle_t
*pamh
, char *config
,
1930 if ((fd
= open(config
, O_RDONLY
)) == -1) {
1932 __pam_log(LOG_AUTH
| LOG_ALERT
,
1933 "open_pam_conf[%d:%s]: open(%s) failed: %s",
1934 pamh
->include_depth
, pam_trace_cname(pamh
), config
,
1938 /* Check the ownership and file modes */
1939 if (fstat64(fd
, &stb
) < 0) {
1940 __pam_log(LOG_AUTH
| LOG_ALERT
,
1941 "open_pam_conf[%d:%s]: stat(%s) failed: %s",
1942 pamh
->include_depth
, pam_trace_cname(pamh
), config
,
1947 if (stb
.st_uid
!= (uid_t
)0) {
1948 __pam_log(LOG_AUTH
| LOG_ALERT
,
1949 "open_pam_conf[%d:%s]: Owner of %s is not root",
1950 pamh
->include_depth
, pam_trace_cname(pamh
), config
);
1954 if (stb
.st_mode
& S_IWGRP
) {
1955 __pam_log(LOG_AUTH
| LOG_ALERT
,
1956 "open_pam_conf[%d:%s]: %s writable by group",
1957 pamh
->include_depth
, pam_trace_cname(pamh
), config
);
1961 if (stb
.st_mode
& S_IWOTH
) {
1962 __pam_log(LOG_AUTH
| LOG_ALERT
,
1963 "open_pam_conf[%d:%s]: %s writable by world",
1964 pamh
->include_depth
, pam_trace_cname(pamh
), config
);
1968 if ((*pam_fh
= calloc(1, sizeof (struct pam_fh
))) == NULL
) {
1972 (*pam_fh
)->fconfig
= fd
;
1973 (*pam_fh
)->bufsize
= (size_t)stb
.st_size
;
1974 if (((*pam_fh
)->data
= mmap(NULL
, (*pam_fh
)->bufsize
, PROT_READ
,
1975 MAP_PRIVATE
, (*pam_fh
)->fconfig
, 0)) == MAP_FAILED
) {
1980 (*pam_fh
)->bufferp
= (*pam_fh
)->data
;
1986 * close_pam_conf - close pam.conf
1990 close_pam_conf(struct pam_fh
*pam_fh
)
1992 (void) munmap(pam_fh
->data
, pam_fh
->bufsize
);
1993 (void) close(pam_fh
->fconfig
);
1998 * read_pam_conf - read in each entry in pam.conf and store info
1999 * under the pam handle.
2003 read_pam_conf(pam_handle_t
*pamh
, char *config
, char *service
)
2005 struct pam_fh
*pam_fh
;
2009 int i
= pamh
->include_depth
; /* include depth */
2014 * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3)
2016 int service_found
[PAM_NUM_MODULE_TYPES
+1] = {0, 0, 0, 0, 0};
2018 pamh
->pam_conf_name
[i
] = strdup(config
);
2019 pam_trace(PAM_DEBUG_CONF
, "read_pam_conf[%d:%s](%p) open(%s)",
2020 i
, pam_trace_cname(pamh
), (void *)pamh
, config
);
2021 if (open_pam_conf(&pam_fh
, pamh
, config
, 1) == 0) {
2022 /* fall back to /etc/pam.conf */
2023 config
= PAM_CONFIG
;
2026 pam_trace(PAM_DEBUG_CONF
, "read_pam_conf[%d:%s](%p) open(%s)",
2027 i
, pam_trace_cname(pamh
), (void *)pamh
, PAM_CONFIG
);
2028 if (open_pam_conf(&pam_fh
, pamh
, config
, 0) == 0)
2029 return (PAM_SYSTEM_ERR
);
2033 get_pam_conf_entry(pam_fh
, pamh
, &pamentp
, service
, shardfile
))
2034 == PAM_SUCCESS
&& pamentp
) {
2036 /* See if entry is this service and valid */
2037 if (verify_pam_conf(pamentp
, service
)) {
2038 pam_trace(PAM_DEBUG_CONF
,
2039 "read_pam_conf[%d:%s](%p): bad entry error %s",
2040 i
, pam_trace_cname(pamh
), (void *)pamh
, service
);
2042 error
= PAM_SYSTEM_ERR
;
2043 free_pamconf(pamentp
);
2046 if (strcasecmp(pamentp
->pam_service
, service
) == 0) {
2047 pam_trace(PAM_DEBUG_CONF
,
2048 "read_pam_conf[%d:%s](%p): processing %s",
2049 i
, pam_trace_cname(pamh
), (void *)pamh
, service
);
2050 /* process first service entry */
2051 if (service_found
[pamentp
->pam_type
+ 1] == 0) {
2052 /* purge "other" entries */
2053 while ((tpament
= pamh
->pam_conf_info
[i
]
2054 [pamentp
->pam_type
]) != NULL
) {
2055 pam_trace(PAM_DEBUG_CONF
,
2056 "read_pam_conf(%p): purging "
2057 "\"other\"[%d:%s][%s]",
2059 pam_trace_cname(pamh
),
2060 pam_snames
[pamentp
->pam_type
]);
2061 pamh
->pam_conf_info
[i
]
2062 [pamentp
->pam_type
] = tpament
->next
;
2063 free_pamconf(tpament
);
2065 /* add first service entry */
2066 pam_trace(PAM_DEBUG_CONF
,
2067 "read_pam_conf(%p): adding 1st "
2069 (void *)pamh
, service
, i
,
2070 pam_trace_cname(pamh
),
2071 pam_snames
[pamentp
->pam_type
]);
2072 pamh
->pam_conf_info
[i
][pamentp
->pam_type
] =
2074 service_found
[pamentp
->pam_type
+ 1] = 1;
2076 /* append more service entries */
2077 pam_trace(PAM_DEBUG_CONF
,
2078 "read_pam_conf(%p): adding more "
2080 (void *)pamh
, service
, i
,
2081 pam_trace_cname(pamh
),
2082 pam_snames
[pamentp
->pam_type
]);
2084 pamh
->pam_conf_info
[i
][pamentp
->pam_type
];
2085 while (tpament
->next
!= NULL
) {
2086 tpament
= tpament
->next
;
2088 tpament
->next
= pamentp
;
2090 } else if (service_found
[pamentp
->pam_type
+ 1] == 0) {
2091 /* See if "other" entry available and valid */
2092 if (verify_pam_conf(pamentp
, "other")) {
2093 pam_trace(PAM_DEBUG_CONF
,
2094 "read_pam_conf(%p): bad entry error %s "
2096 (void *)pamh
, service
, i
,
2097 pam_trace_cname(pamh
));
2098 error
= PAM_SYSTEM_ERR
;
2099 free_pamconf(pamentp
);
2102 if (strcasecmp(pamentp
->pam_service
, "other") == 0) {
2103 pam_trace(PAM_DEBUG_CONF
,
2104 "read_pam_conf(%p): processing "
2105 "\"other\"[%d:%s]", (void *)pamh
, i
,
2106 pam_trace_cname(pamh
));
2107 if ((tpament
= pamh
->pam_conf_info
[i
]
2108 [pamentp
->pam_type
]) == NULL
) {
2109 /* add first "other" entry */
2110 pam_trace(PAM_DEBUG_CONF
,
2111 "read_pam_conf(%p): adding 1st "
2112 "other[%d:%s][%s]", (void *)pamh
, i
,
2113 pam_trace_cname(pamh
),
2114 pam_snames
[pamentp
->pam_type
]);
2115 pamh
->pam_conf_info
[i
]
2116 [pamentp
->pam_type
] = pamentp
;
2118 /* append more "other" entries */
2119 pam_trace(PAM_DEBUG_CONF
,
2120 "read_pam_conf(%p): adding more "
2121 "other[%d:%s][%s]", (void *)pamh
, i
,
2122 pam_trace_cname(pamh
),
2123 pam_snames
[pamentp
->pam_type
]);
2124 while (tpament
->next
!= NULL
) {
2125 tpament
= tpament
->next
;
2127 tpament
->next
= pamentp
;
2130 /* irrelevant entry */
2131 free_pamconf(pamentp
);
2134 /* irrelevant entry */
2135 free_pamconf(pamentp
);
2140 * If we have no entries for this module type (e.g. "account"), then
2141 * generate a single "include" rule for the shard file "other" as a
2144 if (strcasecmp(service
, "other") == 0)
2147 for (j
= 0; j
< PAM_NUM_MODULE_TYPES
; j
++) {
2150 if (service_found
[j
+ 1] != 0 ||
2151 pamh
->pam_conf_info
[i
][j
] != NULL
)
2154 pe
= calloc(1, sizeof (pamtab_t
));
2156 pam_trace(PAM_DEBUG_CONF
, "read_pam_conf(%p): falling back to "
2157 "\"other\" for module type \"%s\" in service \"%s\"",
2158 (void *)pamh
, pam_snames
[j
], service
);
2160 error
= PAM_SYSTEM_ERR
;
2161 __pam_log(LOG_AUTH
| LOG_ERR
, "calloc: out of memory");
2165 pe
->pam_service
= strdup(service
);
2167 pe
->pam_flag
= PAM_INCLUDE
;
2168 if (asprintf(&pe
->module_path
, "%s%s", PAM_CONFIG_DIR
,
2171 error
= PAM_SYSTEM_ERR
;
2172 __pam_log(LOG_AUTH
| LOG_ERR
, "asprintf: out of memory");
2176 pamh
->pam_conf_info
[i
][j
] = pe
;
2180 (void) close_pam_conf(pam_fh
);
2181 if (error
!= PAM_SUCCESS
)
2182 free_pam_conf_info(pamh
);
2187 * get_pam_conf_entry - get a pam.conf entry
2191 get_pam_conf_entry(struct pam_fh
*pam_fh
, pam_handle_t
*pamh
, pamtab_t
**pam
,
2192 char *service
, int shardfile
)
2196 char *tmp
, *tmp_free
;
2198 char *current_line
= NULL
;
2199 int error
= PAM_SYSTEM_ERR
; /* preset to error */
2202 /* get the next line from pam.conf */
2203 if ((cp
= nextline(pam_fh
, pamh
, &err
)) == NULL
) {
2204 /* no more lines in pam.conf ==> return */
2205 error
= PAM_SUCCESS
;
2210 if ((*pam
= calloc(1, sizeof (pamtab_t
))) == NULL
) {
2211 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2215 /* copy full line for error reporting */
2216 if ((current_line
= strdup(cp
)) == NULL
) {
2217 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2221 pam_trace(PAM_DEBUG_CONF
,
2222 "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh
), current_line
);
2226 * If this is an /etc/pam.d shard file, then the service name
2227 * comes from the file name of the shard.
2229 if (((*pam
)->pam_service
= strdup(service
)) == 0) {
2230 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2234 /* get service name (e.g. login, su, passwd) */
2235 if ((arg
= read_next_token(&cp
)) == 0) {
2236 __pam_log(LOG_AUTH
| LOG_CRIT
,
2237 "illegal pam.conf[%s] entry: %s: missing SERVICE "
2238 "NAME", pam_trace_cname(pamh
), current_line
);
2241 if (((*pam
)->pam_service
= strdup(arg
)) == 0) {
2242 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2247 /* get module type (e.g. authentication, acct mgmt) */
2248 if ((arg
= read_next_token(&cp
)) == 0) {
2249 __pam_log(LOG_AUTH
| LOG_CRIT
,
2250 "illegal pam.conf[%s] entry: %s: missing MODULE TYPE",
2251 pam_trace_cname(pamh
), current_line
);
2252 (*pam
)->pam_type
= -1; /* 0 is a valid value */
2255 if (strcasecmp(arg
, PAM_AUTH_NAME
) == 0) {
2256 (*pam
)->pam_type
= PAM_AUTH_MODULE
;
2257 } else if (strcasecmp(arg
, PAM_ACCOUNT_NAME
) == 0) {
2258 (*pam
)->pam_type
= PAM_ACCOUNT_MODULE
;
2259 } else if (strcasecmp(arg
, PAM_SESSION_NAME
) == 0) {
2260 (*pam
)->pam_type
= PAM_SESSION_MODULE
;
2261 } else if (strcasecmp(arg
, PAM_PASSWORD_NAME
) == 0) {
2262 (*pam
)->pam_type
= PAM_PASSWORD_MODULE
;
2265 __pam_log(LOG_AUTH
| LOG_CRIT
,
2266 "illegal pam.conf[%s] entry: %s: invalid module "
2267 "type: %s", pam_trace_cname(pamh
), current_line
, arg
);
2268 (*pam
)->pam_type
= -1; /* 0 is a valid value */
2272 /* get pam flag (e.g., requisite, required, sufficient, optional) */
2273 if ((arg
= read_next_token(&cp
)) == 0) {
2274 __pam_log(LOG_AUTH
| LOG_CRIT
,
2275 "illegal pam.conf[%s] entry: %s: missing CONTROL FLAG",
2276 pam_trace_cname(pamh
), current_line
);
2279 if (strcasecmp(arg
, PAM_BINDING_NAME
) == 0) {
2280 (*pam
)->pam_flag
= PAM_BINDING
;
2281 } else if (strcasecmp(arg
, PAM_INCLUDE_NAME
) == 0) {
2282 (*pam
)->pam_flag
= PAM_INCLUDE
;
2283 } else if (strcasecmp(arg
, PAM_OPTIONAL_NAME
) == 0) {
2284 (*pam
)->pam_flag
= PAM_OPTIONAL
;
2285 } else if (strcasecmp(arg
, PAM_REQUIRED_NAME
) == 0) {
2286 (*pam
)->pam_flag
= PAM_REQUIRED
;
2287 } else if (strcasecmp(arg
, PAM_REQUISITE_NAME
) == 0) {
2288 (*pam
)->pam_flag
= PAM_REQUISITE
;
2289 } else if (strcasecmp(arg
, PAM_SUFFICIENT_NAME
) == 0) {
2290 (*pam
)->pam_flag
= PAM_SUFFICIENT
;
2293 __pam_log(LOG_AUTH
| LOG_CRIT
,
2294 "illegal pam.conf[%s] entry: %s",
2295 pam_trace_cname(pamh
), current_line
);
2296 __pam_log(LOG_AUTH
| LOG_CRIT
,
2297 "\tinvalid control flag: %s", arg
);
2301 /* get module path (e.g. /usr/lib/security/pam_unix_auth.so.1) */
2302 if ((arg
= read_next_token(&cp
)) == 0) {
2303 __pam_log(LOG_AUTH
| LOG_CRIT
,
2304 "illegal pam.conf[%s] entry: %s: missing MODULE PATH",
2305 pam_trace_cname(pamh
), current_line
);
2306 error
= PAM_SUCCESS
; /* success */
2309 if (arg
[0] != '/') {
2312 * If module path does not start with "/", then
2313 * prepend PAM_LIB_DIR (/usr/lib/security/).
2315 if ((*pam
)->pam_flag
& PAM_INCLUDE
) {
2317 * If this is an /etc/pam.d shard, we want to get
2318 * included files from /etc/pam.d rather than
2319 * /usr/lib/security.
2321 ret
= asprintf(&(*pam
)->module_path
, "%s%s",
2322 (shardfile
? PAM_CONFIG_DIR
: PAM_LIB_DIR
), arg
);
2324 ret
= asprintf(&(*pam
)->module_path
, "%s%s%s",
2325 PAM_LIB_DIR
, PAM_ISA_DIR
, arg
);
2328 __pam_log(LOG_AUTH
| LOG_ERR
,
2329 "asprintf: out of memory");
2333 /* Full path provided for module */
2336 /* Check for Instruction Set Architecture indicator */
2337 if ((isa
= strstr(arg
, PAM_ISA
)) != NULL
) {
2339 len
= strlen(arg
) - (sizeof (PAM_ISA
)-1) +
2340 sizeof (PAM_ISA_DIR
);
2342 /* substitute the architecture dependent path */
2343 if (((*pam
)->module_path
= malloc(len
)) == NULL
) {
2344 __pam_log(LOG_AUTH
| LOG_ERR
,
2345 "strdup: out of memory");
2349 isa
+= strlen(PAM_ISA
);
2350 (void) snprintf((*pam
)->module_path
, len
, "%s%s%s",
2351 arg
, PAM_ISA_DIR
, isa
);
2352 } else if (((*pam
)->module_path
= strdup(arg
)) == 0) {
2353 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2358 /* count the number of module-specific options first */
2360 if ((tmp
= strdup(cp
)) == NULL
) {
2361 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2365 for (arg
= read_next_token(&tmp
); arg
; arg
= read_next_token(&tmp
))
2369 /* allocate array for the module-specific options */
2371 if (((*pam
)->module_argv
=
2372 calloc(argc
+1, sizeof (char *))) == 0) {
2373 __pam_log(LOG_AUTH
| LOG_ERR
, "calloc: out of memory");
2377 for (arg
= read_next_token(&cp
); arg
;
2378 arg
= read_next_token(&cp
)) {
2379 (*pam
)->module_argv
[i
] = strdup(arg
);
2380 if ((*pam
)->module_argv
[i
] == NULL
) {
2381 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup failed");
2386 (*pam
)->module_argv
[argc
] = NULL
;
2388 (*pam
)->module_argc
= argc
;
2390 error
= PAM_SUCCESS
; /* success */
2391 (*pam
)->pam_err
= err
; /* was the line truncated */
2395 if (error
!= PAM_SUCCESS
) {
2396 /* on error free this */
2405 * read_next_token - skip tab and space characters and return the next token
2409 read_next_token(char **cpp
)
2411 register char *cp
= *cpp
;
2418 while (*cp
== ' ' || *cp
== '\t')
2425 while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
2434 pam_conf_strnchr(char *sp
, int c
, intptr_t count
)
2438 return ((char *)sp
);
2448 * nextline - skip all blank lines and comments
2452 nextline(struct pam_fh
*pam_fh
, pam_handle_t
*pamh
, int *err
)
2455 int find_a_line
= 0;
2456 char *data
= pam_fh
->data
;
2457 char *bufferp
= pam_fh
->bufferp
;
2458 char *bufferendp
= &data
[pam_fh
->bufsize
];
2462 * Skip the blank line, comment line
2464 while (!find_a_line
) {
2465 /* if we are at the end of the buffer, there is no next line */
2466 if (bufferp
== bufferendp
)
2469 /* skip blank line */
2470 while (*bufferp
== '\n') {
2472 * If we are at the end of the buffer, there is
2475 if (++bufferp
== bufferendp
) {
2478 /* else we check *bufferp again */
2481 /* skip comment line */
2482 while (*bufferp
== '#') {
2483 if ((ll
= pam_conf_strnchr(bufferp
, '\n',
2484 bufferendp
- bufferp
)) != NULL
) {
2488 * this comment line the last line.
2495 * If we are at the end of the buffer, there is
2498 if (bufferp
== bufferendp
) {
2503 if ((*bufferp
!= '\n') && (*bufferp
!= '#')) {
2509 /* now we find one line */
2510 if ((ll
= pam_conf_strnchr(bufferp
, '\n', bufferendp
- bufferp
))
2512 if ((input_len
= ll
- bufferp
) >= sizeof (pam_fh
->line
)) {
2513 __pam_log(LOG_AUTH
| LOG_ERR
,
2514 "nextline[%d:%s]: pam.conf line too long %.256s",
2515 pamh
->include_depth
, pam_trace_cname(pamh
),
2517 input_len
= sizeof (pam_fh
->line
) - 1;
2518 *err
= PAM_SERVICE_ERR
;
2520 (void) strncpy(pam_fh
->line
, bufferp
, input_len
);
2521 pam_fh
->line
[input_len
] = '\0';
2522 pam_fh
->bufferp
= ll
++;
2525 if ((input_len
= ll
- bufferp
) >= sizeof (pam_fh
->line
)) {
2526 __pam_log(LOG_AUTH
| LOG_ERR
,
2527 "nextline[%d:%s]: pam.conf line too long %.256s",
2528 pamh
->include_depth
, pam_trace_cname(pamh
),
2530 input_len
= sizeof (pam_fh
->line
) - 1;
2531 *err
= PAM_SERVICE_ERR
;
2533 (void) strncpy(pam_fh
->line
, bufferp
, input_len
);
2534 pam_fh
->line
[input_len
] = '\0';
2535 pam_fh
->bufferp
= ll
;
2538 return (pam_fh
->line
);
2542 * verify_pam_conf - verify that the pam_conf entry is filled in.
2544 * True = Error if there is no service.
2545 * True = Error if there is a service and it matches the requested service
2546 * but, the type, flag, line overflow, or path is in error.
2550 verify_pam_conf(pamtab_t
*pam
, char *service
)
2552 return ((pam
->pam_service
== NULL
) ||
2553 ((strcasecmp(pam
->pam_service
, service
) == 0) &&
2554 ((pam
->pam_type
== -1) ||
2555 (pam
->pam_flag
== 0) ||
2556 (pam
->pam_err
!= PAM_SUCCESS
) ||
2557 (pam
->module_path
== NULL
))));
2561 * Routines to free allocated storage
2565 * clean_up - free allocated storage in the pam handle
2569 clean_up(pam_handle_t
*pamh
)
2572 pam_repository_t
*auth_rep
;
2575 while (pamh
->include_depth
>= 0) {
2576 free_pam_conf_info(pamh
);
2577 pamh
->include_depth
--;
2580 /* Cleanup PAM_REPOSITORY structure */
2581 auth_rep
= pamh
->ps_item
[PAM_REPOSITORY
].pi_addr
;
2582 if (auth_rep
!= NULL
) {
2583 free(auth_rep
->type
);
2584 free(auth_rep
->scope
);
2587 for (i
= 0; i
< PAM_MAX_ITEMS
; i
++) {
2588 if (pamh
->ps_item
[i
].pi_addr
!= NULL
) {
2589 if (i
== PAM_AUTHTOK
|| i
== PAM_OLDAUTHTOK
) {
2590 (void) memset(pamh
->ps_item
[i
].pi_addr
,
2591 0, pamh
->ps_item
[i
].pi_size
);
2593 free(pamh
->ps_item
[i
].pi_addr
);
2601 * free_pamconf - free memory used to store pam.conf entry
2605 free_pamconf(pamtab_t
*cp
)
2610 free(cp
->pam_service
);
2611 free(cp
->module_path
);
2612 for (i
= 0; i
< cp
->module_argc
; i
++) {
2613 free(cp
->module_argv
[i
]);
2615 if (cp
->module_argc
> 0)
2616 free(cp
->module_argv
);
2617 free(cp
->function_ptr
);
2624 * free_pam_conf_info - free memory used to store all pam.conf info
2625 * under the pam handle
2629 free_pam_conf_info(pam_handle_t
*pamh
)
2632 pamtab_t
*pament_trail
;
2633 int i
= pamh
->include_depth
;
2636 for (j
= 0; j
< PAM_NUM_MODULE_TYPES
; j
++) {
2637 pamentp
= pamh
->pam_conf_info
[i
][j
];
2638 pamh
->pam_conf_info
[i
][j
] = NULL
;
2639 pament_trail
= pamentp
;
2641 pamentp
= pamentp
->next
;
2642 free_pamconf(pament_trail
);
2643 pament_trail
= pamentp
;
2646 if (pamh
->pam_conf_name
[i
] != NULL
) {
2647 free(pamh
->pam_conf_name
[i
]);
2648 pamh
->pam_conf_name
[i
] = NULL
;
2653 free_env(env_list
*pam_env
)
2656 free(pam_env
->name
);
2657 free(pam_env
->value
);
2663 * Internal convenience functions for Solaris PAM service modules.
2666 #include <libintl.h>
2667 #include <nl_types.h>
2672 typedef struct pam_msg_data
{
2678 * free storage for responses used in the call back "pam_conv" functions
2682 free_resp(int num_msg
, struct pam_response
*resp
)
2685 struct pam_response
*r
;
2689 for (i
= 0; i
< num_msg
; i
++, r
++) {
2691 /* clear before freeing -- may be a password */
2692 bzero(r
->resp
, strlen(r
->resp
));
2702 do_conv(pam_handle_t
*pamh
, int msg_style
, int num_msg
,
2703 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
], void *conv_apdp
,
2704 struct pam_response
*ret_respp
[])
2706 struct pam_message
*msg
;
2707 struct pam_message
*m
;
2711 struct pam_conv
*pam_convp
;
2713 if ((retcode
= pam_get_item(pamh
, PAM_CONV
,
2714 (void **)&pam_convp
)) != PAM_SUCCESS
) {
2719 * When pam_set_item() is called to set PAM_CONV and the
2720 * item is NULL, memset(pip->pi_addr, 0, size) is called.
2721 * So at this point, we should check whether pam_convp->conv
2724 if ((pam_convp
== NULL
) || (pam_convp
->conv
== NULL
))
2725 return (PAM_SYSTEM_ERR
);
2730 msg
= calloc(num_msg
, sizeof (struct pam_message
));
2732 return (PAM_BUF_ERR
);
2738 * fill out the message structure to display prompt message
2740 m
->msg_style
= msg_style
;
2741 m
->msg
= messages
[i
];
2742 pam_trace(PAM_DEBUG_CONV
,
2743 "pam_conv_msg(%p:%d[%d]=%s)",
2744 (void *)pamh
, msg_style
, i
, messages
[i
]);
2750 * The UNIX pam modules always calls __pam_get_authtok() and
2751 * __pam_display_msg() with a NULL pointer as the conv_apdp.
2752 * In case the conv_apdp is NULL and the pam_convp->appdata_ptr
2753 * is not NULL, we should pass the pam_convp->appdata_ptr
2754 * to the conversation function.
2756 if (conv_apdp
== NULL
&& pam_convp
->appdata_ptr
!= NULL
)
2757 conv_apdp
= pam_convp
->appdata_ptr
;
2760 * Call conv function to display the prompt.
2762 retcode
= (pam_convp
->conv
)(num_msg
, &msg
, ret_respp
, conv_apdp
);
2763 pam_trace(PAM_DEBUG_CONV
,
2764 "pam_conv_resp(%p pam_conv = %s) ret_respp = %p",
2765 (void *)pamh
, pam_strerror(pamh
, retcode
), (void *)ret_respp
);
2766 if (*ret_respp
== NULL
) {
2767 pam_trace(PAM_DEBUG_CONV
,
2768 "pam_conv_resp(%p No response requested)", (void *)pamh
);
2769 } else if ((pam_debug
& (PAM_DEBUG_CONV
| PAM_DEBUG_AUTHTOK
)) != 0) {
2770 struct pam_response
*r
= *ret_respp
;
2772 for (i
= 0; i
< num_msg
; i
++, r
++) {
2773 if (r
->resp
== NULL
) {
2774 pam_trace(PAM_DEBUG_CONV
,
2776 "[%d] NULL response string)",
2779 if (msg_style
== PAM_PROMPT_ECHO_OFF
) {
2781 pam_trace(PAM_DEBUG_AUTHTOK
,
2782 "pam_conv_resp(%p:[%d]=%s, "
2784 (void *)pamh
, i
, r
->resp
,
2787 pam_trace(PAM_DEBUG_CONV
,
2788 "pam_conv_resp(%p:[%d] len=%lu, "
2791 (ulong_t
)strlen(r
->resp
),
2794 pam_trace(PAM_DEBUG_CONV
,
2795 "pam_conv_resp(%p:[%d]=%s, "
2797 (void *)pamh
, i
, r
->resp
,
2809 * __pam_display_msg():
2810 * display message by calling the call back functions
2811 * provided by the application through "pam_conv" structure
2815 __pam_display_msg(pam_handle_t
*pamh
, int msg_style
, int num_msg
,
2816 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
], void *conv_apdp
)
2818 struct pam_response
*ret_respp
= NULL
;
2821 ret
= do_conv(pamh
, msg_style
, num_msg
, messages
,
2822 conv_apdp
, &ret_respp
);
2824 if (ret_respp
!= NULL
)
2825 free_resp(num_msg
, ret_respp
);
2831 * __pam_get_authtok()
2832 * retrieves a password of at most PASS_MAX length from the pam
2833 * handle (pam_get_item) or from the input stream (do_conv).
2835 * This function allocates memory for the new authtok.
2836 * Applications calling this function are responsible for
2837 * freeing this memory.
2842 * PAM_AUTHTOK - password is taken from pam handle (PAM_AUTHTOK)
2843 * PAM_OLDAUTHTOK - password is taken from pam handle (PAM_OLDAUTHTOK)
2848 * 0: Prompt for new passwd, do not even attempt
2849 * to store it in the pam handle.
2850 * PAM_AUTHTOK: Prompt for new passwd, store in pam handle as
2851 * PAM_AUTHTOK item if this value is not already set.
2852 * PAM_OLDAUTHTOK: Prompt for new passwd, store in pam handle as
2853 * PAM_OLDAUTHTOK item if this value is not
2857 __pam_get_authtok(pam_handle_t
*pamh
, int source
, int type
, char *prompt
,
2860 int error
= PAM_SYSTEM_ERR
;
2861 char *new_password
= NULL
;
2862 struct pam_response
*ret_resp
= NULL
;
2863 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
];
2865 if ((*authtok
= calloc(PASS_MAX
+1, sizeof (char))) == NULL
)
2866 return (PAM_BUF_ERR
);
2869 prompt
= dgettext(TEXT_DOMAIN
, "password: ");
2874 /* get password from pam handle item list */
2878 case PAM_OLDAUTHTOK
:
2880 if ((error
= pam_get_item(pamh
, type
,
2881 (void **)&new_password
)) != PAM_SUCCESS
)
2884 if (new_password
== NULL
|| new_password
[0] == '\0') {
2888 (void) strlcpy(*authtok
, new_password
,
2893 __pam_log(LOG_AUTH
| LOG_ERR
,
2894 "__pam_get_authtok() invalid type: %d", type
);
2895 error
= PAM_SYMBOL_ERR
;
2902 * Prompt for new password and save in pam handle item list
2903 * if the that item is not already set.
2906 (void) strncpy(messages
[0], prompt
, sizeof (messages
[0]));
2907 if ((error
= do_conv(pamh
, PAM_PROMPT_ECHO_OFF
, 1, messages
,
2908 NULL
, &ret_resp
)) != PAM_SUCCESS
)
2911 if (ret_resp
->resp
== NULL
) {
2912 /* getpass didn't return anything */
2913 error
= PAM_SYSTEM_ERR
;
2917 /* save the new password if this item was NULL */
2919 if ((error
= pam_get_item(pamh
, type
,
2920 (void **)&new_password
)) != PAM_SUCCESS
) {
2921 free_resp(1, ret_resp
);
2924 if (new_password
== NULL
)
2925 (void) pam_set_item(pamh
, type
, ret_resp
->resp
);
2928 (void) strlcpy(*authtok
, ret_resp
->resp
, PASS_MAX
+1);
2929 free_resp(1, ret_resp
);
2932 __pam_log(LOG_AUTH
| LOG_ERR
,
2933 "__pam_get_authtok() invalid source: %d", source
);
2934 error
= PAM_SYMBOL_ERR
;
2938 return (PAM_SUCCESS
);
2941 bzero(*authtok
, PASS_MAX
+1);