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",
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;
104 pam_trace_iname(int item_type
, char *iname_buf
)
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
);
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");
136 pam_trace_cname(pam_handle_t
*pamh
)
138 if (pamh
->pam_conf_name
[pamh
->include_depth
] == NULL
)
140 return (pamh
->pam_conf_name
[pamh
->include_depth
]);
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
156 * "log_facility=" 0-23, the pam_trace syslog facility to use
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
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
189 if ((defp
= defopen_r(PAM_DEBUG
)) != NULL
) {
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) {
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);
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
230 pam_trace(int flag
, char *format
, ...)
236 if ((pam_debug
& flag
) == 0)
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
);
245 (void) setlogmask(savemask
);
249 * __pam_log - logs PAM syslog messages
251 * priority = message priority
252 * format and args = message to log
256 __pam_log(int priority
, const char *format
, ...)
259 int savemask
= setlogmask(LOG_MASK(priority
& LOG_PRIMASK
));
261 va_start(args
, format
);
262 (void) vsyslog(priority
, format
, args
);
264 (void) setlogmask(savemask
);
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
281 pam_start(const char *service
, const char *user
,
282 const struct pam_conv
*pam_conv
, pam_handle_t
**pamh
)
286 *pamh
= calloc(1, sizeof (struct pam_handle
));
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
);
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
))
305 if ((err
= pam_set_item(*pamh
, PAM_USER
, (void *)user
))
312 if ((err
= pam_set_item(*pamh
, PAM_CONV
, (void *)pam_conv
))
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
;
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
));
341 return (PAM_SYSTEM_ERR
);
343 /* call the cleanup routines for module specific data */
348 psd
->cleanup(pamh
, psd
->data
, pam_status
);
352 free(p
->module_data_name
);
357 /* dlclose all module fds */
361 traverse
= traverse
->next
;
362 (void) dlclose(expired
->mh
);
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
);
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
;
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
));
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
]);
416 if (pip
->pi_addr
!= NULL
)
417 (void) memset(pip
->pi_addr
, 0, pip
->pi_size
);
424 case PAM_USER_PROMPT
:
427 if (pip
->pi_addr
!= NULL
) {
435 pip
->pi_addr
= strdup((char *)item
);
436 if (pip
->pi_addr
== NULL
) {
438 return (PAM_BUF_ERR
);
440 pip
->pi_size
= strlen(pip
->pi_addr
);
445 size
= sizeof (struct pam_conv
);
446 if ((pip
->pi_addr
= calloc(1, size
)) == NULL
)
447 return (PAM_BUF_ERR
);
449 (void) memcpy(pip
->pi_addr
, item
, (unsigned int) size
);
451 (void) memset(pip
->pi_addr
, 0, size
);
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
);
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
);
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
;
486 return (PAM_SYMBOL_ERR
);
490 pam_trace(PAM_DEBUG_ITEM
, "pam_set_item(%p:%s)=%p",
492 pam_trace_iname(item_type
, iname_buf
),
493 item
? (void *)((struct pam_conv
*)item
)->conv
:
497 pam_trace(PAM_DEBUG_ITEM
, "pam_set_item(%p:%s)=%s",
499 pam_trace_iname(item_type
, iname_buf
),
500 item
? (((struct pam_repository
*)item
)->type
?
501 ((struct pam_repository
*)item
)->type
: "NULL") :
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");
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");
520 pam_trace(PAM_DEBUG_ITEM
, "pam_set_item(%p:%s)=%s",
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
));
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
;
564 pam_trace(PAM_DEBUG_ITEM
, "pam_get_item(%p:%s)=%p",
566 pam_trace_iname(item_type
, iname_buf
),
567 (void *)((struct pam_conv
*)*item
)->conv
);
570 pam_trace(PAM_DEBUG_ITEM
, "pam_get_item(%p:%s)=%s",
572 pam_trace_iname(item_type
, iname_buf
),
573 *item
? (((struct pam_repository
*)*item
)->type
?
574 ((struct pam_repository
*)*item
)->type
: "NULL") :
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");
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");
593 pam_trace(PAM_DEBUG_ITEM
, "pam_get_item(%p:%s)=%s",
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.
610 parse_user_name(char *user_input
, char **ret_username
)
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
623 bzero((void *)username
, PAM_MAX_RESP_SIZE
);
626 * The user_input is guaranteed to be terminated by a null character.
630 /* Skip all the leading whitespaces if there are any. */
631 while ((*ptr
== ' ') || (*ptr
== '\t'))
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'))
650 username
[index
] = *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.
672 pam_get_user(pam_handle_t
*pamh
, char **user
, const char *prompt_override
)
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");
684 return (PAM_SYSTEM_ERR
);
686 if ((status
= pam_get_item(pamh
, PAM_USER
, (void **)user
))
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
;
705 status
= pam_get_item(pamh
, PAM_USER_PROMPT
, (void**)&prompt
);
706 if (status
!= PAM_SUCCESS
) {
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]));
722 int state
= WHITESPACE
;
724 status
= do_conv(pamh
, PAM_PROMPT_ECHO_ON
, 1, messages
,
727 if (status
!= PAM_SUCCESS
) {
731 if (ret_resp
->resp
&& ret_resp
->resp
[0] != '\0') {
732 int len
= strlen(ret_resp
->resp
);
735 for (i
= 0; i
< len
; i
++) {
736 if ((ret_resp
->resp
[i
] != ' ') &&
737 (ret_resp
->resp
[i
] != '\t')) {
743 if (state
== USERNAME
)
746 /* essentially empty response, try again */
747 free_resp(1, ret_resp
);
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
) {
757 free_resp(1, ret_resp
);
761 status
= pam_set_item(pamh
, PAM_USER
, real_username
);
765 free_resp(1, ret_resp
);
766 if (status
!= PAM_SUCCESS
) {
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
);
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
,
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 */
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
));
814 return (PAM_BUF_ERR
);
816 psd
->module_data_name
= strdup(module_data_name
);
817 if (psd
->module_data_name
== NULL
) {
819 return (PAM_BUF_ERR
);
822 psd
->data
= (void *)data
;
823 psd
->cleanup
= cleanup
;
824 psd
->next
= pamh
->ssd
;
826 return (PAM_SUCCESS
);
830 * get module specific data
834 pam_get_data(const pam_handle_t
*pamh
, const char *module_data_name
,
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) {
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()
869 pam_strerror(pam_handle_t
*pamh
, int errnum
)
873 return (dgettext(TEXT_DOMAIN
, "Success"));
875 return (dgettext(TEXT_DOMAIN
, "Dlopen failure"));
877 return (dgettext(TEXT_DOMAIN
, "Symbol not found"));
878 case PAM_SERVICE_ERR
:
879 return (dgettext(TEXT_DOMAIN
,
880 "Error in underlying service module"));
882 return (dgettext(TEXT_DOMAIN
, "System error"));
884 return (dgettext(TEXT_DOMAIN
, "Memory buffer error"));
886 return (dgettext(TEXT_DOMAIN
, "Conversation failure"));
887 case PAM_PERM_DENIED
:
888 return (dgettext(TEXT_DOMAIN
, "Permission denied"));
890 return (dgettext(TEXT_DOMAIN
,
891 "Maximum number of attempts exceeded"));
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"));
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"));
935 return (dgettext(TEXT_DOMAIN
, "Ignore module"));
937 return (dgettext(TEXT_DOMAIN
, "General PAM failure "));
939 return (dgettext(TEXT_DOMAIN
,
940 "Unable to complete operation. Try again"));
942 return (dgettext(TEXT_DOMAIN
, "Unknown error"));
950 case PAM_AUTHENTICATE
:
951 return (PAM_SM_AUTHENTICATE
);
953 return (PAM_SM_SETCRED
);
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
);
961 return (PAM_SM_CHAUTHTOK
);
967 (*func(pamtab_t
*modulep
, int ind
))()
971 if ((funcp
= modulep
->function_ptr
) == NULL
)
975 case PAM_AUTHENTICATE
:
976 return (((struct auth_module
*)funcp
)->pam_sm_authenticate
);
978 return (((struct auth_module
*)funcp
)->pam_sm_setcred
);
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
);
986 return (((struct password_module
*)funcp
)->pam_sm_chauthtok
);
992 * Run through the PAM service module stack for the given module type.
995 run_stack(pam_handle_t
*pamh
, int flags
, int type
, int def_err
, int ind
,
998 int err
= PAM_SYSTEM_ERR
; /* preset */
999 int optional_error
= 0;
1000 int required_error
= 0;
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
))
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
);
1026 service_file
= NULL
;
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
));
1035 pamh
->pam_inmodule
= WO_OK
; /* OK to get AUTHTOK */
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
] =
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
],
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
);
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
);
1078 if (modulep
->pam_flag
& PAM_INCLUDE
) {
1079 /* first line another 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
),
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
);
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
));
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
);
1110 sm_func
= func(modulep
, ind
);
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
));
1126 if ((modulep
->pam_flag
& PAM_SUFFI_BIND
) &&
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
) ?
1136 PAM_SUFFICIENT_NAME
);
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
;
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
,
1165 required_error
? required_error
:
1167 err
= required_error
?
1168 required_error
: err
;
1170 } else if (modulep
->pam_flag
& PAM_REQRD_BIND
) {
1171 if (!required_error
)
1172 required_error
= err
;
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
));
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
);
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
);
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
;
1230 * pam_authenticate - authenticate a user
1234 pam_authenticate(pam_handle_t
*pamh
, int flags
)
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
);
1247 * pam_setcred - modify or retrieve user credentials
1251 pam_setcred(pam_handle_t
*pamh
, int flags
)
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
);
1264 * pam_acct_mgmt - check password aging, account expiration
1268 pam_acct_mgmt(pam_handle_t
*pamh
, int flags
)
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
);
1283 * pam_open_session - begin session management
1287 pam_open_session(pam_handle_t
*pamh
, int flags
)
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
);
1300 * pam_close_session - terminate session management
1304 pam_close_session(pam_handle_t
*pamh
, int flags
)
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
);
1317 * pam_chauthtok - change user authentication token
1321 pam_chauthtok(pam_handle_t
*pamh
, int flags
)
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
)
1340 if (retval
!= PAM_SUCCESS
) {
1341 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
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
);
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
)
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
;
1385 (void) strncpy(name
, name_value
, equal_sign
- name_value
);
1386 if ((value
= strdup(++equal_sign
)) == 0) {
1387 error
= PAM_BUF_ERR
;
1391 if ((name
= strdup(name_value
)) == 0) {
1392 error
= PAM_BUF_ERR
;
1397 /* check to see if we already have this variable in the PAM handle */
1398 traverse
= pamh
->pam_env
;
1400 while (traverse
&& strncmp(traverse
->name
, name
, strlen(name
))) {
1402 traverse
= traverse
->next
;
1408 /* remove the env variable */
1409 if (pamh
->pam_env
== traverse
)
1410 pamh
->pam_env
= traverse
->next
;
1412 trail
->next
= traverse
->next
;
1414 } else if (strlen(value
) == 0) {
1415 /* set env variable to empty value */
1416 if ((tmp_value
= strdup("")) == 0) {
1417 error
= PAM_SYSTEM_ERR
;
1420 free(traverse
->value
);
1421 traverse
->value
= tmp_value
;
1423 /* set the new value */
1424 if ((tmp_value
= strdup(value
)) == 0) {
1425 error
= PAM_SYSTEM_ERR
;
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
;
1441 if ((traverse
->name
= strdup(name
)) == 0) {
1443 error
= PAM_BUF_ERR
;
1446 if ((traverse
->value
= strdup(value
)) == 0) {
1448 error
= PAM_BUF_ERR
;
1452 /* new head of list */
1453 pamh
->pam_env
= traverse
;
1455 /* adding to end of list */
1456 trail
->next
= traverse
;
1460 error
= PAM_SUCCESS
;
1462 if (error
!= PAM_SUCCESS
) {
1464 free(traverse
->name
);
1465 free(traverse
->value
);
1475 * pam_getenv - retrieve an environment variable from the PAM handle
1478 pam_getenv(pam_handle_t
*pamh
, const char *name
)
1480 int error
= PAM_SYSTEM_ERR
;
1483 pam_trace(PAM_DEBUG_DEFAULT
,
1484 "pam_getenv(%p, %p)", (void *)pamh
, (void *)name
);
1486 if (pamh
== NULL
|| name
== NULL
)
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");
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.
1507 pam_getenvlist(pam_handle_t
*pamh
)
1509 int error
= PAM_SYSTEM_ERR
;
1516 pam_trace(PAM_DEBUG_DEFAULT
,
1517 "pam_getenvlist(%p)", (void *)pamh
);
1522 /* find out how many environment variables we have */
1523 traverse
= pamh
->pam_env
;
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
;
1535 /* add the variables one by one */
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
;
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
;
1554 if (error
!= PAM_SUCCESS
) {
1555 /* free the partially constructed list */
1558 while (list
[length
] != NULL
) {
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.
1579 load_modules(pam_handle_t
*pamh
, int type
, char *function_name
,
1580 pamtab_t
*pam_entry
)
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
);
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
));
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
);
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
)
1646 /* return error if dlsym fails */
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 */
1657 return (PAM_SYMBOL_ERR
);
1660 pam_entry
->function_ptr
= authp
;
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
);
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
));
1699 return (PAM_SYMBOL_ERR
);
1701 pam_entry
->function_ptr
= accountp
;
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
);
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
) {
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
) {
1745 return (PAM_SYMBOL_ERR
);
1747 pam_entry
->function_ptr
= sessionp
;
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
);
1776 return (PAM_OPEN_ERR
);
1779 if (load_function(mh
, PAM_SM_CHAUTHTOK
,
1780 &passwdp
->pam_sm_chauthtok
) != PAM_SUCCESS
) {
1782 return (PAM_SYMBOL_ERR
);
1784 pam_entry
->function_ptr
= passwdp
;
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
);
1794 pam_entry
= pam_entry
->next
;
1797 pam_trace(PAM_DEBUG_MODULE
, "load_modules[%d:%s](%p, %s)=done",
1798 pamh
->include_depth
, pam_trace_cname(pamh
), (void *)pamh
,
1801 return (PAM_SUCCESS
);
1805 * open_module - Open the module first checking for
1806 * propers modes and ownerships on the file.
1810 open_module(pam_handle_t
*pamh
, char *module_so
)
1815 fd_list
*module_fds
= 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
,
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
);
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
);
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
);
1847 * Perform the dlopen()
1849 lfd
= (void *)dlopen(module_so
, RTLD_LAZY
);
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");
1858 /* add this fd to the pam handle */
1859 if ((module_fds
= calloc(1, sizeof (fd_list
))) == 0) {
1860 (void) dlclose(lfd
);
1864 module_fds
->mh
= lfd
;
1866 if (pamh
->fd
== 0) {
1867 /* adding new head of list */
1868 pamh
->fd
= module_fds
;
1870 /* appending to end of list */
1871 traverse
= pamh
->fd
;
1874 traverse
= traverse
->next
;
1876 trail
->next
= module_fds
;
1884 * load_function - call dlsym() to resolve the function address
1887 load_function(void *lfd
, char *name
, int (**func
)())
1889 char *errmsg
= NULL
;
1892 return (PAM_SYMBOL_ERR
);
1894 *func
= (int (*)())dlsym(lfd
, name
);
1895 if (*func
== NULL
) {
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
1916 open_pam_conf(struct pam_fh
**pam_fh
, pam_handle_t
*pamh
, char *config
,
1922 if ((fd
= open(config
, O_RDONLY
)) == -1) {
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
,
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
,
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
);
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
);
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
);
1960 if ((*pam_fh
= calloc(1, sizeof (struct pam_fh
))) == NULL
) {
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
) {
1972 (*pam_fh
)->bufferp
= (*pam_fh
)->data
;
1978 * close_pam_conf - close pam.conf
1982 close_pam_conf(struct pam_fh
*pam_fh
)
1984 (void) munmap(pam_fh
->data
, pam_fh
->bufsize
);
1985 (void) close(pam_fh
->fconfig
);
1990 * read_pam_conf - read in each entry in pam.conf and store info
1991 * under the pam handle.
1995 read_pam_conf(pam_handle_t
*pamh
, char *config
, char *service
)
1997 struct pam_fh
*pam_fh
;
2001 int i
= pamh
->include_depth
; /* include depth */
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
;
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
);
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
);
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]",
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 "
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
] =
2066 service_found
[pamentp
->pam_type
+ 1] = 1;
2068 /* append more service entries */
2069 pam_trace(PAM_DEBUG_CONF
,
2070 "read_pam_conf(%p): adding more "
2072 (void *)pamh
, service
, i
,
2073 pam_trace_cname(pamh
),
2074 pam_snames
[pamentp
->pam_type
]);
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 "
2088 (void *)pamh
, service
, i
,
2089 pam_trace_cname(pamh
));
2090 error
= PAM_SYSTEM_ERR
;
2091 free_pamconf(pamentp
);
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
;
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
;
2122 /* irrelevant entry */
2123 free_pamconf(pamentp
);
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
2136 if (strcasecmp(service
, "other") == 0)
2139 for (j
= 0; j
< PAM_NUM_MODULE_TYPES
; j
++) {
2142 if (service_found
[j
+ 1] != 0 ||
2143 pamh
->pam_conf_info
[i
][j
] != NULL
)
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
);
2152 error
= PAM_SYSTEM_ERR
;
2153 __pam_log(LOG_AUTH
| LOG_ERR
, "calloc: out of memory");
2157 pe
->pam_service
= strdup(service
);
2159 pe
->pam_flag
= PAM_INCLUDE
;
2160 if (asprintf(&pe
->module_path
, "%s%s", PAM_CONFIG_DIR
,
2163 error
= PAM_SYSTEM_ERR
;
2164 __pam_log(LOG_AUTH
| LOG_ERR
, "asprintf: out of memory");
2168 pamh
->pam_conf_info
[i
][j
] = pe
;
2172 (void) close_pam_conf(pam_fh
);
2173 if (error
!= PAM_SUCCESS
)
2174 free_pam_conf_info(pamh
);
2179 * get_pam_conf_entry - get a pam.conf entry
2183 get_pam_conf_entry(struct pam_fh
*pam_fh
, pam_handle_t
*pamh
, pamtab_t
**pam
,
2184 char *service
, int shardfile
)
2188 char *tmp
, *tmp_free
;
2190 char *current_line
= NULL
;
2191 int error
= PAM_SYSTEM_ERR
; /* preset to error */
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
;
2202 if ((*pam
= calloc(1, sizeof (pamtab_t
))) == NULL
) {
2203 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
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");
2213 pam_trace(PAM_DEBUG_CONF
,
2214 "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh
), current_line
);
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");
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
);
2233 if (((*pam
)->pam_service
= strdup(arg
)) == 0) {
2234 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
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 */
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
;
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 */
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
);
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
;
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
);
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 */
2301 if (arg
[0] != '/') {
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
);
2316 ret
= asprintf(&(*pam
)->module_path
, "%s%s%s",
2317 PAM_LIB_DIR
, PAM_ISA_DIR
, arg
);
2320 __pam_log(LOG_AUTH
| LOG_ERR
,
2321 "asprintf: out of memory");
2325 /* Full path provided for module */
2328 /* Check for Instruction Set Architecture indicator */
2329 if ((isa
= strstr(arg
, PAM_ISA
)) != NULL
) {
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");
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");
2350 /* count the number of module-specific options first */
2352 if ((tmp
= strdup(cp
)) == NULL
) {
2353 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2357 for (arg
= read_next_token(&tmp
); arg
; arg
= read_next_token(&tmp
))
2361 /* allocate array for the module-specific options */
2363 if (((*pam
)->module_argv
=
2364 calloc(argc
+1, sizeof (char *))) == 0) {
2365 __pam_log(LOG_AUTH
| LOG_ERR
, "calloc: out of memory");
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");
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 */
2387 if (error
!= PAM_SUCCESS
) {
2388 /* on error free this */
2397 * read_next_token - skip tab and space characters and return the next token
2401 read_next_token(char **cpp
)
2403 register char *cp
= *cpp
;
2410 while (*cp
== ' ' || *cp
== '\t')
2417 while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
2426 pam_conf_strnchr(char *sp
, int c
, intptr_t count
)
2430 return ((char *)sp
);
2440 * nextline - skip all blank lines and comments
2444 nextline(struct pam_fh
*pam_fh
, pam_handle_t
*pamh
, int *err
)
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
];
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
)
2461 /* skip blank line */
2462 while (*bufferp
== '\n') {
2464 * If we are at the end of the buffer, there is
2467 if (++bufferp
== bufferendp
) {
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
) {
2480 * this comment line the last line.
2487 * If we are at the end of the buffer, there is
2490 if (bufferp
== bufferendp
) {
2495 if ((*bufferp
!= '\n') && (*bufferp
!= '#')) {
2501 /* now we find one line */
2502 if ((ll
= pam_conf_strnchr(bufferp
, '\n', bufferendp
- bufferp
))
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
),
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
++;
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
),
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.
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
2561 clean_up(pam_handle_t
*pamh
)
2564 pam_repository_t
*auth_rep
;
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
);
2593 * free_pamconf - free memory used to store pam.conf entry
2597 free_pamconf(pamtab_t
*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
);
2616 * free_pam_conf_info - free memory used to store all pam.conf info
2617 * under the pam handle
2621 free_pam_conf_info(pam_handle_t
*pamh
)
2624 pamtab_t
*pament_trail
;
2625 int i
= pamh
->include_depth
;
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
;
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
;
2645 free_env(env_list
*pam_env
)
2648 free(pam_env
->name
);
2649 free(pam_env
->value
);
2655 * Internal convenience functions for Solaris PAM service modules.
2658 #include <libintl.h>
2659 #include <nl_types.h>
2664 typedef struct pam_msg_data
{
2670 * free storage for responses used in the call back "pam_conv" functions
2674 free_resp(int num_msg
, struct pam_response
*resp
)
2677 struct pam_response
*r
;
2681 for (i
= 0; i
< num_msg
; i
++, r
++) {
2683 /* clear before freeing -- may be a password */
2684 bzero(r
->resp
, strlen(r
->resp
));
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
;
2703 struct pam_conv
*pam_convp
;
2705 if ((retcode
= pam_get_item(pamh
, PAM_CONV
,
2706 (void **)&pam_convp
)) != PAM_SUCCESS
) {
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
2716 if ((pam_convp
== NULL
) || (pam_convp
->conv
== NULL
))
2717 return (PAM_SYSTEM_ERR
);
2722 msg
= calloc(num_msg
, sizeof (struct pam_message
));
2724 return (PAM_BUF_ERR
);
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
]);
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
,
2768 "[%d] NULL response string)",
2771 if (msg_style
== PAM_PROMPT_ECHO_OFF
) {
2773 pam_trace(PAM_DEBUG_AUTHTOK
,
2774 "pam_conv_resp(%p:[%d]=%s, "
2776 (void *)pamh
, i
, r
->resp
,
2779 pam_trace(PAM_DEBUG_CONV
,
2780 "pam_conv_resp(%p:[%d] len=%lu, "
2783 (ulong_t
)strlen(r
->resp
),
2786 pam_trace(PAM_DEBUG_CONV
,
2787 "pam_conv_resp(%p:[%d]=%s, "
2789 (void *)pamh
, i
, r
->resp
,
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
;
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
);
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.
2834 * PAM_AUTHTOK - password is taken from pam handle (PAM_AUTHTOK)
2835 * PAM_OLDAUTHTOK - password is taken from pam handle (PAM_OLDAUTHTOK)
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
2849 __pam_get_authtok(pam_handle_t
*pamh
, int source
, int type
, char *prompt
,
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
);
2861 prompt
= dgettext(TEXT_DOMAIN
, "password: ");
2866 /* get password from pam handle item list */
2870 case PAM_OLDAUTHTOK
:
2872 if ((error
= pam_get_item(pamh
, type
,
2873 (void **)&new_password
)) != PAM_SUCCESS
)
2876 if (new_password
== NULL
|| new_password
[0] == '\0') {
2880 (void) strlcpy(*authtok
, new_password
,
2885 __pam_log(LOG_AUTH
| LOG_ERR
,
2886 "__pam_get_authtok() invalid type: %d", type
);
2887 error
= PAM_SYMBOL_ERR
;
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
)
2903 if (ret_resp
->resp
== NULL
) {
2904 /* getpass didn't return anything */
2905 error
= PAM_SYSTEM_ERR
;
2909 /* save the new password if this item was NULL */
2911 if ((error
= pam_get_item(pamh
, type
,
2912 (void **)&new_password
)) != PAM_SUCCESS
) {
2913 free_resp(1, ret_resp
);
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
);
2924 __pam_log(LOG_AUTH
| LOG_ERR
,
2925 "__pam_get_authtok() invalid source: %d", source
);
2926 error
= PAM_SYMBOL_ERR
;
2930 return (PAM_SUCCESS
);
2933 bzero(*authtok
, PASS_MAX
+1);