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 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 * 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 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 * 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 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 * 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 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 ** 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 ** 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 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 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