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 37/* 38 * 39 */ 40 41void 42krb5_kdc_update_time(struct timeval *tv) 43{ 44 if (tv == NULL) 45 gettimeofday(&_kdc_now, NULL); 46 else 47 _kdc_now = *tv; 48} 49 50static krb5_error_code 51kdc_as_req(krb5_context context, 52 krb5_kdc_configuration *config, 53 krb5_data *req_buffer, 54 krb5_data *reply, 55 const char *from, 56 struct sockaddr *addr, 57 int datagram_reply, 58 int *claim) 59{ 60 krb5_error_code ret; 61 KDC_REQ req; 62 size_t len; 63 64 ret = decode_AS_REQ(req_buffer->data, req_buffer->length, &req, &len); 65 if (ret) 66 return ret; 67 68 *claim = 1; 69 70 ret = _kdc_as_rep(context, config, &req, req_buffer, 71 reply, from, addr, datagram_reply); 72 free_AS_REQ(&req); 73 return ret; 74} 75 76 77static krb5_error_code 78kdc_tgs_req(krb5_context context, 79 krb5_kdc_configuration *config, 80 krb5_data *req_buffer, 81 krb5_data *reply, 82 const char *from, 83 struct sockaddr *addr, 84 int datagram_reply, 85 int *claim) 86{ 87 krb5_error_code ret; 88 KDC_REQ req; 89 size_t len; 90 91 ret = decode_TGS_REQ(req_buffer->data, req_buffer->length, &req, &len); 92 if (ret) 93 return ret; 94 95 *claim = 1; 96 97 ret = _kdc_tgs_rep(context, config, &req, reply, 98 from, addr, datagram_reply); 99 free_TGS_REQ(&req); 100 return ret; 101} 102 103#ifdef DIGEST 104 105static krb5_error_code 106kdc_digest(krb5_context context, 107 krb5_kdc_configuration *config, 108 krb5_data *req_buffer, 109 krb5_data *reply, 110 const char *from, 111 struct sockaddr *addr, 112 int datagram_reply, 113 int *claim) 114{ 115 DigestREQ digestreq; 116 krb5_error_code ret; 117 size_t len; 118 119 ret = decode_DigestREQ(req_buffer->data, req_buffer->length, 120 &digestreq, &len); 121 if (ret) 122 return ret; 123 124 *claim = 1; 125 126 ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr); 127 free_DigestREQ(&digestreq); 128 return ret; 129} 130 131#endif 132 133#ifdef KX509 134 135static krb5_error_code 136kdc_kx509(krb5_context context, 137 krb5_kdc_configuration *config, 138 krb5_data *req_buffer, 139 krb5_data *reply, 140 const char *from, 141 struct sockaddr *addr, 142 int datagram_reply, 143 int *claim) 144{ 145 Kx509Request kx509req; 146 krb5_error_code ret; 147 size_t len; 148 149 ret = _kdc_try_kx509_request(req_buffer->data, req_buffer->length, 150 &kx509req, &len); 151 if (ret) 152 return ret; 153 154 *claim = 1; 155 156 ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr); 157 free_Kx509Request(&kx509req); 158 return ret; 159} 160 161#endif 162 163 164#ifdef KRB4 165 166static krb5_error_code 167kdc_524(krb5_context context, 168 krb5_kdc_configuration *config, 169 krb5_data *req_buffer, 170 krb5_data *reply, 171 const char *from, 172 struct sockaddr *addr, 173 int datagram_reply, 174 int *claim) 175{ 176 krb5_error_code ret; 177 Ticket ticket; 178 size_t len; 179 180 ret = decode_Ticket(req_buffer->data, req_buffer->length, &ticket, &len); 181 if (ret) 182 return ret; 183 184 *claim = 1; 185 186 ret = _kdc_do_524(context, config, &ticket, reply, from, addr); 187 free_Ticket(&ticket); 188 return ret; 189} 190 191static krb5_error_code 192kdc_krb4(krb5_context context, 193 krb5_kdc_configuration *config, 194 krb5_data *req_buffer, 195 krb5_data *reply, 196 const char *from, 197 struct sockaddr *addr, 198 int datagram_reply, 199 int *claim) 200{ 201 if (_kdc_maybe_version4(req_buffer->data, req_buffer->length) == 0) 202 return -1; 203 204 *claim = 1; 205 206 return _kdc_do_version4(context, config, 207 req_buffer->data, req_buffer->length, 208 reply, from, 209 (struct sockaddr_in*)addr); 210} 211 212static krb5_error_code 213kdc_kaserver(krb5_context context, 214 krb5_kdc_configuration *config, 215 krb5_data *req_buffer, 216 krb5_data *reply, 217 const char *from, 218 struct sockaddr *addr, 219 int datagram_reply, 220 int *claim) 221{ 222 if (config->enable_kaserver == 0) 223 return -1; 224 225 *claim = 1; 226 227 return _kdc_do_kaserver(context, config, 228 req_buffer->data, req_buffer->length, 229 reply, from, 230 (struct sockaddr_in*)addr); 231} 232 233#endif /* KRB4 */ 234 235 236static struct krb5_kdc_service services[] = { 237 { KS_KRB5, kdc_as_req }, 238 { KS_KRB5, kdc_tgs_req }, 239#ifdef DIGEST 240 { 0, kdc_digest }, 241#endif 242#ifdef KX509 243 { 0, kdc_kx509 }, 244#endif 245#ifdef KRB4 246 { 0, kdc_524 }, 247 { KS_NO_LENGTH, kdc_krb4 }, 248 { 0, kdc_kaserver }, 249#endif 250 { 0, NULL } 251}; 252 253/* 254 * handle the request in `buf, len', from `addr' (or `from' as a string), 255 * sending a reply in `reply'. 256 */ 257 258int 259krb5_kdc_process_request(krb5_context context, 260 krb5_kdc_configuration *config, 261 unsigned char *buf, 262 size_t len, 263 krb5_data *reply, 264 krb5_boolean *prependlength, 265 const char *from, 266 struct sockaddr *addr, 267 int datagram_reply) 268{ 269 krb5_error_code ret; 270 unsigned int i; 271 krb5_data req_buffer; 272 int claim = 0; 273 274 req_buffer.data = buf; 275 req_buffer.length = len; 276 277 for (i = 0; services[i].process != NULL; i++) { 278 ret = (*services[i].process)(context, config, &req_buffer, 279 reply, from, addr, datagram_reply, 280 &claim); 281 if (claim) { 282 if (services[i].flags & KS_NO_LENGTH) 283 *prependlength = 0; 284 return ret; 285 } 286 } 287 288 return -1; 289} 290 291/* 292 * handle the request in `buf, len', from `addr' (or `from' as a string), 293 * sending a reply in `reply'. 294 * 295 * This only processes krb5 requests 296 */ 297 298int 299krb5_kdc_process_krb5_request(krb5_context context, 300 krb5_kdc_configuration *config, 301 unsigned char *buf, 302 size_t len, 303 krb5_data *reply, 304 const char *from, 305 struct sockaddr *addr, 306 int datagram_reply) 307{ 308 krb5_error_code ret; 309 unsigned int i; 310 krb5_data req_buffer; 311 int claim = 0; 312 313 req_buffer.data = buf; 314 req_buffer.length = len; 315 316 for (i = 0; services[i].process != NULL; i++) { 317 if ((services[i].flags & KS_KRB5) == 0) 318 continue; 319 ret = (*services[i].process)(context, config, &req_buffer, 320 reply, from, addr, datagram_reply, 321 &claim); 322 if (claim) 323 return ret; 324 } 325 326 return -1; 327} 328 329/* 330 * 331 */ 332 333int 334krb5_kdc_save_request(krb5_context context, 335 const char *fn, 336 const unsigned char *buf, 337 size_t len, 338 const krb5_data *reply, 339 const struct sockaddr *sa) 340{ 341 krb5_storage *sp; 342 krb5_address a; 343 int fd, ret; 344 uint32_t t; 345 krb5_data d; 346 347 memset(&a, 0, sizeof(a)); 348 349 d.data = rk_UNCONST(buf); 350 d.length = len; 351 t = _kdc_now.tv_sec; 352 353 fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600); 354 if (fd < 0) { 355 int saved_errno = errno; 356 krb5_set_error_message(context, saved_errno, "Failed to open: %s", fn); 357 return saved_errno; 358 } 359 360 sp = krb5_storage_from_fd(fd); 361 close(fd); 362 if (sp == NULL) { 363 krb5_set_error_message(context, ENOMEM, "Storage failed to open fd"); 364 return ENOMEM; 365 } 366 367 ret = krb5_sockaddr2address(context, sa, &a); 368 if (ret) 369 goto out; 370 371 krb5_store_uint32(sp, 1); 372 krb5_store_uint32(sp, t); 373 krb5_store_address(sp, a); 374 krb5_store_data(sp, d); 375 { 376 Der_class cl; 377 Der_type ty; 378 unsigned int tag; 379 ret = der_get_tag (reply->data, reply->length, 380 &cl, &ty, &tag, NULL); 381 if (ret) { 382 krb5_store_uint32(sp, 0xffffffff); 383 krb5_store_uint32(sp, 0xffffffff); 384 } else { 385 krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0)); 386 krb5_store_uint32(sp, tag); 387 } 388 } 389 390 krb5_free_address(context, &a); 391out: 392 krb5_storage_free(sp); 393 394 return 0; 395} 396