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

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libpam/pam_framework.c
          +++ new/usr/src/lib/libpam/pam_framework.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
       24 + *
       25 + * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
  24   26   */
  25   27  
  26   28  #include <syslog.h>
  27   29  #include <dlfcn.h>
  28   30  #include <sys/types.h>
  29   31  #include <sys/stat.h>
  30   32  #include <stdlib.h>
  31   33  #include <strings.h>
  32   34  #include <malloc.h>
  33   35  #include <unistd.h>
↓ open down ↓ 39 lines elided ↑ open up ↑
  73   75  #if !defined(_LFS64_LARGEFILE)
  74   76  #define stat64  stat
  75   77  #endif  /* !defined(_LFS64_LARGEFILE) */
  76   78  
  77   79  /* functions to dynamically load modules */
  78   80  static int      load_modules(pam_handle_t *, int, char *, pamtab_t *);
  79   81  static void     *open_module(pam_handle_t *, char *);
  80   82  static int      load_function(void *, char *, int (**func)());
  81   83  
  82   84  /* functions to read and store the pam.conf configuration file */
  83      -static int      open_pam_conf(struct pam_fh **, pam_handle_t *, char *);
       85 +static int      open_pam_conf(struct pam_fh **, pam_handle_t *, char *, int);
  84   86  static void     close_pam_conf(struct pam_fh *);
  85      -static int      read_pam_conf(pam_handle_t *, char *);
       87 +static int      read_pam_conf(pam_handle_t *, char *, char *, int);
  86   88  static int      get_pam_conf_entry(struct pam_fh *, pam_handle_t *,
  87      -    pamtab_t **);
       89 +    pamtab_t **, char *, int);
  88   90  static char     *read_next_token(char **);
  89   91  static char     *nextline(struct pam_fh *, pam_handle_t *, int *);
  90   92  static int      verify_pam_conf(pamtab_t *, char *);
  91   93  
  92   94  /* functions to clean up and free memory */
  93   95  static void     clean_up(pam_handle_t *);
  94   96  static void     free_pamconf(pamtab_t *);
  95   97  static void     free_pam_conf_info(pam_handle_t *);
  96   98  static void     free_env(env_list *);
  97   99  
↓ open down ↓ 905 lines elided ↑ open up ↑
1003 1005  static int
1004 1006  run_stack(pam_handle_t *pamh, int flags, int type, int def_err, int ind,
1005 1007      char *function_name)
1006 1008  {
1007 1009          int     err = PAM_SYSTEM_ERR;  /* preset */
1008 1010          int     optional_error = 0;
1009 1011          int     required_error = 0;
1010 1012          int     success = 0;
1011 1013          pamtab_t *modulep;
1012 1014          int     (*sm_func)();
     1015 +        char    *service;
     1016 +        char    *service_file;
     1017 +        int     shardfile = 1;
1013 1018  
1014 1019          if (pamh == NULL)
1015 1020                  return (PAM_SYSTEM_ERR);
1016 1021  
1017      -        /* read initial entries from pam.conf */
1018      -        if ((err = read_pam_conf(pamh, PAM_CONFIG)) != PAM_SUCCESS) {
1019      -                return (err);
     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);
1020 1026          }
1021 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 +
1022 1047          if ((modulep =
1023 1048              pamh->pam_conf_info[pamh->include_depth][type]) == NULL) {
1024 1049                  __pam_log(LOG_AUTH | LOG_ERR, "%s no initial module present",
1025 1050                      pam_trace_cname(pamh));
1026 1051                  goto exit_return;
1027 1052          }
1028 1053  
1029 1054          pamh->pam_inmodule = WO_OK;     /* OK to get AUTHTOK */
1030 1055  include:
1031 1056          pam_trace(PAM_DEBUG_MODULE,
↓ open down ↓ 14 lines elided ↑ open up ↑
1046 1071                                      "run_stack: includes too deep %d "
1047 1072                                      "found trying to include %s from %s, %d "
1048 1073                                      "allowed", pamh->include_depth,
1049 1074                                      modulep->module_path, pamh->pam_conf_name
1050 1075                                      [PAM_MAX_INCLUDE] == NULL ? "NULL" :
1051 1076                                      pamh->pam_conf_name[PAM_MAX_INCLUDE],
1052 1077                                      PAM_MAX_INCLUDE);
1053 1078                                  goto exit_return;
1054 1079                          }
1055 1080                          if ((err = read_pam_conf(pamh,
1056      -                            modulep->module_path)) != PAM_SUCCESS) {
     1081 +                            modulep->module_path, service, shardfile))
     1082 +                            != PAM_SUCCESS) {
1057 1083                                  __pam_log(LOG_AUTH | LOG_ERR,
1058 1084                                      "run_stack[%d:%s]: can't read included "
1059 1085                                      "conf %s", pamh->include_depth,
1060 1086                                      pam_trace_cname(pamh),
1061 1087                                      modulep->module_path);
1062 1088                                  goto exit_return;
1063 1089                          }
1064 1090                          if ((modulep = pamh->pam_conf_info
1065 1091                              [pamh->include_depth][type]) == NULL) {
1066 1092                                  __pam_log(LOG_AUTH | LOG_ERR,
↓ open down ↓ 837 lines elided ↑ open up ↑
1904 1930  
1905 1931  /*
1906 1932   * Routines to read the pam.conf configuration file
1907 1933   */
1908 1934  
1909 1935  /*
1910 1936   * open_pam_conf - open the pam.conf config file
1911 1937   */
1912 1938  
1913 1939  static int
1914      -open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config)
     1940 +open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config,
     1941 +    int shardfile)
