Commit | Line | Data |
---|---|---|
805e021f CE |
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 | } |