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