1 /* $NetBSD: process.c,v 1.2 2017/01/28 21:31:44 christos Exp $ */
2
3 /*
4 * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of the Institute nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include "kdc_locl.h"
38
39 /*
40 *
41 */
42
43 void
krb5_kdc_update_time(struct timeval * tv)44 krb5_kdc_update_time(struct timeval *tv)
45 {
46 if (tv == NULL)
47 gettimeofday(&_kdc_now, NULL);
48 else
49 _kdc_now = *tv;
50 }
51
52 static krb5_error_code
kdc_as_req(krb5_context context,krb5_kdc_configuration * config,krb5_data * req_buffer,krb5_data * reply,const char * from,struct sockaddr * addr,int datagram_reply,int * claim)53 kdc_as_req(krb5_context context,
54 krb5_kdc_configuration *config,
55 krb5_data *req_buffer,
56 krb5_data *reply,
57 const char *from,
58 struct sockaddr *addr,
59 int datagram_reply,
60 int *claim)
61 {
62 struct kdc_request_desc r;
63 krb5_error_code ret;
64 size_t len;
65
66 memset(&r, 0, sizeof(r));
67
68 ret = decode_AS_REQ(req_buffer->data, req_buffer->length, &r.req, &len);
69 if (ret)
70 return ret;
71
72 r.context = context;
73 r.config = config;
74 r.request.data = req_buffer->data;
75 r.request.length = req_buffer->length;
76
77 *claim = 1;
78
79 ret = _kdc_as_rep(&r, reply, from, addr, datagram_reply);
80 free_AS_REQ(&r.req);
81 return ret;
82 }
83
84
85 static krb5_error_code
kdc_tgs_req(krb5_context context,krb5_kdc_configuration * config,krb5_data * req_buffer,krb5_data * reply,const char * from,struct sockaddr * addr,int datagram_reply,int * claim)86 kdc_tgs_req(krb5_context context,
87 krb5_kdc_configuration *config,
88 krb5_data *req_buffer,
89 krb5_data *reply,
90 const char *from,
91 struct sockaddr *addr,
92 int datagram_reply,
93 int *claim)
94 {
95 krb5_error_code ret;
96 KDC_REQ req;
97 size_t len;
98
99 ret = decode_TGS_REQ(req_buffer->data, req_buffer->length, &req, &len);
100 if (ret)
101 return ret;
102
103 *claim = 1;
104
105 ret = _kdc_tgs_rep(context, config, &req, reply,
106 from, addr, datagram_reply);
107 free_TGS_REQ(&req);
108 return ret;
109 }
110
111 #ifdef DIGEST
112
113 static krb5_error_code
kdc_digest(krb5_context context,krb5_kdc_configuration * config,krb5_data * req_buffer,krb5_data * reply,const char * from,struct sockaddr * addr,int datagram_reply,int * claim)114 kdc_digest(krb5_context context,
115 krb5_kdc_configuration *config,
116 krb5_data *req_buffer,
117 krb5_data *reply,
118 const char *from,
119 struct sockaddr *addr,
120 int datagram_reply,
121 int *claim)
122 {
123 DigestREQ digestreq;
124 krb5_error_code ret;
125 size_t len;
126
127 ret = decode_DigestREQ(req_buffer->data, req_buffer->length,
128 &digestreq, &len);
129 if (ret)
130 return ret;
131
132 *claim = 1;
133
134 ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr);
135 free_DigestREQ(&digestreq);
136 return ret;
137 }
138
139 #endif
140
141 #ifdef KX509
142
143 static krb5_error_code
kdc_kx509(krb5_context context,krb5_kdc_configuration * config,krb5_data * req_buffer,krb5_data * reply,const char * from,struct sockaddr * addr,int datagram_reply,int * claim)144 kdc_kx509(krb5_context context,
145 krb5_kdc_configuration *config,
146 krb5_data *req_buffer,
147 krb5_data *reply,
148 const char *from,
149 struct sockaddr *addr,
150 int datagram_reply,
151 int *claim)
152 {
153 Kx509Request kx509req;
154 krb5_error_code ret;
155 size_t len;
156
157 ret = _kdc_try_kx509_request(req_buffer->data, req_buffer->length,
158 &kx509req, &len);
159 if (ret)
160 return ret;
161
162 *claim = 1;
163
164 ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr);
165 free_Kx509Request(&kx509req);
166 return ret;
167 }
168
169 #endif
170
171
172 static struct krb5_kdc_service services[] = {
173 { KS_KRB5, kdc_as_req },
174 { KS_KRB5, kdc_tgs_req },
175 #ifdef DIGEST
176 { 0, kdc_digest },
177 #endif
178 #ifdef KX509
179 { 0, kdc_kx509 },
180 #endif
181 { 0, NULL }
182 };
183
184 /*
185 * handle the request in `buf, len', from `addr' (or `from' as a string),
186 * sending a reply in `reply'.
187 */
188
189 int
krb5_kdc_process_request(krb5_context context,krb5_kdc_configuration * config,unsigned char * buf,size_t len,krb5_data * reply,krb5_boolean * prependlength,const char * from,struct sockaddr * addr,int datagram_reply)190 krb5_kdc_process_request(krb5_context context,
191 krb5_kdc_configuration *config,
192 unsigned char *buf,
193 size_t len,
194 krb5_data *reply,
195 krb5_boolean *prependlength,
196 const char *from,
197 struct sockaddr *addr,
198 int datagram_reply)
199 {
200 krb5_error_code ret;
201 unsigned int i;
202 krb5_data req_buffer;
203 int claim = 0;
204 heim_auto_release_t pool = heim_auto_release_create();
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, datagram_reply,
212 &claim);
213 if (claim) {
214 if (services[i].flags & KS_NO_LENGTH)
215 *prependlength = 0;
216
217 heim_release(pool);
218 return ret;
219 }
220 }
221
222 heim_release(pool);
223
224 return -1;
225 }
226
227 /*
228 * handle the request in `buf, len', from `addr' (or `from' as a string),
229 * sending a reply in `reply'.
230 *
231 * This only processes krb5 requests
232 */
233
234 int
krb5_kdc_process_krb5_request(krb5_context context,krb5_kdc_configuration * config,unsigned char * buf,size_t len,krb5_data * reply,const char * from,struct sockaddr * addr,int datagram_reply)235 krb5_kdc_process_krb5_request(krb5_context context,
236 krb5_kdc_configuration *config,
237 unsigned char *buf,
238 size_t len,
239 krb5_data *reply,
240 const char *from,
241 struct sockaddr *addr,
242 int datagram_reply)
243 {
244 krb5_error_code ret;
245 unsigned int i;
246 krb5_data req_buffer;
247 int claim = 0;
248
249 req_buffer.data = buf;
250 req_buffer.length = len;
251
252 for (i = 0; services[i].process != NULL; i++) {
253 if ((services[i].flags & KS_KRB5) == 0)
254 continue;
255 ret = (*services[i].process)(context, config, &req_buffer,
256 reply, from, addr, datagram_reply,
257 &claim);
258 if (claim)
259 return ret;
260 }
261
262 return -1;
263 }
264
265 /*
266 *
267 */
268
269 int
krb5_kdc_save_request(krb5_context context,const char * fn,const unsigned char * buf,size_t len,const krb5_data * reply,const struct sockaddr * sa)270 krb5_kdc_save_request(krb5_context context,
271 const char *fn,
272 const unsigned char *buf,
273 size_t len,
274 const krb5_data *reply,
275 const struct sockaddr *sa)
276 {
277 krb5_storage *sp;
278 krb5_address a;
279 int fd, ret;
280 uint32_t t;
281 krb5_data d;
282
283 memset(&a, 0, sizeof(a));
284
285 d.data = rk_UNCONST(buf);
286 d.length = len;
287 t = _kdc_now.tv_sec;
288
289 fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600);
290 if (fd < 0) {
291 int saved_errno = errno;
292 krb5_set_error_message(context, saved_errno, "Failed to open: %s", fn);
293 return saved_errno;
294 }
295
296 sp = krb5_storage_from_fd(fd);
297 close(fd);
298 if (sp == NULL) {
299 krb5_set_error_message(context, ENOMEM, "Storage failed to open fd");
300 return ENOMEM;
301 }
302
303 ret = krb5_sockaddr2address(context, sa, &a);
304 if (ret)
305 goto out;
306
307 krb5_store_uint32(sp, 1);
308 krb5_store_uint32(sp, t);
309 krb5_store_address(sp, a);
310 krb5_store_data(sp, d);
311 {
312 Der_class cl;
313 Der_type ty;
314 unsigned int tag;
315 ret = der_get_tag (reply->data, reply->length,
316 &cl, &ty, &tag, NULL);
317 if (ret) {
318 krb5_store_uint32(sp, 0xffffffff);
319 krb5_store_uint32(sp, 0xffffffff);
320 } else {
321 krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0));
322 krb5_store_uint32(sp, tag);
323 }
324 }
325
326 krb5_free_address(context, &a);
327 out:
328 krb5_storage_free(sp);
329
330 return 0;
331 }
332