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