hx509: For times before 2050 use UTCTime (fix pasto)
[heimdal.git] / kdc / process.c
bloba0f51f27874b0316d5c7f6180c4f64fa215aad74
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 void
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 void
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 void
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 void
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 void
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);
98 * Add up to 3 key value pairs to record HostAddresses from request body or
99 * PA-TGS ticket or whatever.
101 void
102 _kdc_audit_addaddrs(kdc_request_t r, HostAddresses *a, const char *key)
104 size_t i;
105 char buf[128];
107 if (a->len > 3) {
108 char numkey[32];
110 if (snprintf(numkey, sizeof(numkey), "num%s", key) >= sizeof(numkey))
111 numkey[31] = '\0';
112 _kdc_audit_addkv(r, 0, numkey, "%llu", (unsigned long long)a->len);
115 for (i = 0; i < 3 && i < a->len; i++) {
116 if (krb5_print_address(&a->val[i], buf, sizeof(buf), NULL) == 0)
117 _kdc_audit_addkv(r, 0, key, "%s", buf);
121 void
122 _kdc_audit_trail(kdc_request_t r, krb5_error_code ret)
124 const char *retname = NULL;
126 /* Get a symbolic name for some error codes */
127 #define CASE(x) case x : retname = #x; break
128 switch (ret) {
129 CASE(ENOMEM);
130 CASE(EACCES);
131 CASE(HDB_ERR_NOT_FOUND_HERE);
132 CASE(HDB_ERR_WRONG_REALM);
133 CASE(HDB_ERR_EXISTS);
134 CASE(HDB_ERR_KVNO_NOT_FOUND);
135 CASE(HDB_ERR_NOENTRY);
136 CASE(HDB_ERR_NO_MKEY);
137 CASE(KRB5KDC_ERR_BADOPTION);
138 CASE(KRB5KDC_ERR_CANNOT_POSTDATE);
139 CASE(KRB5KDC_ERR_CLIENT_NOTYET);
140 CASE(KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN);
141 CASE(KRB5KDC_ERR_ETYPE_NOSUPP);
142 CASE(KRB5KDC_ERR_KEY_EXPIRED);
143 CASE(KRB5KDC_ERR_NAME_EXP);
144 CASE(KRB5KDC_ERR_NEVER_VALID);
145 CASE(KRB5KDC_ERR_NONE);
146 CASE(KRB5KDC_ERR_NULL_KEY);
147 CASE(KRB5KDC_ERR_PADATA_TYPE_NOSUPP);
148 CASE(KRB5KDC_ERR_POLICY);
149 CASE(KRB5KDC_ERR_PREAUTH_FAILED);
150 CASE(KRB5KDC_ERR_PREAUTH_REQUIRED);
151 CASE(KRB5KDC_ERR_SERVER_NOMATCH);
152 CASE(KRB5KDC_ERR_SERVICE_EXP);
153 CASE(KRB5KDC_ERR_SERVICE_NOTYET);
154 CASE(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
155 CASE(KRB5KDC_ERR_TRTYPE_NOSUPP);
156 CASE(KRB5KRB_ERR_RESPONSE_TOO_BIG);
157 case 0:
158 retname = "SUCCESS";
159 break;
160 default:
161 retname = NULL;
162 break;
165 /* Let's save a few bytes */
166 #define PREFIX "KRB5KDC_"
167 if (retname && !strncmp(PREFIX, retname, strlen(PREFIX)))
168 retname += strlen(PREFIX);
169 #undef PREFIX
171 heim_audit_trail((heim_svc_req_desc)r, ret, retname);
174 void
175 krb5_kdc_update_time(struct timeval *tv)
177 if (tv == NULL)
178 gettimeofday(&_kdc_now, NULL);
179 else
180 _kdc_now = *tv;
184 #define EXTEND_REQUEST_T(LHS, RHS) do { \
185 RHS = realloc(LHS, sizeof(*RHS)); \
186 if (!RHS) \
187 return krb5_enomem((LHS)->context); \
188 LHS = (void *)RHS; \
189 memset(((char *)LHS) + sizeof(*LHS), \
190 0x0, \
191 sizeof(*RHS) - sizeof(*LHS)); \
192 } while (0)
194 static krb5_error_code
195 kdc_as_req(kdc_request_t *rptr, int *claim)
197 astgs_request_t r;
198 krb5_error_code ret;
199 size_t len;
201 /* We must free things in the extensions */
202 EXTEND_REQUEST_T(*rptr, r);
204 ret = decode_AS_REQ(r->request.data, r->request.length, &r->req, &len);
205 if (ret)
206 return ret;
208 r->reqtype = "AS-REQ";
209 r->use_request_t = 1;
210 *claim = 1;
212 ret = _kdc_as_rep(r);
213 free_AS_REQ(&r->req);
214 return ret;
218 static krb5_error_code
219 kdc_tgs_req(kdc_request_t *rptr, int *claim)
221 astgs_request_t r;
222 krb5_error_code ret;
223 size_t len;
225 /* We must free things in the extensions */
226 EXTEND_REQUEST_T(*rptr, r);
228 ret = decode_TGS_REQ(r->request.data, r->request.length, &r->req, &len);
229 if (ret)
230 return ret;
232 r->reqtype = "TGS-REQ";
233 r->use_request_t = 1;
234 *claim = 1;
236 ret = _kdc_tgs_rep(r);
237 free_TGS_REQ(&r->req);
238 return ret;
241 #ifdef DIGEST
243 static krb5_error_code
244 kdc_digest(kdc_request_t *rptr, int *claim)
246 kdc_request_t r;
247 DigestREQ digestreq;
248 krb5_error_code ret;
249 size_t len;
251 r = *rptr;
253 ret = decode_DigestREQ(r->request.data, r->request.length,
254 &digestreq, &len);
255 if (ret)
256 return ret;
258 r->use_request_t = 0;
259 *claim = 1;
261 ret = _kdc_do_digest(r->context, r->config, &digestreq,
262 r->reply, r->from, r->addr);
263 free_DigestREQ(&digestreq);
264 return ret;
267 #endif
269 #ifdef KX509
271 static krb5_error_code
272 kdc_kx509(kdc_request_t *rptr, int *claim)
274 kx509_req_context r;
275 krb5_error_code ret;
277 /* We must free things in the extensions */
278 EXTEND_REQUEST_T(*rptr, r);
280 ret = _kdc_try_kx509_request(r);
281 if (ret)
282 return ret;
284 r->use_request_t = 1;
285 r->reqtype = "KX509";
286 *claim = 1;
288 return _kdc_do_kx509(r); /* Must clean up the req struct extensions */
291 #endif
294 static struct krb5_kdc_service services[] = {
295 { KS_KRB5, "AS-REQ", kdc_as_req },
296 { KS_KRB5, "TGS-REQ", kdc_tgs_req },
297 #ifdef DIGEST
298 { 0, "DIGEST", kdc_digest },
299 #endif
300 #ifdef KX509
301 { 0, "KX509", kdc_kx509 },
302 #endif
303 { 0, NULL, NULL }
306 static int
307 process_request(krb5_context context,
308 krb5_kdc_configuration *config,
309 unsigned int krb5_only,
310 unsigned char *buf,
311 size_t len,
312 krb5_data *reply,
313 krb5_boolean *prependlength,
314 const char *from,
315 struct sockaddr *addr,
316 int datagram_reply)
318 kdc_request_t r;
319 krb5_error_code ret;
320 unsigned int i;
321 int claim = 0;
323 r = calloc(sizeof(*r), 1);
324 if (!r)
325 return krb5_enomem(context);
327 r->context = context;
328 r->hcontext = context->hcontext;
329 r->config = config;
330 r->logf = config->logf;
331 r->from = from;
332 r->addr = addr;
333 r->request.data = buf;
334 r->request.length = len;
335 r->datagram_reply = datagram_reply;
336 r->reply = reply;
337 r->kv = heim_array_create();
338 if (!r->kv) {
339 free(r);
340 return krb5_enomem(context);
343 gettimeofday(&r->tv_start, NULL);
345 for (i = 0; services[i].process != NULL; i++) {
346 if (krb5_only && (services[i].flags & KS_KRB5) == 0)
347 continue;
348 kdc_log(context, config, 7, "Probing for %s", services[i].name);
349 ret = (*services[i].process)(&r, &claim);
350 if (claim) {
351 if (prependlength && services[i].flags & KS_NO_LENGTH)
352 *prependlength = 0;
354 if (r->use_request_t) {
355 gettimeofday(&r->tv_end, NULL);
356 _kdc_audit_trail(r, ret);
357 free(r->cname);
358 free(r->sname);
359 free(r->e_text_buf);
362 heim_release(r->reason);
363 heim_release(r->kv);
364 free(r);
365 return ret;
369 heim_release(r->reason);
370 heim_release(r->kv);
371 free(r);
372 return -1;
376 * handle the request in `buf, len', from `addr' (or `from' as a string),
377 * sending a reply in `reply'.
381 krb5_kdc_process_request(krb5_context context,
382 krb5_kdc_configuration *config,
383 unsigned char *buf,
384 size_t len,
385 krb5_data *reply,
386 krb5_boolean *prependlength,
387 const char *from,
388 struct sockaddr *addr,
389 int datagram_reply)
391 return process_request(context, config, 0, buf, len, reply, prependlength,
392 from, addr, datagram_reply);
396 * handle the request in `buf, len', from `addr' (or `from' as a string),
397 * sending a reply in `reply'.
399 * This only processes krb5 requests
403 krb5_kdc_process_krb5_request(krb5_context context,
404 krb5_kdc_configuration *config,
405 unsigned char *buf,
406 size_t len,
407 krb5_data *reply,
408 const char *from,
409 struct sockaddr *addr,
410 int datagram_reply)
412 return process_request(context, config, 1, buf, len, reply, NULL,
413 from, addr, datagram_reply);
422 krb5_kdc_save_request(krb5_context context,
423 const char *fn,
424 const unsigned char *buf,
425 size_t len,
426 const krb5_data *reply,
427 const struct sockaddr *sa)
429 krb5_storage *sp;
430 krb5_address a;
431 int fd, ret;
432 uint32_t t;
433 krb5_data d;
435 memset(&a, 0, sizeof(a));
437 d.data = rk_UNCONST(buf);
438 d.length = len;
439 t = _kdc_now.tv_sec;
441 fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600);
442 if (fd < 0) {
443 int saved_errno = errno;
444 krb5_set_error_message(context, saved_errno, "Failed to open: %s", fn);
445 return saved_errno;
448 sp = krb5_storage_from_fd(fd);
449 close(fd);
450 if (sp == NULL) {
451 krb5_set_error_message(context, ENOMEM, "Storage failed to open fd");
452 return ENOMEM;
455 ret = krb5_sockaddr2address(context, sa, &a);
456 if (ret)
457 goto out;
459 krb5_store_uint32(sp, 1);
460 krb5_store_uint32(sp, t);
461 krb5_store_address(sp, a);
462 krb5_store_data(sp, d);
464 Der_class cl;
465 Der_type ty;
466 unsigned int tag;
467 ret = der_get_tag (reply->data, reply->length,
468 &cl, &ty, &tag, NULL);
469 if (ret) {
470 krb5_store_uint32(sp, 0xffffffff);
471 krb5_store_uint32(sp, 0xffffffff);
472 } else {
473 krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0));
474 krb5_store_uint32(sp, tag);
478 krb5_free_address(context, &a);
479 out:
480 krb5_storage_free(sp);
482 return 0;