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