lib/krb5: krb5_sento_context KRB5_SENDTO_DONE KRB5_SENDTO_FAILED
[heimdal.git] / kdc / process.c
blob6293712f81ab33307909136c0827456a04224caf
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, heim_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, heim_object_t obj)
124 heim_audit_setkv_object((heim_svc_req_desc)r, k, obj);
127 KDC_LIB_FUNCTION heim_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->ret) {
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_ERR_RESPONSE_TOO_BIG);
193 case 0:
194 retname = "SUCCESS";
195 break;
196 default:
197 retname = NULL;
198 break;
201 /* Let's save a few bytes */
202 #define PREFIX "KRB5KDC_"
203 if (retname && strncmp(PREFIX, retname, strlen(PREFIX)) == 0)
204 retname += strlen(PREFIX);
205 #undef PREFIX
207 heim_audit_trail((heim_svc_req_desc)r, ret, retname);
210 KDC_LIB_FUNCTION void KDC_LIB_CALL
211 krb5_kdc_update_time(struct timeval *tv)
213 if (tv == NULL)
214 gettimeofday(&_kdc_now, NULL);
215 else
216 _kdc_now = *tv;
220 #define EXTEND_REQUEST_T(LHS, RHS) do { \
221 RHS = realloc(LHS, sizeof(*RHS)); \
222 if (!RHS) \
223 return krb5_enomem((LHS)->context); \
224 LHS = (void *)RHS; \
225 memset(((char *)LHS) + sizeof(*LHS), \
226 0x0, \
227 sizeof(*RHS) - sizeof(*LHS)); \
228 } while (0)
230 static krb5_error_code
231 kdc_as_req(kdc_request_t *rptr, int *claim)
233 astgs_request_t r;
234 krb5_error_code ret;
235 size_t len;
237 /* We must free things in the extensions */
238 EXTEND_REQUEST_T(*rptr, r);
240 ret = decode_AS_REQ(r->request.data, r->request.length, &r->req, &len);
241 if (ret)
242 return ret;
244 r->reqtype = "AS-REQ";
245 r->use_request_t = 1;
246 *claim = 1;
248 ret = _kdc_as_rep(r);
249 free_AS_REQ(&r->req);
250 return ret;
254 static krb5_error_code
255 kdc_tgs_req(kdc_request_t *rptr, int *claim)
257 astgs_request_t r;
258 krb5_error_code ret;
259 size_t len;
261 /* We must free things in the extensions */
262 EXTEND_REQUEST_T(*rptr, r);
264 ret = decode_TGS_REQ(r->request.data, r->request.length, &r->req, &len);
265 if (ret)
266 return ret;
268 r->reqtype = "TGS-REQ";
269 r->use_request_t = 1;
270 *claim = 1;
272 ret = _kdc_tgs_rep(r);
273 free_TGS_REQ(&r->req);
274 return ret;
277 #ifdef DIGEST
279 static krb5_error_code
280 kdc_digest(kdc_request_t *rptr, int *claim)
282 kdc_request_t r;
283 DigestREQ digestreq;
284 krb5_error_code ret;
285 size_t len;
287 r = *rptr;
289 ret = decode_DigestREQ(r->request.data, r->request.length,
290 &digestreq, &len);
291 if (ret)
292 return ret;
294 r->use_request_t = 0;
295 *claim = 1;
297 ret = _kdc_do_digest(r->context, r->config, &digestreq,
298 r->reply, r->from, r->addr);
299 free_DigestREQ(&digestreq);
300 return ret;
303 #endif
305 #ifdef KX509
307 static krb5_error_code
308 kdc_kx509(kdc_request_t *rptr, int *claim)
310 kx509_req_context r;
311 krb5_error_code ret;
313 /* We must free things in the extensions */
314 EXTEND_REQUEST_T(*rptr, r);
316 ret = _kdc_try_kx509_request(r);
317 if (ret)
318 return ret;
320 r->use_request_t = 1;
321 r->reqtype = "KX509";
322 *claim = 1;
324 return _kdc_do_kx509(r); /* Must clean up the req struct extensions */
327 #endif
330 static struct krb5_kdc_service services[] = {
331 { KS_KRB5, "AS-REQ", kdc_as_req },
332 { KS_KRB5, "TGS-REQ", kdc_tgs_req },
333 #ifdef DIGEST
334 { 0, "DIGEST", kdc_digest },
335 #endif
336 #ifdef KX509
337 { 0, "KX509", kdc_kx509 },
338 #endif
339 { 0, NULL, NULL }
342 static int
343 process_request(krb5_context context,
344 krb5_kdc_configuration *config,
345 unsigned int krb5_only,
346 unsigned char *buf,
347 size_t len,
348 krb5_data *reply,
349 krb5_boolean *prependlength,
350 const char *from,
351 struct sockaddr *addr,
352 int datagram_reply)
354 kdc_request_t r;
355 krb5_error_code ret;
356 unsigned int i;
357 int claim = 0;
359 r = calloc(sizeof(*r), 1);
360 if (!r)
361 return krb5_enomem(context);
363 r->context = context;
364 r->hcontext = context->hcontext;
365 r->config = config;
366 r->logf = config->logf;
367 r->from = from;
368 r->addr = addr;
369 r->request.data = buf;
370 r->request.length = len;
371 r->datagram_reply = datagram_reply;
372 r->reply = reply;
373 r->kv = heim_dict_create(10);
374 r->attributes = heim_dict_create(1);
375 if (r->kv == NULL || r->attributes == NULL) {
376 heim_release(r->kv);
377 heim_release(r->attributes);
378 free(r);
379 return krb5_enomem(context);
382 gettimeofday(&r->tv_start, NULL);
384 for (i = 0; services[i].process != NULL; i++) {
385 if (krb5_only && (services[i].flags & KS_KRB5) == 0)
386 continue;
387 kdc_log(context, config, 7, "Probing for %s", services[i].name);
388 ret = (*services[i].process)(&r, &claim);
389 if (claim) {
390 if (prependlength && services[i].flags & KS_NO_LENGTH)
391 *prependlength = 0;
393 if (r->use_request_t) {
394 gettimeofday(&r->tv_end, NULL);
395 _kdc_audit_trail(r, ret);
396 free(r->cname);
397 free(r->sname);
398 free(r->e_text_buf);
401 heim_release(r->reason);
402 heim_release(r->kv);
403 heim_release(r->attributes);
404 free(r);
405 return ret;
409 heim_release(r->reason);
410 heim_release(r->kv);
411 heim_release(r->attributes);
412 free(r);
413 return -1;
417 * handle the request in `buf, len', from `addr' (or `from' as a string),
418 * sending a reply in `reply'.
421 KDC_LIB_FUNCTION int KDC_LIB_CALL
422 krb5_kdc_process_request(krb5_context context,
423 krb5_kdc_configuration *config,
424 unsigned char *buf,
425 size_t len,
426 krb5_data *reply,
427 krb5_boolean *prependlength,
428 const char *from,
429 struct sockaddr *addr,
430 int datagram_reply)
432 return process_request(context, config, 0, buf, len, reply, prependlength,
433 from, addr, datagram_reply);
437 * handle the request in `buf, len', from `addr' (or `from' as a string),
438 * sending a reply in `reply'.
440 * This only processes krb5 requests
443 KDC_LIB_FUNCTION int KDC_LIB_CALL
444 krb5_kdc_process_krb5_request(krb5_context context,
445 krb5_kdc_configuration *config,
446 unsigned char *buf,
447 size_t len,
448 krb5_data *reply,
449 const char *from,
450 struct sockaddr *addr,
451 int datagram_reply)
453 return process_request(context, config, 1, buf, len, reply, NULL,
454 from, addr, datagram_reply);
462 KDC_LIB_FUNCTION int KDC_LIB_CALL
463 krb5_kdc_save_request(krb5_context context,
464 const char *fn,
465 const unsigned char *buf,
466 size_t len,
467 const krb5_data *reply,
468 const struct sockaddr *sa)
470 krb5_storage *sp;
471 krb5_address a;
472 int fd, ret;
473 uint32_t t;
474 krb5_data d;
476 memset(&a, 0, sizeof(a));
478 d.data = rk_UNCONST(buf);
479 d.length = len;
480 t = _kdc_now.tv_sec;
482 fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600);
483 if (fd < 0) {
484 int saved_errno = errno;
485 krb5_set_error_message(context, saved_errno, "Failed to open: %s", fn);
486 return saved_errno;
489 sp = krb5_storage_from_fd(fd);
490 close(fd);
491 if (sp == NULL) {
492 krb5_set_error_message(context, ENOMEM, "Storage failed to open fd");
493 return ENOMEM;
496 ret = krb5_sockaddr2address(context, sa, &a);
497 if (ret)
498 goto out;
500 krb5_store_uint32(sp, 1);
501 krb5_store_uint32(sp, t);
502 krb5_store_address(sp, a);
503 krb5_store_data(sp, d);
505 Der_class cl;
506 Der_type ty;
507 unsigned int tag;
508 ret = der_get_tag (reply->data, reply->length,
509 &cl, &ty, &tag, NULL);
510 if (ret) {
511 krb5_store_uint32(sp, 0xffffffff);
512 krb5_store_uint32(sp, 0xffffffff);
513 } else {
514 krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0));
515 krb5_store_uint32(sp, tag);
519 krb5_free_address(context, &a);
520 out:
521 krb5_storage_free(sp);
523 return 0;
526 KDC_LIB_FUNCTION krb5_error_code KDC_LIB_CALL
527 krb5_kdc_request_set_attribute(kdc_request_t r, heim_object_t key, heim_object_t value)
529 return heim_dict_set_value(r->attributes, key, value);
532 KDC_LIB_FUNCTION heim_object_t KDC_LIB_CALL
533 krb5_kdc_request_get_attribute(kdc_request_t r, heim_object_t key)
535 return heim_dict_get_value(r->attributes, key);
538 KDC_LIB_FUNCTION heim_object_t KDC_LIB_CALL
539 krb5_kdc_request_copy_attribute(kdc_request_t r, heim_object_t key)
541 return heim_dict_copy_value(r->attributes, key);
544 KDC_LIB_FUNCTION void KDC_LIB_CALL
545 krb5_kdc_request_delete_attribute(kdc_request_t r, heim_object_t key)
547 heim_dict_delete_key(r->attributes, key);