xref: /onnv-gate/usr/src/cmd/gss/gsscred/gsscred_file.c (revision 114:ba10d60d4eda)
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