Print this page
2947 initial /etc/pam.d cut
*** 19,28 ****
--- 19,30 ----
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
*/
#include <syslog.h>
#include <dlfcn.h>
#include <sys/types.h>
*** 78,92 ****
static int load_modules(pam_handle_t *, int, char *, pamtab_t *);
static void *open_module(pam_handle_t *, char *);
static int load_function(void *, char *, int (**func)());
/* functions to read and store the pam.conf configuration file */
! static int open_pam_conf(struct pam_fh **, pam_handle_t *, char *);
static void close_pam_conf(struct pam_fh *);
! static int read_pam_conf(pam_handle_t *, char *);
static int get_pam_conf_entry(struct pam_fh *, pam_handle_t *,
! pamtab_t **);
static char *read_next_token(char **);
static char *nextline(struct pam_fh *, pam_handle_t *, int *);
static int verify_pam_conf(pamtab_t *, char *);
/* functions to clean up and free memory */
--- 80,94 ----
static int load_modules(pam_handle_t *, int, char *, pamtab_t *);
static void *open_module(pam_handle_t *, char *);
static int load_function(void *, char *, int (**func)());
/* functions to read and store the pam.conf configuration file */
! static int open_pam_conf(struct pam_fh **, pam_handle_t *, char *, int);
static void close_pam_conf(struct pam_fh *);
! static int read_pam_conf(pam_handle_t *, char *, char *, int);
static int get_pam_conf_entry(struct pam_fh *, pam_handle_t *,
! pamtab_t **, char *, int);
static char *read_next_token(char **);
static char *nextline(struct pam_fh *, pam_handle_t *, int *);
static int verify_pam_conf(pamtab_t *, char *);
/* functions to clean up and free memory */
*** 1008,1025 ****
int optional_error = 0;
int required_error = 0;
int success = 0;
pamtab_t *modulep;
int (*sm_func)();
if (pamh == NULL)
return (PAM_SYSTEM_ERR);
! /* read initial entries from pam.conf */
! if ((err = read_pam_conf(pamh, PAM_CONFIG)) != PAM_SUCCESS) {
return (err);
}
if ((modulep =
pamh->pam_conf_info[pamh->include_depth][type]) == NULL) {
__pam_log(LOG_AUTH | LOG_ERR, "%s no initial module present",
pam_trace_cname(pamh));
--- 1010,1050 ----
int optional_error = 0;
int required_error = 0;
int success = 0;
pamtab_t *modulep;
int (*sm_func)();
+ char *service;
+ char *service_file;
+ int shardfile = 1;
if (pamh == NULL)
return (PAM_SYSTEM_ERR);
! (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service);
! if (service == NULL || *service == '\0') {
! __pam_log(LOG_AUTH | LOG_ERR, "No service name");
! return (PAM_SYSTEM_ERR);
! }
!
! /* read initial entries from /etc/pam.d/<service> */
! if (asprintf(&service_file, "%s%s", PAM_CONFIG_DIR, service) < 0)
! return (PAM_SYSTEM_ERR);
! if ((err = read_pam_conf(pamh, service_file, service, shardfile))
! != PAM_SUCCESS) {
! shardfile = 0;
! pam_trace(PAM_DEBUG_CONF, "run_stack[%d:%s]: can't read "
! "service-specific conf %s", pamh->include_depth,
! pam_trace_cname(pamh), modulep->module_path, service_file);
!
! /* fall back to reading initial entries from pam.conf */
! if ((err = read_pam_conf(pamh, PAM_CONFIG, service, shardfile))
! != PAM_SUCCESS) {
return (err);
}
+ }
+ free(service_file);
+ service_file = NULL;
if ((modulep =
pamh->pam_conf_info[pamh->include_depth][type]) == NULL) {
__pam_log(LOG_AUTH | LOG_ERR, "%s no initial module present",
pam_trace_cname(pamh));
*** 1051,1061 ****
pamh->pam_conf_name[PAM_MAX_INCLUDE],
PAM_MAX_INCLUDE);
goto exit_return;
}
if ((err = read_pam_conf(pamh,
! modulep->module_path)) != PAM_SUCCESS) {
__pam_log(LOG_AUTH | LOG_ERR,
"run_stack[%d:%s]: can't read included "
"conf %s", pamh->include_depth,
pam_trace_cname(pamh),
modulep->module_path);
--- 1076,1087 ----
pamh->pam_conf_name[PAM_MAX_INCLUDE],
PAM_MAX_INCLUDE);
goto exit_return;
}
if ((err = read_pam_conf(pamh,
! modulep->module_path, service, shardfile))
! != PAM_SUCCESS) {
__pam_log(LOG_AUTH | LOG_ERR,
"run_stack[%d:%s]: can't read included "
"conf %s", pamh->include_depth,
pam_trace_cname(pamh),
modulep->module_path);
*** 1909,1924 ****
/*
* open_pam_conf - open the pam.conf config file
*/
static int
! open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config)
{
struct stat64 stb;
int fd;
if ((fd = open(config, O_RDONLY)) == -1) {
__pam_log(LOG_AUTH | LOG_ALERT,
"open_pam_conf[%d:%s]: open(%s) failed: %s",
pamh->include_depth, pam_trace_cname(pamh), config,
strerror(errno));
return (0);
--- 1935,1952 ----
/*
* open_pam_conf - open the pam.conf config file
*/
static int
! open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config,
! int shardfile)
{
struct stat64 stb;
int fd;
if ((fd = open(config, O_RDONLY)) == -1) {
+ if (!shardfile)
__pam_log(LOG_AUTH | LOG_ALERT,
"open_pam_conf[%d:%s]: open(%s) failed: %s",
pamh->include_depth, pam_trace_cname(pamh), config,
strerror(errno));
return (0);
*** 1986,2025 ****
* read_pam_conf - read in each entry in pam.conf and store info
* under the pam handle.
*/
static int
! read_pam_conf(pam_handle_t *pamh, char *config)
{
struct pam_fh *pam_fh;
pamtab_t *pamentp;
pamtab_t *tpament;
- char *service;
int error;
int i = pamh->include_depth; /* include depth */
/*
* service types:
* error (-1), "auth" (0), "account" (1), "session" (2), "password" (3)
*/
int service_found[PAM_NUM_MODULE_TYPES+1] = {0, 0, 0, 0, 0};
- (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service);
- if (service == NULL || *service == '\0') {
- __pam_log(LOG_AUTH | LOG_ERR, "No service name");
- return (PAM_SYSTEM_ERR);
- }
-
pamh->pam_conf_name[i] = strdup(config);
pam_trace(PAM_DEBUG_CONF, "read_pam_conf[%d:%s](%p) open(%s)",
i, pam_trace_cname(pamh), (void *)pamh, config);
! if (open_pam_conf(&pam_fh, pamh, config) == 0) {
return (PAM_SYSTEM_ERR);
}
while ((error =
! get_pam_conf_entry(pam_fh, pamh, &pamentp)) == PAM_SUCCESS &&
! pamentp) {
/* See if entry is this service and valid */
if (verify_pam_conf(pamentp, service)) {
pam_trace(PAM_DEBUG_CONF,
"read_pam_conf[%d:%s](%p): bad entry error %s",
--- 2014,2047 ----
* read_pam_conf - read in each entry in pam.conf and store info
* under the pam handle.
*/
static int
! read_pam_conf(pam_handle_t *pamh, char *config, char *service, int shardfile)
{
struct pam_fh *pam_fh;
pamtab_t *pamentp;
pamtab_t *tpament;
int error;
int i = pamh->include_depth; /* include depth */
+ int j;
/*
* service types:
* error (-1), "auth" (0), "account" (1), "session" (2), "password" (3)
*/
int service_found[PAM_NUM_MODULE_TYPES+1] = {0, 0, 0, 0, 0};
pamh->pam_conf_name[i] = strdup(config);
pam_trace(PAM_DEBUG_CONF, "read_pam_conf[%d:%s](%p) open(%s)",
i, pam_trace_cname(pamh), (void *)pamh, config);
! if (open_pam_conf(&pam_fh, pamh, config, shardfile) == 0) {
return (PAM_SYSTEM_ERR);
}
while ((error =
! get_pam_conf_entry(pam_fh, pamh, &pamentp, service, shardfile))
! == PAM_SUCCESS && pamentp) {
/* See if entry is this service and valid */
if (verify_pam_conf(pamentp, service)) {
pam_trace(PAM_DEBUG_CONF,
"read_pam_conf[%d:%s](%p): bad entry error %s",
*** 2119,2128 ****
--- 2141,2188 ----
} else {
/* irrelevant entry */
free_pamconf(pamentp);
}
}
+
+ /*
+ * If this is a shard file and we have no entries for this
+ * module type (e.g. "account"), then generate a single
+ * "include" rule for the shard file "other" as a fallback.
+ */
+ if (shardfile && strcasecmp(service, "other") != 0) {
+ for (j = 0; j < PAM_NUM_MODULE_TYPES; j++) {
+ if (service_found[j + 1] == 0 &&
+ pamh->pam_conf_info[i][j] == NULL) {
+ pamtab_t *pe = calloc(1, sizeof (pamtab_t));
+
+ pam_trace(PAM_DEBUG_CONF, "read_pam_conf(%p):"
+ "falling back to \"other\" for module "
+ "type \"%s\" in service \"%s\"",
+ (void *)pamh, pam_snames[j], service);
+ if (pe == NULL) {
+ error = PAM_SYSTEM_ERR;
+ __pam_log(LOG_AUTH | LOG_ERR,
+ "calloc: out of memory");
+ goto out;
+ }
+ pe->pam_service = strdup(service);
+ pe->pam_type = j;
+ pe->pam_flag = PAM_INCLUDE;
+ if (asprintf(&pe->module_path, "%s%s",
+ PAM_CONFIG_DIR, "other") < 0) {
+ free(pe);
+ error = PAM_SYSTEM_ERR;
+ __pam_log(LOG_AUTH | LOG_ERR,
+ "asprintf: out of memory");
+ goto out;
+ }
+ pamh->pam_conf_info[i][j] = pe;
+ }
+ }
+ }
+
out:
(void) close_pam_conf(pam_fh);
if (error != PAM_SUCCESS)
free_pam_conf_info(pamh);
return (error);
*** 2131,2141 ****
/*
* get_pam_conf_entry - get a pam.conf entry
*/
static int
! get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam)
{
char *cp, *arg;
int argc;
char *tmp, *tmp_free;
int i;
--- 2191,2202 ----
/*
* get_pam_conf_entry - get a pam.conf entry
*/
static int
! get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam,
! char *service, int shardfile)
{
char *cp, *arg;
int argc;
char *tmp, *tmp_free;
int i;
*** 2163,2183 ****
}
pam_trace(PAM_DEBUG_CONF,
"pam.conf[%s] entry:\t%s", pam_trace_cname(pamh), current_line);
/* get service name (e.g. login, su, passwd) */
if ((arg = read_next_token(&cp)) == 0) {
__pam_log(LOG_AUTH | LOG_CRIT,
! "illegal pam.conf[%s] entry: %s: missing SERVICE NAME",
! pam_trace_cname(pamh), current_line);
goto out;
}
if (((*pam)->pam_service = strdup(arg)) == 0) {
__pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
goto out;
}
/* get module type (e.g. authentication, acct mgmt) */
if ((arg = read_next_token(&cp)) == 0) {
__pam_log(LOG_AUTH | LOG_CRIT,
"illegal pam.conf[%s] entry: %s: missing MODULE TYPE",
--- 2224,2255 ----
}
pam_trace(PAM_DEBUG_CONF,
"pam.conf[%s] entry:\t%s", pam_trace_cname(pamh), current_line);
+ if (shardfile) {
+ /*
+ * If this is an /etc/pam.d shard file, then the service name
+ * comes from the file name of the shard.
+ */
+ if (((*pam)->pam_service = strdup(service)) == 0) {
+ __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
+ goto out;
+ }
+ } else {
/* get service name (e.g. login, su, passwd) */
if ((arg = read_next_token(&cp)) == 0) {
__pam_log(LOG_AUTH | LOG_CRIT,
! "illegal pam.conf[%s] entry: %s: missing SERVICE "
! "NAME", pam_trace_cname(pamh), current_line);
goto out;
}
if (((*pam)->pam_service = strdup(arg)) == 0) {
__pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
goto out;
}
+ }
/* get module type (e.g. authentication, acct mgmt) */
if ((arg = read_next_token(&cp)) == 0) {
__pam_log(LOG_AUTH | LOG_CRIT,
"illegal pam.conf[%s] entry: %s: missing MODULE TYPE",
*** 2238,2265 ****
pam_trace_cname(pamh), current_line);
error = PAM_SUCCESS; /* success */
goto out;
}
if (arg[0] != '/') {
! size_t len;
/*
* If module path does not start with "/", then
* prepend PAM_LIB_DIR (/usr/lib/security/).
*/
- /* sizeof (PAM_LIB_DIR) has room for '\0' */
- len = sizeof (PAM_LIB_DIR) + sizeof (PAM_ISA_DIR) + strlen(arg);
- if (((*pam)->module_path = malloc(len)) == NULL) {
- __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
- goto out;
- }
if ((*pam)->pam_flag & PAM_INCLUDE) {
! (void) snprintf((*pam)->module_path, len, "%s%s",
! PAM_LIB_DIR, arg);
} else {
! (void) snprintf((*pam)->module_path, len, "%s%s%s",
PAM_LIB_DIR, PAM_ISA_DIR, arg);
}
} else {
/* Full path provided for module */
char *isa;
/* Check for Instruction Set Architecture indicator */
--- 2310,2341 ----
pam_trace_cname(pamh), current_line);
error = PAM_SUCCESS; /* success */
goto out;
}
if (arg[0] != '/') {
! int ret;
/*
* If module path does not start with "/", then
* prepend PAM_LIB_DIR (/usr/lib/security/).
*/
if ((*pam)->pam_flag & PAM_INCLUDE) {
! /*
! * If this is an /etc/pam.d shard, we want to get
! * included files from /etc/pam.d rather than
! * /usr/lib/security.
! */
! ret = asprintf(&(*pam)->module_path, "%s%s",
! (shardfile ? PAM_CONFIG_DIR : PAM_LIB_DIR), arg);
} else {
! ret = asprintf(&(*pam)->module_path, "%s%s%s",
PAM_LIB_DIR, PAM_ISA_DIR, arg);
}
+ if (ret < 0) {
+ __pam_log(LOG_AUTH | LOG_ERR,
+ "asprintf: out of memory");
+ goto out;
+ }
} else {
/* Full path provided for module */
char *isa;
/* Check for Instruction Set Architecture indicator */