/ kdc / process.c
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  	   size_t max_reply_size,
 58  	   int *claim)
 59  {
 60      struct kdc_request_desc r;
 61      krb5_error_code ret;
 62      size_t len;
 63  
 64      memset(&r, 0, sizeof(r));
 65  
 66      ret = decode_AS_REQ(req_buffer->data, req_buffer->length, &r.req, &len);
 67      if (ret)
 68  	return ret;
 69  
 70      r.context = context;
 71      r.config = config;
 72      r.request.data = req_buffer->data;
 73      r.request.length = req_buffer->length;
 74  
 75      *claim = 1;
 76  
 77      ret = _kdc_as_rep(&r, reply, from, addr, max_reply_size);
 78      free_AS_REQ(&r.req);
 79  
 80      return ret;
 81  }
 82  
 83  
 84  static krb5_error_code
 85  kdc_tgs_req(krb5_context context,
 86  	    krb5_kdc_configuration *config,
 87  	    krb5_data *req_buffer,
 88  	    krb5_data *reply,
 89  	    const char *from,
 90  	    struct sockaddr *addr,
 91  	    size_t max_reply_size,
 92  	    int *claim)
 93  {
 94      struct kdc_request_desc r;
 95      krb5_error_code ret;
 96      size_t len;
 97  
 98      memset(&r, 0, sizeof(r));
 99  
100      ret = decode_TGS_REQ(req_buffer->data, req_buffer->length, &r.req, &len);
101      if (ret)
102  	return ret;
103  
104      r.context = context;
105      r.config = config;
106      r.request.data = req_buffer->data;
107      r.request.length = req_buffer->length;
108  
109      *claim = 1;
110  
111      ret = _kdc_tgs_rep(&r, reply, from, addr, max_reply_size);
112  
113      free_TGS_REQ(&r.req);
114  
115      return ret;
116  }
117  
118  #ifdef DIGEST
119  
120  static krb5_error_code
121  kdc_digest(krb5_context context,
122  	   krb5_kdc_configuration *config,
123  	   krb5_data *req_buffer,
124  	   krb5_data *reply,
125  	   const char *from,
126  	   struct sockaddr *addr,
127  	   size_t max_reply_size,
128  	   int *claim)
129  {
130      DigestREQ digestreq;
131      krb5_error_code ret;
132      size_t len;
133  
134      ret = decode_DigestREQ(req_buffer->data, req_buffer->length,
135  			   &digestreq, &len);
136      if (ret)
137  	return ret;
138  
139      *claim = 1;
140  
141      ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr);
142      free_DigestREQ(&digestreq);
143      return ret;
144  }
145  
146  #endif
147  
148  #ifdef KX509
149  
150  static krb5_error_code
151  kdc_kx509(krb5_context context,
152  	  krb5_kdc_configuration *config,
153  	  krb5_data *req_buffer,
154  	  krb5_data *reply,
155  	  const char *from,
156  	  struct sockaddr *addr,
157  	  size_t max_reply_size,
158  	  int *claim)
159  {
160      Kx509Request kx509req;
161      krb5_error_code ret;
162      size_t len;
163  
164      ret = _kdc_try_kx509_request(req_buffer->data, req_buffer->length,
165  				 &kx509req, &len);
166      if (ret)
167  	return ret;
168  
169      *claim = 1;
170  
171      ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr);
172      free_Kx509Request(&kx509req);
173      return ret;
174  }
175  
176  #endif
177  
178  static struct krb5_kdc_service services[] =  {
179      { KS_KRB5,		kdc_as_req },
180      { KS_KRB5,		kdc_tgs_req },
181  #ifdef DIGEST
182      { 0,		kdc_digest },
183  #endif
184  #ifdef KX509
185      { 0,		kdc_kx509 },
186  #endif
187      { 0, NULL }
188  };
189  
190  /*
191   * handle the request in `buf, len', from `addr' (or `from' as a string),
192   * sending a reply in `reply'.
193   */
194  
195  int
196  krb5_kdc_process_request(krb5_context context,
197  			 krb5_kdc_configuration *config,
198  			 unsigned char *buf,
199  			 size_t len,
200  			 krb5_data *reply,
201  			 const char *from,
202  			 struct sockaddr *addr,
203  			 int datagram_reply)
204  {
205      krb5_error_code ret;
206      unsigned int i;
207      krb5_data req_buffer;
208      int claim = 0;
209      size_t max_reply_size = 0;
210  
211      if (datagram_reply)
212  	max_reply_size = config->max_datagram_reply_length;
213      
214      req_buffer.data = buf;
215      req_buffer.length = len;
216  
217      for (i = 0; services[i].process != NULL; i++) {
218  	ret = (*services[i].process)(context, config, &req_buffer,
219  				     reply, from, addr, max_reply_size,
220  				     &claim);
221  	if (claim) {
222  	    return ret;
223  	}
224      }
225  
226      return -1;
227  }
228  
229  /*
230   * handle the request in `buf, len', from `addr' (or `from' as a string),
231   * sending a reply in `reply'.
232   *
233   * This only processes krb5 requests
234   */
235  
236  int
237  krb5_kdc_process_krb5_request(krb5_context context,
238  			      krb5_kdc_configuration *config,
239  			      unsigned char *buf,
240  			      size_t len,
241  			      krb5_data *reply,
242  			      const char *from,
243  			      struct sockaddr *addr,
244  			      int datagram_reply)
245  {
246      krb5_error_code ret;
247      unsigned int i;
248      krb5_data req_buffer;
249      int claim = 0;
250      size_t max_reply_size = 0;
251  
252      if (datagram_reply)
253  	max_reply_size = config->max_datagram_reply_length;
254  
255      req_buffer.data = buf;
256      req_buffer.length = len;
257  
258      for (i = 0; services[i].process != NULL; i++) {
259  	if ((services[i].flags & KS_KRB5) == 0)
260  	    continue;
261  	ret = (*services[i].process)(context, config, &req_buffer,
262  				     reply, from, addr, max_reply_size,
263  				     &claim);
264  	if (claim)
265  	    return ret;
266      }
267  
268      return -1;
269  }
270  
271  /*
272   *
273   */
274  
275  int
276  krb5_kdc_save_request(krb5_context context,
277  		      const char *fn,
278  		      const unsigned char *buf,
279  		      size_t len,
280  		      const krb5_data *reply,
281  		      const struct sockaddr *sa)
282  {
283      krb5_storage *sp;
284      krb5_address a;
285      int fd, ret;
286      time_t t;
287      krb5_data d;
288  
289      memset(&a, 0, sizeof(a));
290  
291      d.data = rk_UNCONST(buf);
292      d.length = len;
293      t = _kdc_now.tv_sec;
294  
295      fd = open(fn, O_WRONLY|O_CREAT|O_APPEND, 0600);
296      if (fd < 0) {
297  	int saved_errno = errno;
298  	krb5_set_error_message(context, saved_errno, "Failed to open: %s", fn);
299  	return saved_errno;
300      }
301  
302      sp = krb5_storage_from_fd(fd);
303      close(fd);
304      if (sp == NULL) {
305  	krb5_set_error_message(context, ENOMEM, "Storage failed to open fd");
306  	return ENOMEM;
307      }
308  
309      ret = krb5_sockaddr2address(context, sa, &a);
310      if (ret)
311  	goto out;
312  
313      krb5_store_uint32(sp, 1);
314      krb5_store_uint32(sp, (uint32_t)t);
315      krb5_store_address(sp, a);
316      krb5_store_data(sp, d);
317      {
318  	Der_class cl;
319  	Der_type ty;
320  	unsigned int tag;
321  	ret = der_get_tag (reply->data, reply->length,
322  			   &cl, &ty, &tag, NULL);
323  	if (ret) {
324  	    krb5_store_uint32(sp, 0xffffffff);
325  	    krb5_store_uint32(sp, 0xffffffff);
326  	} else {
327  	    krb5_store_uint32(sp, MAKE_TAG(cl, ty, 0));
328  	    krb5_store_uint32(sp, tag);
329  	}
330      }
331  
332      krb5_free_address(context, &a);
333  out:
334      krb5_storage_free(sp);
335  
336      return 0;
337  }