/* * Extracts given chains from a policy file. * * Returns the number of policy entries which were found for the specified * service and facility, or -1 if a system error occurred or a syntax * error was encountered. */ static int openpam_parse_chain(pam_handle_t *pamh, const char *service, pam_facility_t facility, FILE *f, const char *filename, openpam_style_t style) { pam_chain_t *this, **next; pam_facility_t fclt; pam_control_t ctlf; char *name, *servicename, *modulename; int count, lineno, ret, serrno; char **wordv, *word; int i, wordc; count = 0; this = NULL; name = NULL; lineno = 0; wordc = 0; wordv = NULL; while ((wordv = openpam_readlinev(f, &lineno, &wordc)) != NULL) { /* blank line? */ if (wordc == 0) { FREEV(wordc, wordv); continue; } i = 0; /* check service name if necessary */ if (style == pam_conf_style && strcmp(wordv[i++], service) != 0) { FREEV(wordc, wordv); continue; } /* check facility name */ if ((word = wordv[i++]) == NULL || (fclt = parse_facility_name(word)) == (pam_facility_t)-1) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid facility", filename, lineno); errno = EINVAL; goto fail; } if (facility != fclt && facility != PAM_FACILITY_ANY) { FREEV(wordc, wordv); continue; } /* check for "include" */ if ((word = wordv[i++]) != NULL && strcmp(word, "include") == 0) { if ((servicename = wordv[i++]) == NULL || !valid_service_name(servicename)) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid service name", filename, lineno); errno = EINVAL; goto fail; } if (wordv[i] != NULL) { openpam_log(PAM_LOG_ERROR, "%s(%d): garbage at end of line", filename, lineno); errno = EINVAL; goto fail; } ret = openpam_load_chain(pamh, servicename, fclt); FREEV(wordc, wordv); if (ret < 0) { /* * Bogus errno, but this ensures that the * outer loop does not just ignore the * error and keep searching. */ if (errno == ENOENT) errno = EINVAL; goto fail; } continue; } /* get control flag */ if (word == NULL || /* same word we compared to "include" */ (ctlf = parse_control_flag(word)) == (pam_control_t)-1) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid control flag", filename, lineno); errno = EINVAL; goto fail; } /* get module name */ if ((modulename = wordv[i++]) == NULL || !valid_module_name(modulename)) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid module name", filename, lineno); errno = EINVAL; goto fail; } /* allocate new entry */ if ((this = calloc(1, sizeof *this)) == NULL) goto syserr; this->flag = ctlf; /* load module */ if ((this->module = openpam_load_module(modulename)) == NULL) { if (errno == ENOENT) errno = ENOEXEC; goto fail; } /* * The remaining items in wordv are the module's * arguments. We could set this->optv = wordv + i, but * then free(this->optv) wouldn't work. Instead, we free * the words we've already consumed, shift the rest up, * and clear the tail end of the array. */ this->optc = wordc - i; for (i = 0; i < wordc - this->optc; ++i) { FREE(wordv[i]); } for (i = 0; i < this->optc; ++i) { wordv[i] = wordv[wordc - this->optc + i]; wordv[wordc - this->optc + i] = NULL; } this->optv = wordv; wordv = NULL; wordc = 0; /* hook it up */ for (next = &pamh->chains[fclt]; *next != NULL; next = &(*next)->next) /* nothing */ ; *next = this; this = NULL; ++count; } /* * The loop ended because openpam_readword() returned NULL, which * can happen for four different reasons: an I/O error (ferror(f) * is true), a memory allocation failure (ferror(f) is false, * feof(f) is false, errno is non-zero), the file ended with an * unterminated quote or backslash escape (ferror(f) is false, * feof(f) is true, errno is non-zero), or the end of the file was * reached without error (ferror(f) is false, feof(f) is true, * errno is zero). */ if (ferror(f) || errno != 0) goto syserr; if (!feof(f)) goto fail; fclose(f); return (count); syserr: serrno = errno; openpam_log(PAM_LOG_ERROR, "%s: %m", filename); errno = serrno; /* fall through */ fail: serrno = errno; if (this && this->optc && this->optv) FREEV(this->optc, this->optv); FREE(this); FREEV(wordc, wordv); FREE(wordv); FREE(name); fclose(f); errno = serrno; return (-1); }
/* * 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); }