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