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