xref: /freebsd/crypto/heimdal/kdc/process.c (revision 59c8e88e72633afbc47a4ace0d2170d00d51f7dc)
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 
41 void
42 krb5_kdc_update_time(struct timeval *tv)
43 {
44     if (tv == NULL)
45 	gettimeofday(&_kdc_now, NULL);
46     else
47 	_kdc_now = *tv;
48 }
49 
50 static krb5_error_code
51 kdc_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 
77 static krb5_error_code
78 kdc_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 
105 static krb5_error_code
106 kdc_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 
135 static krb5_error_code
136 kdc_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 
164 static 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 
181 int
182 krb5_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 
221 int
222 krb5_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 
256 int
257 krb5_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);
314 out:
315     krb5_storage_free(sp);
316 
317     return 0;
318 }
319