1*5e01956fSGlenn Barry /*
2*5e01956fSGlenn Barry  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3*5e01956fSGlenn Barry  */
47c478bd9Sstevel@tonic-gate /*
57c478bd9Sstevel@tonic-gate  * Copyright 1993 by OpenVision Technologies, Inc.
6ab9b2e15Sgtb  *
77c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, distribute, and sell this software
87c478bd9Sstevel@tonic-gate  * and its documentation for any purpose is hereby granted without fee,
97c478bd9Sstevel@tonic-gate  * provided that the above copyright notice appears in all copies and
107c478bd9Sstevel@tonic-gate  * that both that copyright notice and this permission notice appear in
117c478bd9Sstevel@tonic-gate  * supporting documentation, and that the name of OpenVision not be used
127c478bd9Sstevel@tonic-gate  * in advertising or publicity pertaining to distribution of the software
137c478bd9Sstevel@tonic-gate  * without specific, written prior permission. OpenVision makes no
147c478bd9Sstevel@tonic-gate  * representations about the suitability of this software for any
157c478bd9Sstevel@tonic-gate  * purpose.  It is provided "as is" without express or implied warranty.
16ab9b2e15Sgtb  *
177c478bd9Sstevel@tonic-gate  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
187c478bd9Sstevel@tonic-gate  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
197c478bd9Sstevel@tonic-gate  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
207c478bd9Sstevel@tonic-gate  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
217c478bd9Sstevel@tonic-gate  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
227c478bd9Sstevel@tonic-gate  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
237c478bd9Sstevel@tonic-gate  * PERFORMANCE OF THIS SOFTWARE.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
27ab9b2e15Sgtb  * $Id: import_name.c 18015 2006-05-17 05:26:12Z raeburn $
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
30ab9b2e15Sgtb #include "gssapiP_krb5.h"
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #ifndef NO_PASSWORD
337c478bd9Sstevel@tonic-gate #include <pwd.h>
34ab9b2e15Sgtb #include <stdio.h>
357c478bd9Sstevel@tonic-gate #endif
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #ifdef HAVE_STRING_H
387c478bd9Sstevel@tonic-gate #include <string.h>
397c478bd9Sstevel@tonic-gate #else
407c478bd9Sstevel@tonic-gate #include <strings.h>
417c478bd9Sstevel@tonic-gate #endif
42*5e01956fSGlenn Barry #include <locale.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate /*
457c478bd9Sstevel@tonic-gate  * errors:
467c478bd9Sstevel@tonic-gate  * GSS_S_BAD_NAMETYPE	if the type is bogus
477c478bd9Sstevel@tonic-gate  * GSS_S_BAD_NAME	if the type is good but the name is bogus
487c478bd9Sstevel@tonic-gate  * GSS_S_FAILURE	if memory allocation fails
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate OM_uint32
52ab9b2e15Sgtb krb5_gss_import_name(minor_status, input_name_buffer,
537c478bd9Sstevel@tonic-gate 		     input_name_type, output_name)
547c478bd9Sstevel@tonic-gate      OM_uint32 *minor_status;
557c478bd9Sstevel@tonic-gate      gss_buffer_t input_name_buffer;
567c478bd9Sstevel@tonic-gate      gss_OID input_name_type;
577c478bd9Sstevel@tonic-gate      gss_name_t *output_name;
587c478bd9Sstevel@tonic-gate {
597c478bd9Sstevel@tonic-gate    krb5_context context;
607c478bd9Sstevel@tonic-gate    krb5_principal princ;
617c478bd9Sstevel@tonic-gate    krb5_error_code code;
627c478bd9Sstevel@tonic-gate    char *stringrep, *tmp, *tmp2, *cp;
637c478bd9Sstevel@tonic-gate    OM_uint32	length;
647c478bd9Sstevel@tonic-gate #ifndef NO_PASSWORD
657c478bd9Sstevel@tonic-gate    struct passwd *pw;
667c478bd9Sstevel@tonic-gate #endif
677c478bd9Sstevel@tonic-gate 
68ab9b2e15Sgtb    code = krb5_gss_init_context(&context);
69ab9b2e15Sgtb    if (code) {
70ab9b2e15Sgtb        *minor_status = code;
71ab9b2e15Sgtb        return GSS_S_FAILURE;
72ab9b2e15Sgtb    }
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate    /* set up default returns */
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate    *output_name = NULL;
777c478bd9Sstevel@tonic-gate    *minor_status = 0;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate    /* Go find the appropriate string rep to pass into parse_name */
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate    if ((input_name_type != GSS_C_NULL_OID) &&
82ab9b2e15Sgtb        (g_OID_equal(input_name_type, gss_nt_service_name) ||
837c478bd9Sstevel@tonic-gate 	g_OID_equal(input_name_type, gss_nt_service_name_v2))) {
847c478bd9Sstevel@tonic-gate       char *service, *host;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate       if ((tmp =
877c478bd9Sstevel@tonic-gate 	   (char *) xmalloc(input_name_buffer->length + 1)) == NULL) {
887c478bd9Sstevel@tonic-gate 	 *minor_status = ENOMEM;
89ab9b2e15Sgtb 	 krb5_free_context(context);
907c478bd9Sstevel@tonic-gate 	 return(GSS_S_FAILURE);
917c478bd9Sstevel@tonic-gate       }
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate       memcpy(tmp, input_name_buffer->value, input_name_buffer->length);
947c478bd9Sstevel@tonic-gate       tmp[input_name_buffer->length] = 0;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate       service = tmp;
97ab9b2e15Sgtb       if ((host = strchr(tmp, '@'))) {
987c478bd9Sstevel@tonic-gate 	 *host = '\0';
997c478bd9Sstevel@tonic-gate 	 host++;
1007c478bd9Sstevel@tonic-gate       }
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate       code = krb5_sname_to_principal(context, host, service, KRB5_NT_SRV_HST,
1037c478bd9Sstevel@tonic-gate 				     &princ);
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate       xfree(tmp);
1067c478bd9Sstevel@tonic-gate    } else if ((input_name_type != GSS_C_NULL_OID) &&
1077c478bd9Sstevel@tonic-gate 	      (g_OID_equal(input_name_type, gss_nt_krb5_principal))) {
108*5e01956fSGlenn Barry        krb5_principal input;
109*5e01956fSGlenn Barry 
110*5e01956fSGlenn Barry        if (input_name_buffer->length != sizeof(krb5_principal)) {
111*5e01956fSGlenn Barry 	   *minor_status = (OM_uint32) G_WRONG_SIZE;
112*5e01956fSGlenn Barry 	   /* Solaris Kerberos: spruce-up the err msg */
113*5e01956fSGlenn Barry 	   krb5_set_error_message(context, *minor_status,
114*5e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
115*5e01956fSGlenn Barry 					"The size of the specified principal is wrong"));
116*5e01956fSGlenn Barry 	   save_error_info(*minor_status, context);
117*5e01956fSGlenn Barry 	   krb5_free_context(context);
118*5e01956fSGlenn Barry 	   return(GSS_S_BAD_NAME);
1197c478bd9Sstevel@tonic-gate       }
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate       input = *((krb5_principal *) input_name_buffer->value);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate       if ((code = krb5_copy_principal(context, input, &princ))) {
1247c478bd9Sstevel@tonic-gate 	 *minor_status = code;
125*5e01956fSGlenn Barry 	 save_error_info(*minor_status, context);
126ab9b2e15Sgtb 	 krb5_free_context(context);
1277c478bd9Sstevel@tonic-gate 	 return(GSS_S_FAILURE);
1287c478bd9Sstevel@tonic-gate       }
1297c478bd9Sstevel@tonic-gate    } else {
130ab9b2e15Sgtb #ifndef NO_PASSWORD
131ab9b2e15Sgtb       uid_t uid;
132ab9b2e15Sgtb       struct passwd pwx;
133ab9b2e15Sgtb       char pwbuf[BUFSIZ];
134ab9b2e15Sgtb #endif
135ab9b2e15Sgtb 
1367c478bd9Sstevel@tonic-gate       stringrep = NULL;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate       if ((tmp =
1397c478bd9Sstevel@tonic-gate 	   (char *) xmalloc(input_name_buffer->length + 1)) == NULL) {
1407c478bd9Sstevel@tonic-gate 	 *minor_status = ENOMEM;
141ab9b2e15Sgtb 	 krb5_free_context(context);
1427c478bd9Sstevel@tonic-gate 	 return(GSS_S_FAILURE);
1437c478bd9Sstevel@tonic-gate       }
1447c478bd9Sstevel@tonic-gate       tmp2 = 0;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate       memcpy(tmp, input_name_buffer->value, input_name_buffer->length);
1477c478bd9Sstevel@tonic-gate       tmp[input_name_buffer->length] = 0;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate       if ((input_name_type == GSS_C_NULL_OID) ||
1507c478bd9Sstevel@tonic-gate 	  g_OID_equal(input_name_type, gss_nt_krb5_name) ||
151ab9b2e15Sgtb 	  g_OID_equal(input_name_type, gss_nt_user_name)) {
1527c478bd9Sstevel@tonic-gate 	 stringrep = (char *) tmp;
1537c478bd9Sstevel@tonic-gate #ifndef NO_PASSWORD
154ab9b2e15Sgtb       } else if (g_OID_equal(input_name_type, gss_nt_machine_uid_name)) {
155ab9b2e15Sgtb 	 uid = *(uid_t *) input_name_buffer->value;
156ab9b2e15Sgtb       do_getpwuid:
157ab9b2e15Sgtb 	 if (k5_getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) == 0)
158ab9b2e15Sgtb 	     stringrep = pw->pw_name;
1597c478bd9Sstevel@tonic-gate 	 else
1607c478bd9Sstevel@tonic-gate 	    *minor_status = (OM_uint32) G_NOUSER;
161ab9b2e15Sgtb       } else if (g_OID_equal(input_name_type, gss_nt_string_uid_name)) {
162ab9b2e15Sgtb 	 uid = atoi(tmp);
163ab9b2e15Sgtb 	 goto do_getpwuid;
1647c478bd9Sstevel@tonic-gate #endif
1657c478bd9Sstevel@tonic-gate       } else if (g_OID_equal(input_name_type, gss_nt_exported_name)) {
1667c478bd9Sstevel@tonic-gate 	 cp = tmp;
1677c478bd9Sstevel@tonic-gate 	 if (*cp++ != 0x04)
1687c478bd9Sstevel@tonic-gate 		 goto fail_name;
1697c478bd9Sstevel@tonic-gate 	 if (*cp++ != 0x01)
1707c478bd9Sstevel@tonic-gate 		 goto fail_name;
1717c478bd9Sstevel@tonic-gate 	 if (*cp++ != 0x00)
1727c478bd9Sstevel@tonic-gate 		 goto fail_name;
1737c478bd9Sstevel@tonic-gate 	 length = *cp++;
1747c478bd9Sstevel@tonic-gate 	 if (length != gss_mech_krb5->length+2)
1757c478bd9Sstevel@tonic-gate 		 goto fail_name;
1767c478bd9Sstevel@tonic-gate 	 if (*cp++ != 0x06)
1777c478bd9Sstevel@tonic-gate 		 goto fail_name;
1787c478bd9Sstevel@tonic-gate 	 length = *cp++;
1797c478bd9Sstevel@tonic-gate 	 if (length != gss_mech_krb5->length)
1807c478bd9Sstevel@tonic-gate 		 goto fail_name;
1817c478bd9Sstevel@tonic-gate 	 if (memcmp(cp, gss_mech_krb5->elements, length) != 0)
1827c478bd9Sstevel@tonic-gate 		 goto fail_name;
1837c478bd9Sstevel@tonic-gate 	 cp += length;
1847c478bd9Sstevel@tonic-gate 	 length = *cp++;
1857c478bd9Sstevel@tonic-gate 	 length = (length << 8) | *cp++;
1867c478bd9Sstevel@tonic-gate 	 length = (length << 8) | *cp++;
1877c478bd9Sstevel@tonic-gate 	 length = (length << 8) | *cp++;
1887c478bd9Sstevel@tonic-gate 	 tmp2 = malloc(length+1);
1897c478bd9Sstevel@tonic-gate 	 if (tmp2 == NULL) {
1907c478bd9Sstevel@tonic-gate 		 xfree(tmp);
1917c478bd9Sstevel@tonic-gate 		 *minor_status = ENOMEM;
192ab9b2e15Sgtb 		 krb5_free_context(context);
1937c478bd9Sstevel@tonic-gate 		 return GSS_S_FAILURE;
1947c478bd9Sstevel@tonic-gate 	 }
1957c478bd9Sstevel@tonic-gate 	 strncpy(tmp2, cp, length);
1967c478bd9Sstevel@tonic-gate 	 tmp2[length] = 0;
197ab9b2e15Sgtb 
1987c478bd9Sstevel@tonic-gate 	 stringrep = tmp2;
1997c478bd9Sstevel@tonic-gate      } else {
200ab9b2e15Sgtb 	 xfree(tmp);
201ab9b2e15Sgtb 	 krb5_free_context(context);
2027c478bd9Sstevel@tonic-gate 	 return(GSS_S_BAD_NAMETYPE);
2037c478bd9Sstevel@tonic-gate       }
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate       /* at this point, stringrep is set, or if not, *minor_status is. */
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate       if (stringrep)
2087c478bd9Sstevel@tonic-gate 	 code = krb5_parse_name(context, (char *) stringrep, &princ);
2097c478bd9Sstevel@tonic-gate       else {
2107c478bd9Sstevel@tonic-gate       fail_name:
211*5e01956fSGlenn Barry 	  xfree(tmp);
212*5e01956fSGlenn Barry 	  if (tmp2)
2137c478bd9Sstevel@tonic-gate 		 xfree(tmp2);
214*5e01956fSGlenn Barry 
215*5e01956fSGlenn Barry 	  /* Solaris Kerberos: spruce-up (not much, sigh) the err msg */
216*5e01956fSGlenn Barry 	  krb5_set_error_message(context, *minor_status,
217*5e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
218*5e01956fSGlenn Barry 					"Failed to convert the specified principal to GSS-API internal format"));
219*5e01956fSGlenn Barry 	  save_error_info(*minor_status, context);
220*5e01956fSGlenn Barry 
221*5e01956fSGlenn Barry 	  krb5_free_context(context);
222*5e01956fSGlenn Barry 	  return(GSS_S_BAD_NAME);
2237c478bd9Sstevel@tonic-gate       }
224ab9b2e15Sgtb 
2257c478bd9Sstevel@tonic-gate       if (tmp2)
2267c478bd9Sstevel@tonic-gate 	      xfree(tmp2);
2277c478bd9Sstevel@tonic-gate       xfree(tmp);
2287c478bd9Sstevel@tonic-gate    }
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate    /* at this point, a krb5 function has been called to set princ.  code
2317c478bd9Sstevel@tonic-gate       contains the return status */
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate    if (code) {
234*5e01956fSGlenn Barry        /* Solaris Kerberos: spruce-up the err msg */
235*5e01956fSGlenn Barry        *minor_status = (OM_uint32) code;
236*5e01956fSGlenn Barry        /* krb5_sname_to_principal() sets specific err msg for bad hostname. */
237*5e01956fSGlenn Barry        if (*minor_status != (OM_uint32)KRB5_ERR_BAD_HOSTNAME)
238*5e01956fSGlenn Barry 	    krb5_set_error_message(context, *minor_status,
239*5e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
240*5e01956fSGlenn Barry 				  "Failed to convert the specified principal to GSS-API internal format: %s"),
241*5e01956fSGlenn Barry 				error_message(code));
242*5e01956fSGlenn Barry        save_error_info(*minor_status, context);
243*5e01956fSGlenn Barry        krb5_free_context(context);
244*5e01956fSGlenn Barry        return(GSS_S_BAD_NAME);
2457c478bd9Sstevel@tonic-gate    }
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate    /* save the name in the validation database */
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate    if (! kg_save_name((gss_name_t) princ)) {
2507c478bd9Sstevel@tonic-gate       krb5_free_principal(context, princ);
251ab9b2e15Sgtb       krb5_free_context(context);
2527c478bd9Sstevel@tonic-gate       *minor_status = (OM_uint32) G_VALIDATE_FAILED;
2537c478bd9Sstevel@tonic-gate       return(GSS_S_FAILURE);
2547c478bd9Sstevel@tonic-gate    }
2557c478bd9Sstevel@tonic-gate 
256ab9b2e15Sgtb    krb5_free_context(context);
257ab9b2e15Sgtb 
2587c478bd9Sstevel@tonic-gate    /* return it */
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate    *output_name = (gss_name_t) princ;
2617c478bd9Sstevel@tonic-gate    return(GSS_S_COMPLETE);
2627c478bd9Sstevel@tonic-gate }
263