xref: /netbsd-src/crypto/external/bsd/heimdal/dist/kdc/process.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
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