Line data Source code
1 : /*
2 : * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : *
5 : * All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : *
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : *
14 : * 2. Redistributions in binary form must reproduce the above copyright
15 : * notice, this list of conditions and the following disclaimer in the
16 : * documentation and/or other materials provided with the distribution.
17 : *
18 : * 3. Neither the name of the Institute nor the names of its contributors
19 : * may be used to endorse or promote products derived from this software
20 : * without specific prior written permission.
21 : *
22 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 : * SUCH DAMAGE.
33 : */
34 :
35 : #include "kdc_locl.h"
36 : #include <vis.h>
37 :
38 : /*
39 : *
40 : */
41 :
42 : #undef __attribute__
43 : #define __attribute__(x)
44 :
45 : KDC_LIB_FUNCTION void KDC_LIB_CALL
46 0 : kdc_audit_vaddreason(kdc_request_t r, const char *fmt, va_list ap)
47 : __attribute__ ((__format__ (__printf__, 2, 0)))
48 : {
49 0 : heim_audit_vaddreason((heim_svc_req_desc)r, fmt, ap);
50 0 : }
51 :
52 : KDC_LIB_FUNCTION void KDC_LIB_CALL
53 1830 : kdc_audit_addreason(kdc_request_t r, const char *fmt, ...)
54 : __attribute__ ((__format__ (__printf__, 2, 3)))
55 : {
56 0 : va_list ap;
57 :
58 1830 : va_start(ap, fmt);
59 1830 : heim_audit_vaddreason((heim_svc_req_desc)r, fmt, ap);
60 1830 : va_end(ap);
61 1830 : }
62 :
63 : /*
64 : * append_token adds a token which is optionally a kv-pair and it
65 : * also optionally eats the whitespace. If k == NULL, then it's
66 : * not a kv-pair.
67 : */
68 :
69 : KDC_LIB_FUNCTION void KDC_LIB_CALL
70 0 : kdc_audit_vaddkv(kdc_request_t r, int flags, const char *k,
71 : const char *fmt, va_list ap)
72 : __attribute__ ((__format__ (__printf__, 4, 0)))
73 : {
74 0 : heim_audit_vaddkv((heim_svc_req_desc)r, flags, k, fmt, ap);
75 0 : }
76 :
77 : KDC_LIB_FUNCTION void KDC_LIB_CALL
78 434862 : kdc_audit_addkv(kdc_request_t r, int flags, const char *k,
79 : const char *fmt, ...)
80 : __attribute__ ((__format__ (__printf__, 4, 5)))
81 : {
82 15895 : va_list ap;
83 :
84 434862 : va_start(ap, fmt);
85 434862 : heim_audit_vaddkv((heim_svc_req_desc)r, flags, k, fmt, ap);
86 434862 : va_end(ap);
87 434862 : }
88 :
89 : KDC_LIB_FUNCTION void KDC_LIB_CALL
90 0 : kdc_audit_addkv_timediff(kdc_request_t r, const char *k,
91 : const struct timeval *start,
92 : const struct timeval *end)
93 : {
94 0 : heim_audit_addkv_timediff((heim_svc_req_desc)r,k, start, end);
95 0 : }
96 :
97 : KDC_LIB_FUNCTION void KDC_LIB_CALL
98 0 : kdc_audit_setkv_bool(kdc_request_t r, const char *k, krb5_boolean v)
99 : {
100 0 : heim_audit_setkv_bool((heim_svc_req_desc)r, k, (int)v);
101 0 : }
102 :
103 : KDC_LIB_FUNCTION void KDC_LIB_CALL
104 0 : kdc_audit_addkv_number(kdc_request_t r, const char *k, int64_t v)
105 : {
106 0 : heim_audit_addkv_number((heim_svc_req_desc)r, k, v);
107 0 : }
108 :
109 : KDC_LIB_FUNCTION void KDC_LIB_CALL
110 467180 : kdc_audit_setkv_number(kdc_request_t r, const char *k, int64_t v)
111 : {
112 467180 : heim_audit_setkv_number((heim_svc_req_desc)r, k, v);
113 467180 : }
114 :
115 : KDC_LIB_FUNCTION void KDC_LIB_CALL
116 0 : kdc_audit_addkv_object(kdc_request_t r, const char *k, kdc_object_t obj)
117 : {
118 0 : heim_audit_addkv_object((heim_svc_req_desc)r, k, obj);
119 0 : }
120 :
121 : KDC_LIB_FUNCTION void KDC_LIB_CALL
122 0 : kdc_audit_setkv_object(kdc_request_t r, const char *k, kdc_object_t obj)
123 : {
124 0 : heim_audit_setkv_object((heim_svc_req_desc)r, k, obj);
125 0 : }
126 :
127 : KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL
128 30739 : kdc_audit_getkv(kdc_request_t r, const char *k)
129 : {
130 30739 : return heim_audit_getkv((heim_svc_req_desc)r, k);
131 : }
132 :
133 : /*
134 : * Add up to 3 key value pairs to record HostAddresses from request body or
135 : * PA-TGS ticket or whatever.
136 : */
137 : KDC_LIB_FUNCTION void KDC_LIB_CALL
138 417 : kdc_audit_addaddrs(kdc_request_t r, HostAddresses *a, const char *key)
139 : {
140 0 : size_t i;
141 0 : char buf[128];
142 :
143 417 : if (a->len > 3) {
144 0 : char numkey[32];
145 :
146 0 : if (snprintf(numkey, sizeof(numkey), "num%s", key) >= sizeof(numkey))
147 0 : numkey[31] = '\0';
148 0 : kdc_audit_addkv(r, 0, numkey, "%llu", (unsigned long long)a->len);
149 : }
150 :
151 535 : for (i = 0; i < 3 && i < a->len; i++) {
152 118 : if (krb5_print_address(&a->val[i], buf, sizeof(buf), NULL) == 0)
153 118 : kdc_audit_addkv(r, 0, key, "%s", buf);
154 : }
155 417 : }
156 :
157 : KDC_LIB_FUNCTION void KDC_LIB_CALL
158 104689 : _kdc_audit_trail(kdc_request_t r, krb5_error_code ret)
159 : {
160 104689 : const char *retname = NULL;
161 :
162 : /* Get a symbolic name for some error codes */
163 : #define CASE(x) case x : retname = #x; break
164 104689 : switch (ret ? ret : r->error_code) {
165 0 : CASE(ENOMEM);
166 0 : CASE(EACCES);
167 3040 : CASE(HDB_ERR_NOT_FOUND_HERE);
168 0 : CASE(HDB_ERR_WRONG_REALM);
169 0 : CASE(HDB_ERR_EXISTS);
170 0 : CASE(HDB_ERR_KVNO_NOT_FOUND);
171 0 : CASE(HDB_ERR_NOENTRY);
172 0 : CASE(HDB_ERR_NO_MKEY);
173 44 : CASE(KRB5KDC_ERR_BADOPTION);
174 0 : CASE(KRB5KDC_ERR_CANNOT_POSTDATE);
175 0 : CASE(KRB5KDC_ERR_CLIENT_NOTYET);
176 454 : CASE(KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN);
177 565 : CASE(KRB5KDC_ERR_ETYPE_NOSUPP);
178 5 : CASE(KRB5KDC_ERR_KEY_EXPIRED);
179 0 : CASE(KRB5KDC_ERR_NAME_EXP);
180 1 : CASE(KRB5KDC_ERR_NEVER_VALID);
181 0 : CASE(KRB5KDC_ERR_NONE);
182 0 : CASE(KRB5KDC_ERR_NULL_KEY);
183 0 : CASE(KRB5KDC_ERR_PADATA_TYPE_NOSUPP);
184 337 : CASE(KRB5KDC_ERR_POLICY);
185 382 : CASE(KRB5KDC_ERR_PREAUTH_FAILED);
186 18177 : CASE(KRB5KDC_ERR_PREAUTH_REQUIRED);
187 0 : CASE(KRB5KDC_ERR_SERVER_NOMATCH);
188 0 : CASE(KRB5KDC_ERR_SERVICE_EXP);
189 0 : CASE(KRB5KDC_ERR_SERVICE_NOTYET);
190 1259 : CASE(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
191 0 : CASE(KRB5KDC_ERR_TRTYPE_NOSUPP);
192 0 : CASE(KRB5KRB_AP_ERR_BADADDR);
193 0 : CASE(KRB5KRB_AP_ERR_BADDIRECTION);
194 20 : CASE(KRB5KRB_AP_ERR_BAD_INTEGRITY);
195 4 : CASE(KRB5KRB_AP_ERR_BADKEYVER);
196 5 : CASE(KRB5KRB_AP_ERR_BADMATCH);
197 0 : CASE(KRB5KRB_AP_ERR_BADORDER);
198 0 : CASE(KRB5KRB_AP_ERR_BADSEQ);
199 0 : CASE(KRB5KRB_AP_ERR_BADVERSION);
200 0 : CASE(KRB5KRB_AP_ERR_ILL_CR_TKT);
201 28 : CASE(KRB5KRB_AP_ERR_INAPP_CKSUM);
202 0 : CASE(KRB5KRB_AP_ERR_METHOD);
203 7 : CASE(KRB5KRB_AP_ERR_MODIFIED);
204 0 : CASE(KRB5KRB_AP_ERR_MSG_TYPE);
205 0 : CASE(KRB5KRB_AP_ERR_MUT_FAIL);
206 0 : CASE(KRB5KRB_AP_ERR_NOKEY);
207 0 : CASE(KRB5KRB_AP_ERR_NOT_US);
208 0 : CASE(KRB5KRB_AP_ERR_REPEAT);
209 10 : CASE(KRB5KRB_AP_ERR_SKEW);
210 8 : CASE(KRB5KRB_AP_ERR_TKT_EXPIRED);
211 0 : CASE(KRB5KRB_AP_ERR_TKT_INVALID);
212 4 : CASE(KRB5KRB_AP_ERR_TKT_NYV);
213 0 : CASE(KRB5KRB_AP_ERR_V4_REPLY);
214 0 : CASE(KRB5KRB_AP_PATH_NOT_ACCEPTED);
215 0 : CASE(KRB5KRB_AP_WRONG_PRINC);
216 0 : CASE(KRB5KRB_ERR_FIELD_TOOLONG);
217 18 : CASE(KRB5KRB_ERR_GENERIC);
218 12558 : CASE(KRB5KRB_ERR_RESPONSE_TOO_BIG);
219 :
220 67040 : case 0:
221 67040 : retname = "SUCCESS";
222 67040 : break;
223 723 : default:
224 723 : retname = NULL;
225 723 : break;
226 : }
227 :
228 : /* Let's save a few bytes */
229 : #define PREFIX "KRB5KDC_"
230 104689 : if (retname && strncmp(PREFIX, retname, strlen(PREFIX)) == 0)
231 21224 : retname += strlen(PREFIX);
232 : #undef PREFIX
233 :
234 104689 : heim_audit_trail((heim_svc_req_desc)r, ret, retname);
235 104689 : }
236 :
237 : KDC_LIB_FUNCTION void KDC_LIB_CALL
238 104689 : krb5_kdc_update_time(struct timeval *tv)
239 : {
240 104689 : if (tv == NULL)
241 104689 : gettimeofday(&_kdc_now, NULL);
242 : else
243 0 : _kdc_now = *tv;
244 104689 : }
245 :
246 : KDC_LIB_FUNCTION struct timeval KDC_LIB_CALL
247 102844 : krb5_kdc_get_time(void)
248 : {
249 102844 : return _kdc_now;
250 : }
251 :
252 :
253 : #define EXTEND_REQUEST_T(LHS, RHS) do { \
254 : RHS = realloc(LHS, sizeof(*RHS)); \
255 : if (!RHS) \
256 : return krb5_enomem((LHS)->context); \
257 : LHS = (void *)RHS; \
258 : memset(((char *)LHS) + sizeof(*LHS), \
259 : 0x0, \
260 : sizeof(*RHS) - sizeof(*LHS)); \
261 : } while (0)
262 :
263 : static krb5_error_code
264 104689 : kdc_as_req(kdc_request_t *rptr, int *claim)
265 : {
266 3413 : astgs_request_t r;
267 3413 : krb5_error_code ret;
268 3413 : size_t len;
269 :
270 : /* We must free things in the extensions */
271 104689 : EXTEND_REQUEST_T(*rptr, r);
272 :
273 104689 : ret = decode_AS_REQ(r->request.data, r->request.length, &r->req, &len);
274 104689 : if (ret)
275 50871 : return ret;
276 :
277 52160 : r->reqtype = "AS-REQ";
278 52160 : r->use_request_t = 1;
279 52160 : *claim = 1;
280 :
281 52160 : ret = _kdc_as_rep(r);
282 52160 : free_AS_REQ(&r->req);
283 52160 : return ret;
284 : }
285 :
286 :
287 : static krb5_error_code
288 52529 : kdc_tgs_req(kdc_request_t *rptr, int *claim)
289 : {
290 1658 : astgs_request_t r;
291 1658 : krb5_error_code ret;
292 1658 : size_t len;
293 :
294 : /* We must free things in the extensions */
295 52529 : EXTEND_REQUEST_T(*rptr, r);
296 :
297 52529 : ret = decode_TGS_REQ(r->request.data, r->request.length, &r->req, &len);
298 52529 : if (ret)
299 0 : return ret;
300 :
301 52529 : r->reqtype = "TGS-REQ";
302 52529 : r->use_request_t = 1;
303 52529 : *claim = 1;
304 :
305 52529 : ret = _kdc_tgs_rep(r);
306 52529 : free_TGS_REQ(&r->req);
307 52529 : return ret;
308 : }
309 :
310 : #ifdef DIGEST
311 :
312 : static krb5_error_code
313 : kdc_digest(kdc_request_t *rptr, int *claim)
314 : {
315 : kdc_request_t r;
316 : DigestREQ digestreq;
317 : krb5_error_code ret;
318 : size_t len;
319 :
320 : r = *rptr;
321 :
322 : ret = decode_DigestREQ(r->request.data, r->request.length,
323 : &digestreq, &len);
324 : if (ret)
325 : return ret;
326 :
327 : r->use_request_t = 0;
328 : *claim = 1;
329 :
330 : ret = _kdc_do_digest(r->context, r->config, &digestreq,
331 : r->reply, r->from, r->addr);
332 : free_DigestREQ(&digestreq);
333 : return ret;
334 : }
335 :
336 : #endif
337 :
338 : #ifdef KX509
339 :
340 : static krb5_error_code
341 : kdc_kx509(kdc_request_t *rptr, int *claim)
342 : {
343 : kx509_req_context r;
344 : krb5_error_code ret;
345 :
346 : /* We must free things in the extensions */
347 : EXTEND_REQUEST_T(*rptr, r);
348 :
349 : ret = _kdc_try_kx509_request(r);
350 : if (ret)
351 : return ret;
352 :
353 : r->use_request_t = 1;
354 : r->reqtype = "KX509";
355 : *claim = 1;
356 :
357 : return _kdc_do_kx509(r); /* Must clean up the req struct extensions */
358 : }
359 :
360 : #endif
361 :
362 :
363 : static struct krb5_kdc_service services[] = {
364 : { KS_KRB5, "AS-REQ", kdc_as_req },
365 : { KS_KRB5, "TGS-REQ", kdc_tgs_req },
366 : #ifdef DIGEST
367 : { 0, "DIGEST", kdc_digest },
368 : #endif
369 : #ifdef KX509
370 : { 0, "KX509", kdc_kx509 },
371 : #endif
372 : { 0, NULL, NULL }
373 : };
374 :
375 : static int
376 104689 : process_request(krb5_context context,
377 : krb5_kdc_configuration *config,
378 : unsigned int krb5_only,
379 : unsigned char *buf,
380 : size_t len,
381 : krb5_data *reply,
382 : krb5_boolean *prependlength,
383 : const char *from,
384 : struct sockaddr *addr,
385 : int datagram_reply)
386 : {
387 3413 : kdc_request_t r;
388 3413 : krb5_error_code ret;
389 3413 : unsigned int i;
390 104689 : int claim = 0;
391 :
392 104689 : r = calloc(sizeof(*r), 1);
393 104689 : if (!r)
394 0 : return krb5_enomem(context);
395 :
396 104689 : r->context = context;
397 104689 : r->hcontext = context->hcontext;
398 104689 : r->config = config;
399 104689 : r->logf = config->logf;
400 104689 : r->from = from;
401 104689 : r->addr = addr;
402 104689 : r->request.data = buf;
403 104689 : r->request.length = len;
404 104689 : r->datagram_reply = datagram_reply;
405 104689 : r->reply = reply;
406 104689 : r->kv = heim_dict_create(10);
407 104689 : r->attributes = heim_dict_create(1);
408 104689 : if (r->kv == NULL || r->attributes == NULL) {
409 0 : heim_release(r->kv);
410 0 : heim_release(r->attributes);
411 0 : free(r);
412 0 : return krb5_enomem(context);
413 : }
414 :
415 104689 : gettimeofday(&r->tv_start, NULL);
416 :
417 160631 : for (i = 0; services[i].process != NULL; i++) {
418 157218 : if (krb5_only && (services[i].flags & KS_KRB5) == 0)
419 0 : continue;
420 157218 : kdc_log(context, config, 7, "Probing for %s", services[i].name);
421 157218 : ret = (*services[i].process)(&r, &claim);
422 157218 : if (claim) {
423 104689 : if (prependlength && services[i].flags & KS_NO_LENGTH)
424 0 : *prependlength = 0;
425 :
426 104689 : if (r->use_request_t) {
427 104689 : gettimeofday(&r->tv_end, NULL);
428 104689 : _kdc_audit_trail(r, ret);
429 104689 : free(r->cname);
430 104689 : free(r->sname);
431 104689 : free(r->e_text_buf);
432 104689 : krb5_data_free(&r->e_data);
433 : }
434 :
435 104689 : heim_release(r->reason);
436 104689 : heim_release(r->kv);
437 104689 : heim_release(r->attributes);
438 104689 : free(r);
439 104689 : return ret;
440 : }
441 : }
442 :
443 0 : heim_release(r->reason);
444 0 : heim_release(r->kv);
445 0 : heim_release(r->attributes);
446 0 : free(r);
447 0 : return -1;
448 : }
449 :
450 : /*
451 : * handle the request in `buf, len', from `addr' (or `from' as a string),
452 : * sending a reply in `reply'.
453 : */
454 :
455 : KDC_LIB_FUNCTION int KDC_LIB_CALL
456 0 : krb5_kdc_process_request(krb5_context context,
457 : krb5_kdc_configuration *config,
458 : unsigned char *buf,
459 : size_t len,
460 : krb5_data *reply,
461 : krb5_boolean *prependlength,
462 : const char *from,
463 : struct sockaddr *addr,
464 : int datagram_reply)
465 : {
466 0 : return process_request(context, config, 0, buf, len, reply, prependlength,
467 : from, addr, datagram_reply);
468 : }
469 :
470 : /*
471 : * handle the request in `buf, len', from `addr' (or `from' as a string),
472 : * sending a reply in `reply'.
473 : *
474 : * This only processes krb5 requests
475 : */
476 :
477 : KDC_LIB_FUNCTION int KDC_LIB_CALL
478 104689 : krb5_kdc_process_krb5_request(krb5_context context,
479 : krb5_kdc_configuration *config,
480 : unsigned char *buf,
481 : size_t len,
482 : krb5_data *reply,
483 : const char *from,
484 : struct sockaddr *addr,
485 : int datagram_reply)
486 : {
487 104689 : return process_request(context, config, 1, buf, len, reply, NULL,
488 : from, addr, datagram_reply);
489 : }
490 :
491 :
492 : /*
493 : *
494 : */
495 :
496 : KDC_LIB_FUNCTION int KDC_LIB_CALL
497 0 : krb5_kdc_save_request(krb5_context context,
498 : const char *fn,
499 : const unsigned char *buf,
500 : size_t len,
501 : const krb5_data *reply,
502 : const struct sockaddr *sa)
503 : {
504 0 : krb5_storage *sp;
505 0 : krb5_address a;
506 0 : int fd = -1;
507 0 : int ret = 0;
508 0 : uint32_t t;
509 0 : krb5_data d;
510 :
511 0 : memset(&a, 0, sizeof(a));
512 :
513 0 : d.data = rk_UNCONST(buf); /* do not free here */
514 0 : d.length = len;
515 0 : t = _kdc_now.tv_sec;
516 :
517 0 : sp = krb5_storage_emem();
518 0 : if (sp == NULL)
519 0 : ret = krb5_enomem(context);
520 :
521 0 : if (ret == 0)
522 0 : ret = krb5_sockaddr2address(context, sa, &a);
523 0 : if (ret == 0)
524 0 : ret = krb5_store_uint32(sp, 1);
525 0 : if (ret == 0)
526 0 : ret = krb5_store_uint32(sp, t);
527 0 : if (ret == 0)
528 0 : ret = krb5_store_address(sp, a);
529 0 : if (ret == 0)
530 0 : ret = krb5_store_data(sp, d);
531 0 : d.length = 0;
532 0 : d.data = NULL;
533 0 : if (ret == 0) {
534 0 : Der_class cl;
535 0 : Der_type ty;
536 0 : unsigned int tag;
537 0 : ret = der_get_tag (reply->data, reply->length,
538 : &cl, &ty, &tag, NULL);
539 0 : if (ret) {
540 0 : ret = krb5_store_uint32(sp, 0xffffffff);
541 0 : if (ret == 0)
542 0 : ret = krb5_store_uint32(sp, 0xffffffff);
543 : } else {
544 0 : ret = krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0));
545 0 : if (ret == 0)
546 0 : ret = krb5_store_uint32(sp, tag);
547 : }
548 : }
549 :
550 0 : if (ret == 0)
551 0 : ret = krb5_storage_to_data(sp, &d);
552 0 : krb5_storage_free(sp);
553 0 : sp = NULL;
554 :
555 : /*
556 : * We've got KDC concurrency, so we're going to try to do a single O_APPEND
557 : * write(2). Hopefully we manage to write enough of the header that one
558 : * can skip this request if it fails to write completely.
559 : */
560 0 : if (ret == 0)
561 0 : fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600);
562 0 : if (fd < 0)
563 0 : krb5_set_error_message(context, ret = errno, "Failed to open: %s", fn);
564 0 : if (ret == 0) {
565 0 : sp = krb5_storage_from_fd(fd);
566 0 : if (sp == NULL)
567 0 : krb5_set_error_message(context, ret = ENOMEM,
568 : "Storage failed to open fd");
569 : }
570 0 : (void) close(fd);
571 0 : if (ret == 0)
572 0 : ret = krb5_store_data(sp, d);
573 0 : krb5_free_address(context, &a);
574 : /*
575 : * krb5_storage_free() currently always returns 0, but for FDs it sets
576 : * errno to whatever close() set it to if it failed.
577 : */
578 0 : errno = 0;
579 0 : if (ret == 0)
580 0 : ret = krb5_storage_free(sp);
581 : else
582 0 : (void) krb5_storage_free(sp);
583 0 : if (ret == 0 && errno)
584 0 : ret = errno;
585 :
586 0 : return ret;
587 : }
588 :
589 : KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL
590 0 : kdc_request_set_attribute(kdc_request_t r, kdc_object_t key, kdc_object_t value)
591 : {
592 0 : return heim_dict_set_value(r->attributes, key, value);
593 : }
594 :
595 : KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL
596 0 : kdc_request_get_attribute(kdc_request_t r, kdc_object_t key)
597 : {
598 0 : return heim_dict_get_value(r->attributes, key);
599 : }
600 :
601 : KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL
602 0 : kdc_request_copy_attribute(kdc_request_t r, kdc_object_t key)
603 : {
604 0 : return heim_dict_copy_value(r->attributes, key);
605 : }
606 :
607 : KDC_LIB_FUNCTION void KDC_LIB_CALL
608 0 : kdc_request_delete_attribute(kdc_request_t r, kdc_object_t key)
609 : {
610 0 : heim_dict_delete_key(r->attributes, key);
611 0 : }
|