/ lib / gssapi / krb5 / import_name.c
import_name.c
  1  /*
  2   * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
  3   * (Royal Institute of Technology, Stockholm, Sweden).
  4   * All rights reserved.
  5   *
  6   * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
  7   *
  8   * Redistribution and use in source and binary forms, with or without
  9   * modification, are permitted provided that the following conditions
 10   * are met:
 11   *
 12   * 1. Redistributions of source code must retain the above copyright
 13   *    notice, this list of conditions and the following disclaimer.
 14   *
 15   * 2. Redistributions in binary form must reproduce the above copyright
 16   *    notice, this list of conditions and the following disclaimer in the
 17   *    documentation and/or other materials provided with the distribution.
 18   *
 19   * 3. Neither the name of the Institute nor the names of its contributors
 20   *    may be used to endorse or promote products derived from this software
 21   *    without specific prior written permission.
 22   *
 23   * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 24   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 25   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 26   * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 27   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 28   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 29   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 30   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 31   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 32   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 33   * SUCH DAMAGE.
 34   */
 35  
 36  #include "gsskrb5_locl.h"
 37  
 38  static OM_uint32
 39  import_krb5_name(OM_uint32 *minor_status,
 40  		 gss_const_OID mech,
 41  		 const gss_buffer_t input_name_buffer,
 42  		 gss_const_OID input_name_type,
 43  		 gss_name_t *output_name)
 44  {
 45      krb5_context context;
 46      krb5_principal princ;
 47      krb5_error_code ret;
 48      char *tmp;
 49  
 50      GSSAPI_KRB5_INIT (&context);
 51  
 52      tmp = malloc (input_name_buffer->length + 1);
 53      if (tmp == NULL) {
 54  	*minor_status = ENOMEM;
 55  	return GSS_S_FAILURE;
 56      }
 57      memcpy (tmp,
 58  	    input_name_buffer->value,
 59  	    input_name_buffer->length);
 60      tmp[input_name_buffer->length] = '\0';
 61  
 62      if (tmp[0] == '@') {
 63  	princ = calloc(1, sizeof(*princ));
 64  	if (princ == NULL) {
 65  	    free(tmp);
 66  	    *minor_status = ENOMEM;
 67  	    return GSS_S_FAILURE;
 68  	}
 69  
 70  	princ->realm = strdup(&tmp[1]);
 71  	if (princ->realm == NULL) {
 72  	    free(tmp);
 73  	    free(princ);
 74  	    return GSS_S_FAILURE;
 75  	}
 76      } else {
 77  	ret = krb5_parse_name (context, tmp, &princ);
 78  	if (ret) {
 79  	    free(tmp);
 80  	    *minor_status = ret;
 81  
 82  	    if (ret == KRB5_PARSE_ILLCHAR || ret == KRB5_PARSE_MALFORMED)
 83  		return GSS_S_BAD_NAME;
 84  
 85  	    return GSS_S_FAILURE;
 86  	}
 87      }
 88  
 89      if (mech && gss_oid_equal(mech, GSS_PKU2U_MECHANISM) && strchr(tmp, '@') == NULL)
 90  	krb5_principal_set_realm(context, princ, KRB5_PKU2U_REALM_NAME);
 91  
 92      free(tmp);
 93  
 94      if (princ->name.name_string.len == 2 &&
 95  	gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL))
 96  	krb5_principal_set_type(context, princ, KRB5_NT_GSS_HOSTBASED_SERVICE);
 97  
 98      *output_name = (gss_name_t)princ;
 99      return GSS_S_COMPLETE;
