/* * Extracts given chains from a policy file. */ static int openpam_read_chain(pam_handle_t *pamh, const char *service, pam_facility_t facility, const char *filename, openpam_style_t style) { pam_chain_t *this, **next; const char *p, *q; int count, i, lineno, ret; pam_facility_t fclt; pam_control_t ctlf; char *line, *name; FILE *f; if ((f = fopen(filename, "r")) == NULL) { openpam_log(errno == ENOENT ? PAM_LOG_LIBDEBUG : PAM_LOG_NOTICE, "%s: %m", filename); return (0); } this = NULL; count = lineno = 0; while ((line = openpam_readline(f, &lineno, NULL)) != NULL) { p = line; /* match service name */ if (style == pam_conf_style) { if (!match_word(p, service)) { FREE(line); continue; } p = next_word(p); } /* match facility name */ for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) if (match_word(p, _pam_facility_name[fclt])) break; if (fclt == PAM_NUM_FACILITIES) { openpam_log(PAM_LOG_NOTICE, "%s(%d): invalid facility '%.*s' (ignored)", filename, lineno, wordlen(p), p); goto fail; } if (facility != fclt && facility != PAM_FACILITY_ANY) { FREE(line); continue; } p = next_word(p); /* include other chain */ if (match_word(p, "include")) { p = next_word(p); if (*next_word(p) != '\0') openpam_log(PAM_LOG_NOTICE, "%s(%d): garbage at end of 'include' line", filename, lineno); if ((name = dup_word(p)) == NULL) goto syserr; ret = openpam_load_chain(pamh, name, fclt); FREE(name); if (ret < 0) goto fail; count += ret; FREE(line); continue; } /* allocate new entry */ if ((this = calloc(1, sizeof *this)) == NULL) goto syserr; /* control flag */ for (ctlf = 0; ctlf < PAM_NUM_CONTROL_FLAGS; ++ctlf) if (match_word(p, _pam_control_flag_name[ctlf])) break; if (ctlf == PAM_NUM_CONTROL_FLAGS) { openpam_log(PAM_LOG_ERROR, "%s(%d): invalid control flag '%.*s'", filename, lineno, wordlen(p), p); goto fail; } this->flag = ctlf; /* module name */ p = next_word(p); if (*p == '\0') { openpam_log(PAM_LOG_ERROR, "%s(%d): missing module name", filename, lineno); goto fail; } if ((name = dup_word(p)) == NULL) goto syserr; this->module = openpam_load_module(name); FREE(name); if (this->module == NULL) goto fail; /* module options */ p = q = next_word(p); while (*q != '\0') { ++this->optc; q = next_word(q); } this->optv = calloc(this->optc + 1, sizeof(char *)); if (this->optv == NULL) goto syserr; for (i = 0; i < this->optc; ++i) { if ((this->optv[i] = dup_word(p)) == NULL) goto syserr; p = next_word(p); } /* hook it up */ for (next = &pamh->chains[fclt]; *next != NULL; next = &(*next)->next) /* nothing */ ; *next = this; this = NULL; ++count; /* next please... */ FREE(line); } if (!feof(f)) goto syserr; fclose(f); return (count); syserr: openpam_log(PAM_LOG_ERROR, "%s: %m", filename); fail: FREE(this); FREE(line); fclose(f); 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); }