aboutsummaryrefslogtreecommitdiff
path: root/lib/transform.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/transform.c')
-rw-r--r--lib/transform.c244
1 files changed, 185 insertions, 59 deletions
diff --git a/lib/transform.c b/lib/transform.c
index 36972f0..c8ed54d 100644
--- a/lib/transform.c
+++ b/lib/transform.c
@@ -60,29 +60,48 @@ struct transform
{
struct transform *next;
enum transform_type transform_type;
unsigned match_number;
regex_t regex;
int has_regex;
+ int error;
/* Compiled replacement expression */
struct replace_segm *repl_head, *repl_tail;
size_t segm_count; /* Number of elements in the above list */
};
+static inline int
+transform_err(struct transform *tf)
+{
+ return tf->error;
+}
+
+static void
+transform_seterr (struct transform *tf, int ec)
+{
+ errno_to_pam (errno);
+ tf->error = ec;
+}
+
static struct transform *transform_head, *transform_tail;
+static char *case_ctl_buffer;
+static size_t case_ctl_bufsize;
static struct transform *
-new_transform ()
+new_transform (void)
{
- struct transform *p = gray_zalloc (sizeof *p);
- if (transform_tail)
- transform_tail->next = p;
- else
- transform_head = p;
- transform_tail = p;
+ struct transform *p = calloc (1, sizeof *p);
+ if (p)
+ {
+ if (transform_tail)
+ transform_tail->next = p;
+ else
+ transform_head = p;
+ transform_tail = p;
+ }
return p;
}
static void free_segment (struct replace_segm *segm);
static void
@@ -99,103 +118,144 @@ free_transform (struct transform *tr)
}
}
static struct replace_segm *
add_segment (struct transform *tf)
{
- struct replace_segm *segm = gray_malloc (sizeof *segm);
- segm->next = NULL;
- if (tf->repl_tail)
- tf->repl_tail->next = segm;
+ struct replace_segm *segm = malloc (sizeof *segm);
+ if (segm)
+ {
+ segm->next = NULL;
+ if (tf->repl_tail)
+ tf->repl_tail->next = segm;
+ else
+ tf->repl_head = segm;
+ tf->repl_tail = segm;
+ tf->segm_count++;
+ }
else
- tf->repl_head = segm;
- tf->repl_tail = segm;
- tf->segm_count++;
+ transform_seterr (tf, errno_to_pam (errno));
return segm;
}
static void
free_segment (struct replace_segm *segm)
{
if (segm->type == segm_literal)
free (segm->v.literal.ptr);
free (segm);
}
static void
-add_literal_segment (struct transform *tf, char *str, char *end)
+add_literal_segment (struct transform *tf, char const *str, char const *end)
{
size_t len = end - str;
if (len)
{
struct replace_segm *segm = add_segment (tf);
- segm->type = segm_literal;
- segm->v.literal.ptr = gray_malloc (len + 1);
- memcpy (segm->v.literal.ptr, str, len);
- segm->v.literal.ptr[len] = 0;
- segm->v.literal.size = len;
+ if (segm)
+ {
+ segm->type = segm_literal;
+ segm->v.literal.ptr = malloc (len + 1);
+ if (segm->v.literal.ptr)
+ {
+ memcpy (segm->v.literal.ptr, str, len);
+ segm->v.literal.ptr[len] = 0;
+ segm->v.literal.size = len;
+ }
+ else
+ transform_seterr (tf, errno_to_pam (errno));
+ }
}
}
static void
add_char_segment (struct transform *tf, int chr)
{
struct replace_segm *segm = add_segment (tf);
- segm->type = segm_literal;
- segm->v.literal.ptr = gray_malloc (2);
- segm->v.literal.ptr[0] = chr;
- segm->v.literal.ptr[1] = 0;
- segm->v.literal.size = 1;
+ if (segm)
+ {
+ segm->type = segm_literal;
+ segm->v.literal.ptr = malloc (2);
+ if (segm->v.literal.ptr)
+ {
+ segm->v.literal.ptr[0] = chr;
+ segm->v.literal.ptr[1] = 0;
+ segm->v.literal.size = 1;
+ }
+ else
+ transform_seterr (tf, errno_to_pam (errno));
+ }
}
static void
add_backref_segment (struct transform *tf, size_t ref)
{
struct replace_segm *segm = add_segment (tf);
- segm->type = segm_backref;
- segm->v.ref = ref;
+ if (segm)
+ {
+ segm->type = segm_backref;
+ segm->v.ref = ref;
+ }
}
static void
add_case_ctl_segment (struct transform *tf, enum case_ctl_type ctl)
{
struct replace_segm *segm = add_segment (tf);
- segm->type = segm_case_ctl;
- segm->v.ctl = ctl;
+ if (segm)
+ {
+ segm->type = segm_case_ctl;
+ segm->v.ctl = ctl;
+ }
}
-static const char *
-parse_transform_expr (const char *expr)
+static int
+parse_transform_expr (const char *expr, const char **endp)
{
int delim;
int i, j, rc;
- char *str, *beg, *cur;
+ char *str;
+ const char *beg;
+ const char *cur;
const char *p;
int cflags = 0;
struct transform *tf = new_transform ();
if (expr[0] != 's')
- gray_raise ("Invalid transform expression");
+ {
+ _pam_log(LOG_ERR, "invalid transform expression");
+ *endp = expr;
+ return PAM_SERVICE_ERR;
+ }
delim = expr[1];
/* Scan regular expression */
for (i = 2; expr[i] && expr[i] != delim; i++)
if (expr[i] == '\\' && expr[i+1])
i++;
if (expr[i] != delim)
- gray_raise ("Invalid transform expression");
+ {
+ _pam_log(LOG_ERR, "invalid transform expression");
+ *endp = expr + i;
+ return PAM_SERVICE_ERR;
+ }
/* Scan replacement expression */
for (j = i + 1; expr[j] && expr[j] != delim; j++)
if (expr[j] == '\\' && expr[j+1])
j++;
if (expr[j] != delim)
- gray_raise ("Invalid transform expression");
+ {
+ _pam_log(LOG_ERR, "invalid transform expression");
+ *endp = expr + j;
+ return PAM_SERVICE_ERR;
+ }
/* Check flags */
tf->transform_type = transform_first;
for (p = expr + j + 1; *p && *p != ';'; p++)
switch (*p)
{
@@ -215,59 +275,87 @@ parse_transform_expr (const char *expr)
case '5': case '6': case '7': case '8': case '9':
tf->match_number = strtoul (p, (char**) &p, 0);
p--;
break;
default:
- gray_raise("Unknown flag in transform expression: %c", *p);
+ _pam_log(LOG_ERR, "unknown flag in transform expression: %c", *p);
+ *endp = p;
+ return PAM_SERVICE_ERR;
}
if (*p == ';')
p++;
/* Extract and compile regex */
- str = gray_malloc (i - 1);
+ str = malloc (i - 1);
+ if (!str)
+ {
+ *endp = p;
+ return errno_to_pam (errno);
+ }
memcpy (str, expr + 2, i - 2);
str[i - 2] = 0;
rc = regcomp (&tf->regex, str, cflags);
if (rc)
{
char errbuf[512];
regerror (rc, &tf->regex, errbuf, sizeof (errbuf));
- gray_raise("Invalid transform expression: %s", errbuf);
+ _pam_log(LOG_ERR, "invalid transform expression: %s", errbuf);
+ free (str);
+ *endp = p;
+ return PAM_SERVICE_ERR;
}
tf->has_regex = 1;
if (str[0] == '^' || str[strlen (str) - 1] == '$')
tf->transform_type = transform_first;
free (str);
/* Extract and compile replacement expr */
i++;
- str = gray_malloc (j - i + 1);
+ str = malloc (j - i + 1);
+ if (!str)
+ {
+ *endp = p;
+ return errno_to_pam (errno);
+ }
+
memcpy (str, expr + i, j - i);
str[j - i] = 0;
for (cur = beg = str; *cur;)
{
+ if (transform_err (tf))
+ {
+ *endp = expr + i + (beg - str);
+ free (str);
+ return transform_err (tf);
+ }
+
if (*cur == '\\')
{
size_t n;
add_literal_segment (tf, beg, cur);
switch (*++cur)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- n = strtoul (cur, &cur, 10);
+ n = strtoul (cur, (char**)&cur, 10);
if (n > tf->regex.re_nsub)
- gray_raise ("Invalid transform replacement: "
- "back reference out of range");
- add_backref_segment (tf, n);
+ {
+ _pam_log(LOG_ERR,
+ "invalid transform replacement: "
+ "back reference out of range");
+ transform_seterr (tf, PAM_SERVICE_ERR);
+ }
+ else
+ add_backref_segment (tf, n);
break;
case '\\':
add_char_segment (tf, '\\');
cur++;
break;
@@ -364,48 +452,66 @@ parse_transform_expr (const char *expr)
beg = ++cur;
}
else
cur++;
}
add_literal_segment (tf, beg, cur);
-
- return p;
+ if (transform_err (tf))
+ {
+ *endp = expr + i + (beg - str);
+ free (str);
+ return transform_err (tf);
+ }
+ *endp = p;
+ return 0;
}
-void
+int
gray_set_transform_expr (const char *expr)
{
while (*expr)
- expr = parse_transform_expr (expr);
+ {
+ int rc = parse_transform_expr (expr, &expr);
+ if (rc != PAM_SUCCESS)
+ {
+ gray_free_transform_expr ();
+ return rc;
+ }
+ }
+ return PAM_SUCCESS;
}
void
-gray_free_transform_expr ()
+gray_free_transform_expr (void)
{
while (transform_head)
{
struct transform *next = transform_head->next;
free_transform (transform_head);
transform_head = next;
}
transform_tail = NULL;
+ free (case_ctl_buffer);
+ case_ctl_buffer = NULL;
+ case_ctl_bufsize = 0;
}
/* Run case conversion specified by CASE_CTL on array PTR of SIZE
characters. Returns pointer to statically allocated storage. */
static char *
run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
{
- static char *case_ctl_buffer;
- static size_t case_ctl_bufsize;
char *p;
if (case_ctl_bufsize < size)
{
+ p = realloc (case_ctl_buffer, size);
+ if (!p)
+ return NULL;
+ case_ctl_buffer = p;
case_ctl_bufsize = size;
- case_ctl_buffer = gray_realloc (case_ctl_buffer, case_ctl_bufsize);
}
memcpy (case_ctl_buffer, ptr, size);
switch (case_ctl)
{
case ctl_upcase_next:
case_ctl_buffer[0] = toupper (case_ctl_buffer[0]);
@@ -429,13 +535,13 @@ run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
break;
}
return case_ctl_buffer;
}
-void
+static int
_single_transform_name_to_slist (struct transform *tf, gray_slist_t slist,
char *input)
{
regmatch_t *rmp;
int rc;
size_t nmatches = 0;
@@ -447,14 +553,15 @@ _single_transform_name_to_slist (struct transform *tf, gray_slist_t slist,
|| case_ctl == ctl_locase_next) \
{ \
case_ctl = save_ctl; \
save_ctl = ctl_stop; \
}
- rmp = gray_malloc ((tf->regex.re_nsub + 1) * sizeof (*rmp));
-
+ rmp = malloc ((tf->regex.re_nsub + 1) * sizeof (*rmp));
+ if (!rmp)
+ return errno;
while (*input)
{
size_t disp;
char *ptr;
rc = regexec (&tf->regex, input, tf->regex.re_nsub + 1, rmp, 0);
@@ -485,12 +592,14 @@ _single_transform_name_to_slist (struct transform *tf, gray_slist_t slist,
ptr = segm->v.literal.ptr;
else
{
ptr = run_case_conv (case_ctl,
segm->v.literal.ptr,
segm->v.literal.size);
+ if (!ptr)
+ return errno;
CASE_CTL_RESET();
}
gray_slist_append (slist, ptr, segm->v.literal.size);
break;
case segm_backref: /* Back-reference segment */
@@ -500,12 +609,14 @@ _single_transform_name_to_slist (struct transform *tf, gray_slist_t slist,
size_t size = rmp[segm->v.ref].rm_eo
- rmp[segm->v.ref].rm_so;
ptr = input + rmp[segm->v.ref].rm_so;
if (case_ctl != ctl_stop)
{
ptr = run_case_conv (case_ctl, ptr, size);
+ if (!ptr)
+ return errno;
CASE_CTL_RESET();
}
gray_slist_append (slist, ptr, size);
}
break;
@@ -548,23 +659,38 @@ _single_transform_name_to_slist (struct transform *tf, gray_slist_t slist,
break;
}
}
gray_slist_append_char (slist, 0);
free (rmp);
+ return gray_slist_err (slist);
}
int
gray_transform_name_to_slist (gray_slist_t slist, char *input, char **output)
{
- struct transform *tf;
-
- for (tf = transform_head; tf; tf = tf->next)
+ if (transform_head)
+ {
+ struct transform *tf;
+ for (tf = transform_head; tf; tf = tf->next)
+ {
+ int rc = _single_transform_name_to_slist (tf, slist, input);
+ if (rc)
+ return errno_to_pam(rc);
+ input = gray_slist_finish (slist);
+ if (!input)
+ return errno_to_pam(errno);
+ }
+ }
+ else
{
- _single_transform_name_to_slist (tf, slist, input);
+ gray_slist_append(slist, input, strlen(input) + 1);
input = gray_slist_finish (slist);
+ if (!input)
+ return errno_to_pam(errno);
}
*output = input;
- return transform_head != NULL;
+
+ return PAM_SUCCESS;
}

Return to:

Send suggestions and report system problems to the System administrator.