100  }
101  
102  static OM_uint32
103  import_krb5_principal(OM_uint32 *minor_status,
104  		      gss_const_OID mech,
105  		      const gss_buffer_t input_name_buffer,
106  		      gss_const_OID input_name_type,
107  		      gss_name_t *output_name)
108  {
109      krb5_context context;
110      krb5_principal *princ, res = NULL;
111      OM_uint32 ret;
112  
113      GSSAPI_KRB5_INIT (&context);
114  
115      princ = (krb5_principal *)input_name_buffer->value;
116  
117      ret = krb5_copy_principal(context, *princ, &res);
118      if (ret) {
119  	*minor_status = ret;
120  	return GSS_S_FAILURE;
121      }
122      *output_name = (gss_name_t)res;
123      return GSS_S_COMPLETE;
124  }
125  
126  
127  OM_uint32
128  _gsskrb5_canon_name(OM_uint32 *minor_status, krb5_context context,
129  		    int use_dns, krb5_const_principal sourcename, gss_name_t targetname,
130  		    krb5_principal *out)
131  {
132      krb5_principal p = (krb5_principal)targetname;
133      krb5_error_code ret;
134      char *hostname = NULL, *service;
135  
136      *minor_status = 0;
137  
138      /* If its not a hostname */
139      if (krb5_principal_get_type(context, p) != KRB5_NT_GSS_HOSTBASED_SERVICE) {
140  	ret = krb5_copy_principal(context, p, out);
141      } else if (!use_dns) {
142  	ret = krb5_copy_principal(context, p, out);
143  	if (ret)
144  	    goto out;
145  	krb5_principal_set_type(context, *out, KRB5_NT_SRV_HST);
146  	if (sourcename)
147  	    ret = krb5_principal_set_realm(context, *out, sourcename->realm);
148      } else {
149  	if (p->name.name_string.len == 0)
150  	    return GSS_S_BAD_NAME;
151  	else if (p->name.name_string.len > 1)
152  	    hostname = p->name.name_string.val[1];
153  
154  	service = p->name.name_string.val[0];
155  
156  	ret = krb5_sname_to_principal(context,
157  				      hostname,
158  				      service,
159  				      KRB5_NT_SRV_HST,
160  				      out);
161      }
162  
163   out:
164      if (ret) {
165  	*minor_status = ret;
166  	return GSS_S_FAILURE;
167      }
168  
169      return 0;
170  }
171  
172  
173  static OM_uint32
174  import_hostbased_name (OM_uint32 *minor_status,
175  		       gss_const_OID mech,
176  		       const gss_buffer_t input_name_buffer,
177  		       gss_const_OID input_name_type,
178  		       gss_name_t *output_name)
179  {
180      krb5_context context;
181      krb5_principal princ = NULL;
182      krb5_error_code kerr;
183      char *tmp, *p, *host = NULL, *realm = NULL;
184  
185      if (gss_oid_equal(mech, GSS_PKU2U_MECHANISM))
186  	realm = KRB5_PKU2U_REALM_NAME;
187      else
188  	realm = KRB5_GSS_REFERALS_REALM_NAME; /* should never hit the network */
189  
190      GSSAPI_KRB5_INIT (&context);
191  
192      tmp = malloc (input_name_buffer->length + 1);
193      if (tmp == NULL) {
194  	*minor_status = ENOMEM;
195  	return GSS_S_FAILURE;
196      }
197      memcpy (tmp,
198  	    input_name_buffer->value,
199  	    input_name_buffer->length);
200      tmp[input_name_buffer->length] = '\0';
201  
202      p = strchr (tmp, '@');
203      if (p != NULL && p[1] != '\0') {
204  	size_t len;
205  
206  	*p = '\0';
207  	host = p + 1;
208  
209  	/*
210  	 * Squash any trailing . on the hostname since that is jolly
211  	 * good to have when looking up a DNS name (qualified), but
212  	 * its no good to have in the kerberos principal since those
213  	 * are supposed to be in qualified format already.
214  	 */
215  
216  	len = strlen(host);
217  	if (len > 0 && host[len - 1] == '.')
218  	    host[len - 1] = '\0';
219      } else {
220  	host = KRB5_GSS_HOSTBASED_SERVICE_NAME;
221      }
222  
223      kerr = krb5_make_principal(context, &princ, realm, tmp, host, NULL);
224      free (tmp);
225      *minor_status = kerr;
226      if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED)
227  	return GSS_S_BAD_NAME;
228      else if (kerr)
229  	return GSS_S_FAILURE;
230  
231      krb5_principal_set_type(context, princ, KRB5_NT_GSS_HOSTBASED_SERVICE);
232      *output_name = (gss_name_t)princ;
233  
234      return 0;
235  }
236  
237  static OM_uint32
238  import_dn_name(OM_uint32 *minor_status,
239  	       gss_const_OID mech,
240  	       const gss_buffer_t input_name_buffer,
241  	       gss_const_OID input_name_type,
242  	       gss_name_t *output_name)
243  {
244      /* XXX implement me */
245      *output_name = NULL;
246      *minor_status = 0;
247      return GSS_S_FAILURE;
248  }
249  
250  static OM_uint32
251  import_pku2u_export_name(OM_uint32 *minor_status,
252  			 gss_const_OID mech,
253  			 const gss_buffer_t input_name_buffer,
254  			 gss_const_OID input_name_type,
255  			 gss_name_t *output_name)
256  {
257      /* XXX implement me */
258      *output_name = NULL;
259      *minor_status = 0;
260      return GSS_S_FAILURE;
261  }
262  
263  static OM_uint32
264  import_uuid_name(OM_uint32 *minor_status,
265  		 gss_const_OID mech,
266  		 const gss_buffer_t input_name_buffer,
267  		 gss_const_OID input_name_type,
268  		 gss_name_t *output_name)
269  {
270      krb5_context context;
271      krb5_error_code ret;
272      krb5_principal princ;
273      char uuid[36 + 1];
274  
275      GSSAPI_KRB5_INIT(&context);
276      
277      if (input_name_buffer->length < sizeof(uuid) - 1) {
278  	*minor_status = 0;
279  	return GSS_S_BAD_NAME;
280      }
281      
282      memcpy(uuid, input_name_buffer->value, sizeof(uuid) - 1);
283      uuid[sizeof(uuid) - 1] = '\0';
284      
285      /* validate that uuid is only uuid chars and the right length*/
286      if (strspn(uuid, "0123456789abcdefABCDEF-") != 36) {
287  	*minor_status = 0;
288  	return GSS_S_BAD_NAME;
289      }
290      
291      ret = krb5_make_principal(context, &princ, "UUID", uuid, NULL);
292      if (ret) {
293  	*minor_status = ret;
294  	return GSS_S_FAILURE;
295      }
296      krb5_principal_set_type(context, princ, KRB5_NT_CACHE_UUID);
297      
298      *output_name = (gss_name_t)princ;
299      *minor_status = 0;
300  
301      return GSS_S_COMPLETE;
302  }
303  
304  static struct _gss_name_type krb5_names[] = {
305      { GSS_C_NT_HOSTBASED_SERVICE, import_hostbased_name },
306      { GSS_C_NT_HOSTBASED_SERVICE_X, import_hostbased_name },
307      { GSS_KRB5_NT_PRINCIPAL, import_krb5_principal},
308      { GSS_C_NO_OID, import_krb5_name },
309      { GSS_C_NT_USER_NAME, import_krb5_name },
310      { GSS_KRB5_NT_PRINCIPAL_NAME, import_krb5_name },
311      { GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL, import_krb5_name },
312      { GSS_C_NT_EXPORT_NAME, import_krb5_name },
313      { GSS_C_NT_UUID, import_uuid_name },
314      { NULL, NULL }
315  };
316  
317  static struct _gss_name_type pku2u_names[] = {
318      { GSS_C_NT_HOSTBASED_SERVICE, import_hostbased_name },
319      { GSS_C_NT_HOSTBASED_SERVICE_X, import_hostbased_name },
320      { GSS_C_NO_OID, import_krb5_name },
321      { GSS_C_NT_USER_NAME, import_krb5_name },
322      { GSS_KRB5_NT_PRINCIPAL_NAME, import_krb5_name },
323      { GSS_C_NT_DN, import_dn_name },
324      { GSS_C_NT_EXPORT_NAME, import_pku2u_export_name },
325      { GSS_C_NT_UUID, import_uuid_name },
326      { NULL, NULL }
327  };
328  
329  static struct _gss_name_type iakerb_names[] = {
330      { GSS_C_NT_HOSTBASED_SERVICE, import_hostbased_name },
331      { GSS_C_NT_HOSTBASED_SERVICE_X, import_hostbased_name },
332      { GSS_C_NO_OID, import_krb5_name },
333      { GSS_C_NT_USER_NAME, import_krb5_name },
334      { GSS_KRB5_NT_PRINCIPAL_NAME, import_krb5_name },
335      { GSS_KRB5_NT_PRINCIPAL_NAME_REFERRAL, import_krb5_name },
336      { GSS_C_NT_EXPORT_NAME, import_krb5_name },
337      { GSS_C_NT_UUID, import_uuid_name },
338      { NULL, NULL }
339  };
340  
341  OM_uint32 GSSAPI_CALLCONV _gsskrb5_import_name
342             (OM_uint32 * minor_status,
343              const gss_buffer_t input_name_buffer,
344              gss_const_OID input_name_type,
345              gss_name_t * output_name
346             )
347  {
348      return _gss_mech_import_name(minor_status, GSS_KRB5_MECHANISM,
349  				 krb5_names, input_name_buffer,
350  				 input_name_type, output_name);
351  }
352  
353  OM_uint32 _gsspku2u_import_name
354             (OM_uint32 * minor_status,
355              const gss_buffer_t input_name_buffer,
356              gss_const_OID input_name_type,
357              gss_name_t * output_name
358             )
359  {
360      return _gss_mech_import_name(minor_status, GSS_PKU2U_MECHANISM,
361  				 pku2u_names, input_name_buffer,
362  				 input_name_type, output_name);
363  }
364  
365  OM_uint32
366  _gssiakerb_import_name(OM_uint32 * minor_status,
367  		       const gss_buffer_t input_name_buffer,
368  		       gss_const_OID input_name_type,
369  		       gss_name_t * output_name)
370  {
371      return _gss_mech_import_name(minor_status, GSS_IAKERB_MECHANISM,
372  				 iakerb_names, input_name_buffer,
373  				 input_name_type, output_name);
374  }
375  
376  OM_uint32
377  _gsskrb5_inquire_names_for_mech (OM_uint32 * minor_status,
378  				 gss_const_OID mechanism,
379  				 gss_OID_set * name_types)
380  {
381      return _gss_mech_inquire_names_for_mech(minor_status, krb5_names,
382  					    name_types);
383  }
384  
385  OM_uint32
386  _gsspku2u_inquire_names_for_mech (OM_uint32 * minor_status,
387  				  gss_const_OID mechanism,
388  				  gss_OID_set * name_types)
389  {
390      return _gss_mech_inquire_names_for_mech(minor_status, pku2u_names,
391  					    name_types);
392  }
393  
394  OM_uint32
395  _gssiakerb_inquire_names_for_mech (OM_uint32 * minor_status,
396  				   gss_const_OID mechanism,
397  				   gss_OID_set * name_types)
398  {
399      return _gss_mech_inquire_names_for_mech(minor_status, iakerb_names,
400  					    name_types);
401  }