Add new modules to handle administrative protocol keyword=value
authorPaul Park <pjpark@mit.edu>
Tue, 9 May 1995 19:26:03 +0000 (19:26 +0000)
committerPaul Park <pjpark@mit.edu>
Tue, 9 May 1995 19:26:03 +0000 (19:26 +0000)
and keytab representations.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5769 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/kadm/ChangeLog
src/lib/kadm/Makefile.in
src/lib/kadm/adm_kt_dec.c [new file with mode: 0644]
src/lib/kadm/adm_kt_enc.c [new file with mode: 0644]
src/lib/kadm/adm_kw_dec.c [new file with mode: 0644]
src/lib/kadm/adm_kw_enc.c [new file with mode: 0644]

index b490928071ad14f12d129c587c364c6043a2af8a..fef8942cf62703472bf68043c6587a7abf3e658b 100644 (file)
@@ -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
index ab99dffc6a59c3b737dfdc11ae0387003550c4ae..7324a4e406bec8ec8d69f345cf8de0633140037d 100644 (file)
@@ -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 (file)
index 0000000..68d3963
--- /dev/null
@@ -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"
+\f
+/*
+ * 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 (file)
index 0000000..f12eab0
--- /dev/null
@@ -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"
+\f
+/*
+ * 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; i<KRB5_ADM_KT_NCOMPS; i++) {
+               if (clist[i].data) {
+                   memset(clist[i].data, 0, (size_t) clist[i].length);
+                   krb5_xfree(clist[i].data);
+               }
+           }
+           krb5_xfree(clist);
+       }
+       clist = (krb5_data *) NULL;
+       nents = 0;
+    }
+    *complistp = clist;
+    *ncompp = nents;
+    return(kret);
+}
diff --git a/src/lib/kadm/adm_kw_dec.c b/src/lib/kadm/adm_kw_dec.c
new file mode 100644 (file)
index 0000000..d66f615
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * lib/kadm/adm_kw_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_kw_dec.c        - routines to decode keyword-value pairs.
+ */
+#include "k5-int.h"
+#include "adm.h"
+
+#define        char2int(c)     ((c) - '0')
+\f
+/*
+ * string_to_salt_type()       - Convert from salt string to salt type.
+ */
+static krb5_int32
+string_to_salt_type(sstring, retp)
+    char               *sstring;
+    krb5_error_code    *retp;
+{
+    krb5_error_code    kret;
+    krb5_int32         stype;
+
+    kret = EINVAL;
+    stype = -1;
+    if (!strcmp(sstring, KRB5_ADM_SALTTYPE_NORMAL))
+       stype = KRB5_KDB_SALTTYPE_NORMAL;
+    else if (!strcmp(sstring, KRB5_ADM_SALTTYPE_V4))
+       stype = KRB5_KDB_SALTTYPE_V4;
+    else if (!strcmp(sstring, KRB5_ADM_SALTTYPE_NOREALM))
+       stype = KRB5_KDB_SALTTYPE_NOREALM;
+    else if (!strcmp(sstring, KRB5_ADM_SALTTYPE_ONLYREALM))
+       stype = KRB5_KDB_SALTTYPE_ONLYREALM;
+    else if (!strcmp(sstring, KRB5_ADM_SALTTYPE_SPECIAL))
+       stype = KRB5_KDB_SALTTYPE_SPECIAL;
+
+    if (stype != -1)
+       kret = 0;
+
+    *retp = kret;
+    return(stype);
+}
+\f
+/*
+ * keyword_value()     - Find index of keyword value if keyword is present.
+ *
+ * If a value is required, then the index of the keyword value is returned,
+ * otherwise the index of the first character past the end of the keyword
+ * string is returned.
+ */
+static off_t
+keyword_value(dataentp, keyword, value_req)
+    krb5_data          *dataentp;
+    char               *keyword;
+    krb5_boolean       value_req;
+{
+    off_t      len_req;
+
+    len_req = strlen(keyword);
+    if (value_req)
+       len_req++;
+    if ((dataentp->length >= len_req) &&
+       (!strncmp(dataentp->data, keyword, strlen(keyword))) &&
+       (!value_req || (dataentp->data[strlen(keyword)] == '=')))
+       return(len_req);
+    else
+       return(-1);
+}
+\f
+/*
+ * decode_kw_string()  - Decode a keyword=<string> 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);
+}
+\f
+/*
+ * decode_kw_integer() - Decode a keyword=<integer> 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);
+}
+\f
+/*
+ * decode_kw_gentime() - Decode a keyword=<general-time> 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, &timestring))) {
+       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);
+}
+\f
+/*
+ * decode_kw_salttype()        - Decode a keyword=<salttype> 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);
+}
+\f
+/*
+ * 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; i<nent; i++) {
+       /* Check for password */
+       if (!(retval = decode_kw_string(&data[i],
+                                       KRB5_ADM_KW_PASSWORD,
+                                       pwordp))) {
+           parsed_mask |= KRB5_ADM_M_PASSWORD;
+           continue;
+       }
+       else {
+           if (retval != ENOENT)
+               break;
+       }
+
+       /* Check for key version number */
+       if (!(retval = decode_kw_integer(&data[i],
+                                        KRB5_ADM_KW_KVNO,
+                                        (krb5_ui_4 *) &dbentp->kvno))) {
+           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 (file)
index 0000000..9e26f12
--- /dev/null
@@ -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"
+
+\f
+/*
+ * 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);
+}
+\f
+/*
+ * format_kw_string()  - Format a keyword=<string> 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);
+}
+\f
+/*
+ * format_kw_integer() - Format a keyword=<integer> 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);
+}
+\f
+/*
+ * format_kw_gentime() - Format a keyword=<general-time> 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);
+}
+\f
+/*
+ * format_kw_salttype()        - Format a keyword=<salttype> 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);
+}
+\f
+/*
+ * 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<outindex; i++) {
+               if (outlist[i].data) {
+                   memset(outlist[i].data, 0, (size_t) outlist[i].length);
+                   free(outlist[i].data);
+               }
+           }
+           free(outlist);
+       }
+       outlist = (krb5_data *) NULL;
+       outindex = 0;
+    }
+    *datap = outlist;
+    *nentp = outindex;
+    return(kret);
+}
+