1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23 /*
24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28 #pragma ident "%Z%%M% %I% %E% SMI"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include <strings.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <syslog.h>
38 #include <gssapi/gssapi.h>
39 #include <gssapi/gssapi_ext.h>
40 #include <rpc/rpc.h>
41 #include <rpc/rpcsec_defs.h>
42
43 #define SVC_INTEGRITY "integrity"
44 #define SVC_PRIVACY "privacy"
45 #define SVC_NONE "none"
46 #define SVC_DEFAULT "default"
47
48 #define MCALL_MSG_SIZE 24
49 /*
50 * Private data kept per client handle
51 */
52 struct cu_data {
53 int cu_fd; /* connections fd */
54 bool_t cu_closeit; /* opened by library */
55 struct netbuf cu_raddr; /* remote address */
56 struct timeval cu_wait; /* retransmit interval */
57 struct timeval cu_total; /* total time for the call */
58 struct rpc_err cu_error;
59 struct t_unitdata *cu_tr_data;
60 XDR cu_outxdrs;
61 char *cu_outbuf_start;
62 char cu_outbuf[MCALL_MSG_SIZE];
63 uint_t cu_xdrpos;
64 uint_t cu_sendsz; /* send size */
65 uint_t cu_recvsz; /* recv size */
66 struct pollfd pfdp;
67 char cu_inbuf[1];
68 };
69
70 /*
71 * Internal utility routines.
72 */
73 bool_t
__rpc_gss_mech_to_oid(char * mech,rpc_gss_OID * oid)74 __rpc_gss_mech_to_oid(char *mech, rpc_gss_OID *oid)
75 {
76 if (__gss_mech_to_oid(mech, (gss_OID*)oid) != GSS_S_COMPLETE)
77 return (FALSE);
78 return (TRUE);
79 }
80
81 char *
__rpc_gss_oid_to_mech(rpc_gss_OID oid)82 __rpc_gss_oid_to_mech(rpc_gss_OID oid)
83 {
84 return ((char *)__gss_oid_to_mech((const gss_OID)oid));
85 }
86
87
88 bool_t
__rpc_gss_qop_to_num(char * qop,char * mech,OM_uint32 * num)89 __rpc_gss_qop_to_num(char *qop, char *mech, OM_uint32 *num)
90 {
91 if (__gss_qop_to_num(qop, mech, num) != GSS_S_COMPLETE)
92 return (FALSE);
93 return (TRUE);
94 }
95
96 char *
__rpc_gss_num_to_qop(char * mech,OM_uint32 num)97 __rpc_gss_num_to_qop(char *mech, OM_uint32 num)
98 {
99 char *qop;
100
101 if (__gss_num_to_qop(mech, num, &qop) != GSS_S_COMPLETE)
102 return (NULL);
103 return (qop);
104 }
105
106 bool_t
__rpc_gss_svc_to_num(char * svc,rpc_gss_service_t * num)107 __rpc_gss_svc_to_num(char *svc, rpc_gss_service_t *num)
108 {
109 if (strcasecmp(svc, SVC_INTEGRITY) == 0)
110 *num = rpc_gss_svc_integrity;
111 else if (strcasecmp(svc, SVC_PRIVACY) == 0)
112 *num = rpc_gss_svc_privacy;
113 else if (strcasecmp(svc, SVC_NONE) == 0)
114 *num = rpc_gss_svc_none;
115 else if (strcasecmp(svc, SVC_DEFAULT) == 0)
116 *num = rpc_gss_svc_default;
117 else
118 return (FALSE);
119 return (TRUE);
120 }
121
122 char *
__rpc_gss_num_to_svc(rpc_gss_service_t num)123 __rpc_gss_num_to_svc(rpc_gss_service_t num)
124 {
125 switch (num) {
126 case rpc_gss_svc_integrity:
127 return (strdup(SVC_INTEGRITY));
128 case rpc_gss_svc_privacy:
129 return (strdup(SVC_PRIVACY));
130 case rpc_gss_svc_none:
131 return (strdup(SVC_NONE));
132 case rpc_gss_svc_default:
133 return (strdup(SVC_DEFAULT));
134 default:
135 return (NULL);
136 }
137 }
138
139 /*
140 * Given the user name, node, and security domain, get the mechanism
141 * specific principal name (for the user name) in exported form.
142 */
143 bool_t
__rpc_gss_get_principal_name(rpc_gss_principal_t * principal,char * mech,char * user,char * node,char * secdomain)144 __rpc_gss_get_principal_name(rpc_gss_principal_t *principal, char *mech,
145 char *user, char *node, char *secdomain)
146 {
147 gss_name_t gss_name, gss_canon_name;
148 gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER;
149 char user_name[256], *s;
150 gss_OID mech_oid;
151 int nlen = 0, slen = 0, plen;
152 OM_uint32 major, minor;
153
154 *principal = NULL;
155 if (user == NULL || strlen(user) == 0)
156 return (FALSE);
157
158 if (!__rpc_gss_mech_to_oid(mech, (rpc_gss_OID *) &mech_oid)) {
159 syslog(LOG_ERR, "rpc_gss_get_principal_name: can't get"
160 "mech oid");
161 return (FALSE);
162 }
163
164 if (secdomain != NULL)
165 slen = strlen(secdomain);
166
167 if (node != NULL)
168 nlen = strlen(node);
169
170 strcpy(user_name, user);
171 if (nlen > 0) {
172 strcat(user_name, "/");
173 strcat(user_name, node);
174 }
175
176 if (slen > 0) {
177 strcat(user_name, "@");
178 strcat(user_name, secdomain);
179 }
180
181 name_buf.value = user_name;
182 name_buf.length = strlen(user_name);
183
184 /*
185 * Convert a text string to a GSSAPI Internal name.
186 */
187 if ((major = gss_import_name(&minor, &name_buf,
188 (gss_OID) GSS_C_NT_USER_NAME, &gss_name)) != GSS_S_COMPLETE) {
189 syslog(LOG_ERR, "rpc_gss_get_principal_name: import name"
190 "failed 0x%x", major);
191 return (FALSE);
192 }
193
194 /*
195 * Convert the GSSAPI Internal name to a MN - Mechanism Name
196 */
197 if ((major = gss_canonicalize_name(&minor, gss_name, mech_oid,
198 &gss_canon_name)) != GSS_S_COMPLETE) {
199 syslog(LOG_ERR, "rpc_gss_get_principal_name: canonicalize name"
200 "failed 0x%x", major);
201 gss_release_name(&minor, &gss_name);
202 return (FALSE);
203 }
204 gss_release_name(&minor, &gss_name);
205
206 /*
207 * Convert the MN Internal name to an exported flat name, so
208 * it is suitable for binary comparison.
209 */
210 if ((major = gss_export_name(&minor, gss_canon_name, &name_buf)) !=
211 GSS_S_COMPLETE) {
212 syslog(LOG_ERR, "rpc_gss_get_principal_name: export name"
213 "failed %x", major);
214 gss_release_name(&minor, &gss_canon_name);
215 return (FALSE);
216 }
217 gss_release_name(&minor, &gss_canon_name);
218
219 /*
220 * Put the exported name into rpc_gss_principal_t structure.
221 */
222 plen = RNDUP(name_buf.length) + sizeof (int);
223 (*principal) = malloc(plen);
224 if ((*principal) == NULL) {
225 gss_release_buffer(&minor, &name_buf);
226 return (FALSE);
227 }
228 bzero((caddr_t)(*principal), plen);
229 (*principal)->len = RNDUP(name_buf.length);
230 s = (*principal)->name;
231 memcpy(s, name_buf.value, name_buf.length);
232 gss_release_buffer(&minor, &name_buf);
233
234 return (TRUE);
235 }
236
237 /*
238 * Return supported mechanisms.
239 */
240 char **
__rpc_gss_get_mechanisms(void)241 __rpc_gss_get_mechanisms(void)
242 {
243 static char *mech_list[MAX_MECH_OID_PAIRS+1];
244
245 *mech_list = NULL;
246 __gss_get_mechanisms(mech_list, MAX_MECH_OID_PAIRS+1);
247 return (mech_list);
248 }
249
250 /*
251 * For a given mechanism, return information about it.
252 */
253 /*
254 * static char *krb5_qop_list[] = {Q_DEFAULT, NULL};
255 */
256
257 /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
258 /* Don't know how to get the service type for a given mech. */
259 /* "service" should NOT be there! */
260 /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*!!!!!!!!!!! */
261
262 char **
__rpc_gss_get_mech_info(char * mech,rpc_gss_service_t * service)263 __rpc_gss_get_mech_info(char *mech, rpc_gss_service_t *service)
264 {
265 char **l;
266
267 l = calloc(MAX_QOPS_PER_MECH + 1, sizeof (char *));
268 if (l == NULL)
269 return (NULL);
270
271 if (__gss_get_mech_info(mech, l) != GSS_S_COMPLETE) {
272 free(l);
273 return (NULL);
274 }
275 /* !!!!!!!!!!!!!!!! */
276 *service = rpc_gss_svc_privacy; /* What service type? */
277 /* !!!!!!!!!!!!!!!! */
278 return (l);
279 }
280
281 /*
282 * Returns highest and lowest versions of RPCSEC_GSS flavor supported.
283 */
284 bool_t
__rpc_gss_get_versions(uint_t * vers_hi,uint_t * vers_lo)285 __rpc_gss_get_versions(uint_t *vers_hi, uint_t *vers_lo)
286 {
287 *vers_hi = RPCSEC_GSS_VERSION;
288 *vers_lo = RPCSEC_GSS_VERSION;
289 return (TRUE);
290 }
291
292 /*
293 * Check if a mechanism is installed.
294 */
295 bool_t
__rpc_gss_is_installed(char * mech)296 __rpc_gss_is_installed(char *mech)
297 {
298 char **l;
299
300 if (mech == NULL)
301 return (FALSE);
302
303 if ((l = __rpc_gss_get_mechanisms()) == NULL)
304 return (FALSE);
305
306 while (*l != NULL) {
307 if (strcmp(*l, mech) == 0)
308 return (TRUE);
309 l++;
310 }
311 return (FALSE);
312 }
313