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