Be verbose about MIT dump entry parsing failures
This commit is contained in:
		| @@ -1153,7 +1153,7 @@ nexttoken(char **p) | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| static char * | static char * | ||||||
| nexttoken(char **p, size_t len) | nexttoken(char **p, size_t len, const char *what) | ||||||
| { | { | ||||||
|     char *q; |     char *q; | ||||||
|  |  | ||||||
| @@ -1163,17 +1163,23 @@ nexttoken(char **p, size_t len) | |||||||
|     q = *p; |     q = *p; | ||||||
|     *p += len; |     *p += len; | ||||||
|     /* Must be followed by a delimiter (right?) */ |     /* Must be followed by a delimiter (right?) */ | ||||||
|     if (strsep(p, " \t") != q + len) |     if (strsep(p, " \t") != q + len) { | ||||||
|  |         warnx("No tokens left in dump entry while looking for %s", what); | ||||||
|         return NULL; |         return NULL; | ||||||
|  |     } | ||||||
|  |     if (*q == '\0') | ||||||
|  |         warnx("Empty last token in dump entry while looking for %s", what); | ||||||
|     return q; |     return q; | ||||||
| } | } | ||||||
|  |  | ||||||
| static size_t | static size_t | ||||||
| getdata(char **p, unsigned char *buf, size_t len) | getdata(char **p, unsigned char *buf, size_t len, const char *what) | ||||||
| { | { | ||||||
|     size_t i; |     size_t i; | ||||||
|     int v; |     int v; | ||||||
|     char *q = nexttoken(p, 0); |     char *q = nexttoken(p, 0, what); | ||||||
|  |     if (q == NULL) | ||||||
|  |         warnx("Failed to find hex-encoded binary data (%s) in dump", what); | ||||||
|     i = 0; |     i = 0; | ||||||
|     while(*q && i < len) { |     while(*q && i < len) { | ||||||
| 	if(sscanf(q, "%02x", &v) != 1) | 	if(sscanf(q, "%02x", &v) != 1) | ||||||
| @@ -1185,23 +1191,27 @@ getdata(char **p, unsigned char *buf, size_t len) | |||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| getint(char **p) | getint(char **p, const char *what) | ||||||
| { | { | ||||||
|     int val; |     int val; | ||||||
|     char *q = nexttoken(p, 0); |     char *q = nexttoken(p, 0, what); | ||||||
|     if (!q) |     if (!q) { | ||||||
|  |         warnx("Failed to find a signed integer (%s) in dump", what); | ||||||
|         return -1; |         return -1; | ||||||
|  |     } | ||||||
|     sscanf(q, "%d", &val); |     sscanf(q, "%d", &val); | ||||||
|     return val; |     return val; | ||||||
| } | } | ||||||
|  |  | ||||||
| static unsigned int | static unsigned int | ||||||
| getuint(char **p) | getuint(char **p, const char *what) | ||||||
| { | { | ||||||
|     int val; |     int val; | ||||||
|     char *q = nexttoken(p, 0); |     char *q = nexttoken(p, 0, what); | ||||||
|     if (!q) |     if (!q) { | ||||||
|  |         warnx("Failed to find an unsigned integer (%s) in dump", what); | ||||||
|         return 0; |         return 0; | ||||||
|  |     } | ||||||
|     sscanf(q, "%u", &val); |     sscanf(q, "%u", &val); | ||||||
|     return val; |     return val; | ||||||
| } | } | ||||||
| @@ -1246,59 +1256,72 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) | |||||||
|  |  | ||||||
|     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); |     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); | ||||||
|  |  | ||||||
|     q = nexttoken(&p, 0); |     q = nexttoken(&p, 0, "record type (princ or policy)"); | ||||||
|     if (strcmp(q, "kdb5_util") == 0 || strcmp(q, "policy") == 0 || |     if (strcmp(q, "kdb5_util") == 0 || strcmp(q, "policy") == 0 || | ||||||
|         strcmp(q, "princ") != 0) { |         strcmp(q, "princ") != 0) { | ||||||
|  |         warnx("Supposed MIT dump entry does not start with 'kdb5_util', " | ||||||
|  |               "'policy', nor 'princ'"); | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|     if (getint(&p) != 38) |     if (getint(&p, "constant '38'") != 38) { | ||||||
|  |         warnx("Dump entry does not start with '38<TAB>'"); | ||||||
|         return EINVAL; |         return EINVAL; | ||||||
|  |     } | ||||||
| #define KDB_V1_BASE_LENGTH 38 | #define KDB_V1_BASE_LENGTH 38 | ||||||
|     ret = krb5_store_int16(sp, KDB_V1_BASE_LENGTH); |     ret = krb5_store_int16(sp, KDB_V1_BASE_LENGTH); | ||||||
|     if (ret) return ret; |     if (ret) return ret; | ||||||
|  |  | ||||||
|     princ_len = getuint(&p); /* length of principal */ |     princ_len = getuint(&p, "principal name length"); | ||||||
|     if (princ_len > (1<<15) - 1) return EINVAL; |     if (princ_len > (1<<15) - 1) { | ||||||
|     num_tl_data = getuint(&p); /* number of tl-data */ |         warnx("Principal name in dump entry too long (%llu)", | ||||||
|     num_key_data = getuint(&p); /* number of key-data */ |               (unsigned long long)princ_len); | ||||||
|     getint(&p);  /* length of extra data */ |         return EINVAL; | ||||||
|     princ = nexttoken(&p, (int)princ_len); /* principal name */ |     } | ||||||
|  |     num_tl_data = getuint(&p, "number of TL data"); | ||||||
|  |     num_key_data = getuint(&p, "number of key data"); | ||||||
|  |     getint(&p, "5th field, length of 'extra data'"); | ||||||
|  |     princ = nexttoken(&p, (int)princ_len, "principal name"); | ||||||
|  |     if (princ == NULL) { | ||||||
|  |         warnx("Failed to read principal name (expected length %llu)", | ||||||
|  |               (unsigned long long)princ_len); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     attributes = getuint(&p); /* attributes */ |     attributes = getuint(&p, "attributes"); | ||||||
|     ret = krb5_store_uint32(sp, attributes); |     ret = krb5_store_uint32(sp, attributes); | ||||||
|     if (ret) return ret; |     if (ret) return ret; | ||||||
|  |  | ||||||
|     tmp = getint(&p); /* max life */ |     tmp = getint(&p, "max life"); | ||||||
|     CHECK_UINT(tmp); |     CHECK_UINT(tmp); | ||||||
|     ret = krb5_store_uint32(sp, tmp); |     ret = krb5_store_uint32(sp, tmp); | ||||||
|     if (ret) return ret; |     if (ret) return ret; | ||||||
|  |  | ||||||
|     tmp = getint(&p); /* max renewable life */ |     tmp = getint(&p, "max renewable life"); | ||||||
|     CHECK_UINT(tmp); |     CHECK_UINT(tmp); | ||||||
|     ret = krb5_store_uint32(sp, tmp); |     ret = krb5_store_uint32(sp, tmp); | ||||||
|     if (ret) return ret; |     if (ret) return ret; | ||||||
|  |  | ||||||
|     tmp = getint(&p); /* expiration */ |     tmp = getint(&p, "expiration"); | ||||||
|     CHECK_UINT(tmp); |     CHECK_UINT(tmp); | ||||||
|     ret = krb5_store_uint32(sp, tmp); |     ret = krb5_store_uint32(sp, tmp); | ||||||
|     if (ret) return ret; |     if (ret) return ret; | ||||||
|  |  | ||||||
|     tmp = getint(&p); /* pw expiration */ |     tmp = getint(&p, "pw expiration"); | ||||||
|     CHECK_UINT(tmp); |     CHECK_UINT(tmp); | ||||||
|     ret = krb5_store_uint32(sp, tmp); |     ret = krb5_store_uint32(sp, tmp); | ||||||
|     if (ret) return ret; |     if (ret) return ret; | ||||||
|  |  | ||||||
|     tmp = getint(&p); /* last auth */ |     tmp = getint(&p, "last auth"); | ||||||
|     CHECK_UINT(tmp); |     CHECK_UINT(tmp); | ||||||
|     ret = krb5_store_uint32(sp, tmp); |     ret = krb5_store_uint32(sp, tmp); | ||||||
|     if (ret) return ret; |     if (ret) return ret; | ||||||
|  |  | ||||||
|     tmp = getint(&p); /* last failed auth */ |     tmp = getint(&p, "last failed auth"); | ||||||
|     CHECK_UINT(tmp); |     CHECK_UINT(tmp); | ||||||
|     ret = krb5_store_uint32(sp, tmp); |     ret = krb5_store_uint32(sp, tmp); | ||||||
|     if (ret) return ret; |     if (ret) return ret; | ||||||
|  |  | ||||||
|     tmp = getint(&p); /* fail auth count */ |     tmp = getint(&p,"fail auth count"); | ||||||
|     CHECK_UINT(tmp); |     CHECK_UINT(tmp); | ||||||
|     ret = krb5_store_uint32(sp, tmp); |     ret = krb5_store_uint32(sp, tmp); | ||||||
|     if (ret) return ret; |     if (ret) return ret; | ||||||
| @@ -1323,12 +1346,21 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) | |||||||
|  |  | ||||||
|     /* scan and write TL data */ |     /* scan and write TL data */ | ||||||
|     for (i = 0; i < num_tl_data; i++) { |     for (i = 0; i < num_tl_data; i++) { | ||||||
|  |         char *reading_what; | ||||||
|         int tl_type, tl_length; |         int tl_type, tl_length; | ||||||
|         unsigned char *buf; |         unsigned char *buf; | ||||||
|  |  | ||||||
|         tl_type = getint(&p); /* data type */ |         tl_type = getint(&p, "TL data type"); | ||||||
|         tl_length = getint(&p); /* data length */ |         tl_length = getint(&p, "data length"); | ||||||
|  |  | ||||||
|  |         if (asprintf(&reading_what, "TL data type %d (length %d)", | ||||||
|  |                      tl_type, tl_length) < 0) | ||||||
|  |             return ENOMEM; | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |          * XXX Leaking reading_what, but only on ENOMEM cases anyways, | ||||||
|  |          * so we don't care. | ||||||
|  |          */ | ||||||
|         CHECK_UINT16(tl_type); |         CHECK_UINT16(tl_type); | ||||||
|         ret = krb5_store_uint16(sp, tl_type); |         ret = krb5_store_uint16(sp, tl_type); | ||||||
|         if (ret) return ret; |         if (ret) return ret; | ||||||
| @@ -1339,13 +1371,15 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) | |||||||
|         if (tl_length) { |         if (tl_length) { | ||||||
|             buf = malloc(tl_length); |             buf = malloc(tl_length); | ||||||
|             if (!buf) return ENOMEM; |             if (!buf) return ENOMEM; | ||||||
|             if (getdata(&p, buf, tl_length) != tl_length) return EINVAL; |             if (getdata(&p, buf, tl_length, reading_what) != tl_length) | ||||||
|  |                 return EINVAL; | ||||||
|             sz = krb5_storage_write(sp, buf, tl_length); |             sz = krb5_storage_write(sp, buf, tl_length); | ||||||
|             free(buf); |             free(buf); | ||||||
|             if (sz == -1) return ENOMEM; |             if (sz == -1) return ENOMEM; | ||||||
|         } else { |         } else { | ||||||
|             if (strcmp(nexttoken(&p, 0), "-1") != 0) return EINVAL; |             if (strcmp(nexttoken(&p, 0, "'-1' field"), "-1") != 0) return EINVAL; | ||||||
|         } |         } | ||||||
|  |         free(reading_what); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     for (i = 0; i < num_key_data; i++) { |     for (i = 0; i < num_key_data; i++) { | ||||||
| @@ -1356,23 +1390,23 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) | |||||||
|         int keylen; |         int keylen; | ||||||
|         size_t k; |         size_t k; | ||||||
|  |  | ||||||
|         key_versions = getint(&p); /* key data version */ |         key_versions = getint(&p, "key data 'version'"); | ||||||
|         CHECK_UINT16(key_versions); |         CHECK_UINT16(key_versions); | ||||||
|         ret = krb5_store_int16(sp, key_versions); |         ret = krb5_store_int16(sp, key_versions); | ||||||
|         if (ret) return ret; |         if (ret) return ret; | ||||||
|  |  | ||||||
|         kvno = getint(&p); |         kvno = getint(&p, "kvno"); | ||||||
|         CHECK_UINT16(kvno); |         CHECK_UINT16(kvno); | ||||||
|         ret = krb5_store_int16(sp, kvno); |         ret = krb5_store_int16(sp, kvno); | ||||||
|         if (ret) return ret; |         if (ret) return ret; | ||||||
|  |  | ||||||
|         for (k = 0; k < key_versions; k++) { |         for (k = 0; k < key_versions; k++) { | ||||||
|             keytype = getint(&p); |             keytype = getint(&p, "enctype"); | ||||||
|             CHECK_UINT16(keytype); |             CHECK_UINT16(keytype); | ||||||
|             ret = krb5_store_int16(sp, keytype); |             ret = krb5_store_int16(sp, keytype); | ||||||
|             if (ret) return ret; |             if (ret) return ret; | ||||||
|  |  | ||||||
|             keylen = getint(&p); |             keylen = getint(&p, "encrypted key length"); | ||||||
|             CHECK_UINT16(keylen); |             CHECK_UINT16(keylen); | ||||||
|             ret = krb5_store_int16(sp, keylen); |             ret = krb5_store_int16(sp, keylen); | ||||||
|             if (ret) return ret; |             if (ret) return ret; | ||||||
| @@ -1380,12 +1414,18 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) | |||||||
|             if (keylen) { |             if (keylen) { | ||||||
|                 buf = malloc(keylen); |                 buf = malloc(keylen); | ||||||
|                 if (!buf) return ENOMEM; |                 if (!buf) return ENOMEM; | ||||||
|                 if (getdata(&p, buf, keylen) != keylen) return EINVAL; |                 if (getdata(&p, buf, keylen, "key (or salt) data") != keylen) | ||||||
|  |                     return EINVAL; | ||||||
|                 sz = krb5_storage_write(sp, buf, keylen); |                 sz = krb5_storage_write(sp, buf, keylen); | ||||||
|                 free(buf); |                 free(buf); | ||||||
|                 if (sz == -1) return ENOMEM; |                 if (sz == -1) return ENOMEM; | ||||||
|             } else { |             } else { | ||||||
|                 if (strcmp(nexttoken(&p, 0), "-1") != 0) return EINVAL; |                 if (strcmp(nexttoken(&p, 0, | ||||||
|  |                                      "'-1' zero-length key/salt field"), | ||||||
|  |                            "-1") != 0) { | ||||||
|  |                     warnx("Expected '-1' field because key/salt length is 0"); | ||||||
|  |                     return -1; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -1393,7 +1433,7 @@ _hdb_mit_dump2mitdb_entry(krb5_context context, char *line, krb5_storage *sp) | |||||||
|      * The rest is "extra data", but there's never any and we wouldn't |      * The rest is "extra data", but there's never any and we wouldn't | ||||||
|      * know what to do with it. |      * know what to do with it. | ||||||
|      */ |      */ | ||||||
|     /* nexttoken(&p, 0); */ |     /* nexttoken(&p, 0, "extra data"); */ | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Nicolas Williams
					Nicolas Williams