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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <syslog.h>
27 #include <dlfcn.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <stdlib.h>
31 #include <strings.h>
32 #include <malloc.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <errno.h>
36
37 #include <security/pam_appl.h>
38 #include <security/pam_modules.h>
39 #include <sys/mman.h>
40
41 #include <libintl.h>
42
43 #include "pam_impl.h"
63 /* PAM_REPOSITORY */ "repository",
64 /* PAM_RESOURCE */ "resource",
65 /* PAM_AUSER */ "auser",
66 /* Undefined Items */
67 };
68
69 /*
70 * This extra definition is needed in order to build this library
71 * on pre-64-bit-aware systems.
72 */
73 #if !defined(_LFS64_LARGEFILE)
74 #define stat64 stat
75 #endif /* !defined(_LFS64_LARGEFILE) */
76
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)());
81
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 *,
87 pamtab_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 *);
91
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 *);
97
98 /* convenience functions for I18N/L10N communication */
99
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 **);
104
105 static int log_priority; /* pam_trace syslog priority & facility */
106 static int pam_debug = 0;
107
993 return (((struct session_module *)funcp)->pam_sm_close_session);
994 case PAM_CHAUTHTOK:
995 return (((struct password_module *)funcp)->pam_sm_chauthtok);
996 }
997 return (NULL);
998 }
999
1000 /*
1001 * Run through the PAM service module stack for the given module type.
1002 */
1003 static int
1004 run_stack(pam_handle_t *pamh, int flags, int type, int def_err, int ind,
1005 char *function_name)
1006 {
1007 int err = PAM_SYSTEM_ERR; /* preset */
1008 int optional_error = 0;
1009 int required_error = 0;
1010 int success = 0;
1011 pamtab_t *modulep;
1012 int (*sm_func)();
1013
1014 if (pamh == NULL)
1015 return (PAM_SYSTEM_ERR);
1016
1017 /* read initial entries from pam.conf */
1018 if ((err = read_pam_conf(pamh, PAM_CONFIG)) != PAM_SUCCESS) {
1019 return (err);
1020 }
1021
1022 if ((modulep =
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));
1026 goto exit_return;
1027 }
1028
1029 pamh->pam_inmodule = WO_OK; /* OK to get AUTHTOK */
1030 include:
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");
1035
1036 while (modulep != NULL) {
1037 if (modulep->pam_flag & PAM_INCLUDE) {
1038 /* save the return location */
1039 pamh->pam_conf_modulep[pamh->include_depth] =
1040 modulep->next;
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],
1052 PAM_MAX_INCLUDE);
1053 goto exit_return;
1054 }
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);
1062 goto exit_return;
1063 }
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);
1070 goto exit_return;
1071 }
1072 if (modulep->pam_flag & PAM_INCLUDE) {
1073 /* first line another include */
1074 goto include;
1075 }
1076 pam_trace(PAM_DEBUG_DEFAULT, "include[%d:%s]"
1894 errmsg = dlerror();
1895 __pam_log(LOG_AUTH | LOG_ERR, "dlsym failed %s: error %s",
1896 name, errmsg != NULL ? errmsg : "Unknown error");
1897 return (PAM_SYMBOL_ERR);
1898 }
1899
1900 pam_trace(PAM_DEBUG_DEFAULT,
1901 "load_function: successful load of %s", name);
1902 return (PAM_SUCCESS);
1903 }
1904
1905 /*
1906 * Routines to read the pam.conf configuration file
1907 */
1908
1909 /*
1910 * open_pam_conf - open the pam.conf config file
1911 */
1912
1913 static int
1914 open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config)
1915 {
1916 struct stat64 stb;
1917 int fd;
1918
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,
1923 strerror(errno));
1924 return (0);
1925 }
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,
1931 strerror(errno));
1932 (void) close(fd);
1933 return (0);
1934 }
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);
1939 (void) close(fd);
1971 }
1972
1973 /*
1974 * close_pam_conf - close pam.conf
1975 */
1976
1977 static void
1978 close_pam_conf(struct pam_fh *pam_fh)
1979 {
1980 (void) munmap(pam_fh->data, pam_fh->bufsize);
1981 (void) close(pam_fh->fconfig);
1982 free(pam_fh);
1983 }
1984
1985 /*
1986 * read_pam_conf - read in each entry in pam.conf and store info
1987 * under the pam handle.
1988 */
1989
1990 static int
1991 read_pam_conf(pam_handle_t *pamh, char *config)
1992 {
1993 struct pam_fh *pam_fh;
1994 pamtab_t *pamentp;
1995 pamtab_t *tpament;
1996 char *service;
1997 int error;
1998 int i = pamh->include_depth; /* include depth */
1999 /*
2000 * service types:
2001 * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3)
2002 */
2003 int service_found[PAM_NUM_MODULE_TYPES+1] = {0, 0, 0, 0, 0};
2004
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);
2009 }
2010
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);
2016 }
2017
2018 while ((error =
2019 get_pam_conf_entry(pam_fh, pamh, &pamentp)) == PAM_SUCCESS &&
2020 pamentp) {
2021
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);
2027
2028 error = PAM_SYSTEM_ERR;
2029 free_pamconf(pamentp);
2030 goto out;
2031 }
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) {
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;
2112 }
2113 tpament->next = pamentp;
2114 }
2115 } else {
2116 /* irrelevant entry */
2117 free_pamconf(pamentp);
2118 }
2119 } else {
2120 /* irrelevant entry */
2121 free_pamconf(pamentp);
2122 }
2123 }
2124 out:
2125 (void) close_pam_conf(pam_fh);
2126 if (error != PAM_SUCCESS)
2127 free_pam_conf_info(pamh);
2128 return (error);
2129 }
2130
2131 /*
2132 * get_pam_conf_entry - get a pam.conf entry
2133 */
2134
2135 static int
2136 get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam)
2137 {
2138 char *cp, *arg;
2139 int argc;
2140 char *tmp, *tmp_free;
2141 int i;
2142 char *current_line = NULL;
2143 int error = PAM_SYSTEM_ERR; /* preset to error */
2144 int err;
2145
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;
2150 *pam = NULL;
2151 goto out;
2152 }
2153
2154 if ((*pam = calloc(1, sizeof (pamtab_t))) == NULL) {
2155 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2156 goto out;
2157 }
2158
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");
2162 goto out;
2163 }
2164
2165 pam_trace(PAM_DEBUG_CONF,
2166 "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh), current_line);
2167
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);
2173 goto out;
2174 }
2175 if (((*pam)->pam_service = strdup(arg)) == 0) {
2176 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2177 goto out;
2178 }
2179
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 */
2186 goto getflag;
2187 }
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;
2196 } else {
2197 /* error */
2198 __pam_log(LOG_AUTH | LOG_CRIT,
2223 (*pam)->pam_flag = PAM_SUFFICIENT;
2224 } else {
2225 /* error */
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);
2231 }
2232
2233 getpath:
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 */
2240 goto out;
2241 }
2242 if (arg[0] != '/') {
2243 size_t len;
2244 /*
2245 * If module path does not start with "/", then
2246 * prepend PAM_LIB_DIR (/usr/lib/security/).
2247 */
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");
2252 goto out;
2253 }
2254 if ((*pam)->pam_flag & PAM_INCLUDE) {
2255 (void) snprintf((*pam)->module_path, len, "%s%s",
2256 PAM_LIB_DIR, arg);
2257 } else {
2258 (void) snprintf((*pam)->module_path, len, "%s%s%s",
2259 PAM_LIB_DIR, PAM_ISA_DIR, arg);
2260 }
2261 } else {
2262 /* Full path provided for module */
2263 char *isa;
2264
2265 /* Check for Instruction Set Architecture indicator */
2266 if ((isa = strstr(arg, PAM_ISA)) != NULL) {
2267 size_t len;
2268 len = strlen(arg) - (sizeof (PAM_ISA)-1) +
2269 sizeof (PAM_ISA_DIR);
2270
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");
2275 goto out;
2276 }
2277 *isa = '\000';
2278 isa += strlen(PAM_ISA);
2279 (void) snprintf((*pam)->module_path, len, "%s%s%s",
2280 arg, PAM_ISA_DIR, isa);
|
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
26 */
27
28 #include <syslog.h>
29 #include <dlfcn.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <stdlib.h>
33 #include <strings.h>
34 #include <malloc.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <errno.h>
38
39 #include <security/pam_appl.h>
40 #include <security/pam_modules.h>
41 #include <sys/mman.h>
42
43 #include <libintl.h>
44
45 #include "pam_impl.h"
65 /* PAM_REPOSITORY */ "repository",
66 /* PAM_RESOURCE */ "resource",
67 /* PAM_AUSER */ "auser",
68 /* Undefined Items */
69 };
70
71 /*
72 * This extra definition is needed in order to build this library
73 * on pre-64-bit-aware systems.
74 */
75 #if !defined(_LFS64_LARGEFILE)
76 #define stat64 stat
77 #endif /* !defined(_LFS64_LARGEFILE) */
78
79 /* functions to dynamically load modules */
80 static int load_modules(pam_handle_t *, int, char *, pamtab_t *);
81 static void *open_module(pam_handle_t *, char *);
82 static int load_function(void *, char *, int (**func)());
83
84 /* functions to read and store the pam.conf configuration file */
85 static int open_pam_conf(struct pam_fh **, pam_handle_t *, char *, int);
86 static void close_pam_conf(struct pam_fh *);
87 static int read_pam_conf(pam_handle_t *, char *, char *, int);
88 static int get_pam_conf_entry(struct pam_fh *, pam_handle_t *,
89 pamtab_t **, char *, int);
90 static char *read_next_token(char **);
91 static char *nextline(struct pam_fh *, pam_handle_t *, int *);
92 static int verify_pam_conf(pamtab_t *, char *);
93
94 /* functions to clean up and free memory */
95 static void clean_up(pam_handle_t *);
96 static void free_pamconf(pamtab_t *);
97 static void free_pam_conf_info(pam_handle_t *);
98 static void free_env(env_list *);
99
100 /* convenience functions for I18N/L10N communication */
101
102 static void free_resp(int, struct pam_response *);
103 static int do_conv(pam_handle_t *, int, int,
104 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *,
105 struct pam_response **);
106
107 static int log_priority; /* pam_trace syslog priority & facility */
108 static int pam_debug = 0;
109
995 return (((struct session_module *)funcp)->pam_sm_close_session);
996 case PAM_CHAUTHTOK:
997 return (((struct password_module *)funcp)->pam_sm_chauthtok);
998 }
999 return (NULL);
1000 }
1001
1002 /*
1003 * Run through the PAM service module stack for the given module type.
1004 */
1005 static int
1006 run_stack(pam_handle_t *pamh, int flags, int type, int def_err, int ind,
1007 char *function_name)
1008 {
1009 int err = PAM_SYSTEM_ERR; /* preset */
1010 int optional_error = 0;
1011 int required_error = 0;
1012 int success = 0;
1013 pamtab_t *modulep;
1014 int (*sm_func)();
1015 char *service;
1016 char *service_file;
1017 int shardfile = 1;
1018
1019 if (pamh == NULL)
1020 return (PAM_SYSTEM_ERR);
1021
1022 (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service);
1023 if (service == NULL || *service == '\0') {
1024 __pam_log(LOG_AUTH | LOG_ERR, "No service name");
1025 return (PAM_SYSTEM_ERR);
1026 }
1027
1028 /* read initial entries from /etc/pam.d/<service> */
1029 if (asprintf(&service_file, "%s%s", PAM_CONFIG_DIR, service) < 0)
1030 return (PAM_SYSTEM_ERR);
1031 if ((err = read_pam_conf(pamh, service_file, service, shardfile))
1032 != PAM_SUCCESS) {
1033 shardfile = 0;
1034 pam_trace(PAM_DEBUG_CONF, "run_stack[%d:%s]: can't read "
1035 "service-specific conf %s", pamh->include_depth,
1036 pam_trace_cname(pamh), modulep->module_path, service_file);
1037
1038 /* fall back to reading initial entries from pam.conf */
1039 if ((err = read_pam_conf(pamh, PAM_CONFIG, service, shardfile))
1040 != PAM_SUCCESS) {
1041 return (err);
1042 }
1043 }
1044 free(service_file);
1045 service_file = NULL;
1046
1047 if ((modulep =
1048 pamh->pam_conf_info[pamh->include_depth][type]) == NULL) {
1049 __pam_log(LOG_AUTH | LOG_ERR, "%s no initial module present",
1050 pam_trace_cname(pamh));
1051 goto exit_return;
1052 }
1053
1054 pamh->pam_inmodule = WO_OK; /* OK to get AUTHTOK */
1055 include:
1056 pam_trace(PAM_DEBUG_MODULE,
1057 "[%d:%s]:run_stack:%s(%p, %x): %s", pamh->include_depth,
1058 pam_trace_cname(pamh), function_name, (void *)pamh, flags,
1059 modulep ? modulep->module_path : "NULL");
1060
1061 while (modulep != NULL) {
1062 if (modulep->pam_flag & PAM_INCLUDE) {
1063 /* save the return location */
1064 pamh->pam_conf_modulep[pamh->include_depth] =
1065 modulep->next;
1066 pam_trace(PAM_DEBUG_MODULE,
1067 "setting for include[%d:%p]",
1068 pamh->include_depth, (void *)modulep->next);
1069 if (pamh->include_depth++ >= PAM_MAX_INCLUDE) {
1070 __pam_log(LOG_AUTH | LOG_ERR,
1071 "run_stack: includes too deep %d "
1072 "found trying to include %s from %s, %d "
1073 "allowed", pamh->include_depth,
1074 modulep->module_path, pamh->pam_conf_name
1075 [PAM_MAX_INCLUDE] == NULL ? "NULL" :
1076 pamh->pam_conf_name[PAM_MAX_INCLUDE],
1077 PAM_MAX_INCLUDE);
1078 goto exit_return;
1079 }
1080 if ((err = read_pam_conf(pamh,
1081 modulep->module_path, service, shardfile))
1082 != PAM_SUCCESS) {
1083 __pam_log(LOG_AUTH | LOG_ERR,
1084 "run_stack[%d:%s]: can't read included "
1085 "conf %s", pamh->include_depth,
1086 pam_trace_cname(pamh),
1087 modulep->module_path);
1088 goto exit_return;
1089 }
1090 if ((modulep = pamh->pam_conf_info
1091 [pamh->include_depth][type]) == NULL) {
1092 __pam_log(LOG_AUTH | LOG_ERR,
1093 "run_stack[%d:%s]: no include module "
1094 "present %s", pamh->include_depth,
1095 pam_trace_cname(pamh), function_name);
1096 goto exit_return;
1097 }
1098 if (modulep->pam_flag & PAM_INCLUDE) {
1099 /* first line another include */
1100 goto include;
1101 }
1102 pam_trace(PAM_DEBUG_DEFAULT, "include[%d:%s]"
1920 errmsg = dlerror();
1921 __pam_log(LOG_AUTH | LOG_ERR, "dlsym failed %s: error %s",
1922 name, errmsg != NULL ? errmsg : "Unknown error");
1923 return (PAM_SYMBOL_ERR);
1924 }
1925
1926 pam_trace(PAM_DEBUG_DEFAULT,
1927 "load_function: successful load of %s", name);
1928 return (PAM_SUCCESS);
1929 }
1930
1931 /*
1932 * Routines to read the pam.conf configuration file
1933 */
1934
1935 /*
1936 * open_pam_conf - open the pam.conf config file
1937 */
1938
1939 static int
1940 open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config,
1941 int shardfile)
1942 {
1943 struct stat64 stb;
1944 int fd;
1945
1946 if ((fd = open(config, O_RDONLY)) == -1) {
1947 if (!shardfile)
1948 __pam_log(LOG_AUTH | LOG_ALERT,
1949 "open_pam_conf[%d:%s]: open(%s) failed: %s",
1950 pamh->include_depth, pam_trace_cname(pamh), config,
1951 strerror(errno));
1952 return (0);
1953 }
1954 /* Check the ownership and file modes */
1955 if (fstat64(fd, &stb) < 0) {
1956 __pam_log(LOG_AUTH | LOG_ALERT,
1957 "open_pam_conf[%d:%s]: stat(%s) failed: %s",
1958 pamh->include_depth, pam_trace_cname(pamh), config,
1959 strerror(errno));
1960 (void) close(fd);
1961 return (0);
1962 }
1963 if (stb.st_uid != (uid_t)0) {
1964 __pam_log(LOG_AUTH | LOG_ALERT,
1965 "open_pam_conf[%d:%s]: Owner of %s is not root",
1966 pamh->include_depth, pam_trace_cname(pamh), config);
1967 (void) close(fd);
1999 }
2000
2001 /*
2002 * close_pam_conf - close pam.conf
2003 */
2004
2005 static void
2006 close_pam_conf(struct pam_fh *pam_fh)
2007 {
2008 (void) munmap(pam_fh->data, pam_fh->bufsize);
2009 (void) close(pam_fh->fconfig);
2010 free(pam_fh);
2011 }
2012
2013 /*
2014 * read_pam_conf - read in each entry in pam.conf and store info
2015 * under the pam handle.
2016 */
2017
2018 static int
2019 read_pam_conf(pam_handle_t *pamh, char *config, char *service, int shardfile)
2020 {
2021 struct pam_fh *pam_fh;
2022 pamtab_t *pamentp;
2023 pamtab_t *tpament;
2024 int error;
2025 int i = pamh->include_depth; /* include depth */
2026 int j;
2027 /*
2028 * service types:
2029 * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3)
2030 */
2031 int service_found[PAM_NUM_MODULE_TYPES+1] = {0, 0, 0, 0, 0};
2032
2033 pamh->pam_conf_name[i] = strdup(config);
2034 pam_trace(PAM_DEBUG_CONF, "read_pam_conf[%d:%s](%p) open(%s)",
2035 i, pam_trace_cname(pamh), (void *)pamh, config);
2036 if (open_pam_conf(&pam_fh, pamh, config, shardfile) == 0) {
2037 return (PAM_SYSTEM_ERR);
2038 }
2039
2040 while ((error =
2041 get_pam_conf_entry(pam_fh, pamh, &pamentp, service, shardfile))
2042 == PAM_SUCCESS && pamentp) {
2043
2044 /* See if entry is this service and valid */
2045 if (verify_pam_conf(pamentp, service)) {
2046 pam_trace(PAM_DEBUG_CONF,
2047 "read_pam_conf[%d:%s](%p): bad entry error %s",
2048 i, pam_trace_cname(pamh), (void *)pamh, service);
2049
2050 error = PAM_SYSTEM_ERR;
2051 free_pamconf(pamentp);
2052 goto out;
2053 }
2054 if (strcasecmp(pamentp->pam_service, service) == 0) {
2055 pam_trace(PAM_DEBUG_CONF,
2056 "read_pam_conf[%d:%s](%p): processing %s",
2057 i, pam_trace_cname(pamh), (void *)pamh, service);
2058 /* process first service entry */
2059 if (service_found[pamentp->pam_type + 1] == 0) {
2060 /* purge "other" entries */
2061 while ((tpament = pamh->pam_conf_info[i]
2062 [pamentp->pam_type]) != NULL) {
2126 /* append more "other" entries */
2127 pam_trace(PAM_DEBUG_CONF,
2128 "read_pam_conf(%p): adding more "
2129 "other[%d:%s][%s]", (void *)pamh, i,
2130 pam_trace_cname(pamh),
2131 pam_snames[pamentp->pam_type]);
2132 while (tpament->next != NULL) {
2133 tpament = tpament->next;
2134 }
2135 tpament->next = pamentp;
2136 }
2137 } else {
2138 /* irrelevant entry */
2139 free_pamconf(pamentp);
2140 }
2141 } else {
2142 /* irrelevant entry */
2143 free_pamconf(pamentp);
2144 }
2145 }
2146
2147 /*
2148 * If this is a shard file and we have no entries for this
2149 * module type (e.g. "account"), then generate a single
2150 * "include" rule for the shard file "other" as a fallback.
2151 */
2152 if (shardfile && strcasecmp(service, "other") != 0) {
2153 for (j = 0; j < PAM_NUM_MODULE_TYPES; j++) {
2154 if (service_found[j + 1] == 0 &&
2155 pamh->pam_conf_info[i][j] == NULL) {
2156 pamtab_t *pe = calloc(1, sizeof (pamtab_t));
2157
2158 pam_trace(PAM_DEBUG_CONF, "read_pam_conf(%p):"
2159 "falling back to \"other\" for module "
2160 "type \"%s\" in service \"%s\"",
2161 (void *)pamh, pam_snames[j], service);
2162 if (pe == NULL) {
2163 error = PAM_SYSTEM_ERR;
2164 __pam_log(LOG_AUTH | LOG_ERR,
2165 "calloc: out of memory");
2166 goto out;
2167 }
2168 pe->pam_service = strdup(service);
2169 pe->pam_type = j;
2170 pe->pam_flag = PAM_INCLUDE;
2171 if (asprintf(&pe->module_path, "%s%s",
2172 PAM_CONFIG_DIR, "other") < 0) {
2173 free(pe);
2174 error = PAM_SYSTEM_ERR;
2175 __pam_log(LOG_AUTH | LOG_ERR,
2176 "asprintf: out of memory");
2177 goto out;
2178 }
2179 pamh->pam_conf_info[i][j] = pe;
2180 }
2181 }
2182 }
2183
2184 out:
2185 (void) close_pam_conf(pam_fh);
2186 if (error != PAM_SUCCESS)
2187 free_pam_conf_info(pamh);
2188 return (error);
2189 }
2190
2191 /*
2192 * get_pam_conf_entry - get a pam.conf entry
2193 */
2194
2195 static int
2196 get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam,
2197 char *service, int shardfile)
2198 {
2199 char *cp, *arg;
2200 int argc;
2201 char *tmp, *tmp_free;
2202 int i;
2203 char *current_line = NULL;
2204 int error = PAM_SYSTEM_ERR; /* preset to error */
2205 int err;
2206
2207 /* get the next line from pam.conf */
2208 if ((cp = nextline(pam_fh, pamh, &err)) == NULL) {
2209 /* no more lines in pam.conf ==> return */
2210 error = PAM_SUCCESS;
2211 *pam = NULL;
2212 goto out;
2213 }
2214
2215 if ((*pam = calloc(1, sizeof (pamtab_t))) == NULL) {
2216 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2217 goto out;
2218 }
2219
2220 /* copy full line for error reporting */
2221 if ((current_line = strdup(cp)) == NULL) {
2222 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2223 goto out;
2224 }
2225
2226 pam_trace(PAM_DEBUG_CONF,
2227 "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh), current_line);
2228
2229 if (shardfile) {
2230 /*
2231 * If this is an /etc/pam.d shard file, then the service name
2232 * comes from the file name of the shard.
2233 */
2234 if (((*pam)->pam_service = strdup(service)) == 0) {
2235 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2236 goto out;
2237 }
2238 } else {
2239 /* get service name (e.g. login, su, passwd) */
2240 if ((arg = read_next_token(&cp)) == 0) {
2241 __pam_log(LOG_AUTH | LOG_CRIT,
2242 "illegal pam.conf[%s] entry: %s: missing SERVICE "
2243 "NAME", pam_trace_cname(pamh), current_line);
2244 goto out;
2245 }
2246 if (((*pam)->pam_service = strdup(arg)) == 0) {
2247 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2248 goto out;
2249 }
2250 }
2251
2252 /* get module type (e.g. authentication, acct mgmt) */
2253 if ((arg = read_next_token(&cp)) == 0) {
2254 __pam_log(LOG_AUTH | LOG_CRIT,
2255 "illegal pam.conf[%s] entry: %s: missing MODULE TYPE",
2256 pam_trace_cname(pamh), current_line);
2257 (*pam)->pam_type = -1; /* 0 is a valid value */
2258 goto getflag;
2259 }
2260 if (strcasecmp(arg, PAM_AUTH_NAME) == 0) {
2261 (*pam)->pam_type = PAM_AUTH_MODULE;
2262 } else if (strcasecmp(arg, PAM_ACCOUNT_NAME) == 0) {
2263 (*pam)->pam_type = PAM_ACCOUNT_MODULE;
2264 } else if (strcasecmp(arg, PAM_SESSION_NAME) == 0) {
2265 (*pam)->pam_type = PAM_SESSION_MODULE;
2266 } else if (strcasecmp(arg, PAM_PASSWORD_NAME) == 0) {
2267 (*pam)->pam_type = PAM_PASSWORD_MODULE;
2268 } else {
2269 /* error */
2270 __pam_log(LOG_AUTH | LOG_CRIT,
2295 (*pam)->pam_flag = PAM_SUFFICIENT;
2296 } else {
2297 /* error */
2298 __pam_log(LOG_AUTH | LOG_CRIT,
2299 "illegal pam.conf[%s] entry: %s",
2300 pam_trace_cname(pamh), current_line);
2301 __pam_log(LOG_AUTH | LOG_CRIT,
2302 "\tinvalid control flag: %s", arg);
2303 }
2304
2305 getpath:
2306 /* get module path (e.g. /usr/lib/security/pam_unix_auth.so.1) */
2307 if ((arg = read_next_token(&cp)) == 0) {
2308 __pam_log(LOG_AUTH | LOG_CRIT,
2309 "illegal pam.conf[%s] entry: %s: missing MODULE PATH",
2310 pam_trace_cname(pamh), current_line);
2311 error = PAM_SUCCESS; /* success */
2312 goto out;
2313 }
2314 if (arg[0] != '/') {
2315 int ret;
2316 /*
2317 * If module path does not start with "/", then
2318 * prepend PAM_LIB_DIR (/usr/lib/security/).
2319 */
2320 if ((*pam)->pam_flag & PAM_INCLUDE) {
2321 /*
2322 * If this is an /etc/pam.d shard, we want to get
2323 * included files from /etc/pam.d rather than
2324 * /usr/lib/security.
2325 */
2326 ret = asprintf(&(*pam)->module_path, "%s%s",
2327 (shardfile ? PAM_CONFIG_DIR : PAM_LIB_DIR), arg);
2328 } else {
2329 ret = asprintf(&(*pam)->module_path, "%s%s%s",
2330 PAM_LIB_DIR, PAM_ISA_DIR, arg);
2331 }
2332 if (ret < 0) {
2333 __pam_log(LOG_AUTH | LOG_ERR,
2334 "asprintf: out of memory");
2335 goto out;
2336 }
2337 } else {
2338 /* Full path provided for module */
2339 char *isa;
2340
2341 /* Check for Instruction Set Architecture indicator */
2342 if ((isa = strstr(arg, PAM_ISA)) != NULL) {
2343 size_t len;
2344 len = strlen(arg) - (sizeof (PAM_ISA)-1) +
2345 sizeof (PAM_ISA_DIR);
2346
2347 /* substitute the architecture dependent path */
2348 if (((*pam)->module_path = malloc(len)) == NULL) {
2349 __pam_log(LOG_AUTH | LOG_ERR,
2350 "strdup: out of memory");
2351 goto out;
2352 }
2353 *isa = '\000';
2354 isa += strlen(PAM_ISA);
2355 (void) snprintf((*pam)->module_path, len, "%s%s%s",
2356 arg, PAM_ISA_DIR, isa);
|