/ lib / gssapi / krb5 / set_sec_context_option.c
set_sec_context_option.c
  1  /*
  2   * Copyright (c) 2004, PADL Software Pty Ltd.
  3   * All rights reserved.
  4   *
  5   * Portions Copyright (c) 2009 Apple Inc. 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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  /*
 36   *  glue routine for _gsskrb5_inquire_sec_context_by_oid
 37   */
 38  
 39  #include "gsskrb5_locl.h"
 40  
 41  static OM_uint32
 42  get_bool(OM_uint32 *minor_status,
 43  	 const gss_buffer_t value,
 44  	 int *flag)
 45  {
 46      if (value->value == NULL || value->length != 1) {
 47  	*minor_status = EINVAL;
 48  	return GSS_S_FAILURE;
 49      }
 50      *flag = *((const char *)value->value) != 0;
 51      return GSS_S_COMPLETE;
 52  }
 53  
 54  static OM_uint32
 55  get_string(OM_uint32 *minor_status,
 56  	   const gss_buffer_t value,
 57  	   char **str)
 58  {
 59      if (value == NULL || value->length == 0) {
 60  	*str = NULL;
 61      } else {
 62  	*str = malloc(value->length + 1);
 63  	if (*str == NULL) {
 64  	    *minor_status = 0;
 65  	    return GSS_S_UNAVAILABLE;
 66  	}
 67  	memcpy(*str, value->value, value->length);
 68  	(*str)[value->length] = '\0';
 69      }
 70      return GSS_S_COMPLETE;
 71  }
 72  
 73  static OM_uint32
 74  get_int32(OM_uint32 *minor_status,
 75  	  const gss_buffer_t value,
 76  	  OM_uint32 *ret)
 77  {
 78      *minor_status = 0;
 79      if (value == NULL || value->length == 0)
 80  	*ret = 0;
 81      else if (value->length == sizeof(*ret))
 82  	memcpy(ret, value->value, sizeof(*ret));
 83      else
 84  	return GSS_S_UNAVAILABLE;
 85  
 86      return GSS_S_COMPLETE;
 87  }
 88  
 89  static OM_uint32
 90  set_int32(OM_uint32 *minor_status,
 91  	  const gss_buffer_t value,
 92  	  OM_uint32 set)
 93  {
 94      *minor_status = 0;
 95      if (value->length == sizeof(set))
 96  	memcpy(value->value, &set, sizeof(set));
 97      else
 98  	return GSS_S_UNAVAILABLE;
 99  
100      return GSS_S_COMPLETE;
101  }
102  
103  OM_uint32 GSSAPI_CALLCONV
104  _gsskrb5_set_sec_context_option
105             (OM_uint32 *minor_status,
106              gss_ctx_id_t *context_handle,
107              const gss_OID desired_object,
108              const gss_buffer_t value)
109  {
110      krb5_context context;
111      OM_uint32 maj_stat;
112  
113      GSSAPI_KRB5_INIT (&context);
114  
115      if (value == GSS_C_NO_BUFFER) {
116  	*minor_status = EINVAL;
117  	return GSS_S_FAILURE;
118      }
119  
120      if (gss_oid_equal(desired_object, GSS_KRB5_COMPAT_DES3_MIC_X)) {
121  	gsskrb5_ctx ctx;
122  	int flag;
123  
124  	if (*context_handle == GSS_C_NO_CONTEXT) {
125  	    *minor_status = EINVAL;
126  	    return GSS_S_NO_CONTEXT;
127  	}
128  
129  	maj_stat = get_bool(minor_status, value, &flag);
130  	if (maj_stat != GSS_S_COMPLETE)
131  	    return maj_stat;
132  
133  	ctx = (gsskrb5_ctx)*context_handle;
134  	HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
135  	if (flag)
136  	    ctx->more_flags |= COMPAT_OLD_DES3;
137  	else
138  	    ctx->more_flags &= ~COMPAT_OLD_DES3;
139  	ctx->more_flags |= COMPAT_OLD_DES3_SELECTED;
140  	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
141  	return GSS_S_COMPLETE;
142      } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DNS_CANONICALIZE_X)) {
143  	int flag;
144  
145  	maj_stat = get_bool(minor_status, value, &flag);
146  	if (maj_stat != GSS_S_COMPLETE)
147  	    return maj_stat;
148  
149  	krb5_set_dns_canonicalize_hostname(context, flag);
150  	return GSS_S_COMPLETE;
151  
152      } else if (gss_oid_equal(desired_object, GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X)) {
153  	char *str;
154  
155  	maj_stat = get_string(minor_status, value, &str);
156  	if (maj_stat != GSS_S_COMPLETE)
157  	    return maj_stat;
158  
159  	maj_stat = _gsskrb5_register_acceptor_identity(minor_status, str);
160  	free(str);
161  
162  	return maj_stat;
163  
164      } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_DEFAULT_REALM_X)) {
165  	char *str;
166  
167  	maj_stat = get_string(minor_status, value, &str);
168  	if (maj_stat != GSS_S_COMPLETE)
169  	    return maj_stat;
170  	if (str == NULL) {
171  	    *minor_status = 0;
172  	    return GSS_S_CALL_INACCESSIBLE_READ;
173  	}
174  
175  	krb5_set_default_realm(context, str);
176  	free(str);
177  
178  	*minor_status = 0;
179  	return GSS_S_COMPLETE;
180  
181  #ifndef HEIMDAL_SMALLER
182      } else if (gss_oid_equal(desired_object, GSS_KRB5_SEND_TO_KDC_X)) {
183  
184  	if (value == NULL || value->length == 0) {
185  	    krb5_set_send_to_kdc_func(context, NULL, NULL);
186  	} else {
187  	    struct gsskrb5_send_to_kdc c;
188  
189  	    if (value->length != sizeof(c)) {
190  		*minor_status = EINVAL;
191  		return GSS_S_FAILURE;
192  	    }
193  	    memcpy(&c, value->value, sizeof(c));
194  	    krb5_set_send_to_kdc_func(context,
195  				      (krb5_send_to_kdc_func)c.func,
196  				      c.ptr);
197  	}
198  
199  	*minor_status = 0;
200  	return GSS_S_COMPLETE;
201  #endif
202      } else if (gss_oid_equal(desired_object, GSS_KRB5_CCACHE_NAME_X)) {
203  	char *str;
204  
205  	maj_stat = get_string(minor_status, value, &str);
206  	if (maj_stat != GSS_S_COMPLETE)
207  	    return maj_stat;
208  
209  	*minor_status = krb5_cc_set_default_name(context, str);
210  	if (str)
211  	    free(str);
212  	if (*minor_status)
213  	    return GSS_S_FAILURE;
214  
215  	return GSS_S_COMPLETE;
216      } else if (gss_oid_equal(desired_object, GSS_KRB5_SET_TIME_OFFSET_X)) {
217  	OM_uint32 offset;
218  	time_t t;
219  
220  	maj_stat = get_int32(minor_status, value, &offset);
221  	if (maj_stat != GSS_S_COMPLETE)
222  	    return maj_stat;
223  
224  	t = time(NULL) + offset;
225  
226  	krb5_set_real_time(context, t, 0);
227  
228  	*minor_status = 0;
229  	return GSS_S_COMPLETE;
230      } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_TIME_OFFSET_X)) {
231  	krb5_timestamp sec;
232  	int32_t usec;
233  	time_t t;
234  
235  	t = time(NULL);
236  
237  	krb5_us_timeofday (context, &sec, &usec);
238  
239  	maj_stat = set_int32(minor_status, value, (OM_uint32)(sec - t));
240  	if (maj_stat != GSS_S_COMPLETE)
241  	    return maj_stat;
242  
243  	*minor_status = 0;
244  	return GSS_S_COMPLETE;
245      } else if (gss_oid_equal(desired_object, GSS_KRB5_PLUGIN_REGISTER_X)) {
246  	struct gsskrb5_krb5_plugin c;
247  
248  	if (value->length != sizeof(c)) {
249  	    *minor_status = EINVAL;
250  	    return GSS_S_FAILURE;
251  	}
252  	memcpy(&c, value->value, sizeof(c));
253  	krb5_plugin_register(context, c.type, c.name, c.symbol);
254  
255  	*minor_status = 0;
256  	return GSS_S_COMPLETE;
257      }
258  
259      *minor_status = EINVAL;
260      return GSS_S_FAILURE;
261  }