Rewrite asetkey to support extended key types
[openafs.git] / src / aklog / asetkey.c
index 106c100..2db399f 100644 (file)
 #endif
 
 static int
+stringToType(const char *string) {
+    if (strcmp(string, "rxkad") == 0)
+       return afsconf_rxkad;
+
+    return atoi(string);
+}
+
+static void
+printKey(const struct rx_opaque *key)
+{
+    int i;
+
+    for (i = 0; i < key->len; i++)
+       printf("%02x", ((unsigned char *)key->val)[i]);
+    printf("\n");
+}
+
+
+static int
 char2hex(char c)
 {
   if (c >= '0' && c <= '9')
@@ -42,11 +61,207 @@ char2hex(char c)
   return -1;
 }
 
+static struct afsconf_typedKey *
+keyFromCommandLine(afsconf_keyType type, int kvno, int subType,
+                  const char *string, size_t length)
+{
+    struct rx_opaque key;
+    struct afsconf_typedKey *typedKey;
+    const char *cp;
+    int i;
+
+    if (strlen(string) != 2*length) {
+       printf("key %s is not in right format\n", string);
+       printf(" <key> should be an %d byte hex representation \n", (int) length);
+       exit(1);
+    }
+
+    rx_opaque_alloc(&key, length);
+    cp = string;
+    for (i = 0; i< length; i++) {
+       ((char *)key.val)[i] = char2hex(*cp) * 16 + char2hex(*(cp+1));
+       cp+=2;
+    }
+
+    typedKey = afsconf_typedKey_new(type, kvno, subType, &key);
+    rx_opaque_freeContents(&key);
+    return typedKey;
+}
+
+#ifdef USING_HEIMDAL
+#define deref_key_length(key)                  \
+           key->keyvalue.length
+
+#define deref_key_contents(key)                        \
+           key->keyvalue.data
+#else
+#define deref_key_length(key)                  \
+           key->length
+
+#define deref_key_contents(key)                        \
+           key->contents
+#endif
+
+static struct afsconf_typedKey *
+keyFromKeytab(int kvno, const char *keytab, const char *princ)
+{
+    int retval;
+    krb5_principal principal;
+    krb5_keyblock *key;
+    krb5_context context;
+    struct rx_opaque buffer;
+    struct afsconf_typedKey *typedKey;
+
+    krb5_init_context(&context);
+
+    retval = krb5_parse_name(context, princ, &principal);
+    if (retval) {
+       afs_com_err("asetkey", retval, "while parsing AFS principal");
+       exit(1);
+    }
+
+    retval = krb5_kt_read_service_key(context, (char *)keytab, principal,
+                                     kvno, ENCTYPE_DES_CBC_CRC, &key);
+    if (retval == KRB5_KT_NOTFOUND)
+       retval = krb5_kt_read_service_key(context, (char *)keytab,
+                                         principal, kvno,
+                                         ENCTYPE_DES_CBC_MD5, &key);
+    if (retval == KRB5_KT_NOTFOUND)
+       retval = krb5_kt_read_service_key(context, (char *)keytab,
+                                         principal, kvno,
+                                         ENCTYPE_DES_CBC_MD4, &key);
+
+    if (retval == KRB5_KT_NOTFOUND) {
+       char * princname = NULL;
+
+       krb5_unparse_name(context, principal, &princname);
+
+       afs_com_err("asetkey", retval,
+                   "for keytab entry with Principal %s, kvno %u, "
+                   "DES-CBC-CRC/MD5/MD4",
+                   princname ? princname : princ, kvno);
+       exit(1);
+    }
+
+    if (retval != 0) {
+       afs_com_err("asetkey", retval, "while extracting AFS service key");
+       exit(1);
+    }
+
+    if (deref_key_length(key) != 8) {
+       fprintf(stderr, "Key length should be 8, but is really %u!\n",
+               (unsigned int)deref_key_length(key));
+       exit(1);
+    }
+
+    rx_opaque_populate(&buffer, deref_key_contents(key), deref_key_length(key));
+
+    typedKey = afsconf_typedKey_new(afsconf_rxkad, kvno, 0, &buffer);
+    rx_opaque_freeContents(&buffer);
+    krb5_free_principal(context, principal);
+    krb5_free_keyblock(context, key);
+    return typedKey;
+}
+
+static void
+addKey(struct afsconf_dir *dir, int argc, char **argv) {
+    struct afsconf_typedKey *typedKey;
+    int type;
+    int kvno;
+    int code;
+
+    switch (argc) {
+      case 4:
+       typedKey = keyFromCommandLine(afsconf_rxkad, atoi(argv[2]), 0,
+                                     argv[3], 8);
+       break;
+      case 5:
+       typedKey = keyFromKeytab(atoi(argv[2]), argv[3], argv[4]);
+       break;
+      case 6:
+       type = stringToType(argv[2]);
+       kvno = atoi(argv[3]);
+       if (type == afsconf_rxkad) {
+           typedKey = keyFromCommandLine(afsconf_rxkad, kvno, 0, argv[5], 8);
+       }
+       break;
+      default:
+       fprintf(stderr, "%s add: usage is '%s add <kvno> <keyfile> "
+                       "<princ>\n", argv[0], argv[0]);
+       fprintf(stderr, "\tOR\n\t%s add <kvno> <key>\n", argv[0]);
+       fprintf(stderr, "\tOR\n\t%s add <type> <kvno> <subtype> <key>\n",
+               argv[0]);
+       fprintf(stderr, "\t\tEx: %s add 0 \"80b6a7cd7a9dadb6\"\n", argv[0]);
+               exit(1);
+    }
+    code = afsconf_AddTypedKey(dir, typedKey, 1);
+    afsconf_typedKey_put(&typedKey);
+    if (code) {
+       afs_com_err("asetkey", code, "while adding new key");
+       exit(1);
+    }
+}
+
+static void
+deleteKey(struct afsconf_dir *dir, int argc, char **argv)
+{
+    int kvno;
+    int code;
+
+    if (argc != 3) {
+       fprintf(stderr, "%s delete: usage is '%s delete <kvno>\n",
+               argv[0], argv[0]);
+       exit(1);
+    }
+    kvno = atoi(argv[2]);
+    code = afsconf_DeleteKey(dir, kvno);
+    if (code) {
+       afs_com_err(argv[0], code, "while deleting key %d", kvno);
+       exit(1);
+    }
+}
+
+static void
+listKey(struct afsconf_dir *dir, int argc, char **argv)
+{
+    struct afsconf_typedKeyList *keys;
+    int i;
+    int code;
+
+    code = afsconf_GetAllKeys(dir, &keys);
+    if (code) {
+       afs_com_err("asetkey", code, "while retrieving keys");
+       exit(1);
+    }
+    for (i = 0; i < keys->nkeys; i++) {
+       afsconf_keyType type;
+       int kvno;
+       int minorType;
+       struct rx_opaque *keyMaterial;
+
+       afsconf_typedKey_values(keys->keys[i], &type, &kvno, &minorType,
+                                   &keyMaterial);
+       switch(type) {
+         case afsconf_rxkad:
+           if (kvno != -1) {
+               printf("rxkad\tkvno %4d: key is: ", kvno);
+               printKey(keyMaterial);
+           }
+           break;
+         default:
+           printf("unknown(%d)\tkvno %4d subtype %d key is: ", type,
+                  kvno, minorType);
+           printKey(keyMaterial);
+           break;
+         }
+    }
+    printf("All done.\n");
+}
+
 int
 main(int argc, char *argv[])
 {
     struct afsconf_dir *tdir;
-    long code;
     const char *confdir;
 
     if (argc == 1) {
@@ -54,6 +269,8 @@ main(int argc, char *argv[])
                argv[0], argv[0]);
        fprintf(stderr, "\t%s add <kvno> <keyfile> <princ>\n", argv[0]);
        fprintf(stderr, "\tOR\n\t%s add <kvno> <key>\n", argv[0]);
+       fprintf(stderr, "\tOR\n\t%s add <type> <kvno> <subtype> <key>\n",
+               argv[0]);
        fprintf(stderr, "\t\tEx: %s add 0 \"80b6a7cd7a9dadb6\"\n", argv[0]);
        fprintf(stderr, "\t%s delete <kvno>\n", argv[0]);
        fprintf(stderr, "\t%s list\n", argv[0]);
@@ -69,133 +286,14 @@ main(int argc, char *argv[])
        exit(1);
     }
     if (strcmp(argv[1], "add")==0) {
-       krb5_context context;
-       krb5_principal principal;
-       krb5_keyblock *key;
-       krb5_error_code retval;
-       int kvno, keymode = 0;
-
-       if (argc != 5) {
-           if (argc == 4)
-               keymode = 1;
-           else {
-               fprintf(stderr, "%s add: usage is '%s add <kvno> <keyfile> "
-                       "<princ>\n", argv[0], argv[0]);
-               fprintf(stderr, "\tOR\n\t%s add <kvno> <key>\n", argv[0]);
-               fprintf(stderr, "\t\tEx: %s add 0 \"80b6a7cd7a9dadb6\"\n", argv[0]);
-               exit(1);
-           }
-       }
-
-       kvno = atoi(argv[2]);
-       if (keymode) {
-           char tkey[8];
-           int i;
-           char *cp;
-           if (strlen(argv[3]) != 16) {
-               printf("key %s is not in right format\n", argv[3]);
-               printf(" <key> should be an 8byte hex representation \n");
-               printf("  Ex: setkey add 0 \"80b6a7cd7a9dadb6\"\n");
-               exit(1);
-           }
-           memset(tkey, 0, sizeof(tkey));
-           for (i = 7, cp = argv[3] + 15; i >= 0; i--, cp -= 2)
-               tkey[i] = char2hex(*cp) + char2hex(*(cp - 1)) * 16;
-           code = afsconf_AddKey(tdir, kvno, tkey, 1);
-       } else {
-           krb5_init_context(&context);
-
-           retval = krb5_parse_name(context, argv[4], &principal);
-           if (retval != 0) {
-               afs_com_err(argv[0], retval, "while parsing AFS principal");
-               exit(1);
-           }
-           retval = krb5_kt_read_service_key(context, argv[3], principal, kvno,
-                                             ENCTYPE_DES_CBC_CRC, &key);
-            if (retval == KRB5_KT_NOTFOUND)
-                retval = krb5_kt_read_service_key(context, argv[3], principal, kvno,
-                                                   ENCTYPE_DES_CBC_MD5, &key);
-            if (retval == KRB5_KT_NOTFOUND)
-                retval = krb5_kt_read_service_key(context, argv[3], principal, kvno,
-                                                   ENCTYPE_DES_CBC_MD4, &key);
-            if (retval == KRB5_KT_NOTFOUND) {
-                char * princname = NULL;
-
-                krb5_unparse_name(context, principal, &princname);
-
-                afs_com_err(argv[0], retval,
-                            "for keytab entry with Principal %s, kvno %u, DES-CBC-CRC/MD5/MD4",
-                            princname ? princname : argv[4],
-                            kvno);
-                exit(1);
-            } else if (retval != 0) {
-               afs_com_err(argv[0], retval, "while extracting AFS service key");
-               exit(1);
-           }
-
-#ifdef USING_HEIMDAL
-#define deref_key_length(key)                  \
-           key->keyvalue.length
-
-#define deref_key_contents(key)                        \
-           key->keyvalue.data
-#else
-#define deref_key_length(key)                  \
-           key->length
-
-#define deref_key_contents(key)                        \
-           key->contents
-#endif
-           if (deref_key_length(key) != 8) {
-               fprintf(stderr, "Key length should be 8, but is really %u!\n",
-                       (unsigned int)deref_key_length(key));
-               exit(1);
-           }
-           code = afsconf_AddKey(tdir, kvno, (char *) deref_key_contents(key), 1);
-       }
-
-       if (code) {
-           fprintf(stderr, "%s: failed to set key, code %ld.\n", argv[0], code);
-           exit(1);
-       }
-       if (keymode == 0) {
-           krb5_free_principal(context, principal);
-           krb5_free_keyblock(context, key);
-       }
+       addKey(tdir, argc, argv);
     }
     else if (strcmp(argv[1], "delete")==0) {
-       long kvno;
-       if (argc != 3) {
-           fprintf(stderr, "%s delete: usage is '%s delete <kvno>\n",
-                   argv[0], argv[0]);
-           exit(1);
-       }
-       kvno = atoi(argv[2]);
-       code = afsconf_DeleteKey(tdir, kvno);
-       if (code) {
-           fprintf(stderr, "%s: failed to delete key %ld, (code %ld)\n",
-                   argv[0], kvno, code);
-           exit(1);
-       }
+       deleteKey(tdir, argc, argv);
     }
     else if (strcmp(argv[1], "list") == 0) {
-       struct afsconf_keys tkeys;
-       int i, j;
+       listKey(tdir, argc, argv);
 
-       code = afsconf_GetKeys(tdir, &tkeys);
-       if (code) {
-           fprintf(stderr, "%s: failed to get keys, code %ld\n", argv[0], code);
-           exit(1);
-       }
-       for(i=0;i<tkeys.nkeys;i++) {
-           if (tkeys.key[i].kvno != -1) {
-               printf("kvno %4d: key is: ", tkeys.key[i].kvno);
-               for (j = 0; j < 8; j++)
-                       printf("%02x", (unsigned char) tkeys.key[i].key[j]);
-               printf("\n");
-           }
-       }
-       printf("All done.\n");
     }
     else {
        fprintf(stderr, "%s: unknown operation '%s', type '%s' for "