diff options
Diffstat (limited to 'lib/transform.c')
-rw-r--r-- | lib/transform.c | 244 |
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; } |