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