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