1915 1942  {
1916 1943          struct stat64   stb;
1917 1944          int             fd;
1918 1945  
1919 1946          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));
     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));
1924 1952                  return (0);
1925 1953          }
1926 1954          /* Check the ownership and file modes */
1927 1955          if (fstat64(fd, &stb) < 0) {
1928 1956                  __pam_log(LOG_AUTH | LOG_ALERT,
1929 1957                      "open_pam_conf[%d:%s]: stat(%s) failed: %s",
1930 1958                      pamh->include_depth, pam_trace_cname(pamh), config,
1931 1959                      strerror(errno));
1932 1960                  (void) close(fd);
1933 1961                  return (0);
↓ open down ↓ 47 lines elided ↑ open up ↑
1981 2009          (void) close(pam_fh->fconfig);
1982 2010          free(pam_fh);
1983 2011  }
1984 2012  
1985 2013  /*
1986 2014   * read_pam_conf - read in each entry in pam.conf and store info
1987 2015   *                 under the pam handle.
1988 2016   */
1989 2017  
1990 2018  static int
1991      -read_pam_conf(pam_handle_t *pamh, char *config)
     2019 +read_pam_conf(pam_handle_t *pamh, char *config, char *service, int shardfile)
1992 2020  {
1993 2021          struct pam_fh   *pam_fh;
1994 2022          pamtab_t        *pamentp;
1995 2023          pamtab_t        *tpament;
1996      -        char            *service;
1997 2024          int             error;
1998 2025          int             i = pamh->include_depth;        /* include depth */
     2026 +        int             j;
1999 2027          /*
2000 2028           * service types:
2001 2029           * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3)
2002 2030           */
2003 2031          int service_found[PAM_NUM_MODULE_TYPES+1] = {0, 0, 0, 0, 0};
2004 2032  
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 2033          pamh->pam_conf_name[i] = strdup(config);
2012 2034          pam_trace(PAM_DEBUG_CONF, "read_pam_conf[%d:%s](%p) open(%s)",
2013 2035              i, pam_trace_cname(pamh), (void *)pamh, config);
2014      -        if (open_pam_conf(&pam_fh, pamh, config) == 0) {
     2036 +        if (open_pam_conf(&pam_fh, pamh, config, shardfile) == 0) {
2015 2037                  return (PAM_SYSTEM_ERR);
2016 2038          }
2017 2039  
2018 2040          while ((error =
2019      -            get_pam_conf_entry(pam_fh, pamh, &pamentp)) == PAM_SUCCESS &&
2020      -            pamentp) {
     2041 +            get_pam_conf_entry(pam_fh, pamh, &pamentp, service, shardfile))
     2042 +            == PAM_SUCCESS && pamentp) {
2021 2043  
2022 2044                  /* See if entry is this service and valid */
2023 2045                  if (verify_pam_conf(pamentp, service)) {
2024 2046                          pam_trace(PAM_DEBUG_CONF,
2025 2047                              "read_pam_conf[%d:%s](%p): bad entry error %s",
2026 2048                              i, pam_trace_cname(pamh), (void *)pamh, service);
2027 2049  
2028 2050                          error = PAM_SYSTEM_ERR;
2029 2051                          free_pamconf(pamentp);
2030 2052                          goto out;
↓ open down ↓ 83 lines elided ↑ open up ↑
2114 2136                                  }
2115 2137                          } else {
2116 2138                                  /* irrelevant entry */
2117 2139                                  free_pamconf(pamentp);
2118 2140                          }
2119 2141                  } else {
2120 2142                          /* irrelevant entry */
2121 2143                          free_pamconf(pamentp);
2122 2144                  }
2123 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 +
2124 2184  out:
2125 2185          (void) close_pam_conf(pam_fh);
2126 2186          if (error != PAM_SUCCESS)
2127 2187                  free_pam_conf_info(pamh);
2128 2188          return (error);
2129 2189  }
2130 2190  
2131 2191  /*
2132 2192   * get_pam_conf_entry - get a pam.conf entry
2133 2193   */
2134 2194  
2135 2195  static int
2136      -get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam)
     2196 +get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam,
     2197 +    char *service, int shardfile)
