From e03553f3ca060560d5614beb9b0d657eb4bd9af8 Mon Sep 17 00:00:00 2001 From: Paul Park Date: Tue, 9 May 1995 19:26:03 +0000 Subject: [PATCH] Add new modules to handle administrative protocol keyword=value and keytab representations. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5769 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/kadm/ChangeLog | 8 + src/lib/kadm/Makefile.in | 8 + src/lib/kadm/adm_kt_dec.c | 138 +++++++++++ src/lib/kadm/adm_kt_enc.c | 181 ++++++++++++++ src/lib/kadm/adm_kw_dec.c | 494 ++++++++++++++++++++++++++++++++++++++ src/lib/kadm/adm_kw_enc.c | 405 +++++++++++++++++++++++++++++++ 6 files changed, 1234 insertions(+) create mode 100644 src/lib/kadm/adm_kt_dec.c create mode 100644 src/lib/kadm/adm_kt_enc.c create mode 100644 src/lib/kadm/adm_kw_dec.c create mode 100644 src/lib/kadm/adm_kw_enc.c diff --git a/src/lib/kadm/ChangeLog b/src/lib/kadm/ChangeLog index b49092807..fef8942cf 100644 --- a/src/lib/kadm/ChangeLog +++ b/src/lib/kadm/ChangeLog @@ -1,4 +1,12 @@ +Tue May 9 15:21:49 EDT 1995 Paul Park (pjpark@mit.edu) + * adm_conn.c - use profile information to locate the admin_server. + Also, return the correct value from krb5_adm_connect + instead of always returning zero. + * adm_{kw,kt}_{enc,dec}.c - New modules to [en/de]code administrative + protocol keyword=value pairs and keytab entries. + + Fri Apr 28 09:47:29 EDT 1995 Paul Park (pjpark@mit.edu) Create a new library consisting of functions which communicate with diff --git a/src/lib/kadm/Makefile.in b/src/lib/kadm/Makefile.in index ab99dffc6..7324a4e40 100644 --- a/src/lib/kadm/Makefile.in +++ b/src/lib/kadm/Makefile.in @@ -4,9 +4,17 @@ LDFLAGS = -g all:: $(OBJS) OBJS= adm_conn.o \ + adm_kw_dec.o \ + adm_kw_enc.o \ + adm_kt_dec.o \ + adm_kt_enc.o \ adm_rw.o SRCS= $(srcdir)/adm_conn.c \ + $(srcdir)/adm_kw_dec.c \ + $(srcdir)/adm_kw_enc.c \ + $(srcdir)/adm_kt_dec.c \ + $(srcdir)/adm_kt_enc.c \ $(srcdir)/adm_rw.c libkadm.a: ${OBJS} diff --git a/src/lib/kadm/adm_kt_dec.c b/src/lib/kadm/adm_kt_dec.c new file mode 100644 index 000000000..68d3963c3 --- /dev/null +++ b/src/lib/kadm/adm_kt_dec.c @@ -0,0 +1,138 @@ +/* + * lib/kadm/adm_kt_dec.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * adm_kt_dec.c - Decode keytab entry according to protocol. + */ +#include "k5-int.h" +#include "adm.h" + +/* + * krb5_adm_proto_to_ktent() - Convert a list of reply components to + * a keytab entry according to procotol. + * + * Successful callers of this routine should free ktentp->principal + * and ktentp->key.contents. + */ +krb5_error_code +krb5_adm_proto_to_ktent(kcontext, ncomp, complist, ktentp) + krb5_context kcontext; + krb5_int32 ncomp; + krb5_data *complist; + krb5_keytab_entry *ktentp; +{ + krb5_error_code kret; + char *v; + + /* + * Clear out the keytab entry. + */ + memset((char *) ktentp, 0, sizeof(krb5_keytab_entry)); + + /* + * Figure out how many components we have. We expect KRB5_ADM_KT_NCOMPS + * components. + */ + if (ncomp != KRB5_ADM_KT_NCOMPS) + return(EINVAL); + + /* Parse the supplied principal name */ + if (kret = krb5_parse_name(kcontext, + complist[KRB5_ADM_KT_PRINCIPAL].data, + &ktentp->principal)) + goto done; + + /* Parse the supplied timestamp */ + if (complist[KRB5_ADM_KT_TIMESTAMP].length < sizeof(krb5_timestamp)) { + kret = EINVAL; + goto done; + } + v = complist[KRB5_ADM_KT_TIMESTAMP].data; + ktentp->timestamp = (krb5_timestamp) + (((krb5_int32) ((unsigned char) v[0]) << 24) + + ((krb5_int32) ((unsigned char) v[1]) << 16) + + ((krb5_int32) ((unsigned char) v[2]) << 8) + + ((krb5_int32) ((unsigned char) v[3]))); + + /* Parse the supplied vno */ + if (complist[KRB5_ADM_KT_VNO].length < sizeof(krb5_kvno)) { + kret = EINVAL; + goto done; + } + v = complist[KRB5_ADM_KT_VNO].data; + ktentp->vno = (krb5_kvno) + (((krb5_int32) ((unsigned char) v[0]) << 24) + + ((krb5_int32) ((unsigned char) v[1]) << 16) + + ((krb5_int32) ((unsigned char) v[2]) << 8) + + ((krb5_int32) ((unsigned char) v[3]))); + + /* Parse the supplied key_keytype */ + if (complist[KRB5_ADM_KT_KEY_KEYTYPE].length < sizeof(krb5_keytype)) { + kret = EINVAL; + goto done; + } + v = complist[KRB5_ADM_KT_KEY_KEYTYPE].data; + ktentp->key.keytype = (krb5_keytype) + (((krb5_int32) ((unsigned char) v[0]) << 24) + + ((krb5_int32) ((unsigned char) v[1]) << 16) + + ((krb5_int32) ((unsigned char) v[2]) << 8) + + ((krb5_int32) ((unsigned char) v[3]))); + + /* Parse the supplied key_etype */ + if (complist[KRB5_ADM_KT_KEY_ETYPE].length < sizeof(krb5_enctype)) { + kret = EINVAL; + goto done; + } + v = complist[KRB5_ADM_KT_KEY_ETYPE].data; + ktentp->key.etype = (krb5_enctype) + (((krb5_int32) ((unsigned char) v[0]) << 24) + + ((krb5_int32) ((unsigned char) v[1]) << 16) + + ((krb5_int32) ((unsigned char) v[2]) << 8) + + ((krb5_int32) ((unsigned char) v[3]))); + + /* Finally, shuck the key contents */ + if (ktentp->key.contents = (krb5_octet *) + malloc((size_t) complist[KRB5_ADM_KT_KEY_KEY].length)) { + ktentp->key.length = complist[KRB5_ADM_KT_KEY_KEY].length; + memcpy(ktentp->key.contents, + complist[KRB5_ADM_KT_KEY_KEY].data, + (size_t) ktentp->key.length); + kret = 0; + } + else + kret = ENOMEM; + + done: + if (kret) { + if (ktentp->principal) + krb5_free_principal(kcontext, ktentp->principal); + if (ktentp->key.contents) { + memset((char *) ktentp->key.contents, 0, + (size_t) ktentp->key.length); + krb5_xfree(ktentp->key.contents); + } + memset((char *) ktentp, 0, sizeof(krb5_keytab_entry)); + } + return(kret); +} diff --git a/src/lib/kadm/adm_kt_enc.c b/src/lib/kadm/adm_kt_enc.c new file mode 100644 index 000000000..f12eab0b4 --- /dev/null +++ b/src/lib/kadm/adm_kt_enc.c @@ -0,0 +1,181 @@ +/* + * lib/kadm/adm_kt_enc.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * adm_kt_enc.c - Encode keytab entry according to protocol. + */ +#include "k5-int.h" +#include "adm.h" + +/* + * krb5_adm_ktent_to_proto() - Convert a keytab entry into an external + * list of reply components. + * + * Successful callers must free the storage for complistp and complistp->data + * either manually or by using krb5_free_adm_data(). + */ +krb5_error_code +krb5_adm_ktent_to_proto(kcontext, ktentp, ncompp, complistp) + krb5_context kcontext; + krb5_keytab_entry *ktentp; + krb5_int32 *ncompp; + krb5_data **complistp; +{ + krb5_error_code kret; + krb5_data *clist; + krb5_int32 nents; + + kret = ENOMEM; + nents = 0; + if (clist = (krb5_data *) malloc((size_t) KRB5_ADM_KT_NCOMPS * + sizeof(krb5_data))) { + memset((char *) clist, 0, ((size_t) KRB5_ADM_KT_NCOMPS * + sizeof(krb5_data))); + /* + * Fill in the principal field. + */ + if (kret = krb5_unparse_name(kcontext, + ktentp->principal, + &clist[KRB5_ADM_KT_PRINCIPAL].data)) + goto done; + clist[KRB5_ADM_KT_PRINCIPAL].length = + strlen(clist[KRB5_ADM_KT_PRINCIPAL].data); + nents++; + + /* + * Fill in timestamp. + */ + if (kret = krb5_timeofday(kcontext, &ktentp->timestamp)) + goto done; + if (clist[KRB5_ADM_KT_TIMESTAMP].data = + (char *) malloc(sizeof(krb5_ui_4))) { + clist[KRB5_ADM_KT_TIMESTAMP].length = sizeof(krb5_ui_4); + clist[KRB5_ADM_KT_TIMESTAMP].data[0] = + (ktentp->timestamp >> 24) && 0xff; + clist[KRB5_ADM_KT_TIMESTAMP].data[1] = + (ktentp->timestamp >> 16) && 0xff; + clist[KRB5_ADM_KT_TIMESTAMP].data[2] = + (ktentp->timestamp >> 8) && 0xff; + clist[KRB5_ADM_KT_TIMESTAMP].data[3] = + ktentp->timestamp && 0xff; + nents++; + } + else { + kret = ENOMEM; + goto done; + } + + /* + * Fill in vno. + */ + if (clist[KRB5_ADM_KT_VNO].data = + (char *) malloc(sizeof(krb5_ui_4))) { + clist[KRB5_ADM_KT_VNO].length = sizeof(krb5_ui_4); + clist[KRB5_ADM_KT_VNO].data[0] = (ktentp->vno >> 24) && 0xff; + clist[KRB5_ADM_KT_VNO].data[1] = (ktentp->vno >> 16) && 0xff; + clist[KRB5_ADM_KT_VNO].data[2] = (ktentp->vno >> 8) && 0xff; + clist[KRB5_ADM_KT_VNO].data[3] = ktentp->vno && 0xff; + nents++; + } + else { + kret = ENOMEM; + goto done; + } + + /* + * Fill in key_keytype. + */ + if (clist[KRB5_ADM_KT_KEY_KEYTYPE].data = + (char *) malloc(sizeof(krb5_ui_4))) { + clist[KRB5_ADM_KT_KEY_KEYTYPE].length = sizeof(krb5_ui_4); + clist[KRB5_ADM_KT_KEY_KEYTYPE].data[0] = + (ktentp->key.keytype >> 24) && 0xff; + clist[KRB5_ADM_KT_KEY_KEYTYPE].data[1] = + (ktentp->key.keytype >> 16) && 0xff; + clist[KRB5_ADM_KT_KEY_KEYTYPE].data[2] = + (ktentp->key.keytype >> 8) && 0xff; + clist[KRB5_ADM_KT_KEY_KEYTYPE].data[3] = + ktentp->key.keytype && 0xff; + nents++; + } + else { + kret = ENOMEM; + goto done; + } + + /* + * Fill in key_etype. + */ + if (clist[KRB5_ADM_KT_KEY_ETYPE].data = + (char *) malloc(sizeof(krb5_ui_4))) { + clist[KRB5_ADM_KT_KEY_ETYPE].length = sizeof(krb5_ui_4); + clist[KRB5_ADM_KT_KEY_ETYPE].data[0] = + (ktentp->key.etype >> 24) && 0xff; + clist[KRB5_ADM_KT_KEY_ETYPE].data[1] = + (ktentp->key.etype >> 16) && 0xff; + clist[KRB5_ADM_KT_KEY_ETYPE].data[2] = + (ktentp->key.etype >> 8) && 0xff; + clist[KRB5_ADM_KT_KEY_ETYPE].data[3] = + ktentp->key.etype && 0xff; + nents++; + } + else { + kret = ENOMEM; + goto done; + } + + /* + * Fill in key_key. + */ + if (clist[KRB5_ADM_KT_KEY_KEY].data = + (char *) malloc((size_t) ktentp->key.length)) { + memcpy(clist[KRB5_ADM_KT_KEY_KEY].data, + ktentp->key.contents, + (size_t) ktentp->key.length); + clist[KRB5_ADM_KT_KEY_KEY].length = ktentp->key.length; + nents++; + kret = 0; + } + else + kret = ENOMEM; + } + done: + if (kret) { + if (clist) { + int i; + for (i=0; ilength >= len_req) && + (!strncmp(dataentp->data, keyword, strlen(keyword))) && + (!value_req || (dataentp->data[strlen(keyword)] == '='))) + return(len_req); + else + return(-1); +} + +/* + * decode_kw_string() - Decode a keyword= pair and return the + * string value if the pair is present. + * + * Note: successful callers must free the string storage. + */ +static krb5_error_code +decode_kw_string(dataentp, keyword, stringp) + krb5_data *dataentp; + char *keyword; + char **stringp; +{ + krb5_error_code kret; + off_t valueoff; + size_t len2copy; + + kret = ENOENT; + if ((valueoff = keyword_value(dataentp, keyword, 1)) >= 0) { + kret = ENOMEM; + len2copy = dataentp->length - valueoff; + *stringp = (char *) malloc(len2copy+1); + if (*stringp) { + strncpy(*stringp, &dataentp->data[valueoff], len2copy); + (*stringp)[len2copy] = '\0'; + kret = 0; + } + } + return(kret); +} + +/* + * decode_kw_integer() - Decode a keyword= pair and return the value + * if the pair is present. + */ +static krb5_error_code +decode_kw_integer(dataentp, keyword, uintp) + krb5_data *dataentp; + char *keyword; + krb5_ui_4 *uintp; +{ + krb5_error_code kret; + off_t voff; + size_t len2copy; + + kret = ENOENT; + if ((voff = keyword_value(dataentp, keyword, 1)) >= 0) { + kret = EINVAL; + len2copy = dataentp->length - voff; + if (len2copy == sizeof(krb5_ui_4)) { + *uintp = (((krb5_int32) ((unsigned char) dataentp->data[voff]) + << 24) + + ((krb5_int32) ((unsigned char) dataentp->data[voff+1]) + << 16) + + ((krb5_int32) ((unsigned char) dataentp->data[voff+2]) + << 8) + + ((krb5_int32) ((unsigned char) dataentp->data[voff+3]))); + kret = 0; + } + } + return(kret); +} + +/* + * decode_kw_gentime() - Decode a keyword= pair and return the + * time result if the pair is present. + * + * XXX - this knows too much about how Kerberos time is encoded. + */ +static krb5_error_code +decode_kw_gentime(dataentp, keyword, gtimep) + krb5_data *dataentp; + char *keyword; + krb5_timestamp *gtimep; +{ + krb5_error_code kret; + char *timestring; + struct tm tval; + time_t temp_time; + + memset((char *) &tval, 0, sizeof(tval)); + timestring = (char *) NULL; + if (!(kret = decode_kw_string(dataentp, keyword, ×tring))) { + kret = EINVAL; + if ((strlen(timestring) == 15) && + (timestring[14] == 'Z')) { + tval.tm_year = 1000*char2int(timestring[0]) + + 100*char2int(timestring[1]) + + 10*char2int(timestring[2]) + + char2int(timestring[3]) - 1900; + tval.tm_mon = 10*char2int(timestring[4]) + + char2int(timestring[5]) - 1; + tval.tm_mday = 10*char2int(timestring[6]) + + char2int(timestring[7]); + tval.tm_hour = 10*char2int(timestring[8]) + + char2int(timestring[9]); + tval.tm_min = 10*char2int(timestring[10]) + + char2int(timestring[11]); + tval.tm_sec = 10*char2int(timestring[12]) + + char2int(timestring[13]); + tval.tm_isdst = -1; + temp_time = gmt_mktime(&tval); + if (temp_time >= 0) { + kret = 0; + *gtimep = (krb5_timestamp) temp_time; + } + } + free(timestring); + } + return(kret); +} + +/* + * decode_kw_salttype() - Decode a keyword= pair and fill in the + * salt type values if the pair is present. + */ +static krb5_error_code +decode_kw_salttype(dataentp, keyword, dbentp) + krb5_data *dataentp; + char *keyword; + krb5_db_entry *dbentp; +{ + krb5_error_code kret; + char *saltstring; + char *sentp; + + saltstring = (char *) NULL; + if (!(kret = decode_kw_string(dataentp, keyword, &saltstring))) { + kret = EINVAL; + if (sentp = strchr(saltstring, (int) ',')) { + *sentp = '\0'; + sentp++; + } + dbentp->salt_type = string_to_salt_type(saltstring, &kret); + if (!kret && sentp) { + dbentp->alt_salt_type = string_to_salt_type(sentp, &kret); + } + free(saltstring); + } + return(kret); +} + +/* + * krb5_adm_proto_to_dbent() - Convert external attribute list into a + * database entry. + * + * Scan through the keyword=value pairs in "data" until either the end of + * the list (as determined from "nent") is reached, or an error occurs. + * Return a mask of attributes which are set in "validp", the actual + * attribute values in "dbentp" and "pwordp" if a password is specified. + * + * Successful callers must allocate the storage for "validp", "dbentp" and + * must free the storage allocated for "pwordp" if a password is specified + * and free the storage allocated for "validp->mod_name" if a modifier name + * is specified. + */ +krb5_error_code +krb5_adm_proto_to_dbent(kcontext, nent, data, validp, dbentp, pwordp) + krb5_context kcontext; /* Kerberos context */ /* In */ + krb5_int32 nent; /* Number of components */ /* In */ + krb5_data *data; /* Component list */ /* In */ + krb5_ui_4 *validp; /* Valid bitmask */ /* Out */ + krb5_db_entry *dbentp; /* Database entry */ /* Out */ + char **pwordp; /* Password string */ /* Out */ +{ + int i; + krb5_error_code retval; + krb5_ui_4 parsed_mask; + char *modifier_name; + + /* Initialize */ + retval = 0; + parsed_mask = 0; + *pwordp = (char *) NULL; + + /* Loop through all the specified keyword=value pairs. */ + for (i=0; ikvno))) { + parsed_mask |= KRB5_ADM_M_KVNO; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for maximum lifetime */ + if (!(retval = decode_kw_integer(&data[i], + KRB5_ADM_KW_MAXLIFE, + (krb5_ui_4 *) &dbentp->max_life))) { + parsed_mask |= KRB5_ADM_M_MAXLIFE; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for maximum renewable lifetime */ + if (!(retval = decode_kw_integer(&data[i], + KRB5_ADM_KW_MAXRENEWLIFE, + (krb5_ui_4 *) + &dbentp->max_renewable_life))) { + parsed_mask |= KRB5_ADM_M_MAXRENEWLIFE; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for principal expiration */ + if (!(retval = decode_kw_gentime(&data[i], + KRB5_ADM_KW_EXPIRATION, + &dbentp->expiration))) { + parsed_mask |= KRB5_ADM_M_EXPIRATION; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for password expiration */ + if (!(retval = decode_kw_gentime(&data[i], + KRB5_ADM_KW_PWEXPIRATION, + &dbentp->pw_expiration))) { + parsed_mask |= KRB5_ADM_M_PWEXPIRATION; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* random key - value optional */ + if (keyword_value(&data[i], + KRB5_ADM_KW_RANDOMKEY, + 0) >= 0) { + krb5_ui_4 value; + + if (retval = decode_kw_integer(&data[i], + KRB5_ADM_KW_RANDOMKEY, + &value)) { + value = 1; + retval = 0; + } + if (value) + parsed_mask |= KRB5_ADM_M_RANDOMKEY; + else + parsed_mask &= ~KRB5_ADM_M_RANDOMKEY; + continue; + } + + /* Check for flags */ + if (!(retval = decode_kw_integer(&data[i], + KRB5_ADM_KW_FLAGS, + (krb5_ui_4 *) &dbentp->attributes))) { + parsed_mask |= KRB5_ADM_M_FLAGS; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for salttype */ + if (!(retval = decode_kw_salttype(&data[i], + KRB5_ADM_KW_SALTTYPE, + dbentp))) { + parsed_mask |= KRB5_ADM_M_SALTTYPE; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for master key version number */ + if (!(retval = decode_kw_integer(&data[i], + KRB5_ADM_KW_MKVNO, + (krb5_ui_4 *) &dbentp->mkvno))) { + parsed_mask |= KRB5_ADM_M_MKVNO; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for last password change */ + if (!(retval = decode_kw_gentime(&data[i], + KRB5_ADM_KW_LASTPWCHANGE, + &dbentp->last_pwd_change))) { + parsed_mask |= KRB5_ADM_M_LASTPWCHANGE; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for last successful password entry */ + if (!(retval = decode_kw_gentime(&data[i], + KRB5_ADM_KW_LASTSUCCESS, + &dbentp->last_success))) { + parsed_mask |= KRB5_ADM_M_LASTSUCCESS; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for last failed entry */ + if (!(retval = decode_kw_gentime(&data[i], + KRB5_ADM_KW_LASTFAILED, + &dbentp->last_failed))) { + parsed_mask |= KRB5_ADM_M_LASTFAILED; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for failure count */ + if (!(retval = decode_kw_integer(&data[i], + KRB5_ADM_KW_FAILCOUNT, + (krb5_ui_4 *) + &dbentp->fail_auth_count))) { + parsed_mask |= KRB5_ADM_M_FAILCOUNT; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for modification principal */ + if (!(retval = decode_kw_string(&data[i], + KRB5_ADM_KW_MODNAME, + &modifier_name))) { + krb5_principal modifier; + retval = krb5_parse_name(kcontext, modifier_name, &modifier); + free(modifier_name); + if (!retval) { + if (dbentp->mod_name) + krb5_free_principal(kcontext, dbentp->mod_name); + dbentp->mod_name = modifier; + parsed_mask |= KRB5_ADM_M_MODNAME; + continue; + } + else + break; + } + else { + if (retval != ENOENT) + break; + } + + /* Check for modification time */ + if (!(retval = decode_kw_gentime(&data[i], + KRB5_ADM_KW_MODDATE, + &dbentp->mod_date))) { + parsed_mask |= KRB5_ADM_M_MODDATE; + continue; + } + else { + if (retval != ENOENT) + break; + } + + /* If we fall through here, we've got something unrecognized */ + if (retval) { + retval = EINVAL; + break; + } + } + + if (retval) { + if (*pwordp) { + memset(*pwordp, 0, strlen(*pwordp)); + free(*pwordp); + *pwordp = (char *) NULL; + } + parsed_mask = 0; + } + *validp |= parsed_mask; + return(retval); +} diff --git a/src/lib/kadm/adm_kw_enc.c b/src/lib/kadm/adm_kw_enc.c new file mode 100644 index 000000000..9e26f12a6 --- /dev/null +++ b/src/lib/kadm/adm_kw_enc.c @@ -0,0 +1,405 @@ +/* + * lib/kadm/adm_kw_enc.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * adm_kw_enc.c - routines to encode principal attributes in keyword-value + * pairs. + */ +#include "k5-int.h" +#include "adm.h" + + +/* + * salt_type_to_string() - Return a string for a given salt type. + * + * Add support for different salt types here. + */ +static char * +salt_type_to_string(stype) + krb5_int32 stype; +{ + char *retval = (char *) NULL; + + switch (stype) { + case KRB5_KDB_SALTTYPE_NORMAL: + retval = KRB5_ADM_SALTTYPE_NORMAL; break; + case KRB5_KDB_SALTTYPE_V4: + retval = KRB5_ADM_SALTTYPE_V4; break; + case KRB5_KDB_SALTTYPE_NOREALM: + retval = KRB5_ADM_SALTTYPE_NOREALM; break; + case KRB5_KDB_SALTTYPE_ONLYREALM: + retval = KRB5_ADM_SALTTYPE_ONLYREALM; break; + case KRB5_KDB_SALTTYPE_SPECIAL: + retval = KRB5_ADM_SALTTYPE_SPECIAL; break; + } + return(retval); +} + +/* + * format_kw_string() - Format a keyword= pair. + * + * Work routine for other string-based formatters also. + */ +static krb5_error_code +format_kw_string(datap, kwordp, valp) + krb5_data *datap; + char *kwordp; + char *valp; +{ + krb5_error_code retval; + char fbuffer[BUFSIZ]; + + retval = ENOMEM; + sprintf(fbuffer,"%s=%s", kwordp, valp); + datap->data = (char *) malloc(strlen(fbuffer)+1); + if (datap->data) { + datap->length = strlen(fbuffer); + strcpy(datap->data, fbuffer); + retval = 0; + } + return(retval); +} + +/* + * format_kw_integer() - Format a keyword= pair. + */ +static krb5_error_code +format_kw_integer(datap, kwordp, val) + krb5_data *datap; + char *kwordp; + krb5_ui_4 val; +{ + krb5_error_code retval; + char fbuffer[BUFSIZ]; + + retval = ENOMEM; + sprintf(fbuffer,"%s=", kwordp); + datap->data = (char *) malloc(strlen(fbuffer)+sizeof(krb5_ui_4)); + if (datap->data) { + datap->length = strlen(fbuffer); + strcpy(datap->data, fbuffer); + datap->data[datap->length] = (val >> 24) & 0xff; + datap->data[datap->length+1] = (val >> 16) & 0xff; + datap->data[datap->length+2] = (val >> 8) & 0xff; + datap->data[datap->length+3] = val & 0xff; + datap->length += sizeof(krb5_ui_4); + retval = 0; + } + return(retval); +} + +/* + * format_kw_gentime() - Format a keyword= pair. + * + * XXX - should this routine know so much about how generaltime is encoded? + */ +static krb5_error_code +format_kw_gentime(datap, kwordp, timep) + krb5_data *datap; + char *kwordp; + krb5_timestamp *timep; +{ + krb5_error_code retval; + char fbuffer[BUFSIZ]; + time_t tval; + struct tm *time_gmt; + + retval = EINVAL; + tval = (time_t) *timep; + time_gmt = gmtime(&tval); + if (time_gmt) { + sprintf(fbuffer,"%04d%02d%02d%02d%02d%02dZ", + time_gmt->tm_year+1900, + time_gmt->tm_mon+1, + time_gmt->tm_mday, + time_gmt->tm_hour, + time_gmt->tm_min, + time_gmt->tm_sec); + retval = format_kw_string(datap, kwordp, fbuffer); + } + return(retval); +} + +/* + * format_kw_salttype() - Format a keyword= pair. + */ +static krb5_error_code +format_kw_salttype(datap, kwordp, dbentp) + krb5_data *datap; + char *kwordp; + krb5_db_entry *dbentp; +{ + krb5_error_code retval; + char fbuffer[BUFSIZ]; + char *sstring; + + retval = EINVAL; + sstring = salt_type_to_string(dbentp->salt_type); + if (sstring) { + strcpy(fbuffer, sstring); + /* Only add secondary salt type if it's different and valid */ + if ((dbentp->salt_type != dbentp->alt_salt_type) && + (sstring = salt_type_to_string(dbentp->alt_salt_type))) { + strcat(fbuffer,","); + strcat(fbuffer,sstring); + } + retval = format_kw_string(datap, kwordp, fbuffer); + } + return(retval); +} + +/* + * krb5_adm_dbent_to_proto() - Convert database a database entry into + * an external attribute list. + * + * "valid" controls the generation of "datap" and "nentp". For each + * corresponding bit in "valid" a keyword-value pair is generated from + * values in "dbentp" or "password" and put into "datap". The number of + * generated pairs is returned in "nentp". Additionally, the KRB5_ADM_M_SET + * and KRB5_ADM_M_GET bits control whether we are generating attribute lists + * for a "set" operation or a "get" operation. One of these bits must be + * specified. + * + * Successful callers must free the storage for datap and datap->data + * either manually or using krb5_free_adm_data(). + */ +krb5_error_code +krb5_adm_dbent_to_proto(kcontext, valid, dbentp, password, nentp, datap) + krb5_context kcontext; /* Kerberos context */ /* In */ + krb5_ui_4 valid; /* Valid bitmask */ /* In */ + krb5_db_entry *dbentp; /* Database entry */ /* In */ + char *password; /* New password for set */ /* In */ + krb5_int32 *nentp; /* Number of components */ /* Out */ + krb5_data **datap; /* Output list */ /* Out */ +{ + krb5_error_code kret; + krb5_data *outlist; + size_t n2alloc; + int outindex; + krb5_boolean is_set; + + kret = 0; + /* First check out whether this is a set or get and the mask */ + is_set = ((valid & KRB5_ADM_M_SET) == KRB5_ADM_M_SET); + if ((is_set && ((valid & ~KRB5_ADM_M_SET_VALID) != 0)) || + (!is_set && ((valid & ~KRB5_ADM_M_GET_VALID) != 0)) || + (!is_set && ((valid & KRB5_ADM_M_GET) == 0))) + return(EINVAL); + + /* Allocate a new array of output data */ + n2alloc = (is_set) ? KRB5_ADM_KW_MAX_SET : KRB5_ADM_KW_MAX_GET; + n2alloc *= sizeof(krb5_data); + outindex = 0; + outlist = (krb5_data *) malloc(n2alloc); + if (outlist) { + /* Clear out the output data list */ + memset((char *) outlist, 0, n2alloc); + + /* Handle password only for set request */ + if (is_set && + ((valid & KRB5_ADM_M_PASSWORD) != 0) && + password) { + if (kret = format_kw_string(&outlist[outindex], + KRB5_ADM_KW_PASSWORD, + password)) + goto choke; + else + outindex++; + } + /* Handle key version number */ + if ((valid & KRB5_ADM_M_KVNO) != 0) { + if (kret = format_kw_integer(&outlist[outindex], + KRB5_ADM_KW_KVNO, + (krb5_ui_4) dbentp->kvno)) + goto choke; + else + outindex++; + } + /* Handle maximum ticket lifetime */ + if ((valid & KRB5_ADM_M_MAXLIFE) != 0) { + if (kret = format_kw_integer(&outlist[outindex], + KRB5_ADM_KW_MAXLIFE, + (krb5_ui_4) dbentp->max_life)) + goto choke; + else + outindex++; + } + /* Handle maximum renewable ticket lifetime */ + if ((valid & KRB5_ADM_M_MAXRENEWLIFE) != 0) { + if (kret = + format_kw_integer(&outlist[outindex], + KRB5_ADM_KW_MAXRENEWLIFE, + (krb5_ui_4) dbentp->max_renewable_life)) + goto choke; + else + outindex++; + } + /* Handle principal expiration */ + if ((valid & KRB5_ADM_M_EXPIRATION) != 0) { + if (kret = format_kw_gentime(&outlist[outindex], + KRB5_ADM_KW_EXPIRATION, + &dbentp->expiration)) + goto choke; + else + outindex++; + } + /* Handle password expiration */ + if ((valid & KRB5_ADM_M_PWEXPIRATION) != 0) { + if (kret = format_kw_gentime(&outlist[outindex], + KRB5_ADM_KW_PWEXPIRATION, + &dbentp->pw_expiration)) + goto choke; + else + outindex++; + } + /* Random key */ + if ((valid & KRB5_ADM_M_RANDOMKEY) != 0) { + if (kret = format_kw_integer(&outlist[outindex], + KRB5_ADM_KW_RANDOMKEY, + 1)) + goto choke; + else + outindex++; + } + /* Handle flags */ + if ((valid & KRB5_ADM_M_FLAGS) != 0) { + if (kret = format_kw_integer(&outlist[outindex], + KRB5_ADM_KW_FLAGS, + (krb5_ui_4) dbentp->attributes)) + goto choke; + else + outindex++; + } + /* Handle salt types */ + if ((valid & KRB5_ADM_M_SALTTYPE) != 0) { + if (kret = format_kw_salttype(&outlist[outindex], + KRB5_ADM_KW_SALTTYPE, + dbentp)) + goto choke; + else + outindex++; + } + /* Handle master key version number */ + if (!is_set && + ((valid & KRB5_ADM_M_MKVNO) != 0)) { + if (kret = format_kw_integer(&outlist[outindex], + KRB5_ADM_KW_MKVNO, + (krb5_ui_4) dbentp->mkvno)) + goto choke; + else + outindex++; + } + /* Handle last successful password change */ + if (!is_set && + ((valid & KRB5_ADM_M_LASTPWCHANGE) != 0)) { + if (kret = format_kw_gentime(&outlist[outindex], + KRB5_ADM_KW_LASTPWCHANGE, + &dbentp->last_pwd_change)) + goto choke; + else + outindex++; + } + /* Handle last successful password entry */ + if (!is_set && + ((valid & KRB5_ADM_M_LASTSUCCESS) != 0)) { + if (kret = format_kw_gentime(&outlist[outindex], + KRB5_ADM_KW_LASTSUCCESS, + &dbentp->last_success)) + goto choke; + else + outindex++; + } + /* Handle last failed password attempt */ + if (!is_set && + ((valid & KRB5_ADM_M_LASTFAILED) != 0)) { + if (kret = format_kw_gentime(&outlist[outindex], + KRB5_ADM_KW_LASTFAILED, + &dbentp->last_failed)) + goto choke; + else + outindex++; + } + /* Handle number of failed password attempts */ + if (!is_set && + ((valid & KRB5_ADM_M_FAILCOUNT) != 0)) { + if (kret = format_kw_integer(&outlist[outindex], + KRB5_ADM_KW_FAILCOUNT, + (krb5_ui_4) dbentp->fail_auth_count)) + goto choke; + else + outindex++; + } + /* Handle last modification principal name */ + if (!is_set && + ((valid & KRB5_ADM_M_MODNAME) != 0)) { + char *modifier_name; + + /* Flatten the name, format it then free it. */ + if (kret = krb5_unparse_name(kcontext, + dbentp->mod_name, + &modifier_name)) + goto choke; + + kret = format_kw_string(&outlist[outindex], + KRB5_ADM_KW_MODNAME, + modifier_name); + krb5_xfree(modifier_name); + if (kret) + goto choke; + else + outindex++; + } + /* Handle last modification time */ + if (!is_set && + ((valid & KRB5_ADM_M_MODDATE) != 0)) { + if (kret = format_kw_gentime(&outlist[outindex], + KRB5_ADM_KW_MODDATE, + &dbentp->mod_date)) + goto choke; + else + outindex++; + } + } + else + kret = ENOMEM; + choke: + if (kret) { + if (outlist) { + int i; + for (i=0; i