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 41 void 42 krb5_kdc_update_time(struct timeval *tv) 43 { 44 if (tv == NULL) 45 gettimeofday(&_kdc_now, NULL); 46 else 47 _kdc_now = *tv; 48 } 49 50 static krb5_error_code 51 kdc_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 77 static krb5_error_code 78 kdc_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 105 static krb5_error_code 106 kdc_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 135 static krb5_error_code 136 kdc_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 static struct krb5_kdc_service services[] = { 165 { KS_KRB5, kdc_as_req }, 166 { KS_KRB5, kdc_tgs_req }, 167 #ifdef DIGEST 168 { 0, kdc_digest }, 169 #endif 170 #ifdef KX509 171 { 0, kdc_kx509 }, 172 #endif 173 { 0, NULL } 174 }; 175 176 /* 177 * handle the request in `buf, len', from `addr' (or `from' as a string), 178 * sending a reply in `reply'. 179 */ 180 181 int 182 krb5_kdc_process_request(krb5_context context, 183 krb5_kdc_configuration *config, 184 unsigned char *buf, 185 size_t len, 186 krb5_data *reply, 187 krb5_boolean *prependlength, 188 const char *from, 189 struct sockaddr *addr, 190 int datagram_reply) 191 { 192 krb5_error_code ret; 193 unsigned int i; 194 krb5_data req_buffer; 195 int claim = 0; 196 197 req_buffer.data = buf; 198 req_buffer.length = len; 199 200 for (i = 0; services[i].process != NULL; i++) { 201 ret = (*services[i].process)(context, config, &req_buffer, 202 reply, from, addr, datagram_reply, 203 &claim); 204 if (claim) { 205 if (services[i].flags & KS_NO_LENGTH) 206 *prependlength = 0; 207 return ret; 208 } 209 } 210 211 return -1; 212 } 213 214 /* 215 * handle the request in `buf, len', from `addr' (or `from' as a string), 216 * sending a reply in `reply'. 217 * 218 * This only processes krb5 requests 219 */ 220 221 int 222 krb5_kdc_process_krb5_request(krb5_context context, 223 krb5_kdc_configuration *config, 224 unsigned char *buf, 225 size_t len, 226 krb5_data *reply, 227 const char *from, 228 struct sockaddr *addr, 229 int datagram_reply) 230 { 231 krb5_error_code ret; 232 unsigned int i; 233 krb5_data req_buffer; 234 int claim = 0; 235 236 req_buffer.data = buf; 237 req_buffer.length = len; 238 239 for (i = 0; services[i].process != NULL; i++) { 240 if ((services[i].flags & KS_KRB5) == 0) 241 continue; 242 ret = (*services[i].process)(context, config, &req_buffer, 243 reply, from, addr, datagram_reply, 244 &claim); 245 if (claim) 246 return ret; 247 } 248 249 return -1; 250 } 251 252 /* 253 * 254 */ 255 256 int 257 krb5_kdc_save_request(krb5_context context, 258 const char *fn, 259 const unsigned char *buf, 260 size_t len, 261 const krb5_data *reply, 262 const struct sockaddr *sa) 263 { 264 krb5_storage *sp; 265 krb5_address a; 266 int fd, ret; 267 uint32_t t; 268 krb5_data d; 269 270 memset(&a, 0, sizeof(a)); 271 272 d.data = rk_UNCONST(buf); 273 d.length = len; 274 t = _kdc_now.tv_sec; 275 276 fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600); 277 if (fd < 0) { 278 int saved_errno = errno; 279 krb5_set_error_message(context, saved_errno, "Failed to open: %s", fn); 280 return saved_errno; 281 } 282 283 sp = krb5_storage_from_fd(fd); 284 close(fd); 285 if (sp == NULL) { 286 krb5_set_error_message(context, ENOMEM, "Storage failed to open fd"); 287 return ENOMEM; 288 } 289 290 ret = krb5_sockaddr2address(context, sa, &a); 291 if (ret) 292 goto out; 293 294 krb5_store_uint32(sp, 1); 295 krb5_store_uint32(sp, t); 296 krb5_store_address(sp, a); 297 krb5_store_data(sp, d); 298 { 299 Der_class cl; 300 Der_type ty; 301 unsigned int tag; 302 ret = der_get_tag (reply->data, reply->length, 303 &cl, &ty, &tag, NULL); 304 if (ret) { 305 krb5_store_uint32(sp, 0xffffffff); 306 krb5_store_uint32(sp, 0xffffffff); 307 } else { 308 krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0)); 309 krb5_store_uint32(sp, tag); 310 } 311 } 312 313 krb5_free_address(context, &a); 314 out: 315 krb5_storage_free(sp); 316 317 return 0; 318 } 319