]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - crypto/heimdal/kdc/process.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / crypto / heimdal / kdc / process.c
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 }