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