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
51OM_uint32
52krb5_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