e73fe57b3b57cfefd765f02472bca0cf18472349
[openafs.git] / src / aklog / asetkey.c
1 /*
2  * $Id$
3  *
4  * asetkey - Manipulates an AFS KeyFile
5  *
6  * Updated for Kerberos 5
7  */
8
9 #include <afsconfig.h>
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <roken.h>
14
15 #include <krb5.h>
16
17 #ifndef HAVE_KERBEROSV_HEIM_ERR_H
18 #include <afs/com_err.h>
19 #endif
20 #include <afs/cellconfig.h>
21 #include <afs/keys.h>
22 #include <afs/dirpath.h>
23
24 #ifdef HAVE_KRB5_CREDS_KEYBLOCK
25 #define USING_MIT 1
26 #endif
27 #ifdef HAVE_KRB5_CREDS_SESSION
28 #define USING_HEIMDAL 1
29 #endif
30
31 static int
32 stringToType(const char *string) {
33     if (strcmp(string, "rxkad") == 0)
34         return afsconf_rxkad;
35
36     return atoi(string);
37 }
38
39 static void
40 printKey(const struct rx_opaque *key)
41 {
42     int i;
43
44     for (i = 0; i < key->len; i++)
45         printf("%02x", ((unsigned char *)key->val)[i]);
46     printf("\n");
47 }
48
49
50 static int
51 char2hex(char c)
52 {
53   if (c >= '0' && c <= '9')
54     return (c - 48);
55   if ((c >= 'a') && (c <= 'f'))
56     return (c - 'a' + 10);
57
58   if ((c >= 'A') && (c <= 'F'))
59     return (c - 'A' + 10);
60
61   return -1;
62 }
63
64 static struct afsconf_typedKey *
65 keyFromCommandLine(afsconf_keyType type, int kvno, int subType,
66                    const char *string, size_t length)
67 {
68     struct rx_opaque key;
69     struct afsconf_typedKey *typedKey;
70     const char *cp;
71     int i;
72
73     if (strlen(string) != 2*length) {
74         printf("key %s is not in right format\n", string);
75         printf(" <key> should be an %d byte hex representation \n", (int) length);
76         exit(1);
77     }
78
79     rx_opaque_alloc(&key, length);
80     cp = string;
81     for (i = 0; i< length; i++) {
82        ((char *)key.val)[i] = char2hex(*cp) * 16 + char2hex(*(cp+1));
83        cp+=2;
84     }
85
86     typedKey = afsconf_typedKey_new(type, kvno, subType, &key);
87     rx_opaque_freeContents(&key);
88     return typedKey;
89 }
90
91 #ifdef USING_HEIMDAL
92 #define deref_key_length(key)                   \
93             key->keyvalue.length
94
95 #define deref_key_contents(key)                 \
96             key->keyvalue.data
97 #else
98 #define deref_key_length(key)                   \
99             key->length
100
101 #define deref_key_contents(key)                 \
102             key->contents
103 #endif
104
105 static struct afsconf_typedKey *
106 keyFromKeytab(int kvno, const char *keytab, const char *princ)
107 {
108     int retval;
109     krb5_principal principal;
110     krb5_keyblock *key;
111     krb5_context context;
112     struct rx_opaque buffer;
113     struct afsconf_typedKey *typedKey;
114
115     krb5_init_context(&context);
116
117     retval = krb5_parse_name(context, princ, &principal);
118     if (retval) {
119         afs_com_err("asetkey", retval, "while parsing AFS principal");
120         exit(1);
121     }
122
123     retval = krb5_kt_read_service_key(context, (char *)keytab, principal,
124                                       kvno, ENCTYPE_DES_CBC_CRC, &key);
125     if (retval == KRB5_KT_NOTFOUND)
126         retval = krb5_kt_read_service_key(context, (char *)keytab,
127                                           principal, kvno,
128                                           ENCTYPE_DES_CBC_MD5, &key);
129     if (retval == KRB5_KT_NOTFOUND)
130         retval = krb5_kt_read_service_key(context, (char *)keytab,
131                                           principal, kvno,
132                                           ENCTYPE_DES_CBC_MD4, &key);
133
134     if (retval == KRB5_KT_NOTFOUND) {
135         char * princname = NULL;
136
137         krb5_unparse_name(context, principal, &princname);
138
139         afs_com_err("asetkey", retval,
140                     "for keytab entry with Principal %s, kvno %u, "
141                     "DES-CBC-CRC/MD5/MD4",
142                     princname ? princname : princ, kvno);
143         exit(1);
144     }
145
146     if (retval != 0) {
147         afs_com_err("asetkey", retval, "while extracting AFS service key");
148         exit(1);
149     }
150
151     if (deref_key_length(key) != 8) {
152         fprintf(stderr, "Key length should be 8, but is really %u!\n",
153                 (unsigned int)deref_key_length(key));
154         exit(1);
155     }
156
157     rx_opaque_populate(&buffer, deref_key_contents(key), deref_key_length(key));
158
159     typedKey = afsconf_typedKey_new(afsconf_rxkad, kvno, 0, &buffer);
160     rx_opaque_freeContents(&buffer);
161     krb5_free_principal(context, principal);
162     krb5_free_keyblock(context, key);
163     return typedKey;
164 }
165
166 static void
167 addKey(struct afsconf_dir *dir, int argc, char **argv) {
168     struct afsconf_typedKey *typedKey;
169     int type;
170     int kvno;
171     int code;
172
173     switch (argc) {
174       case 4:
175         typedKey = keyFromCommandLine(afsconf_rxkad, atoi(argv[2]), 0,
176                                       argv[3], 8);
177         break;
178       case 5:
179         typedKey = keyFromKeytab(atoi(argv[2]), argv[3], argv[4]);
180         break;
181       case 6:
182         type = stringToType(argv[2]);
183         kvno = atoi(argv[3]);
184         if (type == afsconf_rxkad) {
185             typedKey = keyFromCommandLine(afsconf_rxkad, kvno, 0, argv[5], 8);
186         } else {
187             fprintf(stderr, "Unknown key type %s\n", argv[2]);
188             exit(1);
189         }
190         break;
191       default:
192         fprintf(stderr, "%s add: usage is '%s add <kvno> <keyfile> "
193                         "<princ>\n", argv[0], argv[0]);
194         fprintf(stderr, "\tOR\n\t%s add <kvno> <key>\n", argv[0]);
195         fprintf(stderr, "\tOR\n\t%s add <type> <kvno> <subtype> <key>\n",
196                 argv[0]);
197         fprintf(stderr, "\t\tEx: %s add 0 \"80b6a7cd7a9dadb6\"\n", argv[0]);
198                 exit(1);
199     }
200     code = afsconf_AddTypedKey(dir, typedKey, 1);
201     afsconf_typedKey_put(&typedKey);
202     if (code) {
203         afs_com_err("asetkey", code, "while adding new key");
204         exit(1);
205     }
206 }
207
208 static void
209 deleteKey(struct afsconf_dir *dir, int argc, char **argv)
210 {
211     int kvno;
212     int code;
213
214     if (argc != 3) {
215         fprintf(stderr, "%s delete: usage is '%s delete <kvno>\n",
216                 argv[0], argv[0]);
217         exit(1);
218     }
219     kvno = atoi(argv[2]);
220     code = afsconf_DeleteKey(dir, kvno);
221     if (code) {
222         afs_com_err(argv[0], code, "while deleting key %d", kvno);
223         exit(1);
224     }
225 }
226
227 static void
228 listKey(struct afsconf_dir *dir, int argc, char **argv)
229 {
230     struct afsconf_typedKeyList *keys;
231     int i;
232     int code;
233
234     code = afsconf_GetAllKeys(dir, &keys);
235     if (code) {
236         afs_com_err("asetkey", code, "while retrieving keys");
237         exit(1);
238     }
239     for (i = 0; i < keys->nkeys; i++) {
240         afsconf_keyType type;
241         int kvno;
242         int minorType;
243         struct rx_opaque *keyMaterial;
244
245         afsconf_typedKey_values(keys->keys[i], &type, &kvno, &minorType,
246                                     &keyMaterial);
247         switch(type) {
248           case afsconf_rxkad:
249             if (kvno != -1) {
250                 printf("rxkad\tkvno %4d: key is: ", kvno);
251                 printKey(keyMaterial);
252             }
253             break;
254           default:
255             printf("unknown(%d)\tkvno %4d subtype %d key is: ", type,
256                    kvno, minorType);
257             printKey(keyMaterial);
258             break;
259           }
260     }
261     printf("All done.\n");
262 }
263
264 int
265 main(int argc, char *argv[])
266 {
267     struct afsconf_dir *tdir;
268     const char *confdir;
269
270     if (argc == 1) {
271         fprintf(stderr, "%s: usage is '%s <opcode> options, e.g.\n",
272                 argv[0], argv[0]);
273         fprintf(stderr, "\t%s add <kvno> <keyfile> <princ>\n", argv[0]);
274         fprintf(stderr, "\tOR\n\t%s add <kvno> <key>\n", argv[0]);
275         fprintf(stderr, "\tOR\n\t%s add <type> <kvno> <subtype> <key>\n",
276                 argv[0]);
277         fprintf(stderr, "\t\tEx: %s add 0 \"80b6a7cd7a9dadb6\"\n", argv[0]);
278         fprintf(stderr, "\t%s delete <kvno>\n", argv[0]);
279         fprintf(stderr, "\t%s list\n", argv[0]);
280         exit(1);
281     }
282
283     confdir = AFSDIR_SERVER_ETC_DIRPATH;
284
285     tdir = afsconf_Open(confdir);
286     if (!tdir) {
287         fprintf(stderr, "%s: can't initialize conf dir '%s'\n", argv[0],
288                 confdir);
289         exit(1);
290     }
291     if (strcmp(argv[1], "add")==0) {
292         addKey(tdir, argc, argv);
293     }
294     else if (strcmp(argv[1], "delete")==0) {
295         deleteKey(tdir, argc, argv);
296     }
297     else if (strcmp(argv[1], "list") == 0) {
298         listKey(tdir, argc, argv);
299
300     }
301     else {
302         fprintf(stderr, "%s: unknown operation '%s', type '%s' for "
303                 "assistance\n", argv[0], argv[1], argv[0]);
304         exit(1);
305     }
306     exit(0);
307 }