1 | /*
|
---|
2 | * Copyright (c) 2008 Kungliga Tekniska Högskolan
|
---|
3 | * (Royal Institute of Technology, Stockholm, Sweden).
|
---|
4 | * All rights reserved.
|
---|
5 | *
|
---|
6 | * Redistribution and use in source and binary forms, with or without
|
---|
7 | * modification, are permitted provided that the following conditions
|
---|
8 | * are met:
|
---|
9 | *
|
---|
10 | * 1. Redistributions of source code must retain the above copyright
|
---|
11 | * notice, this list of conditions and the following disclaimer.
|
---|
12 | *
|
---|
13 | * 2. Redistributions in binary form must reproduce the above copyright
|
---|
14 | * notice, this list of conditions and the following disclaimer in the
|
---|
15 | * documentation and/or other materials provided with the distribution.
|
---|
16 | *
|
---|
17 | * 3. Neither the name of the Institute nor the names of its contributors
|
---|
18 | * may be used to endorse or promote products derived from this software
|
---|
19 | * without specific prior written permission.
|
---|
20 | *
|
---|
21 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
---|
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
---|
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
---|
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
---|
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
---|
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
---|
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
---|
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
---|
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
---|
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
---|
31 | * SUCH DAMAGE.
|
---|
32 | */
|
---|
33 |
|
---|
34 | #include "kadmin_locl.h"
|
---|
35 |
|
---|
36 | #include <gssapi.h>
|
---|
37 | #include <gssapi_krb5.h>
|
---|
38 | #include <gssapi_spnego.h>
|
---|
39 |
|
---|
40 | #define CHECK(x) \
|
---|
41 | do { \
|
---|
42 | int __r; \
|
---|
43 | if ((__r = (x))) { \
|
---|
44 | krb5_errx(dcontext, 1, "Failed (%d) on %s:%d", \
|
---|
45 | __r, __FILE__, __LINE__); \
|
---|
46 | } \
|
---|
47 | } while(0)
|
---|
48 |
|
---|
49 | static krb5_context dcontext;
|
---|
50 |
|
---|
51 | #define INSIST(x) CHECK(!(x))
|
---|
52 |
|
---|
53 | #define VERSION2 0x12345702
|
---|
54 |
|
---|
55 | #define LAST_FRAGMENT 0x80000000
|
---|
56 |
|
---|
57 | #define RPC_VERSION 2
|
---|
58 | #define KADM_SERVER 2112
|
---|
59 | #define VVERSION 2
|
---|
60 | #define FLAVOR_GSS 6
|
---|
61 | #define FLAVOR_GSS_VERSION 1
|
---|
62 |
|
---|
63 | struct opaque_auth {
|
---|
64 | uint32_t flavor;
|
---|
65 | krb5_data data;
|
---|
66 | };
|
---|
67 |
|
---|
68 | struct call_header {
|
---|
69 | uint32_t xid;
|
---|
70 | uint32_t rpcvers;
|
---|
71 | uint32_t prog;
|
---|
72 | uint32_t vers;
|
---|
73 | uint32_t proc;
|
---|
74 | struct opaque_auth cred;
|
---|
75 | struct opaque_auth verf;
|
---|
76 | };
|
---|
77 |
|
---|
78 | enum {
|
---|
79 | RPG_DATA = 0,
|
---|
80 | RPG_INIT = 1,
|
---|
81 | RPG_CONTINUE_INIT = 2,
|
---|
82 | RPG_DESTROY = 3
|
---|
83 | };
|
---|
84 |
|
---|
85 | enum {
|
---|
86 | rpg_privacy = 3
|
---|
87 | };
|
---|
88 |
|
---|
89 | /*
|
---|
90 | struct chrand_ret {
|
---|
91 | krb5_ui_4 api_version;
|
---|
92 | kadm5_ret_t ret;
|
---|
93 | int n_keys;
|
---|
94 | krb5_keyblock *keys;
|
---|
95 | };
|
---|
96 | */
|
---|
97 |
|
---|
98 |
|
---|
99 | struct gcred {
|
---|
100 | uint32_t version;
|
---|
101 | uint32_t proc;
|
---|
102 | uint32_t seq_num;
|
---|
103 | uint32_t service;
|
---|
104 | krb5_data handle;
|
---|
105 | };
|
---|
106 |
|
---|
107 | static int
|
---|
108 | parse_name(const unsigned char *p, size_t len,
|
---|
109 | const gss_OID oid, char **name)
|
---|
110 | {
|
---|
111 | size_t l;
|
---|
112 |
|
---|
113 | if (len < 4)
|
---|
114 | return 1;
|
---|
115 |
|
---|
116 | /* TOK_ID */
|
---|
117 | if (memcmp(p, "\x04\x01", 2) != 0)
|
---|
118 | return 1;
|
---|
119 | len -= 2;
|
---|
120 | p += 2;
|
---|
121 |
|
---|
122 | /* MECH_LEN */
|
---|
123 | l = (p[0] << 8) | p[1];
|
---|
124 | len -= 2;
|
---|
125 | p += 2;
|
---|
126 | if (l < 2 || len < l)
|
---|
127 | return 1;
|
---|
128 |
|
---|
129 | /* oid wrapping */
|
---|
130 | if (p[0] != 6 || p[1] != l - 2)
|
---|
131 | return 1;
|
---|
132 | p += 2;
|
---|
133 | l -= 2;
|
---|
134 | len -= 2;
|
---|
135 |
|
---|
136 | /* MECH */
|
---|
137 | if (l != oid->length || memcmp(p, oid->elements, oid->length) != 0)
|
---|
138 | return 1;
|
---|
139 | len -= l;
|
---|
140 | p += l;
|
---|
141 |
|
---|
142 | /* MECHNAME_LEN */
|
---|
143 | if (len < 4)
|
---|
144 | return 1;
|
---|
145 | l = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
|
---|
146 | len -= 4;
|
---|
147 | p += 4;
|
---|
148 |
|
---|
149 | /* MECH NAME */
|
---|
150 | if (len != l)
|
---|
151 | return 1;
|
---|
152 |
|
---|
153 | *name = malloc(l + 1);
|
---|
154 | INSIST(*name != NULL);
|
---|
155 | memcpy(*name, p, l);
|
---|
156 | (*name)[l] = '\0';
|
---|
157 |
|
---|
158 | return 0;
|
---|
159 | }
|
---|
160 |
|
---|
161 |
|
---|
162 |
|
---|
163 | static void
|
---|
164 | gss_error(krb5_context contextp,
|
---|
165 | gss_OID mech, OM_uint32 type, OM_uint32 error)
|
---|
166 | {
|
---|
167 | OM_uint32 new_stat;
|
---|
168 | OM_uint32 msg_ctx = 0;
|
---|
169 | gss_buffer_desc status_string;
|
---|
170 | OM_uint32 ret;
|
---|
171 |
|
---|
172 | do {
|
---|
173 | ret = gss_display_status (&new_stat,
|
---|
174 | error,
|
---|
175 | type,
|
---|
176 | mech,
|
---|
177 | &msg_ctx,
|
---|
178 | &status_string);
|
---|
179 | krb5_warnx(contextp, "%.*s",
|
---|
180 | (int)status_string.length,
|
---|
181 | (char *)status_string.value);
|
---|
182 | gss_release_buffer (&new_stat, &status_string);
|
---|
183 | } while (!GSS_ERROR(ret) && msg_ctx != 0);
|
---|
184 | }
|
---|
185 |
|
---|
186 | static void
|
---|
187 | gss_print_errors (krb5_context contextp,
|
---|
188 | OM_uint32 maj_stat, OM_uint32 min_stat)
|
---|
189 | {
|
---|
190 | gss_error(contextp, GSS_C_NO_OID, GSS_C_GSS_CODE, maj_stat);
|
---|
191 | gss_error(contextp, GSS_C_NO_OID, GSS_C_MECH_CODE, min_stat);
|
---|
192 | }
|
---|
193 |
|
---|
194 | static int
|
---|
195 | read_data(krb5_storage *sp, krb5_storage *msg, size_t len)
|
---|
196 | {
|
---|
197 | char buf[1024];
|
---|
198 |
|
---|
199 | while (len) {
|
---|
200 | size_t tlen = len;
|
---|
201 | ssize_t slen;
|
---|
202 |
|
---|
203 | if (tlen > sizeof(buf))
|
---|
204 | tlen = sizeof(buf);
|
---|
205 |
|
---|
206 | slen = krb5_storage_read(sp, buf, tlen);
|
---|
207 | INSIST((size_t)slen == tlen);
|
---|
208 |
|
---|
209 | slen = krb5_storage_write(msg, buf, tlen);
|
---|
210 | INSIST((size_t)slen == tlen);
|
---|
211 |
|
---|
212 | len -= tlen;
|
---|
213 | }
|
---|
214 | return 0;
|
---|
215 | }
|
---|
216 |
|
---|
217 | static int
|
---|
218 | collect_framents(krb5_storage *sp, krb5_storage *msg)
|
---|
219 | {
|
---|
220 | krb5_error_code ret;
|
---|
221 | uint32_t len;
|
---|
222 | int last_fragment;
|
---|
223 | size_t total_len = 0;
|
---|
224 |
|
---|
225 | do {
|
---|
226 | ret = krb5_ret_uint32(sp, &len);
|
---|
227 | if (ret)
|
---|
228 | return ret;
|
---|
229 |
|
---|
230 | last_fragment = (len & LAST_FRAGMENT);
|
---|
231 | len &= ~LAST_FRAGMENT;
|
---|
232 |
|
---|
233 | CHECK(read_data(sp, msg, len));
|
---|
234 | total_len += len;
|
---|
235 |
|
---|
236 | } while(!last_fragment || total_len == 0);
|
---|
237 |
|
---|
238 | return 0;
|
---|
239 | }
|
---|
240 |
|
---|
241 | static krb5_error_code
|
---|
242 | store_data_xdr(krb5_storage *sp, krb5_data data)
|
---|
243 | {
|
---|
244 | krb5_error_code ret;
|
---|
245 | size_t res;
|
---|
246 |
|
---|
247 | ret = krb5_store_data(sp, data);
|
---|
248 | if (ret)
|
---|
249 | return ret;
|
---|
250 | res = 4 - (data.length % 4);
|
---|
251 | if (res != 4) {
|
---|
252 | static const char zero[4] = { 0, 0, 0, 0 };
|
---|
253 |
|
---|
254 | ret = krb5_storage_write(sp, zero, res);
|
---|
255 | if((size_t)ret != res)
|
---|
256 | return (ret < 0)? errno : krb5_storage_get_eof_code(sp);
|
---|
257 | }
|
---|
258 | return 0;
|
---|
259 | }
|
---|
260 |
|
---|
261 | static krb5_error_code
|
---|
262 | ret_data_xdr(krb5_storage *sp, krb5_data *data)
|
---|
263 | {
|
---|
264 | krb5_error_code ret;
|
---|
265 | ret = krb5_ret_data(sp, data);
|
---|
266 | if (ret)
|
---|
267 | return ret;
|
---|
268 |
|
---|
269 | if ((data->length % 4) != 0) {
|
---|
270 | char buf[4];
|
---|
271 | size_t res;
|
---|
272 |
|
---|
273 | res = 4 - (data->length % 4);
|
---|
274 | if (res != 4) {
|
---|
275 | ret = krb5_storage_read(sp, buf, res);
|
---|
276 | if((size_t)ret != res)
|
---|
277 | return (ret < 0)? errno : krb5_storage_get_eof_code(sp);
|
---|
278 | }
|
---|
279 | }
|
---|
280 | return 0;
|
---|
281 | }
|
---|
282 |
|
---|
283 | static krb5_error_code
|
---|
284 | ret_auth_opaque(krb5_storage *msg, struct opaque_auth *ao)
|
---|
285 | {
|
---|
286 | krb5_error_code ret;
|
---|
287 | ret = krb5_ret_uint32(msg, &ao->flavor);
|
---|
288 | if (ret) return ret;
|
---|
289 | ret = ret_data_xdr(msg, &ao->data);
|
---|
290 | return ret;
|
---|
291 | }
|
---|
292 |
|
---|
293 | static int
|
---|
294 | ret_gcred(krb5_data *data, struct gcred *gcred)
|
---|
295 | {
|
---|
296 | krb5_storage *sp;
|
---|
297 |
|
---|
298 | memset(gcred, 0, sizeof(*gcred));
|
---|
299 |
|
---|
300 | sp = krb5_storage_from_data(data);
|
---|
301 | INSIST(sp != NULL);
|
---|
302 |
|
---|
303 | CHECK(krb5_ret_uint32(sp, &gcred->version));
|
---|
304 | CHECK(krb5_ret_uint32(sp, &gcred->proc));
|
---|
305 | CHECK(krb5_ret_uint32(sp, &gcred->seq_num));
|
---|
306 | CHECK(krb5_ret_uint32(sp, &gcred->service));
|
---|
307 | CHECK(ret_data_xdr(sp, &gcred->handle));
|
---|
308 |
|
---|
309 | krb5_storage_free(sp);
|
---|
310 |
|
---|
311 | return 0;
|
---|
312 | }
|
---|
313 |
|
---|
314 | static krb5_error_code
|
---|
315 | store_gss_init_res(krb5_storage *sp, krb5_data handle,
|
---|
316 | OM_uint32 maj_stat, OM_uint32 min_stat,
|
---|
317 | uint32_t seq_window, gss_buffer_t gout)
|
---|
318 | {
|
---|
319 | krb5_error_code ret;
|
---|
320 | krb5_data out;
|
---|
321 |
|
---|
322 | out.data = gout->value;
|
---|
323 | out.length = gout->length;
|
---|
324 |
|
---|
325 | ret = store_data_xdr(sp, handle);
|
---|
326 | if (ret) return ret;
|
---|
327 | ret = krb5_store_uint32(sp, maj_stat);
|
---|
328 | if (ret) return ret;
|
---|
329 | ret = krb5_store_uint32(sp, min_stat);
|
---|
330 | if (ret) return ret;
|
---|
331 | ret = store_data_xdr(sp, out);
|
---|
332 | return ret;
|
---|
333 | }
|
---|
334 |
|
---|
335 | static int
|
---|
336 | store_string_xdr(krb5_storage *sp, const char *str)
|
---|
337 | {
|
---|
338 | krb5_data c;
|
---|
339 | if (str) {
|
---|
340 | c.data = rk_UNCONST(str);
|
---|
341 | c.length = strlen(str) + 1;
|
---|
342 | } else
|
---|
343 | krb5_data_zero(&c);
|
---|
344 |
|
---|
345 | return store_data_xdr(sp, c);
|
---|
346 | }
|
---|
347 |
|
---|
348 | static int
|
---|
349 | ret_string_xdr(krb5_storage *sp, char **str)
|
---|
350 | {
|
---|
351 | krb5_data c;
|
---|
352 | *str = NULL;
|
---|
353 | CHECK(ret_data_xdr(sp, &c));
|
---|
354 | if (c.length) {
|
---|
355 | *str = malloc(c.length + 1);
|
---|
356 | INSIST(*str != NULL);
|
---|
357 | memcpy(*str, c.data, c.length);
|
---|
358 | (*str)[c.length] = '\0';
|
---|
359 | }
|
---|
360 | krb5_data_free(&c);
|
---|
361 | return 0;
|
---|
362 | }
|
---|
363 |
|
---|
364 | static int
|
---|
365 | store_principal_xdr(krb5_context contextp,
|
---|
366 | krb5_storage *sp,
|
---|
367 | krb5_principal p)
|
---|
368 | {
|
---|
369 | char *str;
|
---|
370 | CHECK(krb5_unparse_name(contextp, p, &str));
|
---|
371 | CHECK(store_string_xdr(sp, str));
|
---|
372 | free(str);
|
---|
373 | return 0;
|
---|
374 | }
|
---|
375 |
|
---|
376 | static int
|
---|
377 | ret_principal_xdr(krb5_context contextp,
|
---|
378 | krb5_storage *sp,
|
---|
379 | krb5_principal *p)
|
---|
380 | {
|
---|
381 | char *str;
|
---|
382 | *p = NULL;
|
---|
383 | CHECK(ret_string_xdr(sp, &str));
|
---|
384 | if (str) {
|
---|
385 | CHECK(krb5_parse_name(contextp, str, p));
|
---|
386 | free(str);
|
---|
387 | }
|
---|
388 | return 0;
|
---|
389 | }
|
---|
390 |
|
---|
391 | static int
|
---|
392 | store_principal_ent(krb5_context contextp,
|
---|
393 | krb5_storage *sp,
|
---|
394 | kadm5_principal_ent_rec *ent)
|
---|
395 | {
|
---|
396 | int i;
|
---|
397 |
|
---|
398 | CHECK(store_principal_xdr(contextp, sp, ent->principal));
|
---|
399 | CHECK(krb5_store_uint32(sp, ent->princ_expire_time));
|
---|
400 | CHECK(krb5_store_uint32(sp, ent->pw_expiration));
|
---|
401 | CHECK(krb5_store_uint32(sp, ent->last_pwd_change));
|
---|
402 | CHECK(krb5_store_uint32(sp, ent->max_life));
|
---|
403 | CHECK(krb5_store_int32(sp, ent->mod_name == NULL));
|
---|
404 | if (ent->mod_name)
|
---|
405 | CHECK(store_principal_xdr(contextp, sp, ent->mod_name));
|
---|
406 | CHECK(krb5_store_uint32(sp, ent->mod_date));
|
---|
407 | CHECK(krb5_store_uint32(sp, ent->attributes));
|
---|
408 | CHECK(krb5_store_uint32(sp, ent->kvno));
|
---|
409 | CHECK(krb5_store_uint32(sp, ent->mkvno));
|
---|
410 | CHECK(store_string_xdr(sp, ent->policy));
|
---|
411 | CHECK(krb5_store_int32(sp, ent->aux_attributes));
|
---|
412 | CHECK(krb5_store_int32(sp, ent->max_renewable_life));
|
---|
413 | CHECK(krb5_store_int32(sp, ent->last_success));
|
---|
414 | CHECK(krb5_store_int32(sp, ent->last_failed));
|
---|
415 | CHECK(krb5_store_int32(sp, ent->fail_auth_count));
|
---|
416 | CHECK(krb5_store_int32(sp, ent->n_key_data));
|
---|
417 | CHECK(krb5_store_int32(sp, ent->n_tl_data));
|
---|
418 | CHECK(krb5_store_int32(sp, ent->n_tl_data == 0));
|
---|
419 | if (ent->n_tl_data) {
|
---|
420 | krb5_tl_data *tp;
|
---|
421 |
|
---|
422 | for (tp = ent->tl_data; tp; tp = tp->tl_data_next) {
|
---|
423 | krb5_data c;
|
---|
424 | c.length = tp->tl_data_length;
|
---|
425 | c.data = tp->tl_data_contents;
|
---|
426 |
|
---|
427 | CHECK(krb5_store_int32(sp, 0)); /* last item */
|
---|
428 | CHECK(krb5_store_int32(sp, tp->tl_data_type));
|
---|
429 | CHECK(store_data_xdr(sp, c));
|
---|
430 | }
|
---|
431 | CHECK(krb5_store_int32(sp, 1)); /* last item */
|
---|
432 | }
|
---|
433 |
|
---|
434 | CHECK(krb5_store_int32(sp, ent->n_key_data));
|
---|
435 | for (i = 0; i < ent->n_key_data; i++) {
|
---|
436 | CHECK(krb5_store_uint32(sp, 2));
|
---|
437 | CHECK(krb5_store_uint32(sp, ent->kvno));
|
---|
438 | CHECK(krb5_store_uint32(sp, ent->key_data[i].key_data_type[0]));
|
---|
439 | CHECK(krb5_store_uint32(sp, ent->key_data[i].key_data_type[1]));
|
---|
440 | }
|
---|
441 |
|
---|
442 | return 0;
|
---|
443 | }
|
---|
444 |
|
---|
445 | static int
|
---|
446 | ret_principal_ent(krb5_context contextp,
|
---|
447 | krb5_storage *sp,
|
---|
448 | kadm5_principal_ent_rec *ent)
|
---|
449 | {
|
---|
450 | uint32_t flag, num;
|
---|
451 | size_t i;
|
---|
452 |
|
---|
453 | memset(ent, 0, sizeof(*ent));
|
---|
454 |
|
---|
455 | CHECK(ret_principal_xdr(contextp, sp, &ent->principal));
|
---|
456 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
457 | ent->princ_expire_time = flag;
|
---|
458 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
459 | ent->pw_expiration = flag;
|
---|
460 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
461 | ent->last_pwd_change = flag;
|
---|
462 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
463 | ent->max_life = flag;
|
---|
464 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
465 | if (flag == 0)
|
---|
466 | ret_principal_xdr(contextp, sp, &ent->mod_name);
|
---|
467 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
468 | ent->mod_date = flag;
|
---|
469 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
470 | ent->attributes = flag;
|
---|
471 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
472 | ent->kvno = flag;
|
---|
473 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
474 | ent->mkvno = flag;
|
---|
475 | CHECK(ret_string_xdr(sp, &ent->policy));
|
---|
476 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
477 | ent->aux_attributes = flag;
|
---|
478 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
479 | ent->max_renewable_life = flag;
|
---|
480 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
481 | ent->last_success = flag;
|
---|
482 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
483 | ent->last_failed = flag;
|
---|
484 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
485 | ent->fail_auth_count = flag;
|
---|
486 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
487 | ent->n_key_data = flag;
|
---|
488 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
489 | ent->n_tl_data = flag;
|
---|
490 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
491 | if (flag == 0) {
|
---|
492 | krb5_tl_data **tp = &ent->tl_data;
|
---|
493 | size_t count = 0;
|
---|
494 |
|
---|
495 | while(1) {
|
---|
496 | krb5_data c;
|
---|
497 | CHECK(krb5_ret_uint32(sp, &flag)); /* last item */
|
---|
498 | if (flag)
|
---|
499 | break;
|
---|
500 | *tp = calloc(1, sizeof(**tp));
|
---|
501 | INSIST(*tp != NULL);
|
---|
502 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
503 | (*tp)->tl_data_type = flag;
|
---|
504 | CHECK(ret_data_xdr(sp, &c));
|
---|
505 | (*tp)->tl_data_length = c.length;
|
---|
506 | (*tp)->tl_data_contents = c.data;
|
---|
507 | tp = &(*tp)->tl_data_next;
|
---|
508 |
|
---|
509 | count++;
|
---|
510 | }
|
---|
511 | INSIST((size_t)ent->n_tl_data == count);
|
---|
512 | } else {
|
---|
513 | INSIST(ent->n_tl_data == 0);
|
---|
514 | }
|
---|
515 |
|
---|
516 | CHECK(krb5_ret_uint32(sp, &num));
|
---|
517 | INSIST(num == (uint32_t)ent->n_key_data);
|
---|
518 |
|
---|
519 | ent->key_data = calloc(num, sizeof(ent->key_data[0]));
|
---|
520 | INSIST(ent->key_data != NULL);
|
---|
521 |
|
---|
522 | for (i = 0; i < num; i++) {
|
---|
523 | CHECK(krb5_ret_uint32(sp, &flag)); /* data version */
|
---|
524 | INSIST(flag > 1);
|
---|
525 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
526 | ent->kvno = flag;
|
---|
527 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
528 | ent->key_data[i].key_data_type[0] = flag;
|
---|
529 | CHECK(krb5_ret_uint32(sp, &flag));
|
---|
530 | ent->key_data[i].key_data_type[1] = flag;
|
---|
531 | }
|
---|
532 |
|
---|
533 | return 0;
|
---|
534 | }
|
---|
535 |
|
---|
536 | /*
|
---|
537 | *
|
---|
538 | */
|
---|
539 |
|
---|
540 | static void
|
---|
541 | proc_create_principal(kadm5_server_context *contextp,
|
---|
542 | krb5_storage *in,
|
---|
543 | krb5_storage *out)
|
---|
544 | {
|
---|
545 | uint32_t version, mask;
|
---|
546 | kadm5_principal_ent_rec ent;
|
---|
547 | krb5_error_code ret;
|
---|
548 | char *password;
|
---|
549 |
|
---|
550 | memset(&ent, 0, sizeof(ent));
|
---|
551 |
|
---|
552 | CHECK(krb5_ret_uint32(in, &version));
|
---|
553 | INSIST(version == VERSION2);
|
---|
554 | CHECK(ret_principal_ent(contextp->context, in, &ent));
|
---|
555 | CHECK(krb5_ret_uint32(in, &mask));
|
---|
556 | CHECK(ret_string_xdr(in, &password));
|
---|
557 |
|
---|
558 | INSIST(ent.principal);
|
---|
559 |
|
---|
560 |
|
---|
561 | ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD, ent.principal);
|
---|
562 | if (ret)
|
---|
563 | goto fail;
|
---|
564 |
|
---|
565 | ret = kadm5_create_principal(contextp, &ent, mask, password);
|
---|
566 |
|
---|
567 | fail:
|
---|
568 | krb5_warn(contextp->context, ret, "create principal");
|
---|
569 | CHECK(krb5_store_uint32(out, VERSION2)); /* api version */
|
---|
570 | CHECK(krb5_store_uint32(out, ret)); /* code */
|
---|
571 |
|
---|
572 | free(password);
|
---|
573 | kadm5_free_principal_ent(contextp, &ent);
|
---|
574 | }
|
---|
575 |
|
---|
576 | static void
|
---|
577 | proc_delete_principal(kadm5_server_context *contextp,
|
---|
578 | krb5_storage *in,
|
---|
579 | krb5_storage *out)
|
---|
580 | {
|
---|
581 | uint32_t version;
|
---|
582 | krb5_principal princ;
|
---|
583 | krb5_error_code ret;
|
---|
584 |
|
---|
585 | CHECK(krb5_ret_uint32(in, &version));
|
---|
586 | INSIST(version == VERSION2);
|
---|
587 | CHECK(ret_principal_xdr(contextp->context, in, &princ));
|
---|
588 |
|
---|
589 | ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ);
|
---|
590 | if (ret)
|
---|
591 | goto fail;
|
---|
592 |
|
---|
593 | ret = kadm5_delete_principal(contextp, princ);
|
---|
594 |
|
---|
595 | fail:
|
---|
596 | krb5_warn(contextp->context, ret, "delete principal");
|
---|
597 | CHECK(krb5_store_uint32(out, VERSION2)); /* api version */
|
---|
598 | CHECK(krb5_store_uint32(out, ret)); /* code */
|
---|
599 |
|
---|
600 | krb5_free_principal(contextp->context, princ);
|
---|
601 | }
|
---|
602 |
|
---|
603 | static void
|
---|
604 | proc_get_principal(kadm5_server_context *contextp,
|
---|
605 | krb5_storage *in,
|
---|
606 | krb5_storage *out)
|
---|
607 | {
|
---|
608 | uint32_t version, mask;
|
---|
609 | krb5_principal princ;
|
---|
610 | kadm5_principal_ent_rec ent;
|
---|
611 | krb5_error_code ret;
|
---|
612 |
|
---|
613 | memset(&ent, 0, sizeof(ent));
|
---|
614 |
|
---|
615 | CHECK(krb5_ret_uint32(in, &version));
|
---|
616 | INSIST(version == VERSION2);
|
---|
617 | CHECK(ret_principal_xdr(contextp->context, in, &princ));
|
---|
618 | CHECK(krb5_ret_uint32(in, &mask));
|
---|
619 |
|
---|
620 | ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ);
|
---|
621 | if(ret)
|
---|
622 | goto fail;
|
---|
623 |
|
---|
624 | ret = kadm5_get_principal(contextp, princ, &ent, mask);
|
---|
625 |
|
---|
626 | fail:
|
---|
627 | krb5_warn(contextp->context, ret, "get principal principal");
|
---|
628 |
|
---|
629 | CHECK(krb5_store_uint32(out, VERSION2)); /* api version */
|
---|
630 | CHECK(krb5_store_uint32(out, ret)); /* code */
|
---|
631 | if (ret == 0) {
|
---|
632 | CHECK(store_principal_ent(contextp->context, out, &ent));
|
---|
633 | }
|
---|
634 | krb5_free_principal(contextp->context, princ);
|
---|
635 | kadm5_free_principal_ent(contextp, &ent);
|
---|
636 | }
|
---|
637 |
|
---|
638 | static void
|
---|
639 | proc_chrand_principal_v2(kadm5_server_context *contextp,
|
---|
640 | krb5_storage *in,
|
---|
641 | krb5_storage *out)
|
---|
642 | {
|
---|
643 | krb5_error_code ret;
|
---|
644 | krb5_principal princ;
|
---|
645 | uint32_t version;
|
---|
646 | krb5_keyblock *new_keys;
|
---|
647 | int n_keys;
|
---|
648 |
|
---|
649 | CHECK(krb5_ret_uint32(in, &version));
|
---|
650 | INSIST(version == VERSION2);
|
---|
651 | CHECK(ret_principal_xdr(contextp->context, in, &princ));
|
---|
652 |
|
---|
653 | ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
|
---|
654 | if(ret)
|
---|
655 | goto fail;
|
---|
656 |
|
---|
657 | ret = kadm5_randkey_principal(contextp, princ,
|
---|
658 | &new_keys, &n_keys);
|
---|
659 |
|
---|
660 | fail:
|
---|
661 | krb5_warn(contextp->context, ret, "rand key principal");
|
---|
662 |
|
---|
663 | CHECK(krb5_store_uint32(out, VERSION2)); /* api version */
|
---|
664 | CHECK(krb5_store_uint32(out, ret));
|
---|
665 | if (ret == 0) {
|
---|
666 | int i;
|
---|
667 | CHECK(krb5_store_int32(out, n_keys));
|
---|
668 |
|
---|
669 | for(i = 0; i < n_keys; i++){
|
---|
670 | CHECK(krb5_store_uint32(out, new_keys[i].keytype));
|
---|
671 | CHECK(store_data_xdr(out, new_keys[i].keyvalue));
|
---|
672 | krb5_free_keyblock_contents(contextp->context, &new_keys[i]);
|
---|
673 | }
|
---|
674 | free(new_keys);
|
---|
675 | }
|
---|
676 | krb5_free_principal(contextp->context, princ);
|
---|
677 | }
|
---|
678 |
|
---|
679 | static void
|
---|
680 | proc_init(kadm5_server_context *contextp,
|
---|
681 | krb5_storage *in,
|
---|
682 | krb5_storage *out)
|
---|
683 | {
|
---|
684 | CHECK(krb5_store_uint32(out, VERSION2)); /* api version */
|
---|
685 | CHECK(krb5_store_uint32(out, 0)); /* code */
|
---|
686 | CHECK(krb5_store_uint32(out, 0)); /* code */
|
---|
687 | }
|
---|
688 |
|
---|
689 | struct krb5_proc {
|
---|
690 | const char *name;
|
---|
691 | void (*func)(kadm5_server_context *, krb5_storage *, krb5_storage *);
|
---|
692 | } procs[] = {
|
---|
693 | { "NULL", NULL },
|
---|
694 | { "create principal", proc_create_principal },
|
---|
695 | { "delete principal", proc_delete_principal },
|
---|
696 | { "modify principal", NULL },
|
---|
697 | { "rename principal", NULL },
|
---|
698 | { "get principal", proc_get_principal },
|
---|
699 | { "chpass principal", NULL },
|
---|
700 | { "chrand principal", proc_chrand_principal_v2 },
|
---|
701 | { "create policy", NULL },
|
---|
702 | { "delete policy", NULL },
|
---|
703 | { "modify policy", NULL },
|
---|
704 | { "get policy", NULL },
|
---|
705 | { "get privs", NULL },
|
---|
706 | { "init", proc_init },
|
---|
707 | { "get principals", NULL },
|
---|
708 | { "get polices", NULL },
|
---|
709 | { "setkey principal", NULL },
|
---|
710 | { "setkey principal v4", NULL },
|
---|
711 | { "create principal v3", NULL },
|
---|
712 | { "chpass principal v3", NULL },
|
---|
713 | { "chrand principal v3", NULL },
|
---|
714 | { "setkey principal v3", NULL }
|
---|
715 | };
|
---|
716 |
|
---|
717 | static krb5_error_code
|
---|
718 | copyheader(krb5_storage *sp, krb5_data *data)
|
---|
719 | {
|
---|
720 | off_t off;
|
---|
721 | ssize_t sret;
|
---|
722 |
|
---|
723 | off = krb5_storage_seek(sp, 0, SEEK_CUR);
|
---|
724 |
|
---|
725 | CHECK(krb5_data_alloc(data, off));
|
---|
726 | INSIST((size_t)off == data->length);
|
---|
727 | krb5_storage_seek(sp, 0, SEEK_SET);
|
---|
728 | sret = krb5_storage_read(sp, data->data, data->length);
|
---|
729 | INSIST(sret == off);
|
---|
730 | INSIST(off == krb5_storage_seek(sp, 0, SEEK_CUR));
|
---|
731 |
|
---|
732 | return 0;
|
---|
733 | }
|
---|
734 |
|
---|
735 | struct gctx {
|
---|
736 | krb5_data handle;
|
---|
737 | gss_ctx_id_t ctx;
|
---|
738 | uint32_t seq_num;
|
---|
739 | int done;
|
---|
740 | int inprogress;
|
---|
741 | };
|
---|
742 |
|
---|
743 | static int
|
---|
744 | process_stream(krb5_context contextp,
|
---|
745 | unsigned char *buf, size_t ilen,
|
---|
746 | krb5_storage *sp)
|
---|
747 | {
|
---|
748 | krb5_error_code ret;
|
---|
749 | krb5_storage *msg, *reply, *dreply;
|
---|
750 | OM_uint32 maj_stat, min_stat;
|
---|
751 | gss_buffer_desc gin, gout;
|
---|
752 | struct gctx gctx;
|
---|
753 | void *server_handle = NULL;
|
---|
754 |
|
---|
755 | memset(&gctx, 0, sizeof(gctx));
|
---|
756 |
|
---|
757 | msg = krb5_storage_emem();
|
---|
758 | reply = krb5_storage_emem();
|
---|
759 | dreply = krb5_storage_emem();
|
---|
760 |
|
---|
761 | /*
|
---|
762 | * First packet comes partly from the caller
|
---|
763 | */
|
---|
764 |
|
---|
765 | INSIST(ilen >= 4);
|
---|
766 |
|
---|
767 | while (1) {
|
---|
768 | struct call_header chdr;
|
---|
769 | struct gcred gcred;
|
---|
770 | uint32_t mtype;
|
---|
771 | krb5_data headercopy;
|
---|
772 |
|
---|
773 | krb5_storage_truncate(dreply, 0);
|
---|
774 | krb5_storage_truncate(reply, 0);
|
---|
775 | krb5_storage_truncate(msg, 0);
|
---|
776 |
|
---|
777 | krb5_data_zero(&headercopy);
|
---|
778 | memset(&chdr, 0, sizeof(chdr));
|
---|
779 | memset(&gcred, 0, sizeof(gcred));
|
---|
780 |
|
---|
781 | /*
|
---|
782 | * This is very icky to handle the the auto-detection between
|
---|
783 | * the Heimdal protocol and the MIT ONC-RPC based protocol.
|
---|
784 | */
|
---|
785 |
|
---|
786 | if (ilen) {
|
---|
787 | int last_fragment;
|
---|
788 | unsigned long len;
|
---|
789 | ssize_t slen;
|
---|
790 | unsigned char tmp[4];
|
---|
791 |
|
---|
792 | if (ilen < 4) {
|
---|
793 | memcpy(tmp, buf, ilen);
|
---|
794 | slen = krb5_storage_read(sp, tmp + ilen, sizeof(tmp) - ilen);
|
---|
795 | INSIST((size_t)slen == sizeof(tmp) - ilen);
|
---|
796 |
|
---|
797 | ilen = sizeof(tmp);
|
---|
798 | buf = tmp;
|
---|
799 | }
|
---|
800 | INSIST(ilen >= 4);
|
---|
801 |
|
---|
802 | _krb5_get_int(buf, &len, 4);
|
---|
803 | last_fragment = (len & LAST_FRAGMENT) != 0;
|
---|
804 | len &= ~LAST_FRAGMENT;
|
---|
805 |
|
---|
806 | ilen -= 4;
|
---|
807 | buf += 4;
|
---|
808 |
|
---|
809 | if (ilen) {
|
---|
810 | if (len < ilen) {
|
---|
811 | slen = krb5_storage_write(msg, buf, len);
|
---|
812 | INSIST((size_t)slen == len);
|
---|
813 | ilen -= len;
|
---|
814 | len = 0;
|
---|
815 | } else {
|
---|
816 | slen = krb5_storage_write(msg, buf, ilen);
|
---|
817 | INSIST((size_t)slen == ilen);
|
---|
818 | len -= ilen;
|
---|
819 | }
|
---|
820 | }
|
---|
821 |
|
---|
822 | CHECK(read_data(sp, msg, len));
|
---|
823 |
|
---|
824 | if (!last_fragment) {
|
---|
825 | ret = collect_framents(sp, msg);
|
---|
826 | if (ret == HEIM_ERR_EOF)
|
---|
827 | krb5_errx(contextp, 0, "client disconnected");
|
---|
828 | INSIST(ret == 0);
|
---|
829 | }
|
---|
830 | } else {
|
---|
831 |
|
---|
832 | ret = collect_framents(sp, msg);
|
---|
833 | if (ret == HEIM_ERR_EOF)
|
---|
834 | krb5_errx(contextp, 0, "client disconnected");
|
---|
835 | INSIST(ret == 0);
|
---|
836 | }
|
---|
837 | krb5_storage_seek(msg, 0, SEEK_SET);
|
---|
838 |
|
---|
839 | CHECK(krb5_ret_uint32(msg, &chdr.xid));
|
---|
840 | CHECK(krb5_ret_uint32(msg, &mtype));
|
---|
841 | CHECK(krb5_ret_uint32(msg, &chdr.rpcvers));
|
---|
842 | CHECK(krb5_ret_uint32(msg, &chdr.prog));
|
---|
843 | CHECK(krb5_ret_uint32(msg, &chdr.vers));
|
---|
844 | CHECK(krb5_ret_uint32(msg, &chdr.proc));
|
---|
845 | CHECK(ret_auth_opaque(msg, &chdr.cred));
|
---|
846 | CHECK(copyheader(msg, &headercopy));
|
---|
847 | CHECK(ret_auth_opaque(msg, &chdr.verf));
|
---|
848 |
|
---|
849 | INSIST(chdr.rpcvers == RPC_VERSION);
|
---|
850 | INSIST(chdr.prog == KADM_SERVER);
|
---|
851 | INSIST(chdr.vers == VVERSION);
|
---|
852 | INSIST(chdr.cred.flavor == FLAVOR_GSS);
|
---|
853 |
|
---|
854 | CHECK(ret_gcred(&chdr.cred.data, &gcred));
|
---|
855 |
|
---|
856 | INSIST(gcred.version == FLAVOR_GSS_VERSION);
|
---|
857 |
|
---|
858 | if (gctx.done) {
|
---|
859 | INSIST(chdr.verf.flavor == FLAVOR_GSS);
|
---|
860 |
|
---|
861 | /* from first byte to last of credential */
|
---|
862 | gin.value = headercopy.data;
|
---|
863 | gin.length = headercopy.length;
|
---|
864 | gout.value = chdr.verf.data.data;
|
---|
865 | gout.length = chdr.verf.data.length;
|
---|
866 |
|
---|
867 | maj_stat = gss_verify_mic(&min_stat, gctx.ctx, &gin, &gout, NULL);
|
---|
868 | INSIST(maj_stat == GSS_S_COMPLETE);
|
---|
869 | }
|
---|
870 |
|
---|
871 | switch(gcred.proc) {
|
---|
872 | case RPG_DATA: {
|
---|
873 | krb5_data data;
|
---|
874 | int conf_state;
|
---|
875 | uint32_t seq;
|
---|
876 | krb5_storage *sp1;
|
---|
877 |
|
---|
878 | INSIST(gcred.service == rpg_privacy);
|
---|
879 |
|
---|
880 | INSIST(gctx.done);
|
---|
881 |
|
---|
882 | INSIST(krb5_data_cmp(&gcred.handle, &gctx.handle) == 0);
|
---|
883 |
|
---|
884 | CHECK(ret_data_xdr(msg, &data));
|
---|
885 |
|
---|
886 | gin.value = data.data;
|
---|
887 | gin.length = data.length;
|
---|
888 |
|
---|
889 | maj_stat = gss_unwrap(&min_stat, gctx.ctx, &gin, &gout,
|
---|
890 | &conf_state, NULL);
|
---|
891 | krb5_data_free(&data);
|
---|
892 | INSIST(maj_stat == GSS_S_COMPLETE);
|
---|
893 | INSIST(conf_state != 0);
|
---|
894 |
|
---|
895 | sp1 = krb5_storage_from_mem(gout.value, gout.length);
|
---|
896 | INSIST(sp1 != NULL);
|
---|
897 |
|
---|
898 | CHECK(krb5_ret_uint32(sp1, &seq));
|
---|
899 | INSIST (seq == gcred.seq_num);
|
---|
900 |
|
---|
901 | /*
|
---|
902 | * Check sequence number
|
---|
903 | */
|
---|
904 | INSIST(seq > gctx.seq_num);
|
---|
905 | gctx.seq_num = seq;
|
---|
906 |
|
---|
907 | /*
|
---|
908 | * If contextp is setup, priv data have the seq_num stored
|
---|
909 | * first in the block, so add it here before users data is
|
---|
910 | * added.
|
---|
911 | */
|
---|
912 | CHECK(krb5_store_uint32(dreply, gctx.seq_num));
|
---|
913 |
|
---|
914 | if (chdr.proc >= sizeof(procs)/sizeof(procs[0])) {
|
---|
915 | krb5_warnx(contextp, "proc number out of array");
|
---|
916 | } else if (procs[chdr.proc].func == NULL) {
|
---|
917 | krb5_warnx(contextp, "proc '%s' never implemented",
|
---|
918 | procs[chdr.proc].name);
|
---|
919 | } else {
|
---|
920 | krb5_warnx(contextp, "proc %s", procs[chdr.proc].name);
|
---|
921 | INSIST(server_handle != NULL);
|
---|
922 | (*procs[chdr.proc].func)(server_handle, sp, dreply);
|
---|
923 | }
|
---|
924 | krb5_storage_free(sp);
|
---|
925 | gss_release_buffer(&min_stat, &gout);
|
---|
926 |
|
---|
927 | break;
|
---|
928 | }
|
---|
929 | case RPG_INIT:
|
---|
930 | INSIST(gctx.inprogress == 0);
|
---|
931 | INSIST(gctx.ctx == NULL);
|
---|
932 |
|
---|
933 | gctx.inprogress = 1;
|
---|
934 | /* FALL THOUGH */
|
---|
935 | case RPG_CONTINUE_INIT: {
|
---|
936 | gss_name_t src_name = GSS_C_NO_NAME;
|
---|
937 | krb5_data in;
|
---|
938 |
|
---|
939 | INSIST(gctx.inprogress);
|
---|
940 |
|
---|
941 | CHECK(ret_data_xdr(msg, &in));
|
---|
942 |
|
---|
943 | gin.value = in.data;
|
---|
944 | gin.length = in.length;
|
---|
945 | gout.value = NULL;
|
---|
946 | gout.length = 0;
|
---|
947 |
|
---|
948 | maj_stat = gss_accept_sec_context(&min_stat,
|
---|
949 | &gctx.ctx,
|
---|
950 | GSS_C_NO_CREDENTIAL,
|
---|
951 | &gin,
|
---|
952 | GSS_C_NO_CHANNEL_BINDINGS,
|
---|
953 | &src_name,
|
---|
954 | NULL,
|
---|
955 | &gout,
|
---|
956 | NULL,
|
---|
957 | NULL,
|
---|
958 | NULL);
|
---|
959 | if (GSS_ERROR(maj_stat)) {
|
---|
960 | gss_print_errors(contextp, maj_stat, min_stat);
|
---|
961 | krb5_errx(contextp, 1, "gss error, exit");
|
---|
962 | }
|
---|
963 | if ((maj_stat & GSS_S_CONTINUE_NEEDED) == 0) {
|
---|
964 | kadm5_config_params realm_params;
|
---|
965 | gss_buffer_desc bufp;
|
---|
966 | char *client;
|
---|
967 |
|
---|
968 | gctx.done = 1;
|
---|
969 |
|
---|
970 | memset(&realm_params, 0, sizeof(realm_params));
|
---|
971 |
|
---|
972 | maj_stat = gss_export_name(&min_stat, src_name, &bufp);
|
---|
973 | INSIST(maj_stat == GSS_S_COMPLETE);
|
---|
974 |
|
---|
975 | CHECK(parse_name(bufp.value, bufp.length,
|
---|
976 | GSS_KRB5_MECHANISM, &client));
|
---|
977 |
|
---|
978 | gss_release_buffer(&min_stat, &bufp);
|
---|
979 |
|
---|
980 | krb5_warnx(contextp, "%s connected", client);
|
---|
981 |
|
---|
982 | ret = kadm5_s_init_with_password_ctx(contextp,
|
---|
983 | client,
|
---|
984 | NULL,
|
---|
985 | KADM5_ADMIN_SERVICE,
|
---|
986 | &realm_params,
|
---|
987 | 0, 0,
|
---|
988 | &server_handle);
|
---|
989 | INSIST(ret == 0);
|
---|
990 | }
|
---|
991 |
|
---|
992 | INSIST(gctx.ctx != GSS_C_NO_CONTEXT);
|
---|
993 |
|
---|
994 | CHECK(krb5_store_uint32(dreply, 0));
|
---|
995 | CHECK(store_gss_init_res(dreply, gctx.handle,
|
---|
996 | maj_stat, min_stat, 1, &gout));
|
---|
997 | if (gout.value)
|
---|
998 | gss_release_buffer(&min_stat, &gout);
|
---|
999 | if (src_name)
|
---|
1000 | gss_release_name(&min_stat, &src_name);
|
---|
1001 |
|
---|
1002 | break;
|
---|
1003 | }
|
---|
1004 | case RPG_DESTROY:
|
---|
1005 | krb5_errx(contextp, 1, "client destroyed gss contextp");
|
---|
1006 | default:
|
---|
1007 | krb5_errx(contextp, 1, "client sent unknown gsscode %d",
|
---|
1008 | (int)gcred.proc);
|
---|
1009 | }
|
---|
1010 |
|
---|
1011 | krb5_data_free(&gcred.handle);
|
---|
1012 | krb5_data_free(&chdr.cred.data);
|
---|
1013 | krb5_data_free(&chdr.verf.data);
|
---|
1014 | krb5_data_free(&headercopy);
|
---|
1015 |
|
---|
1016 | CHECK(krb5_store_uint32(reply, chdr.xid));
|
---|
1017 | CHECK(krb5_store_uint32(reply, 1)); /* REPLY */
|
---|
1018 | CHECK(krb5_store_uint32(reply, 0)); /* MSG_ACCEPTED */
|
---|
1019 |
|
---|
1020 | if (!gctx.done) {
|
---|
1021 | krb5_data data;
|
---|
1022 |
|
---|
1023 | CHECK(krb5_store_uint32(reply, 0)); /* flavor_none */
|
---|
1024 | CHECK(krb5_store_uint32(reply, 0)); /* length */
|
---|
1025 |
|
---|
1026 | CHECK(krb5_store_uint32(reply, 0)); /* SUCCESS */
|
---|
1027 |
|
---|
1028 | CHECK(krb5_storage_to_data(dreply, &data));
|
---|
1029 | INSIST((size_t)krb5_storage_write(reply, data.data, data.length) == data.length);
|
---|
1030 | krb5_data_free(&data);
|
---|
1031 |
|
---|
1032 | } else {
|
---|
1033 | uint32_t seqnum = htonl(gctx.seq_num);
|
---|
1034 | krb5_data data;
|
---|
1035 |
|
---|
1036 | gin.value = &seqnum;
|
---|
1037 | gin.length = sizeof(seqnum);
|
---|
1038 |
|
---|
1039 | maj_stat = gss_get_mic(&min_stat, gctx.ctx, 0, &gin, &gout);
|
---|
1040 | INSIST(maj_stat == GSS_S_COMPLETE);
|
---|
1041 |
|
---|
1042 | data.data = gout.value;
|
---|
1043 | data.length = gout.length;
|
---|
1044 |
|
---|
1045 | CHECK(krb5_store_uint32(reply, FLAVOR_GSS));
|
---|
1046 | CHECK(store_data_xdr(reply, data));
|
---|
1047 | gss_release_buffer(&min_stat, &gout);
|
---|
1048 |
|
---|
1049 | CHECK(krb5_store_uint32(reply, 0)); /* SUCCESS */
|
---|
1050 |
|
---|
1051 | CHECK(krb5_storage_to_data(dreply, &data));
|
---|
1052 |
|
---|
1053 | if (gctx.inprogress) {
|
---|
1054 | ssize_t sret;
|
---|
1055 | gctx.inprogress = 0;
|
---|
1056 | sret = krb5_storage_write(reply, data.data, data.length);
|
---|
1057 | INSIST((size_t)sret == data.length);
|
---|
1058 | krb5_data_free(&data);
|
---|
1059 | } else {
|
---|
1060 | int conf_state;
|
---|
1061 |
|
---|
1062 | gin.value = data.data;
|
---|
1063 | gin.length = data.length;
|
---|
1064 |
|
---|
1065 | maj_stat = gss_wrap(&min_stat, gctx.ctx, 1, 0,
|
---|
1066 | &gin, &conf_state, &gout);
|
---|
1067 | INSIST(maj_stat == GSS_S_COMPLETE);
|
---|
1068 | INSIST(conf_state != 0);
|
---|
1069 | krb5_data_free(&data);
|
---|
1070 |
|
---|
1071 | data.data = gout.value;
|
---|
1072 | data.length = gout.length;
|
---|
1073 |
|
---|
1074 | store_data_xdr(reply, data);
|
---|
1075 | gss_release_buffer(&min_stat, &gout);
|
---|
1076 | }
|
---|
1077 | }
|
---|
1078 |
|
---|
1079 | {
|
---|
1080 | krb5_data data;
|
---|
1081 | ssize_t sret;
|
---|
1082 | CHECK(krb5_storage_to_data(reply, &data));
|
---|
1083 | CHECK(krb5_store_uint32(sp, data.length | LAST_FRAGMENT));
|
---|
1084 | sret = krb5_storage_write(sp, data.data, data.length);
|
---|
1085 | INSIST((size_t)sret == data.length);
|
---|
1086 | krb5_data_free(&data);
|
---|
1087 | }
|
---|
1088 |
|
---|
1089 | }
|
---|
1090 | }
|
---|
1091 |
|
---|
1092 |
|
---|
1093 | int
|
---|
1094 | handle_mit(krb5_context contextp, void *buf, size_t len, krb5_socket_t sock)
|
---|
1095 | {
|
---|
1096 | krb5_storage *sp;
|
---|
1097 |
|
---|
1098 | dcontext = contextp;
|
---|
1099 |
|
---|
1100 | sp = krb5_storage_from_fd(sock);
|
---|
1101 | INSIST(sp != NULL);
|
---|
1102 |
|
---|
1103 | process_stream(contextp, buf, len, sp);
|
---|
1104 |
|
---|
1105 | return 0;
|
---|
1106 | }
|
---|