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.
28 #include <sys/types.h>
37 #include <security/pam_appl.h>
38 #include <security/pam_modules.h>
45 static char *pam_snames
[PAM_NUM_MODULE_TYPES
] = {
52 static char *pam_inames
[PAM_MAX_ITEMS
] = {
54 /* PAM_SERVICE */ "service",
55 /* PAM_USER */ "user",
57 /* PAM_RHOST */ "rhost",
58 /* PAM_CONV */ "conv",
59 /* PAM_AUTHTOK */ "authtok",
60 /* PAM_OLDAUTHTOK */ "oldauthtok",
61 /* PAM_RUSER */ "ruser",
62 /* PAM_USER_PROMPT */ "user_prompt",
63 /* PAM_REPOSITORY */ "repository",
64 /* PAM_RESOURCE */ "resource",
65 /* PAM_AUSER */ "auser",
70 * This extra definition is needed in order to build this library
71 * on pre-64-bit-aware systems.
73 #if !defined(_LFS64_LARGEFILE)
75 #endif /* !defined(_LFS64_LARGEFILE) */
77 /* functions to dynamically load modules */
78 static int load_modules(pam_handle_t
*, int, char *, pamtab_t
*);
79 static void *open_module(pam_handle_t
*, char *);
80 static int load_function(void *, char *, int (**func
)());
82 /* functions to read and store the pam.conf configuration file */
83 static int open_pam_conf(struct pam_fh
**, pam_handle_t
*, char *);
84 static void close_pam_conf(struct pam_fh
*);
85 static int read_pam_conf(pam_handle_t
*, char *);
86 static int get_pam_conf_entry(struct pam_fh
*, pam_handle_t
*,
88 static char *read_next_token(char **);
89 static char *nextline(struct pam_fh
*, pam_handle_t
*, int *);
90 static int verify_pam_conf(pamtab_t
*, char *);
92 /* functions to clean up and free memory */
93 static void clean_up(pam_handle_t
*);
94 static void free_pamconf(pamtab_t
*);
95 static void free_pam_conf_info(pam_handle_t
*);
96 static void free_env(env_list
*);
98 /* convenience functions for I18N/L10N communication */
100 static void free_resp(int, struct pam_response
*);
101 static int do_conv(pam_handle_t
*, int, int,
102 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
], void *,
103 struct pam_response
**);
105 static int log_priority
; /* pam_trace syslog priority & facility */
106 static int pam_debug
= 0;
109 pam_trace_iname(int item_type
, char *iname_buf
)
113 if (item_type
<= 0 ||
114 item_type
>= PAM_MAX_ITEMS
||
115 (name
= pam_inames
[item_type
]) == NULL
) {
116 (void) sprintf(iname_buf
, "%d", item_type
);
123 pam_trace_fname(int flag
)
125 if (flag
& PAM_BINDING
)
126 return (PAM_BINDING_NAME
);
127 if (flag
& PAM_INCLUDE
)
128 return (PAM_INCLUDE_NAME
);
129 if (flag
& PAM_OPTIONAL
)
130 return (PAM_OPTIONAL_NAME
);
131 if (flag
& PAM_REQUIRED
)
132 return (PAM_REQUIRED_NAME
);
133 if (flag
& PAM_REQUISITE
)
134 return (PAM_REQUISITE_NAME
);
135 if (flag
& PAM_SUFFICIENT
)
136 return (PAM_SUFFICIENT_NAME
);
137 return ("bad flag name");
141 pam_trace_cname(pam_handle_t
*pamh
)
143 if (pamh
->pam_conf_name
[pamh
->include_depth
] == NULL
)
145 return (pamh
->pam_conf_name
[pamh
->include_depth
]);
151 * pam_settrace - setup configuration for pam tracing
153 * turn on PAM debug if "magic" file exists
154 * if exists (original), pam_debug = PAM_DEBUG_DEFAULT,
155 * log_priority = LOG_DEBUG(7) and log_facility = LOG_AUTH(4).
157 * if has contents, keywork=value pairs:
159 * "log_priority=" 0-7, the pam_trace syslog priority to use
161 * "log_facility=" 0-23, the pam_trace syslog facility to use
163 * "debug_flags=" PAM_DEBUG_DEFAULT (0x0001), log traditional
164 * (original) debugging.
165 * Plus the logical or of:
166 * PAM_DEBUG_ITEM (0x0002), log item values and
168 * PAM_DEBUG_MODULE (0x0004), log module return status.
169 * PAM_DEBUG_CONF (0x0008), log pam.conf parsing.
170 * PAM_DEBUG_DATA (0x0010), get/set_data.
171 * PAM_DEBUG_CONV (0x0020), conversation/response.
173 * If compiled with DEBUG:
174 * PAM_DEBUG_AUTHTOK (0x8000), display AUTHTOK value if
175 * PAM_DEBUG_ITEM is set and results from
176 * PAM_PROMPT_ECHO_OFF responses.
177 * USE CAREFULLY, THIS EXPOSES THE USER'S PASSWORDS.
179 * or set to 0 and off even if PAM_DEBUG file exists.
181 * Output has the general form:
182 * <whatever was set syslog> PAM[<pid>]: <interface>(<handle> and other info)
183 * <whatever was set syslog> PAM[<pid>]: details requested for <interface> call
184 * Where: <pid> is the process ID of the calling process.
185 * <handle> is the Hex value of the pam_handle associated with the
194 if ((defp
= defopen_r(PAM_DEBUG
)) != NULL
) {
197 int facility
= LOG_AUTH
;
199 pam_debug
= PAM_DEBUG_DEFAULT
;
200 log_priority
= LOG_DEBUG
;
202 (void) defcntl_r(DC_SETFLAGS
, DC_CASE
, defp
);
203 if ((arg
= defread_r(LOG_PRIORITY
, defp
)) != NULL
) {
204 code
= (int)strtol(arg
, NULL
, 10);
205 if ((code
& ~LOG_PRIMASK
) == 0) {
209 if ((arg
= defread_r(LOG_FACILITY
, defp
)) != NULL
) {
210 code
= (int)strtol(arg
, NULL
, 10);
211 if (code
< LOG_NFACILITIES
) {
212 facility
= code
<< 3;
215 if ((arg
= defread_r(DEBUG_FLAGS
, defp
)) != NULL
) {
216 pam_debug
= (int)strtol(arg
, NULL
, 0);
220 log_priority
|= facility
;
225 * pam_trace - logs tracing messages
227 * flag = debug_flags from /etc/pam_debug
228 * format and args = message to print (PAM[<pid>]: is prepended).
230 * global log_priority = pam_trace syslog (log_priority | log_facility)
231 * from /etc/pam_debug
235 pam_trace(int flag
, char *format
, ...)
241 if ((pam_debug
& flag
) == 0)
244 savemask
= setlogmask(LOG_MASK(log_priority
& LOG_PRIMASK
));
245 (void) snprintf(message
, sizeof (message
), "PAM[%ld]: %s",
246 (long)getpid(), format
);
247 va_start(args
, format
);
248 (void) vsyslog(log_priority
, message
, args
);
250 (void) setlogmask(savemask
);
254 * __pam_log - logs PAM syslog messages
256 * priority = message priority
257 * format and args = message to log
261 __pam_log(int priority
, const char *format
, ...)
264 int savemask
= setlogmask(LOG_MASK(priority
& LOG_PRIMASK
));
266 va_start(args
, format
);
267 (void) vsyslog(priority
, format
, args
);
269 (void) setlogmask(savemask
);
276 * These are the entry points to the authentication switch
280 * pam_start - initiate an authentication transaction and
281 * set parameter values to be used during the
286 pam_start(const char *service
, const char *user
,
287 const struct pam_conv
*pam_conv
, pam_handle_t
**pamh
)
291 *pamh
= calloc(1, sizeof (struct pam_handle
));
294 pam_trace(PAM_DEBUG_DEFAULT
,
295 "pam_start(%s,%s,%p:%p) - debug = %x",
296 service
? service
: "NULL", user
? user
: "NULL", (void *)pam_conv
,
297 (void *)*pamh
, pam_debug
);
300 return (PAM_BUF_ERR
);
302 (*pamh
)->pam_inmodule
= RO_OK
; /* OK to set RO items */
303 if ((err
= pam_set_item(*pamh
, PAM_SERVICE
, (void *)service
))
310 if ((err
= pam_set_item(*pamh
, PAM_USER
, (void *)user
))
317 if ((err
= pam_set_item(*pamh
, PAM_CONV
, (void *)pam_conv
))
324 (*pamh
)->pam_inmodule
= RW_OK
;
325 return (PAM_SUCCESS
);
329 * pam_end - terminate an authentication transaction
333 pam_end(pam_handle_t
*pamh
, int pam_status
)
335 struct pam_module_data
*psd
, *p
;
338 env_list
*env_expired
;
339 env_list
*env_traverse
;
341 pam_trace(PAM_DEBUG_DEFAULT
,
342 "pam_end(%p): status = %s", (void *)pamh
,
343 pam_strerror(pamh
, pam_status
));
346 return (PAM_SYSTEM_ERR
);
348 /* call the cleanup routines for module specific data */
353 psd
->cleanup(pamh
, psd
->data
, pam_status
);
357 free(p
->module_data_name
);
362 /* dlclose all module fds */
366 traverse
= traverse
->next
;
367 (void) dlclose(expired
->mh
);
372 /* remove all environment variables */
373 env_traverse
= pamh
->pam_env
;
374 while (env_traverse
) {
375 env_expired
= env_traverse
;
376 env_traverse
= env_traverse
->next
;
377 free_env(env_expired
);
381 return (PAM_SUCCESS
);
385 * pam_set_item - set the value of a parameter that can be
386 * retrieved via a call to pam_get_item()
390 pam_set_item(pam_handle_t
*pamh
, int item_type
, const void *item
)
392 struct pam_item
*pip
;
394 char iname_buf
[PAM_MAX_MSG_SIZE
];
396 if (((pam_debug
& PAM_DEBUG_ITEM
) == 0) || (pamh
== NULL
)) {
397 pam_trace(PAM_DEBUG_DEFAULT
,
398 "pam_set_item(%p:%s)", (void *)pamh
,
399 pam_trace_iname(item_type
, iname_buf
));
403 return (PAM_SYSTEM_ERR
);
405 /* check read only items */
406 if ((item_type
== PAM_SERVICE
) && (pamh
->pam_inmodule
!= RO_OK
))
407 return (PAM_PERM_DENIED
);
410 * Check that item_type is within valid range
413 if (item_type
<= 0 || item_type
>= PAM_MAX_ITEMS
)
414 return (PAM_SYMBOL_ERR
);
416 pip
= &(pamh
->ps_item
[item_type
]);
421 if (pip
->pi_addr
!= NULL
)
422 (void) memset(pip
->pi_addr
, 0, pip
->pi_size
);
429 case PAM_USER_PROMPT
:
432 if (pip
->pi_addr
!= NULL
) {
440 pip
->pi_addr
= strdup((char *)item
);
441 if (pip
->pi_addr
== NULL
) {
443 return (PAM_BUF_ERR
);
445 pip
->pi_size
= strlen(pip
->pi_addr
);
449 if (pip
->pi_addr
!= NULL
)
451 size
= sizeof (struct pam_conv
);
452 if ((pip
->pi_addr
= calloc(1, size
)) == NULL
)
453 return (PAM_BUF_ERR
);
455 (void) memcpy(pip
->pi_addr
, item
, (unsigned int) size
);
457 (void) memset(pip
->pi_addr
, 0, size
);
461 if (pip
->pi_addr
!= NULL
) {
462 pam_repository_t
*auth_rep
;
464 auth_rep
= (pam_repository_t
*)pip
->pi_addr
;
465 if (auth_rep
->type
!= NULL
)
466 free(auth_rep
->type
);
467 if (auth_rep
->scope
!= NULL
)
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
) {
764 if (real_username
!= NULL
)
766 free_resp(1, ret_resp
);
770 status
= pam_set_item(pamh
, PAM_USER
, real_username
);
774 free_resp(1, ret_resp
);
775 if (status
!= PAM_SUCCESS
) {
780 * finally, get PAM_USER. We have to call pam_get_item to get
781 * the value of user because pam_set_item mallocs the memory.
784 status
= pam_get_item(pamh
, PAM_USER
, (void**)user
);
789 * Set module specific data
793 pam_set_data(pam_handle_t
*pamh
, const char *module_data_name
, void *data
,
794 void (*cleanup
)(pam_handle_t
*pamh
, void *data
, int pam_end_status
))
796 struct pam_module_data
*psd
;
798 pam_trace(PAM_DEBUG_DATA
,
799 "pam_set_data(%p:%s:%d)=%p", (void *)pamh
,
800 module_data_name
? module_data_name
: "NULL", pamh
->pam_inmodule
,
802 if (pamh
== NULL
|| (pamh
->pam_inmodule
!= WO_OK
) ||
803 module_data_name
== NULL
) {
804 return (PAM_SYSTEM_ERR
);
807 /* check if module data already exists */
809 for (psd
= pamh
->ssd
; psd
; psd
= psd
->next
) {
810 if (strcmp(psd
->module_data_name
, module_data_name
) == 0) {
811 /* clean up original data before setting the new data */
813 psd
->cleanup(pamh
, psd
->data
, PAM_SUCCESS
);
815 psd
->data
= (void *)data
;
816 psd
->cleanup
= cleanup
;
817 return (PAM_SUCCESS
);
821 psd
= malloc(sizeof (struct pam_module_data
));
823 return (PAM_BUF_ERR
);
825 psd
->module_data_name
= strdup(module_data_name
);
826 if (psd
->module_data_name
== NULL
) {
828 return (PAM_BUF_ERR
);
831 psd
->data
= (void *)data
;
832 psd
->cleanup
= cleanup
;
833 psd
->next
= pamh
->ssd
;
835 return (PAM_SUCCESS
);
839 * get module specific data
843 pam_get_data(const pam_handle_t
*pamh
, const char *module_data_name
,
846 struct pam_module_data
*psd
;
848 if (pamh
== NULL
|| (pamh
->pam_inmodule
!= WO_OK
) ||
849 module_data_name
== NULL
) {
850 pam_trace(PAM_DEBUG_DATA
,
851 "pam_get_data(%p:%s:%d)=%p", (void *)pamh
,
852 module_data_name
? module_data_name
: "NULL",
853 pamh
->pam_inmodule
, *data
);
854 return (PAM_SYSTEM_ERR
);
857 for (psd
= pamh
->ssd
; psd
; psd
= psd
->next
) {
858 if (strcmp(psd
->module_data_name
, module_data_name
) == 0) {
860 pam_trace(PAM_DEBUG_DATA
,
861 "pam_get_data(%p:%s)=%p", (void *)pamh
,
862 module_data_name
, *data
);
863 return (PAM_SUCCESS
);
866 pam_trace(PAM_DEBUG_DATA
,
867 "pam_get_data(%p:%s)=%s", (void *)pamh
, module_data_name
,
868 "PAM_NO_MODULE_DATA");
870 return (PAM_NO_MODULE_DATA
);
874 * PAM equivalent to strerror()
878 pam_strerror(pam_handle_t
*pamh
, int errnum
)
882 return (dgettext(TEXT_DOMAIN
, "Success"));
884 return (dgettext(TEXT_DOMAIN
, "Dlopen failure"));
886 return (dgettext(TEXT_DOMAIN
, "Symbol not found"));
887 case PAM_SERVICE_ERR
:
888 return (dgettext(TEXT_DOMAIN
,
889 "Error in underlying service module"));
891 return (dgettext(TEXT_DOMAIN
, "System error"));
893 return (dgettext(TEXT_DOMAIN
, "Memory buffer error"));
895 return (dgettext(TEXT_DOMAIN
, "Conversation failure"));
896 case PAM_PERM_DENIED
:
897 return (dgettext(TEXT_DOMAIN
, "Permission denied"));
899 return (dgettext(TEXT_DOMAIN
,
900 "Maximum number of attempts exceeded"));
902 return (dgettext(TEXT_DOMAIN
, "Authentication failed"));
903 case PAM_NEW_AUTHTOK_REQD
:
904 return (dgettext(TEXT_DOMAIN
, "Get new authentication token"));
905 case PAM_CRED_INSUFFICIENT
:
906 return (dgettext(TEXT_DOMAIN
, "Insufficient credentials"));
907 case PAM_AUTHINFO_UNAVAIL
:
908 return (dgettext(TEXT_DOMAIN
,
909 "Can not retrieve authentication info"));
910 case PAM_USER_UNKNOWN
:
911 return (dgettext(TEXT_DOMAIN
, "No account present for user"));
912 case PAM_CRED_UNAVAIL
:
913 return (dgettext(TEXT_DOMAIN
,
914 "Can not retrieve user credentials"));
915 case PAM_CRED_EXPIRED
:
916 return (dgettext(TEXT_DOMAIN
,
917 "User credentials have expired"));
919 return (dgettext(TEXT_DOMAIN
,
920 "Failure setting user credentials"));
921 case PAM_ACCT_EXPIRED
:
922 return (dgettext(TEXT_DOMAIN
, "User account has expired"));
923 case PAM_AUTHTOK_EXPIRED
:
924 return (dgettext(TEXT_DOMAIN
, "User password has expired"));
925 case PAM_SESSION_ERR
:
926 return (dgettext(TEXT_DOMAIN
,
927 "Can not make/remove entry for session"));
928 case PAM_AUTHTOK_ERR
:
929 return (dgettext(TEXT_DOMAIN
,
930 "Authentication token manipulation error"));
931 case PAM_AUTHTOK_RECOVERY_ERR
:
932 return (dgettext(TEXT_DOMAIN
,
933 "Authentication token can not be recovered"));
934 case PAM_AUTHTOK_LOCK_BUSY
:
935 return (dgettext(TEXT_DOMAIN
,
936 "Authentication token lock busy"));
937 case PAM_AUTHTOK_DISABLE_AGING
:
938 return (dgettext(TEXT_DOMAIN
,
939 "Authentication token aging disabled"));
940 case PAM_NO_MODULE_DATA
:
941 return (dgettext(TEXT_DOMAIN
,
942 "Module specific data not found"));
944 return (dgettext(TEXT_DOMAIN
, "Ignore module"));
946 return (dgettext(TEXT_DOMAIN
, "General PAM failure "));
948 return (dgettext(TEXT_DOMAIN
,
949 "Unable to complete operation. Try again"));
951 return (dgettext(TEXT_DOMAIN
, "Unknown error"));
959 case PAM_AUTHENTICATE
:
960 return (PAM_SM_AUTHENTICATE
);
962 return (PAM_SM_SETCRED
);
964 return (PAM_SM_ACCT_MGMT
);
965 case PAM_OPEN_SESSION
:
966 return (PAM_SM_OPEN_SESSION
);
967 case PAM_CLOSE_SESSION
:
968 return (PAM_SM_CLOSE_SESSION
);
970 return (PAM_SM_CHAUTHTOK
);
976 (*func(pamtab_t
*modulep
, int ind
))()
980 if ((funcp
= modulep
->function_ptr
) == NULL
)
984 case PAM_AUTHENTICATE
:
985 return (((struct auth_module
*)funcp
)->pam_sm_authenticate
);
987 return (((struct auth_module
*)funcp
)->pam_sm_setcred
);
989 return (((struct account_module
*)funcp
)->pam_sm_acct_mgmt
);
990 case PAM_OPEN_SESSION
:
991 return (((struct session_module
*)funcp
)->pam_sm_open_session
);
992 case PAM_CLOSE_SESSION
:
993 return (((struct session_module
*)funcp
)->pam_sm_close_session
);
995 return (((struct password_module
*)funcp
)->pam_sm_chauthtok
);
1001 * Run through the PAM service module stack for the given module type.
1004 run_stack(pam_handle_t
*pamh
, int flags
, int type
, int def_err
, int ind
,
1005 char *function_name
)
1007 int err
= PAM_SYSTEM_ERR
; /* preset */
1008 int optional_error
= 0;
1009 int required_error
= 0;
1015 return (PAM_SYSTEM_ERR
);
1017 /* read initial entries from pam.conf */
1018 if ((err
= read_pam_conf(pamh
, PAM_CONFIG
)) != PAM_SUCCESS
) {
1023 pamh
->pam_conf_info
[pamh
->include_depth
][type
]) == NULL
) {
1024 __pam_log(LOG_AUTH
| LOG_ERR
, "%s no initial module present",
1025 pam_trace_cname(pamh
));
1029 pamh
->pam_inmodule
= WO_OK
; /* OK to get AUTHTOK */
1031 pam_trace(PAM_DEBUG_MODULE
,
1032 "[%d:%s]:run_stack:%s(%p, %x): %s", pamh
->include_depth
,
1033 pam_trace_cname(pamh
), function_name
, (void *)pamh
, flags
,
1034 modulep
? modulep
->module_path
: "NULL");
1036 while (modulep
!= NULL
) {
1037 if (modulep
->pam_flag
& PAM_INCLUDE
) {
1038 /* save the return location */
1039 pamh
->pam_conf_modulep
[pamh
->include_depth
] =
1041 pam_trace(PAM_DEBUG_MODULE
,
1042 "setting for include[%d:%p]",
1043 pamh
->include_depth
, (void *)modulep
->next
);
1044 if (pamh
->include_depth
++ >= PAM_MAX_INCLUDE
) {
1045 __pam_log(LOG_AUTH
| LOG_ERR
,
1046 "run_stack: includes too deep %d "
1047 "found trying to include %s from %s, %d "
1048 "allowed", pamh
->include_depth
,
1049 modulep
->module_path
, pamh
->pam_conf_name
1050 [PAM_MAX_INCLUDE
] == NULL
? "NULL" :
1051 pamh
->pam_conf_name
[PAM_MAX_INCLUDE
],
1055 if ((err
= read_pam_conf(pamh
,
1056 modulep
->module_path
)) != PAM_SUCCESS
) {
1057 __pam_log(LOG_AUTH
| LOG_ERR
,
1058 "run_stack[%d:%s]: can't read included "
1059 "conf %s", pamh
->include_depth
,
1060 pam_trace_cname(pamh
),
1061 modulep
->module_path
);
1064 if ((modulep
= pamh
->pam_conf_info
1065 [pamh
->include_depth
][type
]) == NULL
) {
1066 __pam_log(LOG_AUTH
| LOG_ERR
,
1067 "run_stack[%d:%s]: no include module "
1068 "present %s", pamh
->include_depth
,
1069 pam_trace_cname(pamh
), function_name
);
1072 if (modulep
->pam_flag
& PAM_INCLUDE
) {
1073 /* first line another include */
1076 pam_trace(PAM_DEBUG_DEFAULT
, "include[%d:%s]"
1077 "(%p, %s)=%s", pamh
->include_depth
,
1078 pam_trace_cname(pamh
), (void *)pamh
,
1079 function_name
, modulep
->module_path
);
1080 if ((err
= load_modules(pamh
, type
, sm_name(ind
),
1082 [pamh
->include_depth
][type
])) != PAM_SUCCESS
) {
1083 pam_trace(PAM_DEBUG_DEFAULT
,
1084 "[%d:%s]:%s(%p, %x): load_modules failed",
1085 pamh
->include_depth
, pam_trace_cname(pamh
),
1086 function_name
, (void *)pamh
, flags
);
1089 if ((modulep
= pamh
->pam_conf_info
1090 [pamh
->include_depth
][type
]) == NULL
) {
1091 __pam_log(LOG_AUTH
| LOG_ERR
,
1092 "%s no initial module present",
1093 pam_trace_cname(pamh
));
1096 } else if ((err
= load_modules(pamh
, type
, sm_name(ind
),
1097 modulep
)) != PAM_SUCCESS
) {
1098 pam_trace(PAM_DEBUG_DEFAULT
,
1099 "[%d:%s]:%s(%p, %x): load_modules failed",
1100 pamh
->include_depth
, pam_trace_cname(pamh
),
1101 function_name
, (void *)pamh
, flags
);
1104 sm_func
= func(modulep
, ind
);
1106 err
= sm_func(pamh
, flags
, modulep
->module_argc
,
1107 (const char **)modulep
->module_argv
);
1109 pam_trace(PAM_DEBUG_MODULE
,
1110 "[%d:%s]:%s(%p, %x): %s returned %s",
1111 pamh
->include_depth
, pam_trace_cname(pamh
),
1112 function_name
, (void *)pamh
, flags
,
1113 modulep
->module_path
, pam_strerror(pamh
, err
));
1120 if ((modulep
->pam_flag
& PAM_SUFFI_BIND
) &&
1122 pamh
->pam_inmodule
= RW_OK
;
1123 pam_trace(PAM_DEBUG_MODULE
,
1124 "[%d:%s]:%s(%p, %x): %s: success",
1125 pamh
->include_depth
,
1126 pam_trace_cname(pamh
),
1127 function_name
, (void *)pamh
, flags
,
1128 (modulep
->pam_flag
& PAM_BINDING
) ?
1130 PAM_SUFFICIENT_NAME
);
1137 * We need to return immediately, and
1138 * we shouldn't reset the AUTHTOK item
1139 * since it is not an error per-se.
1141 pamh
->pam_inmodule
= RW_OK
;
1142 pam_trace(PAM_DEBUG_MODULE
,
1143 "[%d:%s]:%s(%p, %x): TRY_AGAIN: %s",
1144 pamh
->include_depth
, pam_trace_cname(pamh
),
1145 function_name
, (void *)pamh
, flags
,
1146 pam_strerror(pamh
, required_error
?
1147 required_error
: err
));
1148 err
= required_error
? required_error
: err
;
1151 if (modulep
->pam_flag
& PAM_REQUISITE
) {
1152 pamh
->pam_inmodule
= RW_OK
;
1153 pam_trace(PAM_DEBUG_MODULE
,
1154 "[%d:%s]:%s(%p, %x): requisite: %s",
1155 pamh
->include_depth
,
1156 pam_trace_cname(pamh
),
1157 function_name
, (void *)pamh
, flags
,
1159 required_error
? required_error
:
1161 err
= required_error
?
1162 required_error
: err
;
1164 } else if (modulep
->pam_flag
& PAM_REQRD_BIND
) {
1165 if (!required_error
)
1166 required_error
= err
;
1168 if (!optional_error
)
1169 optional_error
= err
;
1171 pam_trace(PAM_DEBUG_DEFAULT
,
1172 "[%d:%s]:%s(%p, %x): error %s",
1173 pamh
->include_depth
, pam_trace_cname(pamh
),
1174 function_name
, (void *)pamh
, flags
,
1175 pam_strerror(pamh
, err
));
1179 modulep
= modulep
->next
;
1182 pam_trace(PAM_DEBUG_MODULE
, "[%d:%s]:stack_end:%s(%p, %x): %s %s: %s",
1183 pamh
->include_depth
, pam_trace_cname(pamh
), function_name
,
1184 (void *)pamh
, flags
, pamh
->include_depth
? "included" : "final",
1185 required_error
? "required" : success
? "success" :
1186 optional_error
? "optional" : "default",
1187 pam_strerror(pamh
, required_error
? required_error
:
1188 success
? PAM_SUCCESS
: optional_error
? optional_error
: def_err
));
1189 if (pamh
->include_depth
> 0) {
1190 free_pam_conf_info(pamh
);
1191 pamh
->include_depth
--;
1192 /* continue at next entry */
1193 modulep
= pamh
->pam_conf_modulep
[pamh
->include_depth
];
1194 pam_trace(PAM_DEBUG_MODULE
, "looping for include[%d:%p]",
1195 pamh
->include_depth
, (void *)modulep
);
1198 free_pam_conf_info(pamh
);
1199 pamh
->pam_inmodule
= RW_OK
;
1200 if (required_error
!= 0)
1201 return (required_error
);
1202 else if (success
!= 0)
1203 return (PAM_SUCCESS
);
1204 else if (optional_error
!= 0)
1205 return (optional_error
);
1211 * All done at whatever depth we're at.
1212 * Go back to not having read /etc/pam.conf
1214 while (pamh
->include_depth
> 0) {
1215 free_pam_conf_info(pamh
);
1216 pamh
->include_depth
--;
1218 free_pam_conf_info(pamh
);
1219 pamh
->pam_inmodule
= RW_OK
;
1224 * pam_authenticate - authenticate a user
1228 pam_authenticate(pam_handle_t
*pamh
, int flags
)
1232 retval
= run_stack(pamh
, flags
, PAM_AUTH_MODULE
, PAM_AUTH_ERR
,
1233 PAM_AUTHENTICATE
, "pam_authenticate");
1235 if (retval
!= PAM_SUCCESS
)
1236 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1241 * pam_setcred - modify or retrieve user credentials
1245 pam_setcred(pam_handle_t
*pamh
, int flags
)
1249 retval
= run_stack(pamh
, flags
, PAM_AUTH_MODULE
, PAM_CRED_ERR
,
1250 PAM_SETCRED
, "pam_setcred");
1252 if (retval
!= PAM_SUCCESS
)
1253 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1258 * pam_acct_mgmt - check password aging, account expiration
1262 pam_acct_mgmt(pam_handle_t
*pamh
, int flags
)
1266 retval
= run_stack(pamh
, flags
, PAM_ACCOUNT_MODULE
, PAM_ACCT_EXPIRED
,
1267 PAM_ACCT_MGMT
, "pam_acct_mgmt");
1269 if (retval
!= PAM_SUCCESS
&&
1270 retval
!= PAM_NEW_AUTHTOK_REQD
) {
1271 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1277 * pam_open_session - begin session management
1281 pam_open_session(pam_handle_t
*pamh
, int flags
)
1285 retval
= run_stack(pamh
, flags
, PAM_SESSION_MODULE
, PAM_SESSION_ERR
,
1286 PAM_OPEN_SESSION
, "pam_open_session");
1288 if (retval
!= PAM_SUCCESS
)
1289 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1294 * pam_close_session - terminate session management
1298 pam_close_session(pam_handle_t
*pamh
, int flags
)
1302 retval
= run_stack(pamh
, flags
, PAM_SESSION_MODULE
, PAM_SESSION_ERR
,
1303 PAM_CLOSE_SESSION
, "pam_close_session");
1305 if (retval
!= PAM_SUCCESS
)
1306 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1311 * pam_chauthtok - change user authentication token
1315 pam_chauthtok(pam_handle_t
*pamh
, int flags
)
1319 /* do not let apps use PAM_PRELIM_CHECK or PAM_UPDATE_AUTHTOK */
1320 if (flags
& (PAM_PRELIM_CHECK
| PAM_UPDATE_AUTHTOK
)) {
1321 pam_trace(PAM_DEBUG_DEFAULT
,
1322 "pam_chauthtok(%p, %x): %s", (void *)pamh
, flags
,
1323 pam_strerror(pamh
, PAM_SYMBOL_ERR
));
1324 return (PAM_SYMBOL_ERR
);
1327 /* 1st pass: PRELIM CHECK */
1328 retval
= run_stack(pamh
, flags
| PAM_PRELIM_CHECK
, PAM_PASSWORD_MODULE
,
1329 PAM_AUTHTOK_ERR
, PAM_CHAUTHTOK
, "pam_chauthtok-prelim");
1331 if (retval
== PAM_TRY_AGAIN
)
1334 if (retval
!= PAM_SUCCESS
) {
1335 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1339 /* 2nd pass: UPDATE AUTHTOK */
1340 retval
= run_stack(pamh
, flags
| PAM_UPDATE_AUTHTOK
,
1341 PAM_PASSWORD_MODULE
, PAM_AUTHTOK_ERR
, PAM_CHAUTHTOK
,
1342 "pam_chauthtok-update");
1344 if (retval
!= PAM_SUCCESS
)
1345 (void) pam_set_item(pamh
, PAM_AUTHTOK
, NULL
);
1351 * pam_putenv - add an environment variable to the PAM handle
1352 * if name_value == 'NAME=VALUE' then set variable to the value
1353 * if name_value == 'NAME=' then set variable to an empty value
1354 * if name_value == 'NAME' then delete the variable
1358 pam_putenv(pam_handle_t
*pamh
, const char *name_value
)
1360 int error
= PAM_SYSTEM_ERR
;
1361 char *equal_sign
= 0;
1362 char *name
= NULL
, *value
= NULL
, *tmp_value
= NULL
;
1363 env_list
*traverse
, *trail
;
1365 pam_trace(PAM_DEBUG_DEFAULT
,
1366 "pam_putenv(%p, %s)", (void *)pamh
,
1367 name_value
? name_value
: "NULL");
1369 if (pamh
== NULL
|| name_value
== NULL
)
1372 /* see if we were passed 'NAME=VALUE', 'NAME=', or 'NAME' */
1373 if ((equal_sign
= strchr(name_value
, '=')) != 0) {
1374 if ((name
= calloc(equal_sign
- name_value
+ 1,
1375 sizeof (char))) == 0) {
1376 error
= PAM_BUF_ERR
;
1379 (void) strncpy(name
, name_value
, equal_sign
- name_value
);
1380 if ((value
= strdup(++equal_sign
)) == 0) {
1381 error
= PAM_BUF_ERR
;
1385 if ((name
= strdup(name_value
)) == 0) {
1386 error
= PAM_BUF_ERR
;
1391 /* check to see if we already have this variable in the PAM handle */
1392 traverse
= pamh
->pam_env
;
1394 while (traverse
&& strncmp(traverse
->name
, name
, strlen(name
))) {
1396 traverse
= traverse
->next
;
1402 /* remove the env variable */
1403 if (pamh
->pam_env
== traverse
)
1404 pamh
->pam_env
= traverse
->next
;
1406 trail
->next
= traverse
->next
;
1408 } else if (strlen(value
) == 0) {
1409 /* set env variable to empty value */
1410 if ((tmp_value
= strdup("")) == 0) {
1411 error
= PAM_SYSTEM_ERR
;
1414 free(traverse
->value
);
1415 traverse
->value
= tmp_value
;
1417 /* set the new value */
1418 if ((tmp_value
= strdup(value
)) == 0) {
1419 error
= PAM_SYSTEM_ERR
;
1422 free(traverse
->value
);
1423 traverse
->value
= tmp_value
;
1426 } else if (traverse
== 0 && value
) {
1428 * could not find a match in the PAM handle.
1429 * add the new value if there is one
1431 if ((traverse
= calloc(1, sizeof (env_list
))) == 0) {
1432 error
= PAM_BUF_ERR
;
1435 if ((traverse
->name
= strdup(name
)) == 0) {
1437 error
= PAM_BUF_ERR
;
1440 if ((traverse
->value
= strdup(value
)) == 0) {
1442 error
= PAM_BUF_ERR
;
1446 /* new head of list */
1447 pamh
->pam_env
= traverse
;
1449 /* adding to end of list */
1450 trail
->next
= traverse
;
1454 error
= PAM_SUCCESS
;
1456 if (error
!= PAM_SUCCESS
) {
1459 free(traverse
->name
);
1460 if (traverse
->value
)
1461 free(traverse
->value
);
1473 * pam_getenv - retrieve an environment variable from the PAM handle
1476 pam_getenv(pam_handle_t
*pamh
, const char *name
)
1478 int error
= PAM_SYSTEM_ERR
;
1481 pam_trace(PAM_DEBUG_DEFAULT
,
1482 "pam_getenv(%p, %p)", (void *)pamh
, (void *)name
);
1484 if (pamh
== NULL
|| name
== NULL
)
1487 /* check to see if we already have this variable in the PAM handle */
1488 traverse
= pamh
->pam_env
;
1489 while (traverse
&& strncmp(traverse
->name
, name
, strlen(name
))) {
1490 traverse
= traverse
->next
;
1492 error
= (traverse
? PAM_SUCCESS
: PAM_SYSTEM_ERR
);
1493 pam_trace(PAM_DEBUG_DEFAULT
,
1494 "pam_getenv(%p, %s)=%s", (void *)pamh
, name
,
1495 traverse
? traverse
->value
: "NULL");
1497 return (error
? NULL
: strdup(traverse
->value
));
1501 * pam_getenvlist - retrieve all environment variables from the PAM handle
1502 * in a NULL terminated array. On error, return NULL.
1505 pam_getenvlist(pam_handle_t
*pamh
)
1507 int error
= PAM_SYSTEM_ERR
;
1514 pam_trace(PAM_DEBUG_DEFAULT
,
1515 "pam_getenvlist(%p)", (void *)pamh
);
1520 /* find out how many environment variables we have */
1521 traverse
= pamh
->pam_env
;
1524 traverse
= traverse
->next
;
1527 /* allocate the array we will return to the caller */
1528 if ((list
= calloc(length
+ 1, sizeof (char *))) == NULL
) {
1529 error
= PAM_BUF_ERR
;
1533 /* add the variables one by one */
1535 traverse
= pamh
->pam_env
;
1536 while (traverse
!= NULL
) {
1537 tenv_size
= strlen(traverse
->name
) +
1538 strlen(traverse
->value
) + 2; /* name=val\0 */
1539 if ((tenv
= malloc(tenv_size
)) == NULL
) {
1540 error
= PAM_BUF_ERR
;
1544 (void) sprintf(tenv
, "%s=%s", traverse
->name
, traverse
->value
);
1545 list
[length
++] = tenv
;
1546 traverse
= traverse
->next
;
1548 list
[length
] = NULL
;
1550 error
= PAM_SUCCESS
;
1552 if (error
!= PAM_SUCCESS
) {
1553 /* free the partially constructed list */
1556 while (list
[length
] != NULL
) {
1563 return (error
? NULL
: list
);
1567 * Routines to load a requested module on demand
1571 * load_modules - load the requested module.
1572 * if the dlopen or dlsym fail, then
1573 * the module is ignored.
1577 load_modules(pam_handle_t
*pamh
, int type
, char *function_name
,
1578 pamtab_t
*pam_entry
)
1581 struct auth_module
*authp
;
1582 struct account_module
*accountp
;
1583 struct session_module
*sessionp
;
1584 struct password_module
*passwdp
;
1585 int loading_functions
= 0; /* are we currently loading functions? */
1587 pam_trace(PAM_DEBUG_MODULE
, "load_modules[%d:%s](%p, %s)=%s:%s",
1588 pamh
->include_depth
, pam_trace_cname(pamh
), (void *)pamh
,
1589 function_name
, pam_trace_fname(pam_entry
->pam_flag
),
1590 pam_entry
->module_path
);
1592 while (pam_entry
!= NULL
) {
1593 pam_trace(PAM_DEBUG_DEFAULT
,
1594 "while load_modules[%d:%s](%p, %s)=%s",
1595 pamh
->include_depth
, pam_trace_cname(pamh
), (void *)pamh
,
1596 function_name
, pam_entry
->module_path
);
1598 if (pam_entry
->pam_flag
& PAM_INCLUDE
) {
1599 pam_trace(PAM_DEBUG_DEFAULT
,
1600 "done load_modules[%d:%s](%p, %s)=%s",
1601 pamh
->include_depth
, pam_trace_cname(pamh
),
1602 (void *)pamh
, function_name
,
1603 pam_entry
->module_path
);
1604 return (PAM_SUCCESS
);
1607 case PAM_AUTH_MODULE
:
1609 /* if the function has already been loaded, return */
1610 authp
= pam_entry
->function_ptr
;
1611 if (!loading_functions
&&
1612 (((strcmp(function_name
, PAM_SM_AUTHENTICATE
)
1613 == 0) && authp
&& authp
->pam_sm_authenticate
) ||
1614 ((strcmp(function_name
, PAM_SM_SETCRED
) == 0) &&
1615 authp
&& authp
->pam_sm_setcred
))) {
1616 return (PAM_SUCCESS
);
1619 /* function has not been loaded yet */
1620 loading_functions
= 1;
1621 if (authp
== NULL
) {
1622 authp
= calloc(1, sizeof (struct auth_module
));
1624 return (PAM_BUF_ERR
);
1627 /* if open_module fails, return error */
1628 if ((mh
= open_module(pamh
,
1629 pam_entry
->module_path
)) == NULL
) {
1630 __pam_log(LOG_AUTH
| LOG_ERR
,
1631 "load_modules[%d:%s]: can not open module "
1632 "%s", pamh
->include_depth
,
1633 pam_trace_cname(pamh
),
1634 pam_entry
->module_path
);
1636 return (PAM_OPEN_ERR
);
1639 /* load the authentication function */
1640 if (strcmp(function_name
, PAM_SM_AUTHENTICATE
) == 0) {
1641 if (load_function(mh
, PAM_SM_AUTHENTICATE
,
1642 &authp
->pam_sm_authenticate
)
1644 /* return error if dlsym fails */
1646 return (PAM_SYMBOL_ERR
);
1649 /* load the setcred function */
1650 } else if (strcmp(function_name
, PAM_SM_SETCRED
) == 0) {
1651 if (load_function(mh
, PAM_SM_SETCRED
,
1652 &authp
->pam_sm_setcred
) != PAM_SUCCESS
) {
1653 /* return error if dlsym fails */
1655 return (PAM_SYMBOL_ERR
);
1658 pam_entry
->function_ptr
= authp
;
1660 case PAM_ACCOUNT_MODULE
:
1661 accountp
= pam_entry
->function_ptr
;
1662 if (!loading_functions
&&
1663 (strcmp(function_name
, PAM_SM_ACCT_MGMT
) == 0) &&
1664 accountp
&& accountp
->pam_sm_acct_mgmt
) {
1665 return (PAM_SUCCESS
);
1669 * If functions are added to the account module,
1670 * verify that one of the other functions hasn't
1671 * already loaded it. See PAM_AUTH_MODULE code.
1673 loading_functions
= 1;
1674 accountp
= calloc(1, sizeof (struct account_module
));
1675 if (accountp
== NULL
)
1676 return (PAM_BUF_ERR
);
1678 /* if open_module fails, return error */
1679 if ((mh
= open_module(pamh
,
1680 pam_entry
->module_path
)) == NULL
) {
1681 __pam_log(LOG_AUTH
| LOG_ERR
,
1682 "load_modules[%d:%s]: can not open module "
1683 "%s", pamh
->include_depth
,
1684 pam_trace_cname(pamh
),
1685 pam_entry
->module_path
);
1687 return (PAM_OPEN_ERR
);
1690 if (load_function(mh
, PAM_SM_ACCT_MGMT
,
1691 &accountp
->pam_sm_acct_mgmt
) != PAM_SUCCESS
) {
1692 __pam_log(LOG_AUTH
| LOG_ERR
,
1693 "load_modules[%d:%s]: pam_sm_acct_mgmt() "
1694 "missing", pamh
->include_depth
,
1695 pam_trace_cname(pamh
));
1697 return (PAM_SYMBOL_ERR
);
1699 pam_entry
->function_ptr
= accountp
;
1701 case PAM_SESSION_MODULE
:
1702 sessionp
= pam_entry
->function_ptr
;
1703 if (!loading_functions
&&
1704 (((strcmp(function_name
,
1705 PAM_SM_OPEN_SESSION
) == 0) &&
1706 sessionp
&& sessionp
->pam_sm_open_session
) ||
1707 ((strcmp(function_name
,
1708 PAM_SM_CLOSE_SESSION
) == 0) &&
1709 sessionp
&& sessionp
->pam_sm_close_session
))) {
1710 return (PAM_SUCCESS
);
1713 loading_functions
= 1;
1714 if (sessionp
== NULL
) {
1715 sessionp
= calloc(1,
1716 sizeof (struct session_module
));
1717 if (sessionp
== NULL
)
1718 return (PAM_BUF_ERR
);
1721 /* if open_module fails, return error */
1722 if ((mh
= open_module(pamh
,
1723 pam_entry
->module_path
)) == NULL
) {
1724 __pam_log(LOG_AUTH
| LOG_ERR
,
1725 "load_modules[%d:%s]: can not open module "
1726 "%s", pamh
->include_depth
,
1727 pam_trace_cname(pamh
),
1728 pam_entry
->module_path
);
1730 return (PAM_OPEN_ERR
);
1733 if ((strcmp(function_name
, PAM_SM_OPEN_SESSION
) == 0) &&
1734 load_function(mh
, PAM_SM_OPEN_SESSION
,
1735 &sessionp
->pam_sm_open_session
) != PAM_SUCCESS
) {
1737 return (PAM_SYMBOL_ERR
);
1738 } else if ((strcmp(function_name
,
1739 PAM_SM_CLOSE_SESSION
) == 0) &&
1740 load_function(mh
, PAM_SM_CLOSE_SESSION
,
1741 &sessionp
->pam_sm_close_session
) != PAM_SUCCESS
) {
1743 return (PAM_SYMBOL_ERR
);
1745 pam_entry
->function_ptr
= sessionp
;
1747 case PAM_PASSWORD_MODULE
:
1748 passwdp
= pam_entry
->function_ptr
;
1749 if (!loading_functions
&&
1750 (strcmp(function_name
, PAM_SM_CHAUTHTOK
) == 0) &&
1751 passwdp
&& passwdp
->pam_sm_chauthtok
) {
1752 return (PAM_SUCCESS
);
1756 * If functions are added to the password module,
1757 * verify that one of the other functions hasn't
1758 * already loaded it. See PAM_AUTH_MODULE code.
1760 loading_functions
= 1;
1761 passwdp
= calloc(1, sizeof (struct password_module
));
1762 if (passwdp
== NULL
)
1763 return (PAM_BUF_ERR
);
1765 /* if open_module fails, continue */
1766 if ((mh
= open_module(pamh
,
1767 pam_entry
->module_path
)) == NULL
) {
1768 __pam_log(LOG_AUTH
| LOG_ERR
,
1769 "load_modules[%d:%s]: can not open module "
1770 "%s", pamh
->include_depth
,
1771 pam_trace_cname(pamh
),
1772 pam_entry
->module_path
);
1774 return (PAM_OPEN_ERR
);
1777 if (load_function(mh
, PAM_SM_CHAUTHTOK
,
1778 &passwdp
->pam_sm_chauthtok
) != PAM_SUCCESS
) {
1780 return (PAM_SYMBOL_ERR
);
1782 pam_entry
->function_ptr
= passwdp
;
1785 pam_trace(PAM_DEBUG_DEFAULT
,
1786 "load_modules[%d:%s](%p, %s): unsupported type %d",
1787 pamh
->include_depth
, pam_trace_cname(pamh
),
1788 (void *)pamh
, function_name
, type
);
1792 pam_entry
= pam_entry
->next
;
1795 pam_trace(PAM_DEBUG_MODULE
, "load_modules[%d:%s](%p, %s)=done",
1796 pamh
->include_depth
, pam_trace_cname(pamh
), (void *)pamh
,
1799 return (PAM_SUCCESS
);
1803 * open_module - Open the module first checking for
1804 * propers modes and ownerships on the file.
1808 open_module(pam_handle_t
*pamh
, char *module_so
)
1813 fd_list
*module_fds
= 0;
1815 fd_list
*traverse
= 0;
1817 /* Check the ownership and file modes */
1818 if (stat64(module_so
, &stb
) < 0) {
1819 __pam_log(LOG_AUTH
| LOG_ERR
,
1820 "open_module[%d:%s]: stat(%s) failed: %s",
1821 pamh
->include_depth
, pam_trace_cname(pamh
), module_so
,
1825 if (stb
.st_uid
!= (uid_t
)0) {
1826 __pam_log(LOG_AUTH
| LOG_ALERT
,
1827 "open_module[%d:%s]: Owner of the module %s is not root",
1828 pamh
->include_depth
, pam_trace_cname(pamh
), module_so
);
1831 if (stb
.st_mode
& S_IWGRP
) {
1832 __pam_log(LOG_AUTH
| LOG_ALERT
,
1833 "open_module[%d:%s]: module %s writable by group",
1834 pamh
->include_depth
, pam_trace_cname(pamh
), module_so
);
1837 if (stb
.st_mode
& S_IWOTH
) {
1838 __pam_log(LOG_AUTH
| LOG_ALERT
,
1839 "open_module[%d:%s]: module %s writable by world",
1840 pamh
->include_depth
, pam_trace_cname(pamh
), module_so
);
1845 * Perform the dlopen()
1847 lfd
= (void *)dlopen(module_so
, RTLD_LAZY
);
1851 __pam_log(LOG_AUTH
| LOG_ERR
, "open_module[%d:%s]: %s "
1852 "failed: %s", pamh
->include_depth
, pam_trace_cname(pamh
),
1853 module_so
, errmsg
!= NULL
? errmsg
: "Unknown error");
1856 /* add this fd to the pam handle */
1857 if ((module_fds
= calloc(1, sizeof (fd_list
))) == 0) {
1858 (void) dlclose(lfd
);
1862 module_fds
->mh
= lfd
;
1864 if (pamh
->fd
== 0) {
1865 /* adding new head of list */
1866 pamh
->fd
= module_fds
;
1868 /* appending to end of list */
1869 traverse
= pamh
->fd
;
1872 traverse
= traverse
->next
;
1874 trail
->next
= module_fds
;
1882 * load_function - call dlsym() to resolve the function address
1885 load_function(void *lfd
, char *name
, int (**func
)())
1887 char *errmsg
= NULL
;
1890 return (PAM_SYMBOL_ERR
);
1892 *func
= (int (*)())dlsym(lfd
, name
);
1893 if (*func
== NULL
) {
1895 __pam_log(LOG_AUTH
| LOG_ERR
, "dlsym failed %s: error %s",
1896 name
, errmsg
!= NULL
? errmsg
: "Unknown error");
1897 return (PAM_SYMBOL_ERR
);
1900 pam_trace(PAM_DEBUG_DEFAULT
,
1901 "load_function: successful load of %s", name
);
1902 return (PAM_SUCCESS
);
1906 * Routines to read the pam.conf configuration file
1910 * open_pam_conf - open the pam.conf config file
1914 open_pam_conf(struct pam_fh
**pam_fh
, pam_handle_t
*pamh
, char *config
)
1919 if ((fd
= open(config
, O_RDONLY
)) == -1) {
1920 __pam_log(LOG_AUTH
| LOG_ALERT
,
1921 "open_pam_conf[%d:%s]: open(%s) failed: %s",
1922 pamh
->include_depth
, pam_trace_cname(pamh
), config
,
1926 /* Check the ownership and file modes */
1927 if (fstat64(fd
, &stb
) < 0) {
1928 __pam_log(LOG_AUTH
| LOG_ALERT
,
1929 "open_pam_conf[%d:%s]: stat(%s) failed: %s",
1930 pamh
->include_depth
, pam_trace_cname(pamh
), config
,
1935 if (stb
.st_uid
!= (uid_t
)0) {
1936 __pam_log(LOG_AUTH
| LOG_ALERT
,
1937 "open_pam_conf[%d:%s]: Owner of %s is not root",
1938 pamh
->include_depth
, pam_trace_cname(pamh
), config
);
1942 if (stb
.st_mode
& S_IWGRP
) {
1943 __pam_log(LOG_AUTH
| LOG_ALERT
,
1944 "open_pam_conf[%d:%s]: %s writable by group",
1945 pamh
->include_depth
, pam_trace_cname(pamh
), config
);
1949 if (stb
.st_mode
& S_IWOTH
) {
1950 __pam_log(LOG_AUTH
| LOG_ALERT
,
1951 "open_pam_conf[%d:%s]: %s writable by world",
1952 pamh
->include_depth
, pam_trace_cname(pamh
), config
);
1956 if ((*pam_fh
= calloc(1, sizeof (struct pam_fh
))) == NULL
) {
1960 (*pam_fh
)->fconfig
= fd
;
1961 (*pam_fh
)->bufsize
= (size_t)stb
.st_size
;
1962 if (((*pam_fh
)->data
= mmap(0, (*pam_fh
)->bufsize
, PROT_READ
,
1963 MAP_PRIVATE
, (*pam_fh
)->fconfig
, 0)) == MAP_FAILED
) {
1968 (*pam_fh
)->bufferp
= (*pam_fh
)->data
;
1974 * close_pam_conf - close pam.conf
1978 close_pam_conf(struct pam_fh
*pam_fh
)
1980 (void) munmap(pam_fh
->data
, pam_fh
->bufsize
);
1981 (void) close(pam_fh
->fconfig
);
1986 * read_pam_conf - read in each entry in pam.conf and store info
1987 * under the pam handle.
1991 read_pam_conf(pam_handle_t
*pamh
, char *config
)
1993 struct pam_fh
*pam_fh
;
1998 int i
= pamh
->include_depth
; /* include depth */
2001 * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3)
2003 int service_found
[PAM_NUM_MODULE_TYPES
+1] = {0, 0, 0, 0, 0};
2005 (void) pam_get_item(pamh
, PAM_SERVICE
, (void **)&service
);
2006 if (service
== NULL
|| *service
== '\0') {
2007 __pam_log(LOG_AUTH
| LOG_ERR
, "No service name");
2008 return (PAM_SYSTEM_ERR
);
2011 pamh
->pam_conf_name
[i
] = strdup(config
);
2012 pam_trace(PAM_DEBUG_CONF
, "read_pam_conf[%d:%s](%p) open(%s)",
2013 i
, pam_trace_cname(pamh
), (void *)pamh
, config
);
2014 if (open_pam_conf(&pam_fh
, pamh
, config
) == 0) {
2015 return (PAM_SYSTEM_ERR
);
2019 get_pam_conf_entry(pam_fh
, pamh
, &pamentp
)) == PAM_SUCCESS
&&
2022 /* See if entry is this service and valid */
2023 if (verify_pam_conf(pamentp
, service
)) {
2024 pam_trace(PAM_DEBUG_CONF
,
2025 "read_pam_conf[%d:%s](%p): bad entry error %s",
2026 i
, pam_trace_cname(pamh
), (void *)pamh
, service
);
2028 error
= PAM_SYSTEM_ERR
;
2029 free_pamconf(pamentp
);
2032 if (strcasecmp(pamentp
->pam_service
, service
) == 0) {
2033 pam_trace(PAM_DEBUG_CONF
,
2034 "read_pam_conf[%d:%s](%p): processing %s",
2035 i
, pam_trace_cname(pamh
), (void *)pamh
, service
);
2036 /* process first service entry */
2037 if (service_found
[pamentp
->pam_type
+ 1] == 0) {
2038 /* purge "other" entries */
2039 while ((tpament
= pamh
->pam_conf_info
[i
]
2040 [pamentp
->pam_type
]) != NULL
) {
2041 pam_trace(PAM_DEBUG_CONF
,
2042 "read_pam_conf(%p): purging "
2043 "\"other\"[%d:%s][%s]",
2045 pam_trace_cname(pamh
),
2046 pam_snames
[pamentp
->pam_type
]);
2047 pamh
->pam_conf_info
[i
]
2048 [pamentp
->pam_type
] = tpament
->next
;
2049 free_pamconf(tpament
);
2051 /* add first service entry */
2052 pam_trace(PAM_DEBUG_CONF
,
2053 "read_pam_conf(%p): adding 1st "
2055 (void *)pamh
, service
, i
,
2056 pam_trace_cname(pamh
),
2057 pam_snames
[pamentp
->pam_type
]);
2058 pamh
->pam_conf_info
[i
][pamentp
->pam_type
] =
2060 service_found
[pamentp
->pam_type
+ 1] = 1;
2062 /* append more service entries */
2063 pam_trace(PAM_DEBUG_CONF
,
2064 "read_pam_conf(%p): adding more "
2066 (void *)pamh
, service
, i
,
2067 pam_trace_cname(pamh
),
2068 pam_snames
[pamentp
->pam_type
]);
2070 pamh
->pam_conf_info
[i
][pamentp
->pam_type
];
2071 while (tpament
->next
!= NULL
) {
2072 tpament
= tpament
->next
;
2074 tpament
->next
= pamentp
;
2076 } else if (service_found
[pamentp
->pam_type
+ 1] == 0) {
2077 /* See if "other" entry available and valid */
2078 if (verify_pam_conf(pamentp
, "other")) {
2079 pam_trace(PAM_DEBUG_CONF
,
2080 "read_pam_conf(%p): bad entry error %s "
2082 (void *)pamh
, service
, i
,
2083 pam_trace_cname(pamh
));
2084 error
= PAM_SYSTEM_ERR
;
2085 free_pamconf(pamentp
);
2088 if (strcasecmp(pamentp
->pam_service
, "other") == 0) {
2089 pam_trace(PAM_DEBUG_CONF
,
2090 "read_pam_conf(%p): processing "
2091 "\"other\"[%d:%s]", (void *)pamh
, i
,
2092 pam_trace_cname(pamh
));
2093 if ((tpament
= pamh
->pam_conf_info
[i
]
2094 [pamentp
->pam_type
]) == NULL
) {
2095 /* add first "other" entry */
2096 pam_trace(PAM_DEBUG_CONF
,
2097 "read_pam_conf(%p): adding 1st "
2098 "other[%d:%s][%s]", (void *)pamh
, i
,
2099 pam_trace_cname(pamh
),
2100 pam_snames
[pamentp
->pam_type
]);
2101 pamh
->pam_conf_info
[i
]
2102 [pamentp
->pam_type
] = pamentp
;
2104 /* append more "other" entries */
2105 pam_trace(PAM_DEBUG_CONF
,
2106 "read_pam_conf(%p): adding more "
2107 "other[%d:%s][%s]", (void *)pamh
, i
,
2108 pam_trace_cname(pamh
),
2109 pam_snames
[pamentp
->pam_type
]);
2110 while (tpament
->next
!= NULL
) {
2111 tpament
= tpament
->next
;
2113 tpament
->next
= pamentp
;
2116 /* irrelevant entry */
2117 free_pamconf(pamentp
);
2120 /* irrelevant entry */
2121 free_pamconf(pamentp
);
2125 (void) close_pam_conf(pam_fh
);
2126 if (error
!= PAM_SUCCESS
)
2127 free_pam_conf_info(pamh
);
2132 * get_pam_conf_entry - get a pam.conf entry
2136 get_pam_conf_entry(struct pam_fh
*pam_fh
, pam_handle_t
*pamh
, pamtab_t
**pam
)
2140 char *tmp
, *tmp_free
;
2142 char *current_line
= NULL
;
2143 int error
= PAM_SYSTEM_ERR
; /* preset to error */
2146 /* get the next line from pam.conf */
2147 if ((cp
= nextline(pam_fh
, pamh
, &err
)) == NULL
) {
2148 /* no more lines in pam.conf ==> return */
2149 error
= PAM_SUCCESS
;
2154 if ((*pam
= calloc(1, sizeof (pamtab_t
))) == NULL
) {
2155 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2159 /* copy full line for error reporting */
2160 if ((current_line
= strdup(cp
)) == NULL
) {
2161 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2165 pam_trace(PAM_DEBUG_CONF
,
2166 "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh
), current_line
);
2168 /* get service name (e.g. login, su, passwd) */
2169 if ((arg
= read_next_token(&cp
)) == 0) {
2170 __pam_log(LOG_AUTH
| LOG_CRIT
,
2171 "illegal pam.conf[%s] entry: %s: missing SERVICE NAME",
2172 pam_trace_cname(pamh
), current_line
);
2175 if (((*pam
)->pam_service
= strdup(arg
)) == 0) {
2176 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2180 /* get module type (e.g. authentication, acct mgmt) */
2181 if ((arg
= read_next_token(&cp
)) == 0) {
2182 __pam_log(LOG_AUTH
| LOG_CRIT
,
2183 "illegal pam.conf[%s] entry: %s: missing MODULE TYPE",
2184 pam_trace_cname(pamh
), current_line
);
2185 (*pam
)->pam_type
= -1; /* 0 is a valid value */
2188 if (strcasecmp(arg
, PAM_AUTH_NAME
) == 0) {
2189 (*pam
)->pam_type
= PAM_AUTH_MODULE
;
2190 } else if (strcasecmp(arg
, PAM_ACCOUNT_NAME
) == 0) {
2191 (*pam
)->pam_type
= PAM_ACCOUNT_MODULE
;
2192 } else if (strcasecmp(arg
, PAM_SESSION_NAME
) == 0) {
2193 (*pam
)->pam_type
= PAM_SESSION_MODULE
;
2194 } else if (strcasecmp(arg
, PAM_PASSWORD_NAME
) == 0) {
2195 (*pam
)->pam_type
= PAM_PASSWORD_MODULE
;
2198 __pam_log(LOG_AUTH
| LOG_CRIT
,
2199 "illegal pam.conf[%s] entry: %s: invalid module "
2200 "type: %s", pam_trace_cname(pamh
), current_line
, arg
);
2201 (*pam
)->pam_type
= -1; /* 0 is a valid value */
2205 /* get pam flag (e.g., requisite, required, sufficient, optional) */
2206 if ((arg
= read_next_token(&cp
)) == 0) {
2207 __pam_log(LOG_AUTH
| LOG_CRIT
,
2208 "illegal pam.conf[%s] entry: %s: missing CONTROL FLAG",
2209 pam_trace_cname(pamh
), current_line
);
2212 if (strcasecmp(arg
, PAM_BINDING_NAME
) == 0) {
2213 (*pam
)->pam_flag
= PAM_BINDING
;
2214 } else if (strcasecmp(arg
, PAM_INCLUDE_NAME
) == 0) {
2215 (*pam
)->pam_flag
= PAM_INCLUDE
;
2216 } else if (strcasecmp(arg
, PAM_OPTIONAL_NAME
) == 0) {
2217 (*pam
)->pam_flag
= PAM_OPTIONAL
;
2218 } else if (strcasecmp(arg
, PAM_REQUIRED_NAME
) == 0) {
2219 (*pam
)->pam_flag
= PAM_REQUIRED
;
2220 } else if (strcasecmp(arg
, PAM_REQUISITE_NAME
) == 0) {
2221 (*pam
)->pam_flag
= PAM_REQUISITE
;
2222 } else if (strcasecmp(arg
, PAM_SUFFICIENT_NAME
) == 0) {
2223 (*pam
)->pam_flag
= PAM_SUFFICIENT
;
2226 __pam_log(LOG_AUTH
| LOG_CRIT
,
2227 "illegal pam.conf[%s] entry: %s",
2228 pam_trace_cname(pamh
), current_line
);
2229 __pam_log(LOG_AUTH
| LOG_CRIT
,
2230 "\tinvalid control flag: %s", arg
);
2234 /* get module path (e.g. /usr/lib/security/pam_unix_auth.so.1) */
2235 if ((arg
= read_next_token(&cp
)) == 0) {
2236 __pam_log(LOG_AUTH
| LOG_CRIT
,
2237 "illegal pam.conf[%s] entry: %s: missing MODULE PATH",
2238 pam_trace_cname(pamh
), current_line
);
2239 error
= PAM_SUCCESS
; /* success */
2242 if (arg
[0] != '/') {
2245 * If module path does not start with "/", then
2246 * prepend PAM_LIB_DIR (/usr/lib/security/).
2248 /* sizeof (PAM_LIB_DIR) has room for '\0' */
2249 len
= sizeof (PAM_LIB_DIR
) + sizeof (PAM_ISA_DIR
) + strlen(arg
);
2250 if (((*pam
)->module_path
= malloc(len
)) == NULL
) {
2251 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2254 if ((*pam
)->pam_flag
& PAM_INCLUDE
) {
2255 (void) snprintf((*pam
)->module_path
, len
, "%s%s",
2258 (void) snprintf((*pam
)->module_path
, len
, "%s%s%s",
2259 PAM_LIB_DIR
, PAM_ISA_DIR
, arg
);
2262 /* Full path provided for module */
2265 /* Check for Instruction Set Architecture indicator */
2266 if ((isa
= strstr(arg
, PAM_ISA
)) != NULL
) {
2268 len
= strlen(arg
) - (sizeof (PAM_ISA
)-1) +
2269 sizeof (PAM_ISA_DIR
);
2271 /* substitute the architecture dependent path */
2272 if (((*pam
)->module_path
= malloc(len
)) == NULL
) {
2273 __pam_log(LOG_AUTH
| LOG_ERR
,
2274 "strdup: out of memory");
2278 isa
+= strlen(PAM_ISA
);
2279 (void) snprintf((*pam
)->module_path
, len
, "%s%s%s",
2280 arg
, PAM_ISA_DIR
, isa
);
2281 } else if (((*pam
)->module_path
= strdup(arg
)) == 0) {
2282 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2287 /* count the number of module-specific options first */
2289 if ((tmp
= strdup(cp
)) == NULL
) {
2290 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup: out of memory");
2294 for (arg
= read_next_token(&tmp
); arg
; arg
= read_next_token(&tmp
))
2298 /* allocate array for the module-specific options */
2300 if (((*pam
)->module_argv
=
2301 calloc(argc
+1, sizeof (char *))) == 0) {
2302 __pam_log(LOG_AUTH
| LOG_ERR
, "calloc: out of memory");
2306 for (arg
= read_next_token(&cp
); arg
;
2307 arg
= read_next_token(&cp
)) {
2308 (*pam
)->module_argv
[i
] = strdup(arg
);
2309 if ((*pam
)->module_argv
[i
] == NULL
) {
2310 __pam_log(LOG_AUTH
| LOG_ERR
, "strdup failed");
2315 (*pam
)->module_argv
[argc
] = NULL
;
2317 (*pam
)->module_argc
= argc
;
2319 error
= PAM_SUCCESS
; /* success */
2320 (*pam
)->pam_err
= err
; /* was the line truncated */
2325 if (error
!= PAM_SUCCESS
) {
2326 /* on error free this */
2335 * read_next_token - skip tab and space characters and return the next token
2339 read_next_token(char **cpp
)
2341 register char *cp
= *cpp
;
2344 if (cp
== (char *)0) {
2348 while (*cp
== ' ' || *cp
== '\t')
2355 while (*cp
&& *cp
!= ' ' && *cp
!= '\t')
2364 pam_conf_strnchr(char *sp
, int c
, intptr_t count
)
2368 return ((char *)sp
);
2378 * nextline - skip all blank lines and comments
2382 nextline(struct pam_fh
*pam_fh
, pam_handle_t
*pamh
, int *err
)
2385 int find_a_line
= 0;
2386 char *data
= pam_fh
->data
;
2387 char *bufferp
= pam_fh
->bufferp
;
2388 char *bufferendp
= &data
[pam_fh
->bufsize
];
2392 * Skip the blank line, comment line
2394 while (!find_a_line
) {
2395 /* if we are at the end of the buffer, there is no next line */
2396 if (bufferp
== bufferendp
)
2399 /* skip blank line */
2400 while (*bufferp
== '\n') {
2402 * If we are at the end of the buffer, there is
2405 if (++bufferp
== bufferendp
) {
2408 /* else we check *bufferp again */
2411 /* skip comment line */
2412 while (*bufferp
== '#') {
2413 if ((ll
= pam_conf_strnchr(bufferp
, '\n',
2414 bufferendp
- bufferp
)) != NULL
) {
2418 * this comment line the last line.
2425 * If we are at the end of the buffer, there is
2428 if (bufferp
== bufferendp
) {
2433 if ((*bufferp
!= '\n') && (*bufferp
!= '#')) {
2439 /* now we find one line */
2440 if ((ll
= pam_conf_strnchr(bufferp
, '\n', bufferendp
- bufferp
))
2442 if ((input_len
= ll
- bufferp
) >= sizeof (pam_fh
->line
)) {
2443 __pam_log(LOG_AUTH
| LOG_ERR
,
2444 "nextline[%d:%s]: pam.conf line too long %.256s",
2445 pamh
->include_depth
, pam_trace_cname(pamh
),
2447 input_len
= sizeof (pam_fh
->line
) - 1;
2448 *err
= PAM_SERVICE_ERR
;
2450 (void) strncpy(pam_fh
->line
, bufferp
, input_len
);
2451 pam_fh
->line
[input_len
] = '\0';
2452 pam_fh
->bufferp
= ll
++;
2455 if ((input_len
= ll
- bufferp
) >= sizeof (pam_fh
->line
)) {
2456 __pam_log(LOG_AUTH
| LOG_ERR
,
2457 "nextline[%d:%s]: pam.conf line too long %.256s",
2458 pamh
->include_depth
, pam_trace_cname(pamh
),
2460 input_len
= sizeof (pam_fh
->line
) - 1;
2461 *err
= PAM_SERVICE_ERR
;
2463 (void) strncpy(pam_fh
->line
, bufferp
, input_len
);
2464 pam_fh
->line
[input_len
] = '\0';
2465 pam_fh
->bufferp
= ll
;
2468 return (pam_fh
->line
);
2472 * verify_pam_conf - verify that the pam_conf entry is filled in.
2474 * True = Error if there is no service.
2475 * True = Error if there is a service and it matches the requested service
2476 * but, the type, flag, line overflow, or path is in error.
2480 verify_pam_conf(pamtab_t
*pam
, char *service
)
2482 return ((pam
->pam_service
== (char *)NULL
) ||
2483 ((strcasecmp(pam
->pam_service
, service
) == 0) &&
2484 ((pam
->pam_type
== -1) ||
2485 (pam
->pam_flag
== 0) ||
2486 (pam
->pam_err
!= PAM_SUCCESS
) ||
2487 (pam
->module_path
== (char *)NULL
))));
2491 * Routines to free allocated storage
2495 * clean_up - free allocated storage in the pam handle
2499 clean_up(pam_handle_t
*pamh
)
2502 pam_repository_t
*auth_rep
;
2505 while (pamh
->include_depth
>= 0) {
2506 free_pam_conf_info(pamh
);
2507 pamh
->include_depth
--;
2510 /* Cleanup PAM_REPOSITORY structure */
2511 auth_rep
= pamh
->ps_item
[PAM_REPOSITORY
].pi_addr
;
2512 if (auth_rep
!= NULL
) {
2513 if (auth_rep
->type
!= NULL
)
2514 free(auth_rep
->type
);
2515 if (auth_rep
->scope
!= NULL
)
2516 free(auth_rep
->scope
);
2519 for (i
= 0; i
< PAM_MAX_ITEMS
; i
++) {
2520 if (pamh
->ps_item
[i
].pi_addr
!= NULL
) {
2521 if (i
== PAM_AUTHTOK
|| i
== PAM_OLDAUTHTOK
) {
2522 (void) memset(pamh
->ps_item
[i
].pi_addr
,
2523 0, pamh
->ps_item
[i
].pi_size
);
2525 free(pamh
->ps_item
[i
].pi_addr
);
2533 * free_pamconf - free memory used to store pam.conf entry
2537 free_pamconf(pamtab_t
*cp
)
2542 if (cp
->pam_service
)
2543 free(cp
->pam_service
);
2544 if (cp
->module_path
)
2545 free(cp
->module_path
);
2546 for (i
= 0; i
< cp
->module_argc
; i
++) {
2547 if (cp
->module_argv
[i
])
2548 free(cp
->module_argv
[i
]);
2550 if (cp
->module_argc
> 0)
2551 free(cp
->module_argv
);
2552 if (cp
->function_ptr
)
2553 free(cp
->function_ptr
);
2560 * free_pam_conf_info - free memory used to store all pam.conf info
2561 * under the pam handle
2565 free_pam_conf_info(pam_handle_t
*pamh
)
2568 pamtab_t
*pament_trail
;
2569 int i
= pamh
->include_depth
;
2572 for (j
= 0; j
< PAM_NUM_MODULE_TYPES
; j
++) {
2573 pamentp
= pamh
->pam_conf_info
[i
][j
];
2574 pamh
->pam_conf_info
[i
][j
] = NULL
;
2575 pament_trail
= pamentp
;
2577 pamentp
= pamentp
->next
;
2578 free_pamconf(pament_trail
);
2579 pament_trail
= pamentp
;
2582 if (pamh
->pam_conf_name
[i
] != NULL
) {
2583 free(pamh
->pam_conf_name
[i
]);
2584 pamh
->pam_conf_name
[i
] = NULL
;
2589 free_env(env_list
*pam_env
)
2593 free(pam_env
->name
);
2595 free(pam_env
->value
);
2601 * Internal convenience functions for Solaris PAM service modules.
2604 #include <libintl.h>
2605 #include <nl_types.h>
2610 typedef struct pam_msg_data
{
2616 * free storage for responses used in the call back "pam_conv" functions
2620 free_resp(int num_msg
, struct pam_response
*resp
)
2623 struct pam_response
*r
;
2627 for (i
= 0; i
< num_msg
; i
++, r
++) {
2629 /* clear before freeing -- may be a password */
2630 bzero(r
->resp
, strlen(r
->resp
));
2640 do_conv(pam_handle_t
*pamh
, int msg_style
, int num_msg
,
2641 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
], void *conv_apdp
,
2642 struct pam_response
*ret_respp
[])
2644 struct pam_message
*msg
;
2645 struct pam_message
*m
;
2649 struct pam_conv
*pam_convp
;
2651 if ((retcode
= pam_get_item(pamh
, PAM_CONV
,
2652 (void **)&pam_convp
)) != PAM_SUCCESS
) {
2657 * When pam_set_item() is called to set PAM_CONV and the
2658 * item is NULL, memset(pip->pi_addr, 0, size) is called.
2659 * So at this point, we should check whether pam_convp->conv
2662 if ((pam_convp
== NULL
) || (pam_convp
->conv
== NULL
))
2663 return (PAM_SYSTEM_ERR
);
2668 msg
= calloc(num_msg
, sizeof (struct pam_message
));
2670 return (PAM_BUF_ERR
);
2676 * fill out the message structure to display prompt message
2678 m
->msg_style
= msg_style
;
2679 m
->msg
= messages
[i
];
2680 pam_trace(PAM_DEBUG_CONV
,
2681 "pam_conv_msg(%p:%d[%d]=%s)",
2682 (void *)pamh
, msg_style
, i
, messages
[i
]);
2688 * The UNIX pam modules always calls __pam_get_authtok() and
2689 * __pam_display_msg() with a NULL pointer as the conv_apdp.
2690 * In case the conv_apdp is NULL and the pam_convp->appdata_ptr
2691 * is not NULL, we should pass the pam_convp->appdata_ptr
2692 * to the conversation function.
2694 if (conv_apdp
== NULL
&& pam_convp
->appdata_ptr
!= NULL
)
2695 conv_apdp
= pam_convp
->appdata_ptr
;
2698 * Call conv function to display the prompt.
2700 retcode
= (pam_convp
->conv
)(num_msg
, &msg
, ret_respp
, conv_apdp
);
2701 pam_trace(PAM_DEBUG_CONV
,
2702 "pam_conv_resp(%p pam_conv = %s) ret_respp = %p",
2703 (void *)pamh
, pam_strerror(pamh
, retcode
), (void *)ret_respp
);
2704 if (*ret_respp
== NULL
) {
2705 pam_trace(PAM_DEBUG_CONV
,
2706 "pam_conv_resp(%p No response requested)", (void *)pamh
);
2707 } else if ((pam_debug
& (PAM_DEBUG_CONV
| PAM_DEBUG_AUTHTOK
)) != 0) {
2708 struct pam_response
*r
= *ret_respp
;
2710 for (i
= 0; i
< num_msg
; i
++, r
++) {
2711 if (r
->resp
== NULL
) {
2712 pam_trace(PAM_DEBUG_CONV
,
2714 "[%d] NULL response string)",
2717 if (msg_style
== PAM_PROMPT_ECHO_OFF
) {
2719 pam_trace(PAM_DEBUG_AUTHTOK
,
2720 "pam_conv_resp(%p:[%d]=%s, "
2722 (void *)pamh
, i
, r
->resp
,
2725 pam_trace(PAM_DEBUG_CONV
,
2726 "pam_conv_resp(%p:[%d] len=%lu, "
2729 (ulong_t
)strlen(r
->resp
),
2732 pam_trace(PAM_DEBUG_CONV
,
2733 "pam_conv_resp(%p:[%d]=%s, "
2735 (void *)pamh
, i
, r
->resp
,
2748 * __pam_display_msg():
2749 * display message by calling the call back functions
2750 * provided by the application through "pam_conv" structure
2754 __pam_display_msg(pam_handle_t
*pamh
, int msg_style
, int num_msg
,
2755 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
], void *conv_apdp
)
2757 struct pam_response
*ret_respp
= NULL
;
2760 ret
= do_conv(pamh
, msg_style
, num_msg
, messages
,
2761 conv_apdp
, &ret_respp
);
2763 if (ret_respp
!= NULL
)
2764 free_resp(num_msg
, ret_respp
);
2770 * __pam_get_authtok()
2771 * retrieves a password of at most PASS_MAX length from the pam
2772 * handle (pam_get_item) or from the input stream (do_conv).
2774 * This function allocates memory for the new authtok.
2775 * Applications calling this function are responsible for
2776 * freeing this memory.
2781 * PAM_AUTHTOK - password is taken from pam handle (PAM_AUTHTOK)
2782 * PAM_OLDAUTHTOK - password is taken from pam handle (PAM_OLDAUTHTOK)
2787 * 0: Prompt for new passwd, do not even attempt
2788 * to store it in the pam handle.
2789 * PAM_AUTHTOK: Prompt for new passwd, store in pam handle as
2790 * PAM_AUTHTOK item if this value is not already set.
2791 * PAM_OLDAUTHTOK: Prompt for new passwd, store in pam handle as
2792 * PAM_OLDAUTHTOK item if this value is not
2796 __pam_get_authtok(pam_handle_t
*pamh
, int source
, int type
, char *prompt
,
2799 int error
= PAM_SYSTEM_ERR
;
2800 char *new_password
= NULL
;
2801 struct pam_response
*ret_resp
= NULL
;
2802 char messages
[PAM_MAX_NUM_MSG
][PAM_MAX_MSG_SIZE
];
2804 if ((*authtok
= calloc(PASS_MAX
+1, sizeof (char))) == NULL
)
2805 return (PAM_BUF_ERR
);
2808 prompt
= dgettext(TEXT_DOMAIN
, "password: ");
2813 /* get password from pam handle item list */
2817 case PAM_OLDAUTHTOK
:
2819 if ((error
= pam_get_item(pamh
, type
,
2820 (void **)&new_password
)) != PAM_SUCCESS
)
2823 if (new_password
== NULL
|| new_password
[0] == '\0') {
2827 (void) strlcpy(*authtok
, new_password
,
2832 __pam_log(LOG_AUTH
| LOG_ERR
,
2833 "__pam_get_authtok() invalid type: %d", type
);
2834 error
= PAM_SYMBOL_ERR
;
2841 * Prompt for new password and save in pam handle item list
2842 * if the that item is not already set.
2845 (void) strncpy(messages
[0], prompt
, sizeof (messages
[0]));
2846 if ((error
= do_conv(pamh
, PAM_PROMPT_ECHO_OFF
, 1, messages
,
2847 NULL
, &ret_resp
)) != PAM_SUCCESS
)
2850 if (ret_resp
->resp
== NULL
) {
2851 /* getpass didn't return anything */
2852 error
= PAM_SYSTEM_ERR
;
2856 /* save the new password if this item was NULL */
2858 if ((error
= pam_get_item(pamh
, type
,
2859 (void **)&new_password
)) != PAM_SUCCESS
) {
2860 free_resp(1, ret_resp
);
2863 if (new_password
== NULL
)
2864 (void) pam_set_item(pamh
, type
, ret_resp
->resp
);
2867 (void) strlcpy(*authtok
, ret_resp
->resp
, PASS_MAX
+1);
2868 free_resp(1, ret_resp
);
2871 __pam_log(LOG_AUTH
| LOG_ERR
,
2872 "__pam_get_authtok() invalid source: %d", source
);
2873 error
= PAM_SYMBOL_ERR
;
2877 return (PAM_SUCCESS
);
2880 bzero(*authtok
, PASS_MAX
+1);