Major overhaul of the policy parser to support quoted option values. As a
bonus, it should now be much easier to read and understand. This also changes the way options are stored: they are now stored as a list of { key, value } pairs rather than "key=value" strings. git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/trunk@478 185d5e19-27fe-0310-9dcf-9bff6b9f3609
This commit is contained in:
parent
11b10d0991
commit
55f6a50684
|
@ -48,6 +48,7 @@
|
|||
#include <security/pam_appl.h>
|
||||
|
||||
#include "openpam_impl.h"
|
||||
#include "openpam_strlcmp.h"
|
||||
|
||||
const char *pam_facility_name[PAM_NUM_FACILITIES] = {
|
||||
[PAM_ACCOUNT] = "account",
|
||||
|
@ -67,81 +68,301 @@ const char *pam_control_flag_name[PAM_NUM_CONTROL_FLAGS] = {
|
|||
static int openpam_load_chain(pam_handle_t *, const char *, pam_facility_t);
|
||||
|
||||
/*
|
||||
* Matches a word against the first one in a string.
|
||||
* Returns non-zero if they match.
|
||||
* Evaluates to non-zero if the argument is a linear whitespace character.
|
||||
*/
|
||||
#define is_lws(ch) \
|
||||
(ch == ' ' || ch == '\t')
|
||||
|
||||
/*
|
||||
* Evaluates to non-zero if the argument is a printable ASCII character.
|
||||
* Assumes that the execution character set is a superset of ASCII.
|
||||
*/
|
||||
#define is_p(ch) \
|
||||
(ch >= '!' && ch <= '~')
|
||||
|
||||
/*
|
||||
* Returns non-zero if the argument belongs to the POSIX Portable Filename
|
||||
* Character Set. Assumes that the execution character set is a superset
|
||||
* of ASCII.
|
||||
*/
|
||||
#define is_pfcs(ch) \
|
||||
((ch >= '0' && ch <= '9') || \
|
||||
(ch >= 'A' && ch <= 'Z') || \
|
||||
(ch >= 'a' && ch <= 'z') || \
|
||||
ch == '.' || ch == '_' || ch == '-')
|
||||
|
||||
/*
|
||||
* Parse the service name.
|
||||
*
|
||||
* Returns the length of the service name, or 0 if the end of the string
|
||||
* was reached or a disallowed non-whitespace character was encountered.
|
||||
*
|
||||
* If parse_service_name() is successful, it updates *service to point to
|
||||
* the first character of the service name and *line to point one
|
||||
* character past the end. If it reaches the end of the string, it
|
||||
* updates *line to point to the terminating NUL character and leaves
|
||||
* *service unmodified. In all other cases, it leaves both *line and
|
||||
* *service unmodified.
|
||||
*
|
||||
* Allowed characters are all characters in the POSIX portable filename
|
||||
* character set.
|
||||
*/
|
||||
static int
|
||||
match_word(const char *str, const char *word)
|
||||
parse_service_name(char **line, char **service)
|
||||
{
|
||||
char *b, *e;
|
||||
|
||||
while (*str && tolower(*str) == tolower(*word))
|
||||
++str, ++word;
|
||||
return ((*str == ' ' || *str == '\0') && *word == '\0');
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a pointer to the next word (or the final NUL) in a string.
|
||||
*/
|
||||
static const char *
|
||||
next_word(const char *str)
|
||||
{
|
||||
|
||||
/* skip current word */
|
||||
while (*str && *str != ' ')
|
||||
++str;
|
||||
/* skip whitespace */
|
||||
while (*str == ' ')
|
||||
++str;
|
||||
return (str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a malloc()ed copy of the first word in a string.
|
||||
*/
|
||||
static char *
|
||||
dup_word(const char *str)
|
||||
{
|
||||
const char *end;
|
||||
char *word;
|
||||
|
||||
for (end = str; *end && *end != ' '; ++end)
|
||||
for (b = *line; *b && is_lws(*b); ++b)
|
||||
/* nothing */ ;
|
||||
if (asprintf(&word, "%.*s", (int)(end - str), str) < 0)
|
||||
return (NULL);
|
||||
return (word);
|
||||
if (!*b) {
|
||||
*line = b;
|
||||
return (0);
|
||||
}
|
||||
for (e = b; *e && !is_lws(*e); ++e)
|
||||
if (!is_pfcs(*e))
|
||||
return (0);
|
||||
if (e == b)
|
||||
return (0);
|
||||
*line = e;
|
||||
*service = b;
|
||||
return (e - b);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the length of the first word in a string.
|
||||
* Parse the facility name.
|
||||
*
|
||||
* Returns the corresponding pam_facility_t value, or -1 if the end of the
|
||||
* string was reached, a disallowed non-whitespace character was
|
||||
* encountered, or the first word was not a recognized facility name.
|
||||
*
|
||||
* If parse_facility_name() is successful, it updates *line to point one
|
||||
* character past the end of the facility name. If it reaches the end of
|
||||
* the string, it updates *line to point to the terminating NUL character.
|
||||
* In all other cases, it leaves *line unmodified.
|
||||
*/
|
||||
static int
|
||||
wordlen(const char *str)
|
||||
static pam_facility_t
|
||||
parse_facility_name(char **line)
|
||||
{
|
||||
char *b, *e;
|
||||
int i;
|
||||
|
||||
for (i = 0; str[i] && str[i] != ' '; ++i)
|
||||
for (b = *line; *b && is_lws(*b); ++b)
|
||||
/* nothing */ ;
|
||||
if (!*b) {
|
||||
*line = b;
|
||||
return ((pam_facility_t)-1);
|
||||
}
|
||||
for (e = b; *e && !is_lws(*e); ++e)
|
||||
/* nothing */ ;
|
||||
if (e == b)
|
||||
return ((pam_facility_t)-1);
|
||||
for (i = 0; i < PAM_NUM_FACILITIES; ++i)
|
||||
if (strlcmp(pam_facility_name[i], b, e - b) == 0)
|
||||
break;
|
||||
if (i == PAM_NUM_FACILITIES)
|
||||
return ((pam_facility_t)-1);
|
||||
*line = e;
|
||||
return (i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the word "include".
|
||||
*
|
||||
* If the next word on the line is "include", parse_include() updates
|
||||
* *line to point one character past "include" and returns 1. Otherwise,
|
||||
* it leaves *line unmodified and returns 0.
|
||||
*/
|
||||
static int
|
||||
parse_include(char **line)
|
||||
{
|
||||
char *b, *e;
|
||||
|
||||
for (b = *line; *b && is_lws(*b); ++b)
|
||||
/* nothing */ ;
|
||||
if (!*b) {
|
||||
*line = b;
|
||||
return (-1);
|
||||
}
|
||||
for (e = b; *e && !is_lws(*e); ++e)
|
||||
/* nothing */ ;
|
||||
if (e == b)
|
||||
return (0);
|
||||
if (strlcmp("include", b, e - b) != 0)
|
||||
return (0);
|
||||
*line = e;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the control flag.
|
||||
*
|
||||
* Returns the corresponding pam_control_t value, or -1 if the end of the
|
||||
* string was reached, a disallowed non-whitespace character was
|
||||
* encountered, or the first word was not a recognized control flag.
|
||||
*
|
||||
* If parse_control_flag() is successful, it updates *line to point one
|
||||
* character past the end of the control flag. If it reaches the end of
|
||||
* the string, it updates *line to point to the terminating NUL character.
|
||||
* In all other cases, it leaves *line unmodified.
|
||||
*/
|
||||
static pam_control_t
|
||||
parse_control_flag(char **line)
|
||||
{
|
||||
char *b, *e;
|
||||
int i;
|
||||
|
||||
for (b = *line; *b && is_lws(*b); ++b)
|
||||
/* nothing */ ;
|
||||
if (!*b) {
|
||||
*line = b;
|
||||
return ((pam_control_t)-1);
|
||||
}
|
||||
for (e = b; *e && !is_lws(*e); ++e)
|
||||
/* nothing */ ;
|
||||
if (e == b)
|
||||
return ((pam_control_t)-1);
|
||||
for (i = 0; i < PAM_NUM_CONTROL_FLAGS; ++i)
|
||||
if (strlcmp(pam_control_flag_name[i], b, e - b) == 0)
|
||||
break;
|
||||
if (i == PAM_NUM_CONTROL_FLAGS)
|
||||
return ((pam_control_t)-1);
|
||||
*line = e;
|
||||
return (i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a file name.
|
||||
*
|
||||
* Returns the length of the file name, or 0 if the end of the string was
|
||||
* reached or a disallowed non-whitespace character was encountered.
|
||||
*
|
||||
* If parse_filename() is successful, it updates *filename to point to the
|
||||
* first character of the filename and *line to point one character past
|
||||
* the end. If it reaches the end of the string, it updates *line to
|
||||
* point to the terminating NUL character and leaves *filename unmodified.
|
||||
* In all other cases, it leaves both *line and *filename unmodified.
|
||||
*
|
||||
* Allowed characters are all characters in the POSIX portable filename
|
||||
* character set, plus the path separator (forward slash).
|
||||
*/
|
||||
static int
|
||||
parse_filename(char **line, char **filename)
|
||||
{
|
||||
char *b, *e;
|
||||
|
||||
for (b = *line; *b && is_lws(*b); ++b)
|
||||
/* nothing */ ;
|
||||
if (!*b) {
|
||||
*line = b;
|
||||
return (0);
|
||||
}
|
||||
for (e = b; *e && !is_lws(*e); ++e)
|
||||
if (!is_pfcs(*e) && *e != '/')
|
||||
return (0);
|
||||
if (e == b)
|
||||
return (0);
|
||||
*line = e;
|
||||
*filename = b;
|
||||
return (e - b);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse an option.
|
||||
*
|
||||
* Returns a pointer to a dynamically allocated pam_opt_t with the name
|
||||
* and value of the next module option, or NULL if the end of the string
|
||||
* was reached or a disallowed non-whitespace character was encountered.
|
||||
*
|
||||
* An option consists of an option name optionally followed by an equal
|
||||
* sign and an option value.
|
||||
*
|
||||
* The structure and strings are allocated as a single object, so a single
|
||||
* free(3) call is sufficient to release the allocated memory.
|
||||
*
|
||||
* If parse_option() is successful, it updates *line to point one
|
||||
* character past the end of the option. If it reaches the end of the
|
||||
* string, it updates *line to point to the terminating NUL character. In
|
||||
* all other cases, it leaves *line unmodified.
|
||||
*
|
||||
* If parse_option() fails to allocate memory for the option structure, it
|
||||
* will return NULL and set errno to a non-zero value.
|
||||
*
|
||||
* Allowed characters for option names are all characters in the POSIX
|
||||
* portable filename character set. Allowed characters for option values
|
||||
* are any printable non-whitespace characters. The option value may be
|
||||
* quoted in either single or double quotes, in which case space
|
||||
* characters and whichever quote character was not used are allowed.
|
||||
* Note that the entire value must be quoted, not just part of it.
|
||||
*/
|
||||
static pam_opt_t *
|
||||
parse_option(char **line)
|
||||
{
|
||||
char *nb, *ne, *vb, *ve;
|
||||
unsigned char q = 0;
|
||||
pam_opt_t *opt;
|
||||
size_t size;
|
||||
|
||||
errno = 0;
|
||||
for (nb = *line; *nb && is_lws(*nb); ++nb)
|
||||
/* nothing */ ;
|
||||
if (!*nb) {
|
||||
*line = nb;
|
||||
return (NULL);
|
||||
}
|
||||
for (ne = nb; *ne && !is_lws(*ne) && *ne != '='; ++ne)
|
||||
if (!is_pfcs(*ne))
|
||||
return (NULL);
|
||||
if (ne == nb)
|
||||
return (NULL);
|
||||
if (*ne == '=') {
|
||||
vb = ne + 1;
|
||||
if (*vb == '"' || *vb == '\'')
|
||||
q = *vb++;
|
||||
for (ve = vb;
|
||||
*ve && *ve != q && (is_p(*ve) || (q && is_lws(*ve)));
|
||||
++ve)
|
||||
/* nothing */ ;
|
||||
if (q && *ve != q)
|
||||
/* non-printable character or missing endquote */
|
||||
return (NULL);
|
||||
if (q && *(ve + 1) && !is_lws(*(ve + 1)))
|
||||
/* garbage after value */
|
||||
return (NULL);
|
||||
} else {
|
||||
vb = ve = ne;
|
||||
}
|
||||
size = sizeof *opt;
|
||||
size += ne - nb + 1;
|
||||
size += ve - vb + 1;
|
||||
if ((opt = malloc(size)) == NULL)
|
||||
return (NULL);
|
||||
opt->name = (char *)opt + sizeof *opt;
|
||||
strlcpy(opt->name, nb, ne - nb + 1);
|
||||
opt->value = opt->name + (ne - nb) + 1;
|
||||
strlcpy(opt->value, vb, ve - vb + 1);
|
||||
*line = q ? ve + 1 : ve;
|
||||
return (opt);
|
||||
}
|
||||
|
||||
typedef enum { pam_conf_style, pam_d_style } openpam_style_t;
|
||||
|
||||
/*
|
||||
* Extracts given chains from a policy file.
|
||||
*/
|
||||
static int
|
||||
openpam_read_chain(pam_handle_t *pamh,
|
||||
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;
|
||||
const char *p, *q;
|
||||
int count, i, lineno, ret;
|
||||
int count, lineno;
|
||||
pam_facility_t fclt;
|
||||
pam_control_t ctlf;
|
||||
char *line, *name;
|
||||
pam_opt_t *opt;
|
||||
char *line, *str, *name;
|
||||
int len, ret;
|
||||
FILE *f;
|
||||
|
||||
if ((f = fopen(filename, "r")) == NULL) {
|
||||
|
@ -150,43 +371,45 @@ openpam_read_chain(pam_handle_t *pamh,
|
|||
return (0);
|
||||
}
|
||||
this = NULL;
|
||||
name = NULL;
|
||||
count = lineno = 0;
|
||||
while ((line = openpam_readline(f, &lineno, NULL)) != NULL) {
|
||||
p = line;
|
||||
|
||||
/* match service name */
|
||||
/* get service name if necessary */
|
||||
if (style == pam_conf_style) {
|
||||
if (!match_word(p, service)) {
|
||||
if ((len = parse_service_name(&line, &str)) == 0) {
|
||||
openpam_log(PAM_LOG_NOTICE,
|
||||
"%s(%d): invalid service name (ignored)",
|
||||
filename, lineno);
|
||||
FREE(line);
|
||||
continue;
|
||||
}
|
||||
if (strlcmp(service, str, len) != 0) {
|
||||
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);
|
||||
/* 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(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",
|
||||
/* check for "include" */
|
||||
if (parse_include(&line)) {
|
||||
if ((len = parse_filename(&line, &str)) == 0) {
|
||||
openpam_log(PAM_LOG_ERROR,
|
||||
"%s(%d): missing or invalid filename",
|
||||
filename, lineno);
|
||||
if ((name = dup_word(p)) == NULL)
|
||||
goto fail;
|
||||
}
|
||||
if ((name = strndup(str, len)) == NULL)
|
||||
goto syserr;
|
||||
ret = openpam_load_chain(pamh, name, fclt);
|
||||
FREE(name);
|
||||
|
@ -197,52 +420,49 @@ openpam_read_chain(pam_handle_t *pamh,
|
|||
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) {
|
||||
/* get control flag */
|
||||
if ((ctlf = parse_control_flag(&line)) == (pam_control_t)-1) {
|
||||
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",
|
||||
"%s(%d): missing or invalid control flag",
|
||||
filename, lineno);
|
||||
goto fail;
|
||||
}
|
||||
if ((name = dup_word(p)) == NULL)
|
||||
|
||||
/* 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 */
|
||||
/* quick and dirty, wastes a few hundred bytes */
|
||||
if ((this->optv = malloc(sizeof *opt * strlen(line))) == NULL)
|
||||
goto syserr;
|
||||
while ((opt = parse_option(&line)) != NULL)
|
||||
this->optv[this->optc++] = opt;
|
||||
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;
|
||||
|
||||
/* 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)
|
||||
|
@ -261,8 +481,14 @@ openpam_read_chain(pam_handle_t *pamh,
|
|||
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(line);
|
||||
FREE(name);
|
||||
fclose(f);
|
||||
return (-1);
|
||||
}
|
||||
|
@ -296,11 +522,11 @@ openpam_load_chain(pam_handle_t *pamh,
|
|||
openpam_log(PAM_LOG_ERROR, "asprintf(): %m");
|
||||
return (-PAM_BUF_ERR);
|
||||
}
|
||||
r = openpam_read_chain(pamh, service, facility,
|
||||
r = openpam_parse_chain(pamh, service, facility,
|
||||
filename, pam_d_style);
|
||||
FREE(filename);
|
||||
} else {
|
||||
r = openpam_read_chain(pamh, service, facility,
|
||||
r = openpam_parse_chain(pamh, service, facility,
|
||||
*path, pam_conf_style);
|
||||
}
|
||||
if (r != 0)
|
||||
|
|
|
@ -59,22 +59,15 @@ openpam_get_option(pam_handle_t *pamh,
|
|||
const char *option)
|
||||
{
|
||||
pam_chain_t *cur;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
ENTERS(option);
|
||||
if (pamh == NULL || pamh->current == NULL || option == NULL)
|
||||
RETURNS(NULL);
|
||||
cur = pamh->current;
|
||||
len = strlen(option);
|
||||
for (i = 0; i < cur->optc; ++i) {
|
||||
if (strncmp(cur->optv[i], option, len) == 0) {
|
||||
if (cur->optv[i][len] == '\0')
|
||||
RETURNS(&cur->optv[i][len]);
|
||||
else if (cur->optv[i][len] == '=')
|
||||
RETURNS(&cur->optv[i][len + 1]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < cur->optc; ++i)
|
||||
if (strcmp(cur->optv[i]->name, option) == 0)
|
||||
RETURNS(cur->optv[i]->value);
|
||||
RETURNS(NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,12 +71,19 @@ typedef enum {
|
|||
PAM_NUM_FACILITIES
|
||||
} pam_facility_t;
|
||||
|
||||
typedef struct pam_opt pam_opt_t;
|
||||
struct pam_opt {
|
||||
char *name;
|
||||
char *value;
|
||||
char str[];
|
||||
};
|
||||
|
||||
typedef struct pam_chain pam_chain_t;
|
||||
struct pam_chain {
|
||||
pam_module_t *module;
|
||||
int flag;
|
||||
int optc;
|
||||
char **optv;
|
||||
pam_opt_t **optv;
|
||||
pam_chain_t *next;
|
||||
};
|
||||
|
||||
|
|
|
@ -62,22 +62,16 @@ openpam_set_option(pam_handle_t *pamh,
|
|||
const char *value)
|
||||
{
|
||||
pam_chain_t *cur;
|
||||
char *opt, **optv;
|
||||
size_t len;
|
||||
int i;
|
||||
pam_opt_t *opt, **optv;
|
||||
int i, ol, vl;
|
||||
|
||||
ENTERS(option);
|
||||
if (pamh == NULL || pamh->current == NULL || option == NULL)
|
||||
RETURNC(PAM_SYSTEM_ERR);
|
||||
cur = pamh->current;
|
||||
for (len = 0; option[len] != '\0'; ++len)
|
||||
if (option[len] == '=')
|
||||
for (i = 0; i < cur->optc; ++i)
|
||||
if (strcmp(cur->optv[i]->name, option) == 0)
|
||||
break;
|
||||
for (i = 0; i < cur->optc; ++i) {
|
||||
if (strncmp(cur->optv[i], option, len) == 0 &&
|
||||
(cur->optv[i][len] == '\0' || cur->optv[i][len] == '='))
|
||||
break;
|
||||
}
|
||||
if (value == NULL) {
|
||||
/* remove */
|
||||
if (i == cur->optc)
|
||||
|
@ -85,13 +79,20 @@ openpam_set_option(pam_handle_t *pamh,
|
|||
for (free(cur->optv[i]); i < cur->optc; ++i)
|
||||
cur->optv[i] = cur->optv[i + 1];
|
||||
cur->optv[i] = NULL;
|
||||
cur->optc--;
|
||||
RETURNC(PAM_SUCCESS);
|
||||
}
|
||||
if (asprintf(&opt, "%.*s=%s", (int)len, option, value) < 0)
|
||||
ol = strlen(option) + 1;
|
||||
vl = strlen(value) + 1;
|
||||
if ((opt = malloc(sizeof *opt + ol + vl)) == NULL)
|
||||
RETURNC(PAM_BUF_ERR);
|
||||
opt->name = (char *)opt + sizeof *opt;
|
||||
strlcpy(opt->name, option, ol);
|
||||
opt->value = opt->name + ol;
|
||||
strlcpy(opt->value, value, vl);
|
||||
if (i == cur->optc) {
|
||||
/* add */
|
||||
optv = realloc(cur->optv, sizeof(char *) * (cur->optc + 2));
|
||||
optv = realloc(cur->optv, sizeof *optv * (cur->optc + 2));
|
||||
if (optv == NULL) {
|
||||
FREE(opt);
|
||||
RETURNC(PAM_BUF_ERR);
|
||||
|
|
Loading…
Reference in New Issue