2137 2198  {
2138 2199          char            *cp, *arg;
2139 2200          int             argc;
2140 2201          char            *tmp, *tmp_free;
2141 2202          int             i;
2142 2203          char            *current_line = NULL;
2143 2204          int             error = PAM_SYSTEM_ERR; /* preset to error */
2144 2205          int             err;
2145 2206  
2146 2207          /* get the next line from pam.conf */
↓ open down ↓ 11 lines elided ↑ open up ↑
2158 2219  
2159 2220          /* copy full line for error reporting */
2160 2221          if ((current_line = strdup(cp)) == NULL) {
2161 2222                  __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2162 2223                  goto out;
2163 2224          }
2164 2225  
2165 2226          pam_trace(PAM_DEBUG_CONF,
2166 2227              "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh), current_line);
2167 2228  
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;
     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 +                }
2174 2250          }
2175      -        if (((*pam)->pam_service = strdup(arg)) == 0) {
2176      -                __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2177      -                goto out;
2178      -        }
2179 2251  
2180 2252          /* get module type (e.g. authentication, acct mgmt) */
2181 2253          if ((arg = read_next_token(&cp)) == 0) {
2182 2254                  __pam_log(LOG_AUTH | LOG_CRIT,
2183 2255                      "illegal pam.conf[%s] entry: %s: missing MODULE TYPE",
2184 2256                      pam_trace_cname(pamh), current_line);
2185 2257                  (*pam)->pam_type = -1;  /* 0 is a valid value */
2186 2258                  goto getflag;
2187 2259          }
2188 2260          if (strcasecmp(arg, PAM_AUTH_NAME) == 0) {
↓ open down ↓ 44 lines elided ↑ open up ↑
2233 2305  getpath:
2234 2306          /* get module path (e.g. /usr/lib/security/pam_unix_auth.so.1) */
2235 2307          if ((arg = read_next_token(&cp)) == 0) {
2236 2308                  __pam_log(LOG_AUTH | LOG_CRIT,
2237 2309                      "illegal pam.conf[%s] entry: %s: missing MODULE PATH",
2238 2310                      pam_trace_cname(pamh), current_line);
2239 2311                  error = PAM_SUCCESS;    /* success */
2240 2312                  goto out;
2241 2313          }
2242 2314          if (arg[0] != '/') {
2243      -                size_t len;
     2315 +                int ret;
2244 2316                  /*
2245 2317                   * If module path does not start with "/", then
2246 2318                   * prepend PAM_LIB_DIR (/usr/lib/security/).
2247 2319                   */
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 2320                  if ((*pam)->pam_flag & PAM_INCLUDE) {
2255      -                        (void) snprintf((*pam)->module_path, len, "%s%s",
2256      -                            PAM_LIB_DIR, arg);
     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);
2257 2328                  } else {
2258      -                        (void) snprintf((*pam)->module_path, len, "%s%s%s",
     2329 +                        ret = asprintf(&(*pam)->module_path, "%s%s%s",
2259 2330                              PAM_LIB_DIR, PAM_ISA_DIR, arg);
2260 2331                  }
     2332 +                if (ret < 0) {
     2333 +                        __pam_log(LOG_AUTH | LOG_ERR,
     2334 +                            "asprintf: out of memory");
     2335 +                        goto out;
     2336 +                }
2261 2337          } else {
2262 2338                  /* Full path provided for module */
2263 2339                  char *isa;
2264 2340  
2265 2341                  /* Check for Instruction Set Architecture indicator */
2266 2342                  if ((isa = strstr(arg, PAM_ISA)) != NULL) {
2267 2343                          size_t len;
2268 2344                          len = strlen(arg) - (sizeof (PAM_ISA)-1) +
2269 2345                              sizeof (PAM_ISA_DIR);
2270 2346  
↓ open down ↓ 614 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX