diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/base64.c | 20 | ||||
-rw-r--r-- | lib/env.c | 66 | ||||
-rw-r--r-- | lib/graypam.h | 50 | ||||
-rw-r--r-- | lib/ldappass.c | 107 | ||||
-rw-r--r-- | lib/mem.c | 81 | ||||
-rw-r--r-- | lib/slist.c | 127 | ||||
-rw-r--r-- | lib/transform.c | 244 |
7 files changed, 456 insertions, 239 deletions
diff --git a/lib/base64.c b/lib/base64.c index 85b974a..9d0191e 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -51,19 +51,25 @@ gray_base64_decode(gray_slist_t slist, const char *iptr, size_t isize) } } /* I have a entire block of data 32 bits get the output data. */ if (i == 4) { - gray_slist_append_char(slist, - (data[0] << 2) | ((data[1] & 0x30) >> 4)); - gray_slist_append_char(slist, - ((data[1] & 0xf) << 4) | ((data[2] & 0x3c) >> 2)); - gray_slist_append_char(slist, - ((data[2] & 0x3) << 6) | data[3]); + if (gray_slist_append_char(slist, + (data[0] << 2) | ((data[1] & 0x30) >> 4)) != 1) + return -1; + if (gray_slist_append_char(slist, + ((data[1] & 0xf) << 4) | ((data[2] & 0x3c) >> 2)) + != 1) + return -1; + if (gray_slist_append_char(slist, + ((data[2] & 0x3) << 6) | data[3]) != 1) + return -1; nbytes += 3 - pad; - } else + } else { + errno = EILSEQ; return -1; + } i = 0; } return nbytes; } @@ -91,34 +91,45 @@ gray_env_read_tr(const char *file_name, struct gray_env **penv, char **trmap) if (!fp) { _pam_log(LOG_ERR, "cannot open configuration file `%s': %s", file_name, strerror (errno)); return 1; } - while (p = fgets(buf, sizeof buf, fp)) { + while ((p = fgets(buf, sizeof buf, fp))) { int len; struct gray_env *env; line++; while (*p && isspace(*p)) p++; len = strlen(p); if (len == 0) continue; if (p[len-1] != '\n') { - if (!slist) + if (!slist) { slist = gray_slist_create(); - gray_slist_append(slist, p, len); - while (p = fgets(buf, sizeof buf, fp)) { + if (!slist) { + rc = errno; + break; + } + } + if (gray_slist_append(slist, p, len) != len) { + rc = errno; + break; + } + while ((p = fgets(buf, sizeof buf, fp))) { len = strlen(p); gray_slist_append(slist, p, len); if (p[len - 1] == '\n') break; } - gray_slist_append_char(slist, 0); - p = gray_slist_finish(slist); + if (gray_slist_append_char(slist, 0) != 1 + || (p = gray_slist_finish(slist)) == NULL) { + rc = errno; + break; + } len = strlen(p); } p[len-1] = 0; len = gray_trim_ws(p); @@ -126,16 +137,25 @@ gray_env_read_tr(const char *file_name, struct gray_env **penv, char **trmap) continue; if (p[len-1] == '\\') { int err = 0; /* Collect continuation lines */ - if (!slist) + if (!slist) { slist = gray_slist_create(); + if (!slist) { + rc = errno; + break; + } + } do { - gray_slist_append(slist, p, len - 1); + if (gray_slist_append(slist, p, len - 1) + != len - 1) { + rc = errno; + break; + } p = fgets (buf, sizeof buf, fp); if (!p) break; line++; len = strlen(p); if (len == 0) @@ -147,32 +167,39 @@ gray_env_read_tr(const char *file_name, struct gray_env **penv, char **trmap) err = 1; break; } p[len-1] = 0; len = gray_trim_ws(p); } while (p[len-1] == '\\'); - if (len) - gray_slist_append(slist, p, len); - gray_slist_append_char(slist, 0); - p = gray_slist_finish(slist); + if (rc) + break; + if (len) { + if (gray_slist_append(slist, p, len) != len) { + rc = errno; + break; + } + } + if (gray_slist_append_char(slist, 0) != 1 + || (p = gray_slist_finish(slist)) == NULL) { + rc = errno; + break; + } if (err) continue; } env = malloc(sizeof *env); if (!env) { - _pam_log(LOG_EMERG, "not enough memory"); - rc = 1; + rc = errno; break; } env->name = strdup(p); if (!env->name) { - _pam_log(LOG_EMERG, "not enough memory"); + rc = errno; free(env); - rc = 1; break; } for (p = env->name; *p && !isspace(*p); p++) ; if (*p) @@ -192,13 +219,18 @@ gray_env_read_tr(const char *file_name, struct gray_env **penv, char **trmap) env->next = config_env; config_env = env; } gray_slist_free(&slist); fclose(fp); - *penv = config_env; + if (rc) { + _pam_log(LOG_EMERG, "%s", strerror(rc)); + gray_env_free(config_env); + } else { + *penv = config_env; + } return rc; } int gray_env_read(const char *file_name, struct gray_env **penv) { diff --git a/lib/graypam.h b/lib/graypam.h index 76dcd68..69c4909 100644 --- a/lib/graypam.h +++ b/lib/graypam.h @@ -81,61 +81,69 @@ else \ gray_wait_debug(0, __FILE__, line); \ } while (0) extern jmp_buf gray_pam_jmp; -#define gray_pam_init(retval) \ - if (setjmp(gray_pam_jmp)) \ - return retval; \ - -void gray_raise(const char *fmt, ...); - -void *gray_malloc(size_t size); -void *gray_zalloc(size_t size); -void *gray_calloc(size_t count, size_t size); -void *gray_realloc(void *ptr, size_t size); void *gray_2nrealloc(void *ptr, size_t *pcount, size_t elsiz); -char *gray_strdup(const char *str); void gray_pam_delete(char *x); void gray_cleanup_string(pam_handle_t *pamh, void *x, int error_status); void gray_cleanup_regex(pam_handle_t *pamh, void *x, int error_status); void gray_make_str(pam_handle_t *pamh, const char *str, const char *name, char **ret); - typedef struct gray_slist *gray_slist_t; -gray_slist_t gray_slist_create(); +gray_slist_t gray_slist_create(void); +int gray_slist_err(gray_slist_t slist); +void gray_slist_clrerr(gray_slist_t slist); void gray_slist_clear(gray_slist_t slist); void gray_slist_free(gray_slist_t *slist); -void gray_slist_append(gray_slist_t slist, const char *str, size_t n); -void gray_slist_append_char(gray_slist_t slist, char c); +ssize_t gray_slist_append(gray_slist_t slist, const char *str, size_t n); +ssize_t gray_slist_append_char(gray_slist_t slist, char c); size_t gray_slist_size(gray_slist_t slist); -size_t gray_slist_coalesce(gray_slist_t slist); +ssize_t gray_slist_coalesce(gray_slist_t slist); void *gray_slist_head(gray_slist_t slist, size_t *psize); void *gray_slist_finish(gray_slist_t slist); -void gray_slist_grow_backslash_num(gray_slist_t slist, char *text, char **pend, - int len, int base); -void gray_slist_grow_backslash(gray_slist_t slist, char *text, char **endp); +int gray_slist_grow_backslash_num(gray_slist_t slist, char *text, char **pend, + int len, int base); +int gray_slist_grow_backslash(gray_slist_t slist, char *text, char **endp); void gray_log_init(int dont_open, const char *tag, int f); void gray_pam_vlog(int err, const char *format, va_list args); void gray_pam_log(int err, const char *format, ...); void gray_pam_debug(const char *format, ...); void gray_wait_debug(size_t interval, const char *file, size_t line); #define _pam_vlog gray_pam_vlog #define _pam_log gray_pam_log #define _pam_debug gray_pam_debug - + +static inline int +errno_to_pam(int ec) +{ + switch (ec) { + case EILSEQ: + _pam_log(LOG_ERR, "malformed password hash"); + return PAM_SERVICE_ERR; + + case ENOMEM: + _pam_log(LOG_ERR, "%s", strerror(errno)); + return PAM_BUF_ERR; + + default: + break; + } + _pam_log(LOG_ERR, "%s", strerror(errno)); + return PAM_SERVICE_ERR; +} int gray_transform_name_to_slist (gray_slist_t slist, char *input, char **output); -void gray_set_transform_expr (const char *expr); +int gray_set_transform_expr (const char *expr); void gray_free_transform_expr (void); int gray_converse(pam_handle_t *pamh, int nargs, struct pam_message **message, struct pam_response **response); diff --git a/lib/ldappass.c b/lib/ldappass.c index 968078c..247cf16 100644 --- a/lib/ldappass.c +++ b/lib/ldappass.c @@ -45,119 +45,168 @@ chk_crypt (const char *db_pass, const char *pass) static int chk_md5 (const char *db_pass, const char *pass) { unsigned char md5digest[16]; struct gpam_md5_ctx md5context; - gray_slist_t slist = gray_slist_create (); + gray_slist_t slist; ssize_t size; char *p; int rc; + + slist = gray_slist_create (); + if (!slist) + return errno_to_pam(errno); gpam_md5_init_ctx (&md5context); gpam_md5_process_bytes (pass, strlen (pass), &md5context); gpam_md5_finish_ctx (&md5context, md5digest); size = gray_base64_decode(slist, db_pass, strlen (db_pass)); if (size != 16) { + rc = errno_to_pam(errno); gray_slist_free(&slist); - return PAM_AUTH_ERR; + return rc; } p = gray_slist_finish(slist); - rc = memcmp (md5digest, p, sizeof md5digest) == 0 ? - PAM_SUCCESS : PAM_AUTH_ERR; + if (p) + { + rc = memcmp (md5digest, p, sizeof md5digest) == 0 + ? PAM_SUCCESS + : PAM_AUTH_ERR; + } + else + { + rc = errno_to_pam(errno); + } gray_slist_free(&slist); return rc; } static int chk_smd5 (const char *db_pass, const char *pass) { int rc; unsigned char md5digest[16]; unsigned char *d1; struct gpam_md5_ctx md5context; - gray_slist_t slist = gray_slist_create(); + gray_slist_t slist; ssize_t size; + slist = gray_slist_create(); + if (!slist) + return errno_to_pam(errno); + size = gray_base64_decode(slist, db_pass, strlen (db_pass)); if (size <= 16) { - _pam_log(LOG_ERR, "malformed SMD5 password: %s", db_pass); + rc = errno_to_pam(errno); gray_slist_free(&slist); - return PAM_AUTH_ERR; + return rc; } d1 = gray_slist_finish(slist); - - gpam_md5_init_ctx (&md5context); - gpam_md5_process_bytes (pass, strlen (pass), &md5context); - gpam_md5_process_bytes (d1 + 16, size - 16, &md5context); - gpam_md5_finish_ctx (&md5context, md5digest); + if (d1) + { + gpam_md5_init_ctx (&md5context); + gpam_md5_process_bytes (pass, strlen (pass), &md5context); + gpam_md5_process_bytes (d1 + 16, size - 16, &md5context); + gpam_md5_finish_ctx (&md5context, md5digest); - rc = memcmp (md5digest, d1, sizeof md5digest) == 0 ? - PAM_SUCCESS : PAM_AUTH_ERR; + rc = memcmp (md5digest, d1, sizeof md5digest) == 0 + ? PAM_SUCCESS + : PAM_AUTH_ERR; + } + else + { + rc = errno_to_pam(gray_slist_err(slist)); + } + gray_slist_free(&slist); return rc; } static int chk_sha (const char *db_pass, const char *pass) { int rc; unsigned char sha1digest[20]; unsigned char *d1; struct gpam_sha1_ctx sha1context; - gray_slist_t slist = gray_slist_create(); + gray_slist_t slist; ssize_t size; - + + slist = gray_slist_create(); + if (!slist) + return errno_to_pam(errno); + gpam_sha1_init_ctx (&sha1context); gpam_sha1_process_bytes (pass, strlen (pass), &sha1context); gpam_sha1_finish_ctx (&sha1context, sha1digest); size = gray_base64_decode(slist, db_pass, strlen (db_pass)); if (size != 20) { + rc = errno_to_pam(errno); gray_slist_free(&slist); - return 1; + return rc; } d1 = gray_slist_finish(slist); - rc = memcmp (sha1digest, d1, sizeof sha1digest) == 0 ? - PAM_SUCCESS : PAM_AUTH_ERR; + if (d1) + { + rc = memcmp (sha1digest, d1, sizeof sha1digest) == 0 + ? PAM_SUCCESS + : PAM_AUTH_ERR; + } + else + { + rc = errno_to_pam(errno); + } gray_slist_free(&slist); return rc; } static int chk_ssha (const char *db_pass, const char *pass) { int rc; unsigned char sha1digest[20]; unsigned char *d1; struct gpam_sha1_ctx sha1context; - gray_slist_t slist = gray_slist_create(); + gray_slist_t slist; ssize_t size; + slist = gray_slist_create(); + if (!slist) + return errno_to_pam(errno); + size = gray_base64_decode(slist, db_pass, strlen (db_pass)); if (size <= 16) { - _pam_log (LOG_ERR, "malformed SSHA1 password: %s", db_pass); + rc = errno_to_pam(errno); gray_slist_free(&slist); - return 1; + return rc; } d1 = gray_slist_finish(slist); - - gpam_sha1_init_ctx (&sha1context); - gpam_sha1_process_bytes (pass, strlen (pass), &sha1context); - gpam_sha1_process_bytes (d1 + 20, size - 20, &sha1context); - gpam_sha1_finish_ctx (&sha1context, sha1digest); + if (d1) + { + gpam_sha1_init_ctx (&sha1context); + gpam_sha1_process_bytes (pass, strlen (pass), &sha1context); + gpam_sha1_process_bytes (d1 + 20, size - 20, &sha1context); + gpam_sha1_finish_ctx (&sha1context, sha1digest); - rc = memcmp (sha1digest, d1, sizeof sha1digest) == 0 ? - PAM_SUCCESS : PAM_AUTH_ERR; + rc = memcmp (sha1digest, d1, sizeof sha1digest) == 0 + ? PAM_SUCCESS + : PAM_AUTH_ERR; + } + else + { + rc = errno_to_pam(errno); + } gray_slist_free(&slist); return rc; } static struct passwd_algo { @@ -13,87 +13,34 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <graypam.h> -jmp_buf gray_pam_jmp; - -void -gray_raise(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - _pam_vlog(LOG_ERR, fmt, ap); - va_end(ap); - longjmp(gray_pam_jmp, 1); -} - -void * -gray_malloc(size_t size) -{ - void *p = malloc(size); - if (!p) - gray_raise("Not enough memory"); - return p; -} - -void * -gray_zalloc(size_t size) -{ - void *p = malloc(size); - if (!p) - gray_raise("Not enough memory"); - memset(p, 0, size); - return p; -} - -void * -gray_calloc(size_t count, size_t size) -{ - return gray_zalloc(count * size); -} - -void * -gray_realloc(void *ptr, size_t size) -{ - ptr = realloc(ptr, size); - if (!ptr) - gray_raise("Not enough memory"); - return ptr; -} - void * gray_2nrealloc(void *ptr, size_t *pcount, size_t elsiz) { size_t count = *pcount; if (!ptr) { - if (!count) - count = *pcount = 16; - return gray_calloc(count, elsiz); + if (!count) { + count = 64 / elsiz; + count += !count; + } + } else { + if ((size_t)-1 / 2 / elsiz <= count) { + errno = ENOMEM; + return NULL; + } + count += (count + 1) / 2; } - if ((size_t)-1 / 2 / elsiz <= count) - gray_raise("Not enough memory"); - count *= 2; - *pcount = count; - return gray_realloc(ptr, count * elsiz); -} - - -char * -gray_strdup(const char *str) -{ - char *p; - - if (!str) - return NULL; - p = gray_malloc(strlen(str) + 1); - return strcpy(p, str); + ptr = realloc(ptr, count * elsiz); + if (ptr) + *pcount = count; + return ptr; } - void gray_pam_delete(char *x) { PAM_OVERWRITE(x); free(x); diff --git a/lib/slist.c b/lib/slist.c index b110350..46e516e 100644 --- a/lib/slist.c +++ b/lib/slist.c @@ -25,125 +25,161 @@ struct gray_slist_bucket { size_t size; }; struct gray_slist { struct gray_slist_bucket *head, *tail; struct gray_slist_bucket *free; + int ec; /* error code */ }; static struct gray_slist_bucket * alloc_bucket(size_t size) { - struct gray_slist_bucket *p = gray_malloc(sizeof(*p) + size); - p->buf = (char*)(p + 1); - p->level = 0; - p->size = size; - p->next = NULL; + struct gray_slist_bucket *p = malloc(sizeof(*p) + size); + if (p) { + p->buf = (char*)(p + 1); + p->level = 0; + p->size = size; + p->next = NULL; + } return p; } -static void +static int alloc_pool(gray_slist_t slist, size_t size) { struct gray_slist_bucket *p = alloc_bucket(GRAY_SLIST_BUCKET_SIZE); + if (!p) { + slist->ec = errno; + return 1; + } if (slist->tail) slist->tail->next = p; else slist->head = p; slist->tail = p; + return 0; } -static size_t +static ssize_t copy_chars(gray_slist_t slist, const char *str, size_t n) { size_t rest; - - if (!slist->head || slist->tail->level == slist->tail->size) - alloc_pool(slist, GRAY_SLIST_BUCKET_SIZE); + if (!slist->head || slist->tail->level == slist->tail->size) { + if (alloc_pool(slist, GRAY_SLIST_BUCKET_SIZE)) + return -1; + } rest = slist->tail->size - slist->tail->level; if (n > rest) n = rest; memcpy(slist->tail->buf + slist->tail->level, str, n); slist->tail->level += n; return n; } gray_slist_t -gray_slist_create() +gray_slist_create(void) { - gray_slist_t slist = gray_malloc(sizeof(*slist)); - slist->head = slist->tail = slist->free = 0; + gray_slist_t slist = malloc(sizeof(*slist)); + if (slist) { + slist->head = slist->tail = slist->free = 0; + slist->ec = 0; + } return slist; } +int +gray_slist_err(gray_slist_t slist) +{ + return slist->ec; +} + +void +gray_slist_clerr(gray_slist_t slist) +{ + slist->ec = 0; +} + void gray_slist_clear(gray_slist_t slist) { if (slist->tail) { slist->tail->next = slist->free; slist->free = slist->head; slist->head = slist->tail = NULL; } + gray_slist_clerr(slist); } void gray_slist_free(gray_slist_t *slist) { - struct gray_slist_bucket *p; if (*slist) { + struct gray_slist_bucket *p; gray_slist_clear(*slist); for (p = (*slist)->free; p; ) { struct gray_slist_bucket *next = p->next; free(p); p = next; } } free(*slist); *slist = NULL; } -void +ssize_t gray_slist_append(gray_slist_t slist, const char *str, size_t n) { - const char *ptr = str; - while (n) { - size_t s = copy_chars(slist, ptr, n); - ptr += s; - n -= s; + ssize_t total; + + if (slist->ec) + return -1; + total = 0; + while (total < n) { + ssize_t s = copy_chars(slist, str + total, n - total); + if (s == -1) + return -1; + total += s; } + return total; } -void +ssize_t gray_slist_append_char(gray_slist_t slist, char c) { - gray_slist_append(slist, &c, 1); + return gray_slist_append(slist, &c, 1); } size_t gray_slist_size(gray_slist_t slist) { size_t size = 0; struct gray_slist_bucket *p; for (p = slist->head; p; p = p->next) size += p->level; return size; } -size_t +ssize_t gray_slist_coalesce(gray_slist_t slist) { size_t size; - if (slist->head && slist->head->next == NULL) + if (slist->ec) + return -1; + else if (slist->head && slist->head->next == NULL) size = slist->head->level; else { size = gray_slist_size(slist); - struct gray_slist_bucket *bucket = alloc_bucket(size); - struct gray_slist_bucket *p; + struct gray_slist_bucket *bucket, *p; + + bucket = alloc_bucket(size); + if (!bucket) + return -1; for (p = slist->head; p; ) { struct gray_slist_bucket *next = p->next; memcpy(bucket->buf + bucket->level, p->buf, p->level); bucket->level += p->level; free(p); @@ -162,29 +198,34 @@ gray_slist_head(gray_slist_t slist, size_t *psize) return slist->head ? slist->head->buf : NULL; } void * gray_slist_finish(gray_slist_t slist) { - gray_slist_coalesce(slist); + if (slist->ec) + return NULL; + if (gray_slist_coalesce(slist) == -1) + return NULL; gray_slist_clear(slist); return slist->free->buf; } #define to_num(c) \ (isdigit(c) ? c - '0' : (isxdigit(c) ? toupper(c) - 'A' + 10 : 255 )) -void +int gray_slist_grow_backslash_num(gray_slist_t slist, char *text, char **pend, int len, int base) { int i; int val = 0; char *start = text; - + + if (slist->ec) + return -1; if (text[0] == '\\') { text++; if (base == 16) text++; } @@ -193,20 +234,23 @@ gray_slist_grow_backslash_num(gray_slist_t slist, char *text, char **pend, if (n > 127 || (n = to_num(n)) >= base) break; val = val*base + n; } if (i == 0) { - gray_slist_append(slist, start, 1); + if (gray_slist_append(slist, start, 1) != 1) + return -1; if (pend) *pend = start + 1; } else { - gray_slist_append_char(slist, val); + if (gray_slist_append_char(slist, val) != 1) + return -1; if (pend) *pend = text + i; } + return 0; } int gray_decode_backslash(int c) { static char transtab[] = "a\ab\bf\fn\nr\rt\t"; @@ -216,25 +260,30 @@ gray_decode_backslash(int c) if (*p == c) return p[1]; } return c; } -void +int gray_slist_grow_backslash(gray_slist_t slist, char *text, char **endp) { if (text[1] == '\\' || (unsigned char)text[1] > 127) { - gray_slist_append_char(slist, text[1]); + if (gray_slist_append_char(slist, text[1]) != 1) + return -1; text += 2; - } else if (isdigit(text[1])) - gray_slist_grow_backslash_num(slist, text, &text, 3, 8); - else if (text[1] == 'x' || text[1] == 'X') - gray_slist_grow_backslash_num(slist, text, &text, 2, 16); - else { + } else if (isdigit(text[1])) { + if (gray_slist_grow_backslash_num(slist, text, &text, 3, 8)) + return -1; + } else if (text[1] == 'x' || text[1] == 'X') { + if (gray_slist_grow_backslash_num(slist, text, &text, 2, 16)) + return -1; + } else { int c = gray_decode_backslash(text[1]); - gray_slist_append_char(slist, c); + if (gray_slist_append_char(slist, c) != 1) + return -1; text += 2; } *endp = text; + return 0; } 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 *exp |