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
164static 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
181int
182krb5_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
221int
222krb5_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
256int
257krb5_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);
314out:
315    krb5_storage_free(sp);
316
317    return 0;
318}
319