static void * try_dlopen(const char *modfn, int *error) { void *dlh; int fd; openpam_log(PAM_LOG_LIBDEBUG, "dlopen(%s)", modfn); if ((fd = open(modfn, O_RDONLY)) < 0) { if (errno != ENOENT) openpam_log(PAM_LOG_ERROR, "%s: %m", modfn); return (NULL); } if (OPENPAM_FEATURE(VERIFY_MODULE_FILE) && openpam_check_desc_owner_perms(modfn, fd) != 0) { close(fd); return (NULL); } if ((dlh = fdlopen(fd, RTLD_NOW)) == NULL) { openpam_log(PAM_LOG_ERROR, "%s: %s", modfn, dlerror()); close(fd); errno = 0; return (NULL); } close(fd); return (dlh); }
/* * Read the specified chains from the specified file. * * Returns 0 if the file exists but does not contain any matching lines. * * Returns -1 and sets errno to ENOENT if the file does not exist. * * Returns -1 and sets errno to some other non-zero value if the file * exists but is unsafe or unreadable, or an I/O error occurs. */ static int openpam_load_file(pam_handle_t *pamh, const char *service, pam_facility_t facility, const char *filename, openpam_style_t style) { FILE *f; int ret, serrno; /* attempt to open the file */ if ((f = fopen(filename, "r")) == NULL) { serrno = errno; openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_ERROR, "%s: %m", filename); errno = serrno; RETURNN(-1); } else { openpam_log(PAM_LOG_DEBUG, "found %s", filename); } /* verify type, ownership and permissions */ if (OPENPAM_FEATURE(VERIFY_POLICY_FILE) && openpam_check_desc_owner_perms(filename, fileno(f)) != 0) { /* already logged the cause */ serrno = errno; fclose(f); errno = serrno; RETURNN(-1); } /* parse the file */ ret = openpam_parse_chain(pamh, service, facility, f, filename, style); RETURNN(ret); }
/* * Extracts given chains from a policy file. */ static int openpam_parse_chain(pam_handle_t *pamh, const char *service, pam_facility_t facility, const char *filename, openpam_style_t style) { pam_chain_t *this, **next; pam_facility_t fclt; pam_control_t ctlf; char *line0, *line, *str, *name; char *option, **optv; int len, lineno, ret; FILE *f; if ((f = fopen(filename, "r")) == NULL) { openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_NOTICE, "%s: %m", filename); return (PAM_SUCCESS); } if (openpam_check_desc_owner_perms(filename, fileno(f)) != 0) { fclose(f); return (PAM_SYSTEM_ERR); } this = NULL; name = NULL; lineno = 0; while ((line0 = line = openpam_readline(f, &lineno, NULL)) != NULL) { /* get service name if necessary */ if (style == pam_conf_style) { if ((len = parse_service_name(&line, &str)) == 0) { openpam_log(PAM_LOG_NOTICE, "%s(%d): invalid service name (ignored)", filename, lineno); FREE(line0); continue; } if (strlcmp(service, str, len) != 0) { FREE(line0); continue; } } /* get facility name */ if ((fclt = parse_facility_name(&line)) == (pam_facility_t)-1) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid facility", filename, lineno); goto fail; } if (facility != fclt && facility != PAM_FACILITY_ANY) { FREE(line0); continue; } /* check for "include" */ if (parse_include(&line)) { if ((len = parse_service_name(&line, &str)) == 0) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid filename", filename, lineno); goto fail; } if ((name = strndup(str, len)) == NULL) goto syserr; if (parse_eol(&line) != 0) { openpam_log(PAM_LOG_ERROR, "%s(%d): garbage at end of line", filename, lineno); goto fail; } ret = openpam_load_chain(pamh, name, fclt); FREE(name); if (ret != PAM_SUCCESS) goto fail; FREE(line0); continue; } /* get control flag */ if ((ctlf = parse_control_flag(&line)) == (pam_control_t)-1) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid control flag", filename, lineno); goto fail; } /* get module name */ if ((len = parse_filename(&line, &str)) == 0) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid module name", filename, lineno); goto fail; } if ((name = strndup(str, len)) == NULL) goto syserr; /* allocate new entry */ if ((this = calloc(1, sizeof *this)) == NULL) goto syserr; this->flag = ctlf; /* get module options */ if ((this->optv = malloc(sizeof *optv)) == NULL) goto syserr; this->optc = 0; while ((option = parse_option(&line)) != NULL) { optv = realloc(this->optv, (this->optc + 2) * sizeof *optv); if (optv == NULL) goto syserr; this->optv = optv; this->optv[this->optc++] = option; } this->optv[this->optc] = NULL; if (*line != '\0') { openpam_log(PAM_LOG_ERROR, "%s(%d): syntax error in module options", filename, lineno); goto fail; } /* load module */ this->module = openpam_load_module(name); FREE(name); if (this->module == NULL) goto fail; /* hook it up */ for (next = &pamh->chains[fclt]; *next != NULL; next = &(*next)->next) /* nothing */ ; *next = this; this = NULL; /* next please... */ FREE(line0); } if (!feof(f)) goto syserr; fclose(f); return (PAM_SUCCESS); syserr: openpam_log(PAM_LOG_ERROR, "%s: %m", filename); fail: if (this && this->optc) { while (this->optc--) FREE(this->optv[this->optc]); FREE(this->optv); } FREE(this); FREE(line0); FREE(name); fclose(f); return (PAM_SYSTEM_ERR); }