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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * This contains miscellaneous functions moved from commands to the library. 29 */ 30 31 #include "mt.h" 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <syslog.h> 35 #include <string.h> 36 #include <unistd.h> 37 #include <gssapi/gssapi.h> 38 #include <rpc/rpc.h> 39 #include <rpcsvc/nis.h> 40 #include <rpcsvc/nis_dhext.h> 41 #include <rpc/auth.h> 42 #include <rpc/auth_sys.h> 43 #include <rpc/auth_des.h> 44 #include <rpc/key_prot.h> 45 #include <netdir.h> 46 #include <netconfig.h> 47 #include <sys/socket.h> 48 #include <netinet/in.h> 49 #include <netdb.h> 50 #include <dlfcn.h> 51 #include <gssapi/gssapi.h> 52 53 extern int bin2hex(int len, unsigned char *binnum, char *hexnum); 54 extern int hex2bin(int len, char *hexnum, char *binnum); 55 56 #define MECH_LIB_PREFIX1 "/usr/lib/" 57 58 #ifdef _LP64 59 60 #define MECH_LIB_PREFIX2 "64/" 61 62 #else /* _LP64 */ 63 64 #define MECH_LIB_PREFIX2 "" 65 66 #endif /* _LP64 */ 67 68 #define MECH_LIB_DIR "gss/" 69 70 #define MECH_LIB_PREFIX MECH_LIB_PREFIX1 MECH_LIB_PREFIX2 71 72 #define MECHDH MECH_LIB_PREFIX MECH_LIB_DIR "mech_dh.so.1" 73 #define LIBGSS MECH_LIB_PREFIX "libgss.so.1" 74 75 static gss_OID_desc __dh_gss_c_nt_netname = { 76 9, "\053\006\004\001\052\002\032\001\001" 77 }; 78 79 mutex_t gss_load_lock = DEFAULTMUTEX; 80 static gss_OID GSS_EXPORT_NAME = 0; 81 static gss_OID DH_NETNAME = &__dh_gss_c_nt_netname; 82 83 typedef OM_uint32 (*gss_fptr)(); 84 OM_uint32 (*g_import_name)(); 85 OM_uint32 (*g_display_name)(); 86 OM_uint32 (*g_release_name)(); 87 OM_uint32 (*g_release_buffer)(); 88 OM_uint32 (*g_release_oid)(); 89 90 /* 91 * gss_OID_load() 92 * 93 * This routine is called by __nis_gssprin2netname to define values for 94 * the gss-api-export-name OID, the Diffie-Hellman netname OID, and 95 * the gss support routines that it needs. 96 * The reason for this support routine is that libnsl cannot have an 97 * explicit dependency on libgss. Callers of __nisgssprin2netname are 98 * expected to have loaded libgss through the rpcsec layer. The work around 99 * is to dlopen the needed shared objects and grab the symbols with dlsym. 100 * This routine opens libgss RTLD_NOLOAD. If this fails then libgss.so.1 101 * is not loaded and we return error. Otherwise it uses dlsym to 102 * defines GSS_EXPORT_NAME to have the value of GSS_C_NT_EXPORT_NAME and 103 * to assign the above fuction pointers. 104 * If this succeeds then the routine will attempt to load mech_dh.so.1 105 * and over ride DH_NETNAME with the value of __DH_GSS_C_NT_NETNAME from 106 * that shared object. We don't consider it an error if this fails because 107 * its conceivable that another mechanism backend will support the netname 108 * name type and mech_dh.so.1 not be available. 109 * 110 * Return 0 on failer, 1 on success. 111 */ 112 113 static int 114 gss_OID_load() 115 { 116 void *dh; 117 gss_OID *OIDptr; 118 int stat = 0; 119 120 (void) mutex_lock(&gss_load_lock); 121 if (GSS_EXPORT_NAME) { 122 (void) mutex_unlock(&gss_load_lock); 123 return (0); 124 } 125 126 /* if LIBGSS is not loaded return an error */ 127 if ((dh = dlopen(LIBGSS, RTLD_NOLOAD)) == NULL) { 128 (void) mutex_unlock(&gss_load_lock); 129 return (0); 130 } 131 132 OIDptr = (gss_OID *)dlsym(dh, "GSS_C_NT_EXPORT_NAME"); 133 if (OIDptr) 134 GSS_EXPORT_NAME = *OIDptr; 135 else 136 goto Done; 137 138 g_import_name = (gss_fptr)dlsym(dh, "gss_import_name"); 139 if (g_import_name == 0) 140 goto Done; 141 142 g_display_name = (gss_fptr)dlsym(dh, "gss_display_name"); 143 if (g_display_name == 0) 144 goto Done; 145 146 g_release_name = (gss_fptr)dlsym(dh, "gss_release_name"); 147 if (g_release_name == 0) 148 goto Done; 149 150 g_release_buffer = (gss_fptr)dlsym(dh, "gss_release_buffer"); 151 if (g_release_buffer == 0) 152 goto Done; 153 154 g_release_oid = (gss_fptr)dlsym(dh, "gss_release_oid"); 155 if (g_release_oid == 0) 156 goto Done; 157 158 stat = 1; 159 /* 160 * Try and get the official netname oid from mech_dh.so. 161 * If this fails will just keep our default from above. 162 */ 163 164 if ((dh = dlopen(MECHDH, RTLD_LAZY)) != NULL) { 165 166 OIDptr = (gss_OID *)dlsym(dh, "__DH_GSS_C_NT_NETNAME"); 167 if (OIDptr) 168 DH_NETNAME = *OIDptr; 169 } 170 171 Done: 172 (void) mutex_unlock(&gss_load_lock); 173 174 if (stat == 0) 175 GSS_EXPORT_NAME = 0; 176 177 return (stat); 178 } 179 180 181 /* 182 * int 183 * __nis_gssprin2netname(rpc_gss_principal_t prin, 184 * char netname[MAXNETNAMELEN+1]) 185 * 186 * This routine attempts to extract the netname from an rpc_gss_principal_t 187 * which is in { gss-api-exorted-name } format. Return 0 if a netname was 188 * found, else return -1. 189 */ 190 191 /* 192 * This routine has a dependency on libgss.so. So we will pragma weak 193 * the interfaces that we need. When this routine is called libgss 194 * should have been loaded by the rpcsec layer. We will call gss_OID_load 195 * to get the value for GSS_EXPORT_NAME. If gss_OID_load failes return -1. 196 */ 197 198 #define OID_IS_EQUAL(o1, o2) ((o1) && (o2) && \ 199 ((o1)->length == (o2)->length) && \ 200 (memcmp((o1)->elements, (o2)->elements, (o1)->length) == 0)) 201 202 int 203 __nis_gssprin2netname(rpc_gss_principal_t prin, char netname[MAXNETNAMELEN+1]) 204 { 205 gss_buffer_desc display_name; 206 gss_name_t name; 207 gss_OID name_type; 208 gss_buffer_desc expName; 209 int stat = -1; 210 OM_uint32 major, minor; 211 212 /* See if we already got the OID */ 213 if (GSS_EXPORT_NAME == 0) { 214 /* Nope. See if GSS is loaded and get the OIDs */ 215 if (!gss_OID_load()) 216 return (-1); /* if libgss.so.1 isn't loaded */ 217 } 218 219 expName.length = prin->len; 220 expName.value = prin->name; 221 222 major = (*g_import_name)(&minor, &expName, 223 (gss_OID) GSS_EXPORT_NAME, &name); 224 225 if (major == GSS_S_COMPLETE) { 226 major = (*g_display_name)(&minor, name, 227 &display_name, &name_type); 228 229 /* We're done with the gss_internal name */ 230 (void) (*g_release_name)(&minor, &name); 231 232 if (major == GSS_S_COMPLETE) { 233 /* 234 * Check if we've got a netname. If we do we copy it 235 * and make sure that its null terminated. 236 */ 237 if (OID_IS_EQUAL(DH_NETNAME, name_type)) { 238 (void) strncpy(netname, 239 (char *)display_name.value, 240 MAXNETNAMELEN); 241 netname[MAXNETNAMELEN] = '\0'; 242 stat = 0; 243 } 244 /* 245 * If there are other display formats that can 246 * be converted to netnames easily, insert here. 247 * 248 * else if (OID_IS_EQUAL(OTHER_NT_OID, name_type)) { 249 * convert2netname(display_name.value, netname); 250 * } ... 251 */ 252 253 /* Release temporty storage */ 254 (void) (*g_release_buffer)(&minor, &display_name); 255 (void) (*g_release_oid)(&minor, &name_type); 256 } 257 } 258 259 if (stat == 0) 260 return (stat); 261 262 return (stat); 263 } 264 265 /* 266 * Extract a public key given a key length and alg. type from a packed 267 * netobj containing extended Diffie-Hellman keys. 268 */ 269 char * 270 __nis_dhext_extract_pkey(netobj *no, keylen_t keylen, algtype_t algtype) 271 { 272 char *hexkey; 273 /* LINTED pointer cast */ 274 extdhkey_t *keyent = (extdhkey_t *)no->n_bytes; 275 276 /* LINTED pointer cast */ 277 while (keyent < (extdhkey_t *)(no->n_bytes + no->n_len)) { 278 char *keyoffset; 279 size_t binlen = (ntohs(keyent->keylen) + 7) / 8; 280 size_t binpadlen = ((binlen + 3) / 4) * 4; 281 size_t hexkeylen = binlen * 2 + 1; 282 283 if (keylen == ntohs(keyent->keylen) && 284 algtype == ntohs(keyent->algtype)) { 285 286 if (!(hexkey = malloc(hexkeylen))) 287 return (NULL); 288 289 (void) bin2hex(binlen, keyent->key, hexkey); 290 return (hexkey); 291 } 292 keyoffset = (char *)keyent + (sizeof (ushort_t) * 2) + 293 binpadlen; 294 /* LINTED pointer cast */ 295 keyent = (extdhkey_t *)keyoffset; 296 } 297 return (NULL); 298 } 299