10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*114Sdh145677 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <stdio.h> 300Sstevel@tonic-gate #include <stdlib.h> 310Sstevel@tonic-gate #include <string.h> 320Sstevel@tonic-gate #include <unistd.h> 330Sstevel@tonic-gate #include <ctype.h> 340Sstevel@tonic-gate #include "gsscred.h" 350Sstevel@tonic-gate 360Sstevel@tonic-gate /* 370Sstevel@tonic-gate * gsscred utility 380Sstevel@tonic-gate * Manages mapping between a security principal name and unix uid. 390Sstevel@tonic-gate * Implementation file for the file based gsscred utility. 400Sstevel@tonic-gate */ 410Sstevel@tonic-gate 420Sstevel@tonic-gate #define MAX_ENTRY_LEN 1024 430Sstevel@tonic-gate static const char credFile[] = "/etc/gss/gsscred_db"; 440Sstevel@tonic-gate static const char credFileTmp[] = "/etc/gss/gsscred_db.tmp"; 45*114Sdh145677 static const int expNameTokIdLen = 2; 46*114Sdh145677 static const int mechOidLenLen = 2; 47*114Sdh145677 static const int mechOidTagLen = 1; 480Sstevel@tonic-gate 490Sstevel@tonic-gate static int matchEntry(const char *entry, const gss_buffer_t name, 500Sstevel@tonic-gate const char *uid, uid_t *uidOut); 510Sstevel@tonic-gate 52*114Sdh145677 /* From g_glue.c */ 53*114Sdh145677 extern int 54*114Sdh145677 get_der_length(unsigned char **, unsigned int, unsigned int *); 55*114Sdh145677 560Sstevel@tonic-gate /* 570Sstevel@tonic-gate * file_addGssCredEntry 580Sstevel@tonic-gate * 590Sstevel@tonic-gate * Adds a new entry to the gsscred table. 600Sstevel@tonic-gate * Does not check for duplicate entries. 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate int file_addGssCredEntry(const gss_buffer_t hexName, const char *uid, 630Sstevel@tonic-gate const char *comment, char **errDetails) 640Sstevel@tonic-gate { 650Sstevel@tonic-gate FILE *fp; 660Sstevel@tonic-gate char tmpBuf[256]; 670Sstevel@tonic-gate 680Sstevel@tonic-gate if ((fp = fopen(credFile, "a")) == NULL) { 690Sstevel@tonic-gate if (errDetails) { 700Sstevel@tonic-gate (void) snprintf(tmpBuf, sizeof (tmpBuf), 710Sstevel@tonic-gate gettext("Unable to open gsscred file [%s]"), 720Sstevel@tonic-gate credFile); 730Sstevel@tonic-gate *errDetails = strdup(tmpBuf); 740Sstevel@tonic-gate } 750Sstevel@tonic-gate return (0); 760Sstevel@tonic-gate } 770Sstevel@tonic-gate 780Sstevel@tonic-gate (void) fprintf(fp, 790Sstevel@tonic-gate "%s\t%s\t%s\n", (char *)hexName->value, uid, comment); 800Sstevel@tonic-gate (void) fclose(fp); 810Sstevel@tonic-gate return (1); 820Sstevel@tonic-gate } /* ******* file_addGssCredEntry ****** */ 830Sstevel@tonic-gate 840Sstevel@tonic-gate 850Sstevel@tonic-gate 860Sstevel@tonic-gate /* 870Sstevel@tonic-gate * file_getGssCredEntry 880Sstevel@tonic-gate * 890Sstevel@tonic-gate * Searches the file for the file matching the name. Since the name 900Sstevel@tonic-gate * contains a mechanism identifier, to search for all names for a given 910Sstevel@tonic-gate * mechanism just supply the mechanism portion in the name buffer. 920Sstevel@tonic-gate * To search by uid only, supply a non-null value of uid. 930Sstevel@tonic-gate */ 940Sstevel@tonic-gate int file_getGssCredEntry(const gss_buffer_t name, const char *uid, 950Sstevel@tonic-gate char **errDetails) 960Sstevel@tonic-gate { 970Sstevel@tonic-gate FILE *fp; 980Sstevel@tonic-gate char entry[MAX_ENTRY_LEN+1]; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate if ((fp = fopen(credFile, "r")) == NULL) { 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate if (errDetails) { 1030Sstevel@tonic-gate (void) snprintf(entry, sizeof (entry), 1040Sstevel@tonic-gate gettext("Unable to open gsscred file [%s]"), 1050Sstevel@tonic-gate credFile); 1060Sstevel@tonic-gate *errDetails = strdup(entry); 1070Sstevel@tonic-gate } 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate return (0); 1100Sstevel@tonic-gate } 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate /* go through the file in sequential order */ 1130Sstevel@tonic-gate while (fgets(entry, MAX_ENTRY_LEN, fp) != NULL) { 1140Sstevel@tonic-gate /* is there any search criteria */ 1150Sstevel@tonic-gate if (name == NULL && uid == NULL) { 1160Sstevel@tonic-gate (void) fprintf(stdout, "%s", entry); 1170Sstevel@tonic-gate continue; 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate if (matchEntry(entry, name, uid, NULL)) 1210Sstevel@tonic-gate (void) fprintf(stdout, "%s", entry); 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate } /* while */ 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate (void) fclose(fp); 1260Sstevel@tonic-gate return (1); 1270Sstevel@tonic-gate } /* file_getGssCredEntry */ 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate /* 1300Sstevel@tonic-gate * file_getGssCredUid 1310Sstevel@tonic-gate * 1320Sstevel@tonic-gate * GSS entry point for retrieving user uid information. 1330Sstevel@tonic-gate * We need to go through the entire file to ensure that 1340Sstevel@tonic-gate * the last matching entry is retrieved - this is because 1350Sstevel@tonic-gate * new entries are added to the end, and in case of 1360Sstevel@tonic-gate * duplicates we want to get the latest entry. 1370Sstevel@tonic-gate */ 1380Sstevel@tonic-gate int 1390Sstevel@tonic-gate file_getGssCredUid(const gss_buffer_t expName, uid_t *uidOut) 1400Sstevel@tonic-gate { 1410Sstevel@tonic-gate FILE *fp; 1420Sstevel@tonic-gate char entry[MAX_ENTRY_LEN+1]; 1430Sstevel@tonic-gate int retVal = 0; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate if ((fp = fopen(credFile, "r")) == NULL) 1460Sstevel@tonic-gate return (0); 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate /* go through the entire file in sequential order */ 1490Sstevel@tonic-gate while (fgets(entry, MAX_ENTRY_LEN, fp) != NULL) { 1500Sstevel@tonic-gate if (matchEntry(entry, expName, NULL, uidOut)) { 1510Sstevel@tonic-gate retVal = 1; 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate } /* while */ 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate (void) fclose(fp); 1560Sstevel@tonic-gate return (retVal); 1570Sstevel@tonic-gate } /* file_getGssCredUid */ 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* 1620Sstevel@tonic-gate * 1630Sstevel@tonic-gate * file_deleteGssCredEntry 1640Sstevel@tonic-gate * 1650Sstevel@tonic-gate * removes entries form file that match the delete criteria 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate int file_deleteGssCredEntry(const gss_buffer_t name, const char *uid, 1680Sstevel@tonic-gate char **errDetails) 1690Sstevel@tonic-gate { 1700Sstevel@tonic-gate FILE *fp, *tempFp; 1710Sstevel@tonic-gate char entry[MAX_ENTRY_LEN+1]; 1720Sstevel@tonic-gate int foundOne = 0; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate /* are we deleting everyone? */ 1750Sstevel@tonic-gate if (name == NULL && uid == NULL) { 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate if ((fp = fopen(credFile, "w")) == NULL) { 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate if (errDetails) { 1800Sstevel@tonic-gate (void) snprintf(entry, sizeof (entry), 1810Sstevel@tonic-gate gettext("Unable to open gsscred" 1820Sstevel@tonic-gate " file [%s]"), 1830Sstevel@tonic-gate credFile); 1840Sstevel@tonic-gate *errDetails = strdup(entry); 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate return (0); 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate (void) fclose(fp); 1900Sstevel@tonic-gate return (1); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate /* selective delete - might still be everyone */ 1940Sstevel@tonic-gate if ((fp = fopen(credFile, "r")) == NULL) { 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate if (errDetails) { 1970Sstevel@tonic-gate (void) snprintf(entry, sizeof (entry), 1980Sstevel@tonic-gate gettext("Unable to open gsscred file [%s]"), 1990Sstevel@tonic-gate credFile); 2000Sstevel@tonic-gate *errDetails = strdup(entry); 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate return (0); 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate /* also need to open temp file */ 2060Sstevel@tonic-gate if ((tempFp = fopen(credFileTmp, "w")) == NULL) { 2070Sstevel@tonic-gate if (errDetails) { 2080Sstevel@tonic-gate (void) snprintf(entry, sizeof (entry), 2090Sstevel@tonic-gate gettext("Unable to open gsscred temporary" 2100Sstevel@tonic-gate " file [%s]"), 2110Sstevel@tonic-gate credFileTmp); 2120Sstevel@tonic-gate *errDetails = strdup(entry); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate (void) fclose(fp); 2160Sstevel@tonic-gate return (0); 2170Sstevel@tonic-gate } 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate /* go through all the entries sequentially removing ones that match */ 2200Sstevel@tonic-gate while (fgets(entry, MAX_ENTRY_LEN, fp) != NULL) { 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate if (!matchEntry(entry, name, uid, NULL)) 2230Sstevel@tonic-gate (void) fputs(entry, tempFp); 2240Sstevel@tonic-gate else 2250Sstevel@tonic-gate foundOne = 1; 2260Sstevel@tonic-gate } 2270Sstevel@tonic-gate (void) fclose(tempFp); 2280Sstevel@tonic-gate (void) fclose(fp); 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* now make the tempfile the gsscred file */ 2310Sstevel@tonic-gate (void) rename(credFileTmp, credFile); 2320Sstevel@tonic-gate (void) unlink(credFileTmp); 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate if (!foundOne) { 2350Sstevel@tonic-gate *errDetails = strdup(gettext("No users found")); 2360Sstevel@tonic-gate return (0); 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate return (1); 2390Sstevel@tonic-gate } /* file_deleteGssCredEntry */ 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate /* 2440Sstevel@tonic-gate * 2450Sstevel@tonic-gate * match entry 2460Sstevel@tonic-gate * 2470Sstevel@tonic-gate * checks if the specified entry matches the supplied criteria 2480Sstevel@tonic-gate * returns 1 if yes, 0 if no 2490Sstevel@tonic-gate * uidOut value can be used to retrieve the uid from the entry 2500Sstevel@tonic-gate * when the uid string is passed in, the uidOut value is not set 2510Sstevel@tonic-gate */ 2520Sstevel@tonic-gate static int matchEntry(const char *entry, const gss_buffer_t name, 2530Sstevel@tonic-gate const char *uid, uid_t *uidOut) 2540Sstevel@tonic-gate { 255110Sdduvall char fullEntry[MAX_ENTRY_LEN+1], *item; 256*114Sdh145677 unsigned char *buf; 2570Sstevel@tonic-gate char dilims[] = "\t \n"; 258*114Sdh145677 int length; 259*114Sdh145677 unsigned int dummy; 260*114Sdh145677 OM_uint32 minor, result; 261*114Sdh145677 gss_buffer_desc mechOidDesc = GSS_C_EMPTY_BUFFER; 262*114Sdh145677 gss_name_t intName; 263*114Sdh145677 gss_buffer_desc expName; 264*114Sdh145677 char *krb5_oid = "\052\206\110\206\367\022\001\002\002"; 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate if (entry == NULL || isspace(*entry)) 2670Sstevel@tonic-gate return (0); 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate /* save the entry since strtok will chop it up */ 2700Sstevel@tonic-gate (void) strcpy(fullEntry, entry); 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate if ((item = strtok(fullEntry, dilims)) == NULL) 2730Sstevel@tonic-gate return (0); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate /* do wee need to search the name */ 2760Sstevel@tonic-gate if (name != NULL) { 2770Sstevel@tonic-gate /* we can match the prefix of the string */ 2780Sstevel@tonic-gate if (strlen(item) < name->length) 2790Sstevel@tonic-gate return (0); 2800Sstevel@tonic-gate 281*114Sdh145677 if (memcmp(item, name->value, name->length) != 0) { 282*114Sdh145677 283*114Sdh145677 buf = (unsigned char *)name->value; 284*114Sdh145677 buf += expNameTokIdLen; 285*114Sdh145677 286*114Sdh145677 /* skip oid length - get to der */ 287*114Sdh145677 buf += 2; 288*114Sdh145677 289*114Sdh145677 /* skip oid tag */ 290*114Sdh145677 buf++; 291*114Sdh145677 292*114Sdh145677 /* get oid length */ 293*114Sdh145677 length = get_der_length(&buf, 294*114Sdh145677 (name->length - expNameTokIdLen 295*114Sdh145677 - mechOidLenLen - mechOidTagLen), &dummy); 296*114Sdh145677 297*114Sdh145677 if (length == -1) 298*114Sdh145677 return (0); 299*114Sdh145677 300*114Sdh145677 mechOidDesc.length = length; 301*114Sdh145677 302*114Sdh145677 /* 303*114Sdh145677 * check whether exported name length is within the 304*114Sdh145677 * boundary. 305*114Sdh145677 */ 306*114Sdh145677 if (name->length < 307*114Sdh145677 (expNameTokIdLen + mechOidLenLen + length 308*114Sdh145677 + dummy + mechOidTagLen)) 309*114Sdh145677 return (0); 310*114Sdh145677 311*114Sdh145677 mechOidDesc.value = buf; 312*114Sdh145677 313*114Sdh145677 buf += dummy + mechOidDesc.length; 314*114Sdh145677 315*114Sdh145677 /* 316*114Sdh145677 * If the mechoid is that of Kerberos and if the 317*114Sdh145677 * "display" part of the exported file name starts and 318*114Sdh145677 * ends with a zero-valued byte, then we are dealing 319*114Sdh145677 * with old styled gsscred entries. We will then match 320*114Sdh145677 * them in the following manner: 321*114Sdh145677 * - gss_import_name() the name from the file 322*114Sdh145677 * - gss_export_name() the result 323*114Sdh145677 * - mem_cmp() the result with the name we are 324*114Sdh145677 * trying to match. 325*114Sdh145677 */ 326*114Sdh145677 if (mechOidDesc.length == 9 && 327*114Sdh145677 (memcmp(buf, krb5_oid, 328*114Sdh145677 mechOidDesc.length) == 0) && 329*114Sdh145677 (*buf == '\0' && buf[length] == '\0')) { 330*114Sdh145677 if (gss_import_name(&minor, name, 331*114Sdh145677 GSS_C_NT_EXPORT_NAME, 332*114Sdh145677 &intName) != GSS_S_COMPLETE) 333*114Sdh145677 return (0); 334*114Sdh145677 result = gss_export_name(&minor, intName, 335*114Sdh145677 &expName); 336*114Sdh145677 (void) gss_release_name(&minor, &intName); 337*114Sdh145677 if (result != GSS_S_COMPLETE) 338*114Sdh145677 return (0); 339*114Sdh145677 result = memcmp(item, expName.value, 340*114Sdh145677 expName.length); 341*114Sdh145677 (void) gss_release_buffer(&minor, &expName); 342*114Sdh145677 if (result != 0) 343*114Sdh145677 return (0); 344*114Sdh145677 } 345*114Sdh145677 } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate /* do we need to check the uid - if not then we found it */ 3480Sstevel@tonic-gate if (uid == NULL) { 3490Sstevel@tonic-gate /* do we ned to parse out the uid ? */ 3500Sstevel@tonic-gate if (uidOut) { 3510Sstevel@tonic-gate if ((item = strtok(NULL, dilims)) == NULL) 3520Sstevel@tonic-gate return (0); 3530Sstevel@tonic-gate *uidOut = atol(item); 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate return (1); 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate /* continue with checking the uid */ 3590Sstevel@tonic-gate } 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate if (uid == NULL) 3620Sstevel@tonic-gate return (1); 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate /* get the next token from the string - the uid */ 3650Sstevel@tonic-gate if ((item = strtok(NULL, dilims)) == NULL) 3660Sstevel@tonic-gate return (0); 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate if (strcmp(item, uid) == 0) 3690Sstevel@tonic-gate return (1); 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate return (0); 3720Sstevel@tonic-gate } /* ******* matchEntry ****** */ 373