drsuapi.idl: fix source_dsa spelling
[samba4-gss.git] / third_party / heimdal / kdc / process.c
blob91244cd16a38241b3fdb9bb3d393ee1ede0bfd65
1 /*
2 * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
35 #include "kdc_locl.h"
36 #include <vis.h>
42 #undef __attribute__
43 #define __attribute__(x)
45 KDC_LIB_FUNCTION void KDC_LIB_CALL
46 kdc_audit_vaddreason(kdc_request_t r, const char *fmt, va_list ap)
47 __attribute__ ((__format__ (__printf__, 2, 0)))
49 heim_audit_vaddreason((heim_svc_req_desc)r, fmt, ap);
52 KDC_LIB_FUNCTION void KDC_LIB_CALL
53 kdc_audit_addreason(kdc_request_t r, const char *fmt, ...)
54 __attribute__ ((__format__ (__printf__, 2, 3)))
56 va_list ap;
58 va_start(ap, fmt);
59 heim_audit_vaddreason((heim_svc_req_desc)r, fmt, ap);
60 va_end(ap);
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.
69 KDC_LIB_FUNCTION void KDC_LIB_CALL
70 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)))
74 heim_audit_vaddkv((heim_svc_req_desc)r, flags, k, fmt, ap);
77 KDC_LIB_FUNCTION void KDC_LIB_CALL
78 kdc_audit_addkv(kdc_request_t r, int flags, const char *k,
79 const char *fmt, ...)
80 __attribute__ ((__format__ (__printf__, 4, 5)))
82 va_list ap;
84 va_start(ap, fmt);
85 heim_audit_vaddkv((heim_svc_req_desc)r, flags, k, fmt, ap);
86 va_end(ap);
89 KDC_LIB_FUNCTION void KDC_LIB_CALL
90 kdc_audit_addkv_timediff(kdc_request_t r, const char *k,
91 const struct timeval *start,
92 const struct timeval *end)
94 heim_audit_addkv_timediff((heim_svc_req_desc)r,k, start, end);
97 KDC_LIB_FUNCTION void KDC_LIB_CALL
98 kdc_audit_setkv_bool(kdc_request_t r, const char *k, krb5_boolean v)
100 heim_audit_setkv_bool((heim_svc_req_desc)r, k, (int)v);
103 KDC_LIB_FUNCTION void KDC_LIB_CALL
104 kdc_audit_addkv_number(kdc_request_t r, const char *k, int64_t v)
106 heim_audit_addkv_number((heim_svc_req_desc)r, k, v);
109 KDC_LIB_FUNCTION void KDC_LIB_CALL
110 kdc_audit_setkv_number(kdc_request_t r, const char *k, int64_t v)
112 heim_audit_setkv_number((heim_svc_req_desc)r, k, v);
115 KDC_LIB_FUNCTION void KDC_LIB_CALL
116 kdc_audit_addkv_object(kdc_request_t r, const char *k, kdc_object_t obj)
118 heim_audit_addkv_object((heim_svc_req_desc)r, k, obj);
121 KDC_LIB_FUNCTION void KDC_LIB_CALL
122 kdc_audit_setkv_object(kdc_request_t r, const char *k, kdc_object_t obj)
124 heim_audit_setkv_object((heim_svc_req_desc)r, k, obj);
127 KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL
128 kdc_audit_getkv(kdc_request_t r, const char *k)
130 return heim_audit_getkv((heim_svc_req_desc)r, k);
134 * Add up to 3 key value pairs to record HostAddresses from request body or
135 * PA-TGS ticket or whatever.
137 KDC_LIB_FUNCTION void KDC_LIB_CALL
138 kdc_audit_addaddrs(kdc_request_t r, HostAddresses *a, const char *key)
140 size_t i;
141 char buf[128];
143 if (a->len > 3) {
144 char numkey[32];
146 if (snprintf(numkey, sizeof(numkey), "num%s", key) >= sizeof(numkey))
147 numkey[31] = '\0';
148 kdc_audit_addkv(r, 0, numkey, "%llu", (unsigned long long)a->len);
151 for (i = 0; i < 3 && i < a->len; i++) {
152 if (krb5_print_address(&a->val[i], buf, sizeof(buf), NULL) == 0)
153 kdc_audit_addkv(r, 0, key, "%s", buf);
157 KDC_LIB_FUNCTION void KDC_LIB_CALL
158 _kdc_audit_trail(kdc_request_t r, krb5_error_code ret)
160 const char *retname = NULL;
162 /* Get a symbolic name for some error codes */
163 #define CASE(x) case x : retname = #x; break
164 switch (ret ? ret : r->error_code) {
165 CASE(ENOMEM);
166 CASE(EACCES);
167 CASE(HDB_ERR_NOT_FOUND_HERE);
168 CASE(HDB_ERR_WRONG_REALM);
169 CASE(HDB_ERR_EXISTS);
170 CASE(HDB_ERR_KVNO_NOT_FOUND);
171 CASE(HDB_ERR_NOENTRY);
172 CASE(HDB_ERR_NO_MKEY);
173 CASE(KRB5KDC_ERR_BADOPTION);
174 CASE(KRB5KDC_ERR_CANNOT_POSTDATE);
175 CASE(KRB5KDC_ERR_CLIENT_NOTYET);
176 CASE(KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN);
177 CASE(KRB5KDC_ERR_ETYPE_NOSUPP);
178 CASE(KRB5KDC_ERR_KEY_EXPIRED);
179 CASE(KRB5KDC_ERR_NAME_EXP);
180 CASE(KRB5KDC_ERR_NEVER_VALID);
181 CASE(KRB5KDC_ERR_NONE);
182 CASE(KRB5KDC_ERR_NULL_KEY);
183 CASE(KRB5KDC_ERR_PADATA_TYPE_NOSUPP);
184 CASE(KRB5KDC_ERR_POLICY);
185 CASE(KRB5KDC_ERR_PREAUTH_FAILED);
186 CASE(KRB5KDC_ERR_PREAUTH_REQUIRED);
187 CASE(KRB5KDC_ERR_SERVER_NOMATCH);
188 CASE(KRB5KDC_ERR_SERVICE_EXP);
189 CASE(KRB5KDC_ERR_SERVICE_NOTYET);
190 CASE(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
191 CASE(KRB5KDC_ERR_TRTYPE_NOSUPP);
192 CASE(KRB5KRB_AP_ERR_BADADDR);
193 CASE(KRB5KRB_AP_ERR_BADDIRECTION);
194 CASE(KRB5KRB_AP_ERR_BAD_INTEGRITY);
195 CASE(KRB5KRB_AP_ERR_BADKEYVER);
196 CASE(KRB5KRB_AP_ERR_BADMATCH);
197 CASE(KRB5KRB_AP_ERR_BADORDER);
198 CASE(KRB5KRB_AP_ERR_BADSEQ);
199 CASE(KRB5KRB_AP_ERR_BADVERSION);
200 CASE(KRB5KRB_AP_ERR_ILL_CR_TKT);
201 CASE(KRB5KRB_AP_ERR_INAPP_CKSUM);
202 CASE(KRB5KRB_AP_ERR_METHOD);
203 CASE(KRB5KRB_AP_ERR_MODIFIED);
204 CASE(KRB5KRB_AP_ERR_MSG_TYPE);
205 CASE(KRB5KRB_AP_ERR_MUT_FAIL);
206 CASE(KRB5KRB_AP_ERR_NOKEY);
207 CASE(KRB5KRB_AP_ERR_NOT_US);
208 CASE(KRB5KRB_AP_ERR_REPEAT);
209 CASE(KRB5KRB_AP_ERR_SKEW);
210 CASE(KRB5KRB_AP_ERR_TKT_EXPIRED);
211 CASE(KRB5KRB_AP_ERR_TKT_INVALID);
212 CASE(KRB5KRB_AP_ERR_TKT_NYV);
213 CASE(KRB5KRB_AP_ERR_V4_REPLY);
214 CASE(KRB5KRB_AP_PATH_NOT_ACCEPTED);
215 CASE(KRB5KRB_AP_WRONG_PRINC);
216 CASE(KRB5KRB_ERR_FIELD_TOOLONG);
217 CASE(KRB5KRB_ERR_GENERIC);
218 CASE(KRB5KRB_ERR_RESPONSE_TOO_BIG);
220 case 0:
221 retname = "SUCCESS";
222 break;
223 default:
224 retname = NULL;
225 break;
228 /* Let's save a few bytes */
229 #define PREFIX "KRB5KDC_"
230 if (retname && strncmp(PREFIX, retname, strlen(PREFIX)) == 0)
231 retname += strlen(PREFIX);
232 #undef PREFIX
234 heim_audit_trail((heim_svc_req_desc)r, ret, retname);
237 KDC_LIB_FUNCTION void KDC_LIB_CALL
238 krb5_kdc_update_time(struct timeval *tv)
240 if (tv == NULL)
241 gettimeofday(&_kdc_now, NULL);
242 else
243 _kdc_now = *tv;
246 KDC_LIB_FUNCTION struct timeval KDC_LIB_CALL
247 krb5_kdc_get_time(void)
249 return _kdc_now;
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)
263 static krb5_error_code
264 kdc_as_req(kdc_request_t *rptr, int *claim)
266 astgs_request_t r;
267 krb5_error_code ret;
268 size_t len;
270 /* We must free things in the extensions */
271 EXTEND_REQUEST_T(*rptr, r);
273 ret = decode_AS_REQ(r->request.data, r->request.length, &r->req, &len);
274 if (ret)
275 return ret;
277 r->reqtype = "AS-REQ";
278 r->use_request_t = 1;
279 *claim = 1;
281 ret = _kdc_as_rep(r);
282 free_AS_REQ(&r->req);
283 return ret;
287 static krb5_error_code
288 kdc_tgs_req(kdc_request_t *rptr, int *claim)
290 astgs_request_t r;
291 krb5_error_code ret;
292 size_t len;
294 /* We must free things in the extensions */
295 EXTEND_REQUEST_T(*rptr, r);
297 ret = decode_TGS_REQ(r->request.data, r->request.length, &r->req, &len);
298 if (ret)
299 return ret;
301 r->reqtype = "TGS-REQ";
302 r->use_request_t = 1;
303 *claim = 1;
305 ret = _kdc_tgs_rep(r);
306 free_TGS_REQ(&r->req);
307 return ret;
310 #ifdef DIGEST
312 static krb5_error_code
313 kdc_digest(kdc_request_t *rptr, int *claim)
315 kdc_request_t r;
316 DigestREQ digestreq;
317 krb5_error_code ret;
318 size_t len;
320 r = *rptr;
322 ret = decode_DigestREQ(r->request.data, r->request.length,
323 &digestreq, &len);
324 if (ret)
325 return ret;
327 r->use_request_t = 0;
328 *claim = 1;
330 ret = _kdc_do_digest(r->context, r->config, &digestreq,
331 r->reply, r->from, r->addr);
332 free_DigestREQ(&digestreq);
333 return ret;
336 #endif
338 #ifdef KX509
340 static krb5_error_code
341 kdc_kx509(kdc_request_t *rptr, int *claim)
343 kx509_req_context r;
344 krb5_error_code ret;
346 /* We must free things in the extensions */
347 EXTEND_REQUEST_T(*rptr, r);
349 ret = _kdc_try_kx509_request(r);
350 if (ret)
351 return ret;
353 r->use_request_t = 1;
354 r->reqtype = "KX509";
355 *claim = 1;
357 return _kdc_do_kx509(r); /* Must clean up the req struct extensions */
360 #endif
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 }
375 static int
376 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)
387 kdc_request_t r;
388 krb5_error_code ret;
389 unsigned int i;
390 int claim = 0;
392 r = calloc(1, sizeof(*r));
393 if (!r)
394 return krb5_enomem(context);
396 r->context = context;
397 r->hcontext = context->hcontext;
398 r->config = config;
399 r->logf = config->logf;
400 r->from = from;
401 r->addr = addr;
402 r->request.data = buf;
403 r->request.length = len;
404 r->datagram_reply = datagram_reply;
405 r->reply = reply;
406 r->kv = heim_dict_create(10);
407 r->attributes = heim_dict_create(1);
408 if (r->kv == NULL || r->attributes == NULL) {
409 heim_release(r->kv);
410 heim_release(r->attributes);
411 free(r);
412 return krb5_enomem(context);
415 gettimeofday(&r->tv_start, NULL);
417 for (i = 0; services[i].process != NULL; i++) {
418 if (krb5_only && (services[i].flags & KS_KRB5) == 0)
419 continue;
420 kdc_log(context, config, 7, "Probing for %s", services[i].name);
421 ret = (*services[i].process)(&r, &claim);
422 if (claim) {
423 if (prependlength && services[i].flags & KS_NO_LENGTH)
424 *prependlength = 0;
426 if (r->use_request_t) {
427 gettimeofday(&r->tv_end, NULL);
428 _kdc_audit_trail(r, ret);
429 free(r->cname);
430 free(r->sname);
431 free(r->e_text_buf);
432 krb5_data_free(&r->e_data);
435 heim_release(r->reason);
436 heim_release(r->kv);
437 heim_release(r->attributes);
438 free(r);
439 return ret;
443 heim_release(r->reason);
444 heim_release(r->kv);
445 heim_release(r->attributes);
446 free(r);
447 return -1;
451 * handle the request in `buf, len', from `addr' (or `from' as a string),
452 * sending a reply in `reply'.
455 KDC_LIB_FUNCTION int KDC_LIB_CALL
456 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)
466 return process_request(context, config, 0, buf, len, reply, prependlength,
467 from, addr, datagram_reply);
471 * handle the request in `buf, len', from `addr' (or `from' as a string),
472 * sending a reply in `reply'.
474 * This only processes krb5 requests
477 KDC_LIB_FUNCTION int KDC_LIB_CALL
478 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)
487 return process_request(context, config, 1, buf, len, reply, NULL,
488 from, addr, datagram_reply);
496 KDC_LIB_FUNCTION int KDC_LIB_CALL
497 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)
504 krb5_storage *sp;
505 krb5_address a;
506 int fd = -1;
507 int ret = 0;
508 uint32_t t;
509 krb5_data d;
511 memset(&a, 0, sizeof(a));
513 d.data = rk_UNCONST(buf); /* do not free here */
514 d.length = len;
515 t = _kdc_now.tv_sec;
517 sp = krb5_storage_emem();
518 if (sp == NULL)
519 ret = krb5_enomem(context);
521 if (ret == 0)
522 ret = krb5_sockaddr2address(context, sa, &a);
523 if (ret == 0)
524 ret = krb5_store_uint32(sp, 1);
525 if (ret == 0)
526 ret = krb5_store_uint32(sp, t);
527 if (ret == 0)
528 ret = krb5_store_address(sp, a);
529 if (ret == 0)
530 ret = krb5_store_data(sp, d);
531 d.length = 0;
532 d.data = NULL;
533 if (ret == 0) {
534 Der_class cl;
535 Der_type ty;
536 unsigned int tag;
537 ret = der_get_tag (reply->data, reply->length,
538 &cl, &ty, &tag, NULL);
539 if (ret) {
540 ret = krb5_store_uint32(sp, 0xffffffff);
541 if (ret == 0)
542 ret = krb5_store_uint32(sp, 0xffffffff);
543 } else {
544 ret = krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0));
545 if (ret == 0)
546 ret = krb5_store_uint32(sp, tag);
550 if (ret == 0)
551 ret = krb5_storage_to_data(sp, &d);
552 krb5_storage_free(sp);
553 sp = NULL;
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.
560 if (ret == 0)
561 fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600);
562 if (fd < 0)
563 krb5_set_error_message(context, ret = errno, "Failed to open: %s", fn);
564 if (ret == 0) {
565 sp = krb5_storage_from_fd(fd);
566 if (sp == NULL)
567 krb5_set_error_message(context, ret = ENOMEM,
568 "Storage failed to open fd");
570 (void) close(fd);
571 if (ret == 0)
572 ret = krb5_store_data(sp, d);
573 krb5_free_address(context, &a);
575 * krb5_storage_free() currently always returns 0, but for FDs it sets
576 * errno to whatever close() set it to if it failed.
578 errno = 0;
579 if (ret == 0)
580 ret = krb5_storage_free(sp);
581 else
582 (void) krb5_storage_free(sp);
583 if (ret == 0 && errno)
584 ret = errno;
586 return ret;
589 KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL
590 kdc_request_set_attribute(kdc_request_t r, kdc_object_t key, kdc_object_t value)
592 return heim_dict_set_value(r->attributes, key, value);
595 KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL
596 kdc_request_get_attribute(kdc_request_t r, kdc_object_t key)
598 return heim_dict_get_value(r->attributes, key);
601 KDC_LIB_FUNCTION kdc_object_t KDC_LIB_CALL
602 kdc_request_copy_attribute(kdc_request_t r, kdc_object_t key)
604 return heim_dict_copy_value(r->attributes, key);
607 KDC_LIB_FUNCTION void KDC_LIB_CALL
608 kdc_request_delete_attribute(kdc_request_t r, kdc_object_t key)
610 heim_dict_delete_key(r->attributes, key);