1 /*
2  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Copyright 1993 by OpenVision Technologies, Inc.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software
8  * and its documentation for any purpose is hereby granted without fee,
9  * provided that the above copyright notice appears in all copies and
10  * that both that copyright notice and this permission notice appear in
11  * supporting documentation, and that the name of OpenVision not be used
12  * in advertising or publicity pertaining to distribution of the software
13  * without specific, written prior permission. OpenVision makes no
14  * representations about the suitability of this software for any
15  * purpose.  It is provided "as is" without express or implied warranty.
16  *
17  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
21  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
22  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23  * PERFORMANCE OF THIS SOFTWARE.
24  */
25 
26 /*
27  * $Id: import_name.c 18015 2006-05-17 05:26:12Z raeburn $
28  */
29 
30 #include "gssapiP_krb5.h"
31 
32 #ifndef NO_PASSWORD
33 #include <pwd.h>
34 #include <stdio.h>
35 #endif
36 
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #else
40 #include <strings.h>
41 #endif
42 #include <locale.h>
43 
44 /*
45  * errors:
46  * GSS_S_BAD_NAMETYPE	if the type is bogus
47  * GSS_S_BAD_NAME	if the type is good but the name is bogus
48  * GSS_S_FAILURE	if memory allocation fails
49  */
50 
51 OM_uint32
krb5_gss_import_name(minor_status,input_name_buffer,input_name_type,output_name)52 krb5_gss_import_name(minor_status, input_name_buffer,
53 		     input_name_type, output_name)
54      OM_uint32 *minor_status;
55      gss_buffer_t input_name_buffer;
56      gss_OID input_name_type;
57      gss_name_t *output_name;
58 {
59    krb5_context context;
60    krb5_principal princ;
61    krb5_error_code code;
62    char *stringrep, *tmp, *tmp2, *cp;
63    OM_uint32	length;
64 #ifndef NO_PASSWORD
65    struct passwd *pw;
66 #endif
67 
68    code = krb5_gss_init_context(&context);
69    if (code) {
70        *minor_status = code;
71        return GSS_S_FAILURE;
72    }
73 
74    /* set up default returns */
75 
76    *output_name = NULL;
77    *minor_status = 0;
78 
79    /* Go find the appropriate string rep to pass into parse_name */
80 
81    if ((input_name_type != GSS_C_NULL_OID) &&
82        (g_OID_equal(input_name_type, gss_nt_service_name) ||
83 	g_OID_equal(input_name_type, gss_nt_service_name_v2))) {
84       char *service, *host;
85 
86       if ((tmp =
87 	   (char *) xmalloc(input_name_buffer->length + 1)) == NULL) {
88 	 *minor_status = ENOMEM;
89 	 krb5_free_context(context);
90 	 return(GSS_S_FAILURE);
91       }
92 
93       memcpy(tmp, input_name_buffer->value, input_name_buffer->length);
94       tmp[input_name_buffer->length] = 0;
95 
96       service = tmp;
97       if ((host = strchr(tmp, '@'))) {
98 	 *host = '\0';
99 	 host++;
100       }
101 
102       code = krb5_sname_to_principal(context, host, service, KRB5_NT_SRV_HST,
103 				     &princ);
104 
105       xfree(tmp);
106    } else if ((input_name_type != GSS_C_NULL_OID) &&
107 	      (g_OID_equal(input_name_type, gss_nt_krb5_principal))) {
108        krb5_principal input;
109 
110        if (input_name_buffer->length != sizeof(krb5_principal)) {
111 	   *minor_status = (OM_uint32) G_WRONG_SIZE;
112 	   /* Solaris Kerberos: spruce-up the err msg */
113 	   krb5_set_error_message(context, *minor_status,
114 				dgettext(TEXT_DOMAIN,
115 					"The size of the specified principal is wrong"));
116 	   save_error_info(*minor_status, context);
117 	   krb5_free_context(context);
118 	   return(GSS_S_BAD_NAME);
119       }
120 
121       input = *((krb5_principal *) input_name_buffer->value);
122 
123       if ((code = krb5_copy_principal(context, input, &princ))) {
124 	 *minor_status = code;
125 	 save_error_info(*minor_status, context);
126 	 krb5_free_context(context);
127 	 return(GSS_S_FAILURE);
128       }
129    } else {
130 #ifndef NO_PASSWORD
131       uid_t uid;
132       struct passwd pwx;
133       char pwbuf[BUFSIZ];
134 #endif
135 
136       stringrep = NULL;
137 
138       if ((tmp =
139 	   (char *) xmalloc(input_name_buffer->length + 1)) == NULL) {
140 	 *minor_status = ENOMEM;
141 	 krb5_free_context(context);
142 	 return(GSS_S_FAILURE);
143       }
144       tmp2 = 0;
145 
146       memcpy(tmp, input_name_buffer->value, input_name_buffer->length);
147       tmp[input_name_buffer->length] = 0;
148 
149       if ((input_name_type == GSS_C_NULL_OID) ||
150 	  g_OID_equal(input_name_type, gss_nt_krb5_name) ||
151 	  g_OID_equal(input_name_type, gss_nt_user_name)) {
152 	 stringrep = (char *) tmp;
153 #ifndef NO_PASSWORD
154       } else if (g_OID_equal(input_name_type, gss_nt_machine_uid_name)) {
155 	 uid = *(uid_t *) input_name_buffer->value;
156       do_getpwuid:
157 	 if (k5_getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) == 0)
158 	     stringrep = pw->pw_name;
159 	 else
160 	    *minor_status = (OM_uint32) G_NOUSER;
161       } else if (g_OID_equal(input_name_type, gss_nt_string_uid_name)) {
162 	 uid = atoi(tmp);
163 	 goto do_getpwuid;
164 #endif
165       } else if (g_OID_equal(input_name_type, gss_nt_exported_name)) {
166 	 cp = tmp;
167 	 if (*cp++ != 0x04)
168 		 goto fail_name;
169 	 if (*cp++ != 0x01)
170 		 goto fail_name;
171 	 if (*cp++ != 0x00)
172 		 goto fail_name;
173 	 length = *cp++;
174 	 if (length != gss_mech_krb5->length+2)
175 		 goto fail_name;
176 	 if (*cp++ != 0x06)
177 		 goto fail_name;
178 	 length = *cp++;
179 	 if (length != gss_mech_krb5->length)
180 		 goto fail_name;
181 	 if (memcmp(cp, gss_mech_krb5->elements, length) != 0)
182 		 goto fail_name;
183 	 cp += length;
184 	 length = *cp++;
185 	 length = (length << 8) | *cp++;
186 	 length = (length << 8) | *cp++;
187 	 length = (length << 8) | *cp++;
188 	 tmp2 = malloc(length+1);
189 	 if (tmp2 == NULL) {
190 		 xfree(tmp);
191 		 *minor_status = ENOMEM;
192 		 krb5_free_context(context);
193 		 return GSS_S_FAILURE;
194 	 }
195 	 strncpy(tmp2, cp, length);
196 	 tmp2[length] = 0;
197 
198 	 stringrep = tmp2;
199      } else {
200 	 xfree(tmp);
201 	 krb5_free_context(context);
202 	 return(GSS_S_BAD_NAMETYPE);
203       }
204 
205       /* at this point, stringrep is set, or if not, *minor_status is. */
206 
207       if (stringrep)
208 	 code = krb5_parse_name(context, (char *) stringrep, &princ);
209       else {
210       fail_name:
211 	  xfree(tmp);
212 	  if (tmp2)
213 		 xfree(tmp2);
214 
215 	  /* Solaris Kerberos: spruce-up (not much, sigh) the err msg */
216 	  krb5_set_error_message(context, *minor_status,
217 				dgettext(TEXT_DOMAIN,
218 					"Failed to convert the specified principal to GSS-API internal format"));
219 	  save_error_info(*minor_status, context);
220 
221 	  krb5_free_context(context);
222 	  return(GSS_S_BAD_NAME);
223       }
224 
225       if (tmp2)
226 	      xfree(tmp2);
227       xfree(tmp);
228    }
229 
230    /* at this point, a krb5 function has been called to set princ.  code
231       contains the return status */
232 
233    if (code) {
234        /* Solaris Kerberos: spruce-up the err msg */
235        *minor_status = (OM_uint32) code;
236        /* krb5_sname_to_principal() sets specific err msg for bad hostname. */
237        if (*minor_status != (OM_uint32)KRB5_ERR_BAD_HOSTNAME)
238 	    krb5_set_error_message(context, *minor_status,
239 				dgettext(TEXT_DOMAIN,
240 				  "Failed to convert the specified principal to GSS-API internal format: %s"),
241 				error_message(code));
242        save_error_info(*minor_status, context);
243        krb5_free_context(context);
244        return(GSS_S_BAD_NAME);
245    }
246 
247    /* save the name in the validation database */
248 
249    if (! kg_save_name((gss_name_t) princ)) {
250       krb5_free_principal(context, princ);
251       krb5_free_context(context);
252       *minor_status = (OM_uint32) G_VALIDATE_FAILED;
253       return(GSS_S_FAILURE);
254    }
255 
256    krb5_free_context(context);
257 
258    /* return it */
259 
260    *output_name = (gss_name_t) princ;
261    return(GSS_S_COMPLETE);
262 }
263