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