diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-08-27 14:05:40 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-08-27 14:15:07 +0300 |
commit | 6a463b85146fc5a10a297617bd253a19b1bc6da7 (patch) | |
tree | f52df486e862bbdbe7ac341c3b5aa22c6ed32775 | |
parent | 9b752a26211d60c7003a7590b027bd0000344523 (diff) | |
download | nsu-6a463b85146fc5a10a297617bd253a19b1bc6da7.tar.gz nsu-6a463b85146fc5a10a297617bd253a19b1bc6da7.tar.bz2 |
Improve debugging and keyfile support.
* Makefile (NSUSRC): Add log.c
Add clean and allclean goals.
* log.c: New file.
* alg.c (nsu_keyfile_private_read,nsu_keyfile_key_read)
(nsu_keyfile_read): New functions.
* main.c: Move keyfile support to the library.
Add debugging statements.
* nsu.c: Add debugging statements.
* nsu.h (nsu_log_level, nsu_logger): New externs.
(nsu_log_msg): New proto.
(nsu_log_enabled,nsu_log): New defines.
(NSU_KEYFILE_): New constants.
(nsu_keyfile_private_read,nsu_keyfile_key_read)
(nsu_keyfile_read): New protos.
-rw-r--r-- | Makefile | 17 | ||||
-rw-r--r-- | alg.c | 547 | ||||
-rw-r--r-- | log.c | 36 | ||||
-rw-r--r-- | main.c | 253 | ||||
-rw-r--r-- | nsu.c | 8 | ||||
-rw-r--r-- | nsu.h | 41 |
6 files changed, 666 insertions, 236 deletions
@@ -1,13 +1,15 @@ CFLAGS=-ggdb APPSRC=main.c y.tab.c lex.yy.c -APPOBJ=${APPSRC: .c=.o} +APPOBJ=${APPSRC:.c=.o} -NSUSRC=nsu.c typestr.c alg.c -NSUOBJ=${NSUSRC: .c=.o} +NSUSRC=nsu.c typestr.c alg.c log.c +NSUOBJ=${NSUSRC:.c=.o} -nsu: main.o $(NSUOBJ) $(APPOBJ) - cc $(CFLAGS) -o nsu $(NSUOBJ) $(APPOBJ) -lresolv -lnettle +OBJS=$(NSUOBJ) $(APPOBJ) + +nsu: $(OBJS) + cc $(CFLAGS) -o nsu $(OBJS) -lresolv -lnettle $(NSUOBJ) $(APPOBJ): nsu.h @@ -19,4 +21,9 @@ lex.yy.o: y.tab.h lex.yy.c: lexer.l flex -d lexer.l +clean: + rm -f nsu $(OBJS) + +allclean: clean + rm -f lex.yy.c y.tab.c y.tab.h @@ -1,5 +1,8 @@ #include <stdlib.h> #include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <errno.h> #include <nettle/md5.h> #include <nettle/sha1.h> #include <nettle/sha2.h> @@ -168,7 +171,551 @@ nsu_tsig_free(struct nsu_tsig *sgn) free(sgn->digest); free(sgn); } + +/* Parse the keyfile name and attempt to extract the keyname from it. + * + * The FILENAME is expected to match the following pattern: + * + * K<KEYNAME>.+<ALGCODE>+<NUMBER>.<EXT> + * + * where <ALGCODE> and <NUMBER> are decimal numbers, <EXT> is any string, + * and <ALGCODE> equals ALG. If these conditions are met, the <KEYNAME> + * is copied to the allocated memory block and the address of that block + * is stored in KEYNAME. + * + * Return value: 0 - success; KEYNAME holds the key name. + * 1 - FILENAME doesn't match the pattern. + * -1 - system error; inspect errno for details. + */ +static int +filename_to_keyname(char const *filename, int alg, char **keyname) +{ + char const *start, *p, *q; + char *key; + size_t len; + + p = strrchr(filename, '/'); + if (p) + filename = p + 1; + + if (filename[0] != 'K') + return 1; + filename++; + start = filename; + len = strcspn(start, "+"); + if (len < 2 || start[len] != '+' || start[len-1] != '.') + return 1; + filename += len + 1; + + p = strchr(filename, '+'); + if (!p) + return 1; + for (q = p + 1; *q && *q != '.'; q++) { + if (!isdigit(*q)) + return 1; + } + + q = p; + while (alg > 0) { + if (--q == p) + return 1; + else if (alg % 10 + '0' != *q) + return 1; + alg /= 10; + } + + key = malloc(len); + if (!key) + return -1; + len--; + memcpy(key, start, len); + key[len] = 0; + + *keyname = key; + return 0; +} + +static int +filename_to_alg(char const *filename, struct nsu_tsig_alg const **palg) +{ + long n; + char const *p, *q; + char *end; + size_t len; + + p = strrchr(filename, '/'); + if (p) + filename = p + 1; + + if (filename[0] != 'K') + return 1; + filename++; + len = strcspn(filename, "+"); + if (len < 2 || filename[len] != '+' || filename[len-1] != '.') + return 1; + filename += len + 1; + + p = strchr(filename, '+'); + if (!p) + return 1; + for (q = p + 1; *q && *q != '.'; q++) { + if (!isdigit(*q)) + return 1; + } + errno = 0; + n = strtol(filename, &end, 10); + if (errno || *end != '+') + return 1; + + *palg = nsu_tsig_alg_find_code(n); + return 0; +} + +/* Parse the private key file generated by dnssec-keygen. + * On success, fill the return arguments: + * + * palg - pointer to the nsu_tsig_alg structure; + * pkeyname - (malloc) Key name or NULL if unable to deduce; + * pkey - (malloc) Key value. + * pkey_len - length of the key. + * + * Arguments marked with (malloc) are allocated. + * + * Return value: + * NSU_KEYFILE_OK - success; + * NSU_KEYFILE_BAD - bad file format; + * NSU_KEYFILE_ALG - file refers to an unknown or unsupported algorithm; + * NSU_KEYFILE_ERR - system error; inspect errno; + */ +int +nsu_keyfile_private_read(char const *filename, + struct nsu_tsig_alg const **palg, + char **pkeyname, + uint8_t **pkey, size_t *pkey_len) +{ + FILE *fp; + char buf[512]; + int lno = 0; + int rc = NSU_KEYFILE_OK; + struct nsu_tsig_alg const *alg = NULL; + uint8_t *key = NULL; + size_t key_len; + char *keyname = NULL; + + static char algorithm_field[] = "Algorithm"; + static int algorithm_length = sizeof(algorithm_field) - 1; + static char key_field[] = "Key"; + static int key_length = sizeof(key_field) - 1; + + fp = fopen(filename, "r"); + if (!fp) { + nsu_log(NSU_LOG_ERR, "can't open %s: %s", + filename, strerror(errno)); + rc = NSU_KEYFILE_ERR; + } else { + nsu_log(NSU_LOG_DEBUG, "Parsing private keyfile %s", filename); + while (fgets(buf, sizeof(buf), fp)) { + size_t len, n; + lno++; + len = strlen(buf); + if (len == 0) + break; + if (buf[len-1] != '\n') { + nsu_log(NSU_LOG_ERR, "%s:%d: line too long", + filename, lno); + rc = NSU_KEYFILE_BAD; + break; + } + buf[--len] = '\n'; + n = strcspn(buf, ":"); + if (buf[n] == 0) { + nsu_log(NSU_LOG_ERR, "%s:%d: malformed line", + filename, lno); + rc = NSU_KEYFILE_BAD; + break; + } + if (n == algorithm_length && + memcmp(algorithm_field, buf, n) == 0) { + char *p; + long code; + errno = 0; + code = strtol(buf + n + 1, &p, 10); + if (errno || *p != ' ') { + nsu_log(NSU_LOG_ERR, + "%s:%d: malformed line", + filename, lno); + rc = NSU_KEYFILE_BAD; + break; + } + + alg = nsu_tsig_alg_find_code(code); + if (!alg) { + nsu_log(NSU_LOG_ERR, + "%s:%d: unsupported algorithm %s", + filename, lno, buf + n); + rc = NSU_KEYFILE_ALG; + break; + } + } else if (n == key_length && + memcmp(key_field, buf, n) == 0) { + struct base64_decode_ctx ctx; + size_t src_len; + char *p; + + p = buf + n + 1; + while (*p == ' ' || *p == '\t') + p++; + src_len = strlen(p); + key_len = BASE64_DECODE_LENGTH(src_len); + key = malloc(key_len); + if (!key) { + rc = NSU_KEYFILE_ERR; + break; + } + + base64_decode_init(&ctx); + base64_decode_update(&ctx, &key_len, key, + src_len, p); + if (!base64_decode_final(&ctx)) { + nsu_log(NSU_LOG_ERR, + "%s:%d: bad base64", + filename, lno); + rc = NSU_KEYFILE_BAD; + break; + } + } + } + fclose(fp); + } + + if (rc == NSU_KEYFILE_OK) { + if (!alg) { + nsu_log(NSU_LOG_ERR, "%s: no %s clause", + filename, algorithm_field); + rc = NSU_KEYFILE_BAD; + } + if (!key) { + nsu_log(NSU_LOG_ERR, "%s: no %s clause", + filename, key_field); + rc = NSU_KEYFILE_BAD; + } + } + + if (rc == NSU_KEYFILE_OK) { + char const *basename = strrchr(filename, '/'); + if (basename) + basename++; + else + basename = filename; + if (filename_to_keyname(filename, alg->code, &keyname) < 0) + rc = NSU_KEYFILE_ERR; + } + + if (rc == NSU_KEYFILE_OK) { + nsu_log(NSU_LOG_DEBUG, "%s: algo=%s, keyname=%s, key length=%zu", + filename, alg->name, keyname ? keyname : "(unknown)", + key_len); + *pkeyname = keyname; + *palg = alg; + *pkey = key; + *pkey_len = key_len; + } else { + free(key); + free(keyname); + } + + return rc; +} + +/* Parse the private key file generated by dnssec-keygen. + * On success, fill the return arguments: + * + * pkeyname - (malloc) Key name or NULL if unable to deduce; + * pkey - (malloc) Key value. + * pkey_len - length of the key. + * + * Arguments marked with (malloc) are allocated. + * + * Return value: see nsu_keyfile_private_read + */ +int +nsu_keyfile_key_read(char const *filename, + struct nsu_tsig_alg const **palg, + char **pkeyname, + uint8_t **pkey, size_t *pkey_len) +{ + char buf[512]; + char *ret, *keyptr; + size_t n; + uint8_t *key = NULL; + FILE *fp; + int i; + size_t src_len, key_len; + struct base64_decode_ctx ctx; + int rc; + + fp = fopen(filename, "r"); + if (!fp) { + nsu_log(NSU_LOG_ERR, "can't open %s: %s", + filename, strerror(errno)); + rc = NSU_KEYFILE_ERR; + goto err; + } + + nsu_log(NSU_LOG_DEBUG, "Parsing keyfile %s", filename); + if (!fgets(buf, sizeof(buf), fp)) { + nsu_log(NSU_LOG_ERR, "%s: read error", filename); + rc = NSU_KEYFILE_ERR; + goto err; + } + + n = strcspn(buf, " "); + if (strncmp(buf + n, " IN KEY", 7)) { + nsu_log(NSU_LOG_ERR, "%s:%d: malformed line", filename, 1); + rc = NSU_KEYFILE_BAD; + goto err; + } + keyptr = buf + n + 7; + for (i = 0; i < 3; i++) { + while (*keyptr && isspace(*keyptr)) + keyptr++; + while (*keyptr && isdigit(*keyptr)) + keyptr++; + } + while (*keyptr && isspace(*keyptr)) + keyptr++; + + src_len = strlen(keyptr); + key_len = BASE64_DECODE_LENGTH(src_len); + key = malloc(key_len); + if (!key) { + rc = NSU_KEYFILE_ERR; + goto err; + } + + base64_decode_init(&ctx); + base64_decode_update(&ctx, &key_len, key, src_len, keyptr); + if (!base64_decode_final(&ctx)) { + nsu_log(NSU_LOG_ERR, "%s:%d: bad base64", filename, 1); + rc = NSU_KEYFILE_BAD; + goto err; + } + + if (buf[n-1] == '.') + --n; + ret = malloc(n+1); + if (!ret) { + rc = NSU_KEYFILE_ERR; + goto err; + } + memcpy(ret, buf, n); + ret[n] = 0; + + filename_to_alg(filename, palg); + *pkeyname = ret; + *pkey = key; + *pkey_len = key_len; + nsu_log(NSU_LOG_DEBUG, "%s: algo=%s, keyname=%s, key length=%zu", + filename, + *palg ? (*palg)->name : "(unknown)", + ret, key_len); + rc = NSU_KEYFILE_OK; +err: + if (rc != NSU_KEYFILE_OK) + free(key); + + fclose(fp); + + return rc; +} + +static int +is_suffix(char const *suf, char const *str) +{ + size_t suflen = strlen(suf); + size_t len = strlen(str); + return suflen < len && memcmp(str + len - suflen, suf, suflen) == 0; +} + +static char const *priv_suffix = ".private"; +static char const *key_suffix = ".key"; + +/* + * Create new file name by removing last SUFLEN characters from BASENAME + * and appending NEWSUF to the resulting string. Returned value is + * malloced. + */ +static char * +makefilename(char const *basename, size_t suflen, char const *new_suf) +{ + size_t len = strlen(basename); + char *p; + + if (len <= suflen) { + errno = EINVAL; + return NULL; + } + + len -= suflen; + p = malloc(len + strlen(new_suf) + 1); + if (!p) + return p; + + memcpy(p, basename, len); + strcpy(p + len, new_suf); + + return p; +} + +/* + * Read the keyfile NAME. On success, create struct nsu_tsig and + * populate it with the information obtained from the file. + * + * Return NSU_KEYFILE_OK on success, and another NSU_KEYFILE_* constant + * on error (see the description in nsu_keyfile_private_read). + * + * If NAME ends with ".private", that file is read. If the + * key name cannot be deduced from the file name, the ".key" file + * will be read in addition, in order to determine it. + * + * If NAME ends with dot, then first the dot is replaced with + * ".private" and an attempt is made to read that file as described + * above. If the private file does not exist, the suffix is replaced + * with ".key" and the file is read as described below. + * + * If NAME ends with ".key", the key file is read. The algorithm + * is then deduced from the file name. + */ +int +nsu_keyfile_read(char const *name, struct nsu_tsig **ptsig) +{ + struct nsu_tsig_alg const *alg = NULL, *kalg; + uint8_t *key, *kkey; + size_t key_len, kkey_len; + char *keyname = NULL; + struct nsu_tsig *tsig; + int rc; + char *keyfilename = NULL; + + if (is_suffix(priv_suffix, name)) { + rc = nsu_keyfile_private_read(name, &alg, &keyname, + &key, &key_len); + switch (rc) { + case NSU_KEYFILE_OK: + if (keyname) + name = NULL; + else { + keyfilename = makefilename(name, + strlen(priv_suffix), + key_suffix); + if (!keyfilename) + return NSU_KEYFILE_ERR; + name = keyfilename; + nsu_log(NSU_LOG_DEBUG, + "keyname not known, will try %s", name); + } + break; + + case NSU_KEYFILE_BAD: + case NSU_KEYFILE_ALG: + case NSU_KEYFILE_ERR: + return rc; + } + } else if (is_suffix(".", name)) { + char *tmpname = makefilename(name, 1, priv_suffix); + if (!tmpname) + return NSU_KEYFILE_ERR; + rc = nsu_keyfile_private_read(tmpname, + &alg, &keyname, &key, &key_len); + free(tmpname); + switch (rc) { + case NSU_KEYFILE_OK: + if (keyname) + name = NULL; + else { + keyfilename = makefilename(name, + 1, + key_suffix); + if (!keyfilename) + return NSU_KEYFILE_ERR; + name = keyfilename; + nsu_log(NSU_LOG_DEBUG, + "keyname not known, will try %s", name); + } + break; + + case NSU_KEYFILE_BAD: + case NSU_KEYFILE_ALG: + return rc; + + case NSU_KEYFILE_ERR: + if (errno == ENOENT) { + keyfilename = makefilename(name, + 1, + key_suffix); + if (!keyfilename) + return NSU_KEYFILE_ERR; + nsu_log(NSU_LOG_DEBUG, + "file %s does not exist, " + "will try %s", name, keyfilename); + name = keyfilename; + } else + return rc; + } + } else if (!is_suffix(key_suffix, name)) { + nsu_log(NSU_LOG_DEBUG, + "%s: unknown keyfile suffix", name); + return NSU_KEYFILE_BAD; + } + + if (name) { + rc = nsu_keyfile_key_read(name, &kalg, &keyname, + &kkey, &kkey_len); + + if (rc == NSU_KEYFILE_OK) { + if (!alg) + alg = kalg; + else if (kalg != alg) { + nsu_log(NSU_LOG_ERR, "%s: algorithm mismatch", + name); + rc = NSU_KEYFILE_BAD; + } + } + + if (rc == NSU_KEYFILE_OK) { + if (!key) { + key = kkey; + key_len = kkey_len; + kkey = NULL; + } else if (kkey_len != key_len || + memcmp(kkey, key, key_len)) { + nsu_log(NSU_LOG_ERR, "%s: keys don't match", + name); + rc = NSU_KEYFILE_BAD; + } + } + free(kkey); + free(keyfilename); + } + + if (rc == NSU_KEYFILE_OK) { + tsig = nsu_tsig_create(alg, keyname); + if (!tsig) + rc = NSU_KEYFILE_ERR; + else + nsu_tsig_set_key(tsig, key, key_len); + } + + free(keyname); + free(key); + + if (rc == NSU_KEYFILE_OK) + *ptsig = tsig; + + return rc; +} + @@ -0,0 +1,36 @@ +#include <stdio.h> +#include <stdarg.h> +#include "nsu.h" + +int nsu_log_level = NSU_LOG_ERR; + +static char const *nsu_severity_str[] = { + "debug", + "warning", + "error", +}; + +static void +__nsu_log_prt(int severity, char const *fmt, va_list ap) +{ + if (severity >= 0 && + severity < sizeof(nsu_severity_str)/sizeof(nsu_severity_str[0])) { + fprintf(stderr, "nsu %s: ", nsu_severity_str[severity]); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + } +} + +void (*nsu_logger)(int, char const *, va_list) = __nsu_log_prt; + +void +nsu_log_msg(int severity, char const *fmt, ...) +{ + if (nsu_logger) { + va_list ap; + va_start(ap, fmt); + nsu_logger(severity, fmt, ap); + va_end(ap); + } +} + @@ -319,224 +319,6 @@ get_arg_ul(char const *arg, unsigned long *np) return 0; } -static int -is_suffix(char const *suf, char const *str) -{ - size_t suflen = strlen(suf); - size_t len = strlen(str); - return suflen < len && memcmp(str + len - suflen, suf, suflen) == 0; -} - -static char const *priv_suffix = ".private"; -static char const *key_suffix = ".key"; - -static struct nsu_tsig_alg const * -keyfile_read_private(char const *name, uint8_t **pkey, size_t *pkey_len) -{ - char *tmpname = NULL; - FILE *fp; - char buf[512]; - int lno = 0; - - struct nsu_tsig_alg const *alg = NULL; - uint8_t *key; - size_t key_len; - - static char algorithm_field[] = "Algorithm"; - static int algorithm_length = sizeof(algorithm_field) - 1; - static char key_field[] = "Key"; - static int key_length = sizeof(key_field) - 1; - - if (is_suffix(key_suffix, name)) { - size_t baselen = strlen(name) - strlen(key_suffix); - tmpname = malloc(baselen + strlen(priv_suffix) + 1); - if (!tmpname) - abend_nomem(); - memcpy(tmpname, name, baselen); - strcpy(tmpname + baselen, priv_suffix); - name = tmpname; - } else if (access(name, F_OK) && errno == ENOENT) { - size_t namelen = strlen(name); - if (name[namelen-1] == '.') { - tmpname = malloc(namelen + strlen(priv_suffix)); - if (!tmpname) - abend_nomem(); - memcpy(tmpname, name, namelen - 1); - strcpy(tmpname + namelen - 1, priv_suffix); - name = tmpname; - } - } - - fp = fopen(name, "r"); - if (!fp) - abend("can't open %s: %s", name, strerror(errno)); - while (fgets(buf, sizeof(buf), fp)) { - size_t len, n; - lno++; - len = strlen(buf); - if (len == 0) - break; - if (buf[len-1] != '\n') - abend("%s:%d: line too long", name, lno); - buf[--len] = '\n'; - n = strcspn(buf, ":"); - if (buf[n] == 0) - abend("%s:%d: malformed line", name, lno); - if (n == algorithm_length && - memcmp(algorithm_field, buf, n) == 0) { - char *p; - long code; - errno = 0; - code = strtol(buf + n + 1, &p, 10); - if (errno || *p != ' ') - abend("%s:%d: malformed line", name, lno); - - alg = nsu_tsig_alg_find_code(code); - if (!alg) - abend("%s:%d: unsupported algorithm %s", - name, lno, buf + n); - } else if (n == key_length && memcmp(key_field, buf, n) == 0) { - struct base64_decode_ctx ctx; - size_t src_len; - char *p; - - p = buf + n + 1; - while (*p == ' ' || *p == '\t') - p++; - src_len = strlen(p); - key_len = BASE64_DECODE_LENGTH(src_len); - key = malloc(key_len); - if (!key) - abend_nomem(); - - base64_decode_init(&ctx); - base64_decode_update(&ctx, &key_len, key, src_len, p); - if (!base64_decode_final(&ctx)) - abend("%s:%d: bad base64", name, lno); - } - } - fclose(fp); - - if (!alg) - abend("%s:%d: no %s clause", algorithm_field); - if (!key) - abend("%s:%d: no %s clause", key_field); - - free(tmpname); - - *pkey = key; - *pkey_len = key_len; - return alg; - -} - -static char * -keyfile_read_key(char const *name, uint8_t **pkey, size_t *pkey_len) -{ - char *tmpname = NULL; - char buf[512]; - char *ret, *keyptr; - size_t n; - uint8_t *key; - FILE *fp; - int i; - size_t src_len, key_len; - struct base64_decode_ctx ctx; - - if (is_suffix(priv_suffix, name)) { - size_t baselen = strlen(name) - strlen(priv_suffix); - tmpname = malloc(baselen + strlen(key_suffix) + 1); - if (!tmpname) - abend_nomem(); - memcpy(tmpname, name, baselen); - strcpy(tmpname + baselen, key_suffix); - name = tmpname; - } else if (access(name, F_OK) && errno == ENOENT) { - size_t namelen = strlen(name); - if (name[namelen-1] == '.') { - tmpname = malloc(namelen + strlen(key_suffix)); - if (!tmpname) - abend_nomem(); - memcpy(tmpname, name, namelen - 1); - strcpy(tmpname + namelen - 1, key_suffix); - name = tmpname; - } - } - - fp = fopen(name, "r"); - if (!fp) - abend("can't open %s: %s", name, strerror(errno)); - if (!fgets(buf, sizeof(buf), fp)) - abend("%s: read error", name); - fclose(fp); - - n = strcspn(buf, " "); - if (strncmp(buf + n, " IN KEY", 7)) - abend("%s:%d: malformed line", name, 1); - - keyptr = buf + n + 7; - for (i = 0; i < 3; i++) { - while (*keyptr && isspace(*keyptr)) - keyptr++; - while (*keyptr && isdigit(*keyptr)) - keyptr++; - } - while (*keyptr && isspace(*keyptr)) - keyptr++; - - src_len = strlen(keyptr); - key_len = BASE64_DECODE_LENGTH(src_len); - key = malloc(key_len); - if (!key) - abend_nomem(); - - base64_decode_init(&ctx); - base64_decode_update(&ctx, &key_len, key, src_len, keyptr); - if (!base64_decode_final(&ctx)) - abend("%s:%d: bad base64", name, 1); - *pkey = key; - *pkey_len = key_len; - - if (buf[n-1] == '.') - --n; - ret = malloc(n+1); - if (!ret) - abend_nomem(); - memcpy(ret, buf, n); - ret[n] = 0; - - free(tmpname); - - return ret; -} - -static struct nsu_tsig * -keyfile_read(char const *name) -{ - struct nsu_tsig_alg const *alg; - uint8_t *pkey, *key; - size_t pkey_len, key_len; - char *keyname; - struct nsu_tsig *sgn; - - alg = keyfile_read_private(name, &pkey, &pkey_len); - keyname = keyfile_read_key(name, &key, &key_len); - - if (pkey_len != key_len || memcmp(pkey, key, key_len)) - abend("%s: keys don't match", name); - free(pkey); - - sgn = nsu_tsig_create(alg, keyname); - free(keyname); - if (!sgn) - abend_nomem(); - - nsu_tsig_set_key(sgn, key, key_len); - free(key); - - return sgn; -} - /* * nsu */ @@ -576,7 +358,9 @@ main(int argc, char **argv) break; case 'x': - if (yydebug == 1) + if (nsu_log_level != NSU_LOG_DEBUG) + nsu_log_level = NSU_LOG_DEBUG; + else if (yydebug == 1) yy_flex_debug = 1; else yydebug = 1; @@ -590,8 +374,24 @@ main(int argc, char **argv) argc -= optind; argv += optind; - if (keyfile_name) - tsig = keyfile_read(keyfile_name); + if (keyfile_name) { + switch (nsu_keyfile_read(keyfile_name, &tsig)) { + case NSU_KEYFILE_OK: + break; + + case NSU_KEYFILE_BAD: + abend("bad keyfile format"); + + case NSU_KEYFILE_ALG: + abend("unknown or unsupported algorithm in keyfile"); + + case NSU_KEYFILE_ERR: + abend("%s: %s", keyfile_name, strerror(errno)); + + default: + abort(); + } + } if (input_file) lexer_from_file(input_file); @@ -620,7 +420,7 @@ send_update_query(res_state state, char const *zone, u_char *qbuf, int qlen) ns_msg handle; int rcode; - if (state->options & RES_DEBUG) { + if (nsu_log_enabled(NSU_LOG_DEBUG) || state->options & RES_DEBUG) { char name[NS_MAXDNAME]; getnameinfo((struct sockaddr*)state->nsaddr_list, @@ -628,7 +428,7 @@ send_update_query(res_state state, char const *zone, u_char *qbuf, int qlen) name, sizeof(name), NULL, 0, NI_NUMERICHOST); - printf(";; trying nameserver %s\n", name); + nsu_log_msg(NSU_LOG_DEBUG, "trying nameserver %s", name); } rlen = res_nsend(state, qbuf, qlen, @@ -666,7 +466,8 @@ send_update_query(res_state state, char const *zone, u_char *qbuf, int qlen) */ case ns_r_notimpl: case ns_r_servfail: - if (state->options & RES_DEBUG) { + if (nsu_log_enabled(NSU_LOG_DEBUG) + || state->options & RES_DEBUG) { char name[NS_MAXDNAME]; getnameinfo((struct sockaddr*)state->nsaddr_list, @@ -674,8 +475,8 @@ send_update_query(res_state state, char const *zone, u_char *qbuf, int qlen) name, sizeof(name), NULL, 0, NI_NUMERICHOST); - printf(";; nameserver %s: %s", name, - ns_rcodestr(rcode)); + nsu_log_msg(NSU_LOG_DEBUG, "nameserver %s: %s", name, + ns_rcodestr(rcode)); } return update_retry; @@ -126,11 +126,9 @@ nsu_nmkquery(res_state statp, u_char *dnptrs[20], **lastdnptr; int class = ns_c_in; int type = ns_t_soa; - -#ifdef DEBUG - if (statp->options & RES_DEBUG) - printf(";; make_update_query %s", zone); -#endif + + nsu_log(NSU_LOG_DEBUG, "%s: %s", __func__, zone); + /* * Initialize header fields. */ @@ -1,4 +1,5 @@ #include <resolv.h> +#include <stdarg.h> enum { NSU_PREREQ_YXRRSET, /* RRset exists (value independent) */ @@ -107,5 +108,45 @@ int nsu_mkquery(char const *zone, nsu_rr *update, int num_update, struct nsu_tsig *tsig, u_char *buf, int buflen); + +enum { + NSU_LOG_DEBUG, + NSU_LOG_WARN, + NSU_LOG_ERR, + NSU_LOG_NONE +}; + +extern int nsu_log_level; +extern void (*nsu_logger)(int, char const *, va_list); + +void nsu_log_msg(int severity, char const *fmt, ...); + +#define nsu_log_enabled(svr) ((svr) >= nsu_log_level) + +#define nsu_log(svr, fmt, ...) \ + do { \ + if (nsu_log_enabled(svr)) { \ + nsu_log_msg(svr, fmt, __VA_ARGS__); \ + } \ + } while (0) + +enum { + NSU_KEYFILE_OK, + NSU_KEYFILE_BAD, + NSU_KEYFILE_ALG, + NSU_KEYFILE_ERR +}; + +int nsu_keyfile_key_read(char const *filename, + struct nsu_tsig_alg const **palg, + char **pkeyname, + uint8_t **pkey, size_t *pkey_len); +int nsu_keyfile_private_read(char const *filename, + struct nsu_tsig_alg const **palg, + char **pkeyname, + uint8_t **pkey, size_t *pkey_len); + +int nsu_keyfile_read(char const *name, struct nsu_tsig **ptsig); + |