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 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <ctype.h> 34 #include "gsscred.h" 35 36 /* 37 * gsscred utility 38 * Manages mapping between a security principal name and unix uid. 39 * Implementation file for the file based gsscred utility. 40 */ 41 42 #define MAX_ENTRY_LEN 1024 43 static const char credFile[] = "/etc/gss/gsscred_db"; 44 static const char credFileTmp[] = "/etc/gss/gsscred_db.tmp"; 45 static const int expNameTokIdLen = 2; 46 static const int mechOidLenLen = 2; 47 static const int mechOidTagLen = 1; 48 49 static int matchEntry(const char *entry, const gss_buffer_t name, 50 const char *uid, uid_t *uidOut); 51 52 /* From g_glue.c */ 53 extern int 54 get_der_length(unsigned char **, unsigned int, unsigned int *); 55 56 /* 57 * file_addGssCredEntry 58 * 59 * Adds a new entry to the gsscred table. 60 * Does not check for duplicate entries. 61 */ 62 int file_addGssCredEntry(const gss_buffer_t hexName, const char *uid, 63 const char *comment, char **errDetails) 64 { 65 FILE *fp; 66 char tmpBuf[256]; 67 68 if ((fp = fopen(credFile, "a")) == NULL) { 69 if (errDetails) { 70 (void) snprintf(tmpBuf, sizeof (tmpBuf), 71 gettext("Unable to open gsscred file [%s]"), 72 credFile); 73 *errDetails = strdup(tmpBuf); 74 } 75 return (0); 76 } 77 78 (void) fprintf(fp, 79 "%s\t%s\t%s\n", (char *)hexName->value, uid, comment); 80 (void) fclose(fp); 81 return (1); 82 } /* ******* file_addGssCredEntry ****** */ 83 84 85 86 /* 87 * file_getGssCredEntry 88 * 89 * Searches the file for the file matching the name. Since the name 90 * contains a mechanism identifier, to search for all names for a given 91 * mechanism just supply the mechanism portion in the name buffer. 92 * To search by uid only, supply a non-null value of uid. 93 */ 94 int file_getGssCredEntry(const gss_buffer_t name, const char *uid, 95 char **errDetails) 96 { 97 FILE *fp; 98 char entry[MAX_ENTRY_LEN+1]; 99 100 if ((fp = fopen(credFile, "r")) == NULL) { 101 102 if (errDetails) { 103 (void) snprintf(entry, sizeof (entry), 104 gettext("Unable to open gsscred file [%s]"), 105 credFile); 106 *errDetails = strdup(entry); 107 } 108 109 return (0); 110 } 111 112 /* go through the file in sequential order */ 113 while (fgets(entry, MAX_ENTRY_LEN, fp) != NULL) { 114 /* is there any search criteria */ 115 if (name == NULL && uid == NULL) { 116 (void) fprintf(stdout, "%s", entry); 117 continue; 118 } 119 120 if (matchEntry(entry, name, uid, NULL)) 121 (void) fprintf(stdout, "%s", entry); 122 123 } /* while */ 124 125 (void) fclose(fp); 126 return (1); 127 } /* file_getGssCredEntry */ 128 129 /* 130 * file_getGssCredUid 131 * 132 * GSS entry point for retrieving user uid information. 133 * We need to go through the entire file to ensure that 134 * the last matching entry is retrieved - this is because 135 * new entries are added to the end, and in case of 136 * duplicates we want to get the latest entry. 137 */ 138 int 139 file_getGssCredUid(const gss_buffer_t expName, uid_t *uidOut) 140 { 141 FILE *fp; 142 char entry[MAX_ENTRY_LEN+1]; 143 int retVal = 0; 144 145 if ((fp = fopen(credFile, "r")) == NULL) 146 return (0); 147 148 /* go through the entire file in sequential order */ 149 while (fgets(entry, MAX_ENTRY_LEN, fp) != NULL) { 150 if (matchEntry(entry, expName, NULL, uidOut)) { 151 retVal = 1; 152 } 153 } /* while */ 154 155 (void) fclose(fp); 156 return (retVal); 157 } /* file_getGssCredUid */ 158 159 160 161 /* 162 * 163 * file_deleteGssCredEntry 164 * 165 * removes entries form file that match the delete criteria 166 */ 167 int file_deleteGssCredEntry(const gss_buffer_t name, const char *uid, 168 char **errDetails) 169 { 170 FILE *fp, *tempFp; 171 char entry[MAX_ENTRY_LEN+1]; 172 int foundOne = 0; 173 174 /* are we deleting everyone? */ 175 if (name == NULL && uid == NULL) { 176 177 if ((fp = fopen(credFile, "w")) == NULL) { 178 179 if (errDetails) { 180 (void) snprintf(entry, sizeof (entry), 181 gettext("Unable to open gsscred" 182 " file [%s]"), 183 credFile); 184 *errDetails = strdup(entry); 185 } 186 return (0); 187 } 188 189 (void) fclose(fp); 190 return (1); 191 } 192 193 /* selective delete - might still be everyone */ 194 if ((fp = fopen(credFile, "r")) == NULL) { 195 196 if (errDetails) { 197 (void) snprintf(entry, sizeof (entry), 198 gettext("Unable to open gsscred file [%s]"), 199 credFile); 200 *errDetails = strdup(entry); 201 } 202 return (0); 203 } 204 205 /* also need to open temp file */ 206 if ((tempFp = fopen(credFileTmp, "w")) == NULL) { 207 if (errDetails) { 208 (void) snprintf(entry, sizeof (entry), 209 gettext("Unable to open gsscred temporary" 210 " file [%s]"), 211 credFileTmp); 212 *errDetails = strdup(entry); 213 } 214 215 (void) fclose(fp); 216 return (0); 217 } 218 219 /* go through all the entries sequentially removing ones that match */ 220 while (fgets(entry, MAX_ENTRY_LEN, fp) != NULL) { 221 222 if (!matchEntry(entry, name, uid, NULL)) 223 (void) fputs(entry, tempFp); 224 else 225 foundOne = 1; 226 } 227 (void) fclose(tempFp); 228 (void) fclose(fp); 229 230 /* now make the tempfile the gsscred file */ 231 (void) rename(credFileTmp, credFile); 232 (void) unlink(credFileTmp); 233 234 if (!foundOne) { 235 *errDetails = strdup(gettext("No users found")); 236 return (0); 237 } 238 return (1); 239 } /* file_deleteGssCredEntry */ 240 241 242 243 /* 244 * 245 * match entry 246 * 247 * checks if the specified entry matches the supplied criteria 248 * returns 1 if yes, 0 if no 249 * uidOut value can be used to retrieve the uid from the entry 250 * when the uid string is passed in, the uidOut value is not set 251 */ 252 static int matchEntry(const char *entry, const gss_buffer_t name, 253 const char *uid, uid_t *uidOut) 254 { 255 char fullEntry[MAX_ENTRY_LEN+1], *item; 256 unsigned char *buf; 257 char dilims[] = "\t \n"; 258 int length; 259 unsigned int dummy; 260 OM_uint32 minor, result; 261 gss_buffer_desc mechOidDesc = GSS_C_EMPTY_BUFFER; 262 gss_name_t intName; 263 gss_buffer_desc expName; 264 char *krb5_oid = "\052\206\110\206\367\022\001\002\002"; 265 266 if (entry == NULL || isspace(*entry)) 267 return (0); 268 269 /* save the entry since strtok will chop it up */ 270 (void) strcpy(fullEntry, entry); 271 272 if ((item = strtok(fullEntry, dilims)) == NULL) 273 return (0); 274 275 /* do wee need to search the name */ 276 if (name != NULL) { 277 /* we can match the prefix of the string */ 278 if (strlen(item) < name->length) 279 return (0); 280 281 if (memcmp(item, name->value, name->length) != 0) { 282 283 buf = (unsigned char *)name->value; 284 buf += expNameTokIdLen; 285 286 /* skip oid length - get to der */ 287 buf += 2; 288 289 /* skip oid tag */ 290 buf++; 291 292 /* get oid length */ 293 length = get_der_length(&buf, 294 (name->length - expNameTokIdLen 295 - mechOidLenLen - mechOidTagLen), &dummy); 296 297 if (length == -1) 298 return (0); 299 300 mechOidDesc.length = length; 301 302 /* 303 * check whether exported name length is within the 304 * boundary. 305 */ 306 if (name->length < 307 (expNameTokIdLen + mechOidLenLen + length 308 + dummy + mechOidTagLen)) 309 return (0); 310 311 mechOidDesc.value = buf; 312 313 buf += dummy + mechOidDesc.length; 314 315 /* 316 * If the mechoid is that of Kerberos and if the 317 * "display" part of the exported file name starts and 318 * ends with a zero-valued byte, then we are dealing 319 * with old styled gsscred entries. We will then match 320 * them in the following manner: 321 * - gss_import_name() the name from the file 322 * - gss_export_name() the result 323 * - mem_cmp() the result with the name we are 324 * trying to match. 325 */ 326 if (mechOidDesc.length == 9 && 327 (memcmp(buf, krb5_oid, 328 mechOidDesc.length) == 0) && 329 (*buf == '\0' && buf[length] == '\0')) { 330 if (gss_import_name(&minor, name, 331 GSS_C_NT_EXPORT_NAME, 332 &intName) != GSS_S_COMPLETE) 333 return (0); 334 result = gss_export_name(&minor, intName, 335 &expName); 336 (void) gss_release_name(&minor, &intName); 337 if (result != GSS_S_COMPLETE) 338 return (0); 339 result = memcmp(item, expName.value, 340 expName.length); 341 (void) gss_release_buffer(&minor, &expName); 342 if (result != 0) 343 return (0); 344 } 345 } 346 347 /* do we need to check the uid - if not then we found it */ 348 if (uid == NULL) { 349 /* do we ned to parse out the uid ? */ 350 if (uidOut) { 351 if ((item = strtok(NULL, dilims)) == NULL) 352 return (0); 353 *uidOut = atol(item); 354 } 355 return (1); 356 } 357 358 /* continue with checking the uid */ 359 } 360 361 if (uid == NULL) 362 return (1); 363 364 /* get the next token from the string - the uid */ 365 if ((item = strtok(NULL, dilims)) == NULL) 366 return (0); 367 368 if (strcmp(item, uid) == 0) 369 return (1); 370 371 return (0); 372 } /* ******* matchEntry ****** */ 373