2 * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
43 #define __attribute__(x)
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
);
53 _kdc_audit_addreason(kdc_request_t r
, const char *fmt
, ...)
54 __attribute__ ((__format__ (__printf__
, 2, 3)))
59 heim_audit_vaddreason((heim_svc_req_desc
)r
, fmt
, 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
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
);
78 _kdc_audit_addkv(kdc_request_t r
, int flags
, const char *k
,
80 __attribute__ ((__format__ (__printf__
, 4, 5)))
85 heim_audit_vaddkv((heim_svc_req_desc
)r
, flags
, k
, fmt
, ap
);
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.
102 _kdc_audit_addaddrs(kdc_request_t r
, HostAddresses
*a
, const char *key
)
110 if (snprintf(numkey
, sizeof(numkey
), "num%s", key
) >= sizeof(numkey
))
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
);
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
? ret
: r
->ret
) {
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
);
165 /* Let's save a few bytes */
166 #define PREFIX "KRB5KDC_"
167 if (retname
&& strncmp(PREFIX
, retname
, strlen(PREFIX
)) == 0)
168 retname
+= strlen(PREFIX
);
171 heim_audit_trail((heim_svc_req_desc
)r
, ret
, retname
);
175 krb5_kdc_update_time(struct timeval
*tv
)
178 gettimeofday(&_kdc_now
, NULL
);
184 #define EXTEND_REQUEST_T(LHS, RHS) do { \
185 RHS = realloc(LHS, sizeof(*RHS)); \
187 return krb5_enomem((LHS)->context); \
189 memset(((char *)LHS) + sizeof(*LHS), \
191 sizeof(*RHS) - sizeof(*LHS)); \
194 static krb5_error_code
195 kdc_as_req(kdc_request_t
*rptr
, int *claim
)
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
);
208 r
->reqtype
= "AS-REQ";
209 r
->use_request_t
= 1;
212 ret
= _kdc_as_rep(r
);
213 free_AS_REQ(&r
->req
);
218 static krb5_error_code
219 kdc_tgs_req(kdc_request_t
*rptr
, int *claim
)
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
);
232 r
->reqtype
= "TGS-REQ";
233 r
->use_request_t
= 1;
236 ret
= _kdc_tgs_rep(r
);
237 free_TGS_REQ(&r
->req
);
243 static krb5_error_code
244 kdc_digest(kdc_request_t
*rptr
, int *claim
)
253 ret
= decode_DigestREQ(r
->request
.data
, r
->request
.length
,
258 r
->use_request_t
= 0;
261 ret
= _kdc_do_digest(r
->context
, r
->config
, &digestreq
,
262 r
->reply
, r
->from
, r
->addr
);
263 free_DigestREQ(&digestreq
);
271 static krb5_error_code
272 kdc_kx509(kdc_request_t
*rptr
, int *claim
)
277 /* We must free things in the extensions */
278 EXTEND_REQUEST_T(*rptr
, r
);
280 ret
= _kdc_try_kx509_request(r
);
284 r
->use_request_t
= 1;
285 r
->reqtype
= "KX509";
288 return _kdc_do_kx509(r
); /* Must clean up the req struct extensions */
294 static struct krb5_kdc_service services
[] = {
295 { KS_KRB5
, "AS-REQ", kdc_as_req
},
296 { KS_KRB5
, "TGS-REQ", kdc_tgs_req
},
298 { 0, "DIGEST", kdc_digest
},
301 { 0, "KX509", kdc_kx509
},
307 process_request(krb5_context context
,
308 krb5_kdc_configuration
*config
,
309 unsigned int krb5_only
,
313 krb5_boolean
*prependlength
,
315 struct sockaddr
*addr
,
323 r
= calloc(sizeof(*r
), 1);
325 return krb5_enomem(context
);
327 r
->context
= context
;
328 r
->hcontext
= context
->hcontext
;
330 r
->logf
= config
->logf
;
333 r
->request
.data
= buf
;
334 r
->request
.length
= len
;
335 r
->datagram_reply
= datagram_reply
;
337 r
->kv
= heim_array_create();
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)
348 kdc_log(context
, config
, 7, "Probing for %s", services
[i
].name
);
349 ret
= (*services
[i
].process
)(&r
, &claim
);
351 if (prependlength
&& services
[i
].flags
& KS_NO_LENGTH
)
354 if (r
->use_request_t
) {
355 gettimeofday(&r
->tv_end
, NULL
);
356 _kdc_audit_trail(r
, ret
);
362 heim_release(r
->reason
);
369 heim_release(r
->reason
);
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
,
386 krb5_boolean
*prependlength
,
388 struct sockaddr
*addr
,
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
,
409 struct sockaddr
*addr
,
412 return process_request(context
, config
, 1, buf
, len
, reply
, NULL
,
413 from
, addr
, datagram_reply
);
422 krb5_kdc_save_request(krb5_context context
,
424 const unsigned char *buf
,
426 const krb5_data
*reply
,
427 const struct sockaddr
*sa
)
435 memset(&a
, 0, sizeof(a
));
437 d
.data
= rk_UNCONST(buf
);
441 fd
= open(fn
, O_WRONLY
|O_CREAT
|O_APPEND
, 0600);
443 int saved_errno
= errno
;
444 krb5_set_error_message(context
, saved_errno
, "Failed to open: %s", fn
);
448 sp
= krb5_storage_from_fd(fd
);
451 krb5_set_error_message(context
, ENOMEM
, "Storage failed to open fd");
455 ret
= krb5_sockaddr2address(context
, sa
, &a
);
459 krb5_store_uint32(sp
, 1);
460 krb5_store_uint32(sp
, t
);
461 krb5_store_address(sp
, a
);
462 krb5_store_data(sp
, d
);
467 ret
= der_get_tag (reply
->data
, reply
->length
,
468 &cl
, &ty
, &tag
, NULL
);
470 krb5_store_uint32(sp
, 0xffffffff);
471 krb5_store_uint32(sp
, 0xffffffff);
473 krb5_store_uint32(sp
, MAKE_TAG(cl
, ty
, 0));
474 krb5_store_uint32(sp
, tag
);
478 krb5_free_address(context
, &a
);
480 krb5_storage_free(sp
);