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