Print this page
2947 initial /etc/pam.d cut


   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);