/*
 * 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);
}
示例#2
0
/*
 * 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);
}