1178825Sdfr/*
2233294Sstas * Copyright (c) 1997-2005 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4178825Sdfr *
5233294Sstas * All rights reserved.
6178825Sdfr *
7233294Sstas * Redistribution and use in source and binary forms, with or without
8233294Sstas * modification, are permitted provided that the following conditions
9233294Sstas * are met:
10178825Sdfr *
11233294Sstas * 1. Redistributions of source code must retain the above copyright
12233294Sstas *    notice, this list of conditions and the following disclaimer.
13178825Sdfr *
14233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
15233294Sstas *    notice, this list of conditions and the following disclaimer in the
16233294Sstas *    documentation and/or other materials provided with the distribution.
17178825Sdfr *
18233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
19233294Sstas *    may be used to endorse or promote products derived from this software
20233294Sstas *    without specific prior written permission.
21178825Sdfr *
22233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32233294Sstas * SUCH DAMAGE.
33178825Sdfr */
34178825Sdfr
35178825Sdfr#include "kdc_locl.h"
36178825Sdfr
37178825Sdfr/*
38178825Sdfr *
39178825Sdfr */
40178825Sdfr
41178825Sdfrvoid
42178825Sdfrkrb5_kdc_update_time(struct timeval *tv)
43178825Sdfr{
44178825Sdfr    if (tv == NULL)
45178825Sdfr	gettimeofday(&_kdc_now, NULL);
46178825Sdfr    else
47178825Sdfr	_kdc_now = *tv;
48178825Sdfr}
49178825Sdfr
50233294Sstasstatic krb5_error_code
51233294Sstaskdc_as_req(krb5_context context,
52233294Sstas	   krb5_kdc_configuration *config,
53233294Sstas	   krb5_data *req_buffer,
54233294Sstas	   krb5_data *reply,
55233294Sstas	   const char *from,
56233294Sstas	   struct sockaddr *addr,
57233294Sstas	   int datagram_reply,
58233294Sstas	   int *claim)
59233294Sstas{
60233294Sstas    krb5_error_code ret;
61233294Sstas    KDC_REQ req;
62233294Sstas    size_t len;
63233294Sstas
64233294Sstas    ret = decode_AS_REQ(req_buffer->data, req_buffer->length, &req, &len);
65233294Sstas    if (ret)
66233294Sstas	return ret;
67233294Sstas
68233294Sstas    *claim = 1;
69233294Sstas
70233294Sstas    ret = _kdc_as_rep(context, config, &req, req_buffer,
71233294Sstas		      reply, from, addr, datagram_reply);
72233294Sstas    free_AS_REQ(&req);
73233294Sstas    return ret;
74233294Sstas}
75233294Sstas
76233294Sstas
77233294Sstasstatic krb5_error_code
78233294Sstaskdc_tgs_req(krb5_context context,
79233294Sstas	    krb5_kdc_configuration *config,
80233294Sstas	    krb5_data *req_buffer,
81233294Sstas	    krb5_data *reply,
82233294Sstas	    const char *from,
83233294Sstas	    struct sockaddr *addr,
84233294Sstas	    int datagram_reply,
85233294Sstas	    int *claim)
86233294Sstas{
87233294Sstas    krb5_error_code ret;
88233294Sstas    KDC_REQ req;
89233294Sstas    size_t len;
90233294Sstas
91233294Sstas    ret = decode_TGS_REQ(req_buffer->data, req_buffer->length, &req, &len);
92233294Sstas    if (ret)
93233294Sstas	return ret;
94233294Sstas
95233294Sstas    *claim = 1;
96233294Sstas
97233294Sstas    ret = _kdc_tgs_rep(context, config, &req, reply,
98233294Sstas		       from, addr, datagram_reply);
99233294Sstas    free_TGS_REQ(&req);
100233294Sstas    return ret;
101233294Sstas}
102233294Sstas
103233294Sstas#ifdef DIGEST
104233294Sstas
105233294Sstasstatic krb5_error_code
106233294Sstaskdc_digest(krb5_context context,
107233294Sstas	   krb5_kdc_configuration *config,
108233294Sstas	   krb5_data *req_buffer,
109233294Sstas	   krb5_data *reply,
110233294Sstas	   const char *from,
111233294Sstas	   struct sockaddr *addr,
112233294Sstas	   int datagram_reply,
113233294Sstas	   int *claim)
114233294Sstas{
115233294Sstas    DigestREQ digestreq;
116233294Sstas    krb5_error_code ret;
117233294Sstas    size_t len;
118233294Sstas
119233294Sstas    ret = decode_DigestREQ(req_buffer->data, req_buffer->length,
120233294Sstas			   &digestreq, &len);
121233294Sstas    if (ret)
122233294Sstas	return ret;
123233294Sstas
124233294Sstas    *claim = 1;
125233294Sstas
126233294Sstas    ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr);
127233294Sstas    free_DigestREQ(&digestreq);
128233294Sstas    return ret;
129233294Sstas}
130233294Sstas
131233294Sstas#endif
132233294Sstas
133233294Sstas#ifdef KX509
134233294Sstas
135233294Sstasstatic krb5_error_code
136233294Sstaskdc_kx509(krb5_context context,
137233294Sstas	  krb5_kdc_configuration *config,
138233294Sstas	  krb5_data *req_buffer,
139233294Sstas	  krb5_data *reply,
140233294Sstas	  const char *from,
141233294Sstas	  struct sockaddr *addr,
142233294Sstas	  int datagram_reply,
143233294Sstas	  int *claim)
144233294Sstas{
145233294Sstas    Kx509Request kx509req;
146233294Sstas    krb5_error_code ret;
147233294Sstas    size_t len;
148233294Sstas
149233294Sstas    ret = _kdc_try_kx509_request(req_buffer->data, req_buffer->length,
150233294Sstas				 &kx509req, &len);
151233294Sstas    if (ret)
152233294Sstas	return ret;
153233294Sstas
154233294Sstas    *claim = 1;
155233294Sstas
156233294Sstas    ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr);
157233294Sstas    free_Kx509Request(&kx509req);
158233294Sstas    return ret;
159233294Sstas}
160233294Sstas
161233294Sstas#endif
162233294Sstas
163233294Sstas
164233294Sstasstatic struct krb5_kdc_service services[] =  {
165233294Sstas    { KS_KRB5,		kdc_as_req },
166233294Sstas    { KS_KRB5,		kdc_tgs_req },
167233294Sstas#ifdef DIGEST
168233294Sstas    { 0,		kdc_digest },
169233294Sstas#endif
170233294Sstas#ifdef KX509
171233294Sstas    { 0,		kdc_kx509 },
172233294Sstas#endif
173233294Sstas    { 0, NULL }
174233294Sstas};
175233294Sstas
176178825Sdfr/*
177178825Sdfr * handle the request in `buf, len', from `addr' (or `from' as a string),
178178825Sdfr * sending a reply in `reply'.
179178825Sdfr */
180178825Sdfr
181178825Sdfrint
182233294Sstaskrb5_kdc_process_request(krb5_context context,
183178825Sdfr			 krb5_kdc_configuration *config,
184233294Sstas			 unsigned char *buf,
185233294Sstas			 size_t len,
186178825Sdfr			 krb5_data *reply,
187178825Sdfr			 krb5_boolean *prependlength,
188178825Sdfr			 const char *from,
189178825Sdfr			 struct sockaddr *addr,
190178825Sdfr			 int datagram_reply)
191178825Sdfr{
192178825Sdfr    krb5_error_code ret;
193233294Sstas    unsigned int i;
194233294Sstas    krb5_data req_buffer;
195233294Sstas    int claim = 0;
196178825Sdfr
197233294Sstas    req_buffer.data = buf;
198233294Sstas    req_buffer.length = len;
199178825Sdfr
200233294Sstas    for (i = 0; services[i].process != NULL; i++) {
201233294Sstas	ret = (*services[i].process)(context, config, &req_buffer,
202233294Sstas				     reply, from, addr, datagram_reply,
203233294Sstas				     &claim);
204233294Sstas	if (claim) {
205233294Sstas	    if (services[i].flags & KS_NO_LENGTH)
206233294Sstas		*prependlength = 0;
207233294Sstas	    return ret;
208233294Sstas	}
209233294Sstas    }
210178825Sdfr
211178825Sdfr    return -1;
212178825Sdfr}
213178825Sdfr
214178825Sdfr/*
215178825Sdfr * handle the request in `buf, len', from `addr' (or `from' as a string),
216178825Sdfr * sending a reply in `reply'.
217178825Sdfr *
218178825Sdfr * This only processes krb5 requests
219178825Sdfr */
220178825Sdfr
221178825Sdfrint
222233294Sstaskrb5_kdc_process_krb5_request(krb5_context context,
223178825Sdfr			      krb5_kdc_configuration *config,
224233294Sstas			      unsigned char *buf,
225233294Sstas			      size_t len,
226178825Sdfr			      krb5_data *reply,
227178825Sdfr			      const char *from,
228178825Sdfr			      struct sockaddr *addr,
229178825Sdfr			      int datagram_reply)
230178825Sdfr{
231178825Sdfr    krb5_error_code ret;
232233294Sstas    unsigned int i;
233233294Sstas    krb5_data req_buffer;
234233294Sstas    int claim = 0;
235178825Sdfr
236233294Sstas    req_buffer.data = buf;
237233294Sstas    req_buffer.length = len;
238178825Sdfr
239233294Sstas    for (i = 0; services[i].process != NULL; i++) {
240233294Sstas	if ((services[i].flags & KS_KRB5) == 0)
241233294Sstas	    continue;
242233294Sstas	ret = (*services[i].process)(context, config, &req_buffer,
243233294Sstas				     reply, from, addr, datagram_reply,
244233294Sstas				     &claim);
245233294Sstas	if (claim)
246233294Sstas	    return ret;
247233294Sstas    }
248178825Sdfr
249178825Sdfr    return -1;
250178825Sdfr}
251178825Sdfr
252178825Sdfr/*
253178825Sdfr *
254178825Sdfr */
255178825Sdfr
256178825Sdfrint
257233294Sstaskrb5_kdc_save_request(krb5_context context,
258178825Sdfr		      const char *fn,
259178825Sdfr		      const unsigned char *buf,
260178825Sdfr		      size_t len,
261178825Sdfr		      const krb5_data *reply,
262178825Sdfr		      const struct sockaddr *sa)
263178825Sdfr{
264178825Sdfr    krb5_storage *sp;
265178825Sdfr    krb5_address a;
266178825Sdfr    int fd, ret;
267178825Sdfr    uint32_t t;
268178825Sdfr    krb5_data d;
269178825Sdfr
270178825Sdfr    memset(&a, 0, sizeof(a));
271178825Sdfr
272178825Sdfr    d.data = rk_UNCONST(buf);
273178825Sdfr    d.length = len;
274178825Sdfr    t = _kdc_now.tv_sec;
275178825Sdfr
276178825Sdfr    fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600);
277178825Sdfr    if (fd < 0) {
278233294Sstas	int saved_errno = errno;
279233294Sstas	krb5_set_error_message(context, saved_errno, "Failed to open: %s", fn);
280233294Sstas	return saved_errno;
281178825Sdfr    }
282233294Sstas
283178825Sdfr    sp = krb5_storage_from_fd(fd);
284178825Sdfr    close(fd);
285178825Sdfr    if (sp == NULL) {
286233294Sstas	krb5_set_error_message(context, ENOMEM, "Storage failed to open fd");
287178825Sdfr	return ENOMEM;
288178825Sdfr    }
289178825Sdfr
290178825Sdfr    ret = krb5_sockaddr2address(context, sa, &a);
291178825Sdfr    if (ret)
292178825Sdfr	goto out;
293178825Sdfr
294178825Sdfr    krb5_store_uint32(sp, 1);
295178825Sdfr    krb5_store_uint32(sp, t);
296178825Sdfr    krb5_store_address(sp, a);
297178825Sdfr    krb5_store_data(sp, d);
298178825Sdfr    {
299178825Sdfr	Der_class cl;
300178825Sdfr	Der_type ty;
301178825Sdfr	unsigned int tag;
302178825Sdfr	ret = der_get_tag (reply->data, reply->length,
303178825Sdfr			   &cl, &ty, &tag, NULL);
304178825Sdfr	if (ret) {
305178825Sdfr	    krb5_store_uint32(sp, 0xffffffff);
306178825Sdfr	    krb5_store_uint32(sp, 0xffffffff);
307178825Sdfr	} else {
308178825Sdfr	    krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0));
309178825Sdfr	    krb5_store_uint32(sp, tag);
310178825Sdfr	}
311178825Sdfr    }
312178825Sdfr
313178825Sdfr    krb5_free_address(context, &a);
314178825Sdfrout:
315178825Sdfr    krb5_storage_free(sp);
316178825Sdfr
317178825Sdfr    return 0;
318178825Sdfr}
319