xref: /onnv-gate/usr/src/lib/libntfs/common/libntfs/security.c (revision 10214:1f70f0c2183c)
19663SMark.Logan@Sun.COM /**
29663SMark.Logan@Sun.COM  * security.c - Handling security/ACLs in NTFS.  Part of the Linux-NTFS project.
39663SMark.Logan@Sun.COM  *
49663SMark.Logan@Sun.COM  * Copyright (c) 2004 Anton Altaparmakov
59663SMark.Logan@Sun.COM  *
69663SMark.Logan@Sun.COM  * This program/include file is free software; you can redistribute it and/or
79663SMark.Logan@Sun.COM  * modify it under the terms of the GNU General Public License as published
89663SMark.Logan@Sun.COM  * by the Free Software Foundation; either version 2 of the License, or
99663SMark.Logan@Sun.COM  * (at your option) any later version.
109663SMark.Logan@Sun.COM  *
119663SMark.Logan@Sun.COM  * This program/include file is distributed in the hope that it will be
129663SMark.Logan@Sun.COM  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
139663SMark.Logan@Sun.COM  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
149663SMark.Logan@Sun.COM  * GNU General Public License for more details.
159663SMark.Logan@Sun.COM  *
169663SMark.Logan@Sun.COM  * You should have received a copy of the GNU General Public License
179663SMark.Logan@Sun.COM  * along with this program (in the main directory of the Linux-NTFS
189663SMark.Logan@Sun.COM  * distribution in the file COPYING); if not, write to the Free Software
199663SMark.Logan@Sun.COM  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
209663SMark.Logan@Sun.COM  */
219663SMark.Logan@Sun.COM 
229663SMark.Logan@Sun.COM #ifdef HAVE_CONFIG_H
239663SMark.Logan@Sun.COM #include "config.h"
249663SMark.Logan@Sun.COM #endif
259663SMark.Logan@Sun.COM 
269663SMark.Logan@Sun.COM #ifdef HAVE_STDIO_H
279663SMark.Logan@Sun.COM #include <stdio.h>
289663SMark.Logan@Sun.COM #endif
299663SMark.Logan@Sun.COM #ifdef HAVE_STDLIB_H
309663SMark.Logan@Sun.COM #include <stdlib.h>
319663SMark.Logan@Sun.COM #endif
329663SMark.Logan@Sun.COM #ifdef HAVE_STRING_H
339663SMark.Logan@Sun.COM #include <string.h>
349663SMark.Logan@Sun.COM #endif
359663SMark.Logan@Sun.COM #ifdef HAVE_ERRNO_H
369663SMark.Logan@Sun.COM #include <errno.h>
379663SMark.Logan@Sun.COM #endif
389663SMark.Logan@Sun.COM 
39*10214SMark.Logan@Sun.COM #include "compat.h"
409663SMark.Logan@Sun.COM #include "types.h"
419663SMark.Logan@Sun.COM #include "layout.h"
429663SMark.Logan@Sun.COM #include "security.h"
439663SMark.Logan@Sun.COM 
449663SMark.Logan@Sun.COM /*
459663SMark.Logan@Sun.COM  * The zero GUID.
469663SMark.Logan@Sun.COM  */
479663SMark.Logan@Sun.COM static const GUID __zero_guid = { { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } };
489663SMark.Logan@Sun.COM const GUID *const zero_guid = &__zero_guid;
499663SMark.Logan@Sun.COM 
509663SMark.Logan@Sun.COM /**
519663SMark.Logan@Sun.COM  * ntfs_guid_is_zero - check if a GUID is zero
529663SMark.Logan@Sun.COM  * @guid:	[IN] guid to check
539663SMark.Logan@Sun.COM  *
549663SMark.Logan@Sun.COM  * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
559663SMark.Logan@Sun.COM  * and FALSE otherwise.
569663SMark.Logan@Sun.COM  */
ntfs_guid_is_zero(const GUID * guid)579663SMark.Logan@Sun.COM BOOL ntfs_guid_is_zero(const GUID *guid)
589663SMark.Logan@Sun.COM {
599663SMark.Logan@Sun.COM 	return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
609663SMark.Logan@Sun.COM }
619663SMark.Logan@Sun.COM 
629663SMark.Logan@Sun.COM /**
639663SMark.Logan@Sun.COM  * ntfs_guid_to_mbs - convert a GUID to a multi byte string
649663SMark.Logan@Sun.COM  * @guid:	[IN]  guid to convert
659663SMark.Logan@Sun.COM  * @guid_str:	[OUT] string in which to return the GUID (optional)
669663SMark.Logan@Sun.COM  *
679663SMark.Logan@Sun.COM  * Convert the GUID pointed to by @guid to a multi byte string of the form
689663SMark.Logan@Sun.COM  * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX".  Therefore, @guid_str (if not NULL)
699663SMark.Logan@Sun.COM  * needs to be able to store at least 37 bytes.
709663SMark.Logan@Sun.COM  *
719663SMark.Logan@Sun.COM  * If @guid_str is not NULL it will contain the converted GUID on return.  If
729663SMark.Logan@Sun.COM  * it is NULL a string will be allocated and this will be returned.  The caller
739663SMark.Logan@Sun.COM  * is responsible for free()ing the string in that case.
749663SMark.Logan@Sun.COM  *
759663SMark.Logan@Sun.COM  * On success return the converted string and on failure return NULL with errno
769663SMark.Logan@Sun.COM  * set to the error code.
779663SMark.Logan@Sun.COM  */
ntfs_guid_to_mbs(const GUID * guid,char * guid_str)789663SMark.Logan@Sun.COM char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
799663SMark.Logan@Sun.COM {
809663SMark.Logan@Sun.COM 	char *_guid_str;
819663SMark.Logan@Sun.COM 	int res;
829663SMark.Logan@Sun.COM 
839663SMark.Logan@Sun.COM 	if (!guid) {
849663SMark.Logan@Sun.COM 		errno = EINVAL;
859663SMark.Logan@Sun.COM 		return NULL;
869663SMark.Logan@Sun.COM 	}
879663SMark.Logan@Sun.COM 	_guid_str = guid_str;
889663SMark.Logan@Sun.COM 	if (!_guid_str) {
899663SMark.Logan@Sun.COM 		_guid_str = ntfs_malloc(37);
909663SMark.Logan@Sun.COM 		if (!_guid_str)
919663SMark.Logan@Sun.COM 			return _guid_str;
929663SMark.Logan@Sun.COM 	}
939663SMark.Logan@Sun.COM 	res = snprintf(_guid_str, 37, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
949663SMark.Logan@Sun.COM 			"%02x%02x-%02x%02x%02x%02x%02x%02x", guid->raw[0],
959663SMark.Logan@Sun.COM 			guid->raw[1], guid->raw[2], guid->raw[3], guid->raw[4],
969663SMark.Logan@Sun.COM 			guid->raw[5], guid->raw[6], guid->raw[7], guid->raw[8],
979663SMark.Logan@Sun.COM 			guid->raw[9], guid->raw[10], guid->raw[11],
989663SMark.Logan@Sun.COM 			guid->raw[12], guid->raw[13], guid->raw[14],
999663SMark.Logan@Sun.COM 			guid->raw[15]);
1009663SMark.Logan@Sun.COM 	if (res == 36)
1019663SMark.Logan@Sun.COM 		return _guid_str;
1029663SMark.Logan@Sun.COM 	if (!guid_str)
1039663SMark.Logan@Sun.COM 		free(_guid_str);
1049663SMark.Logan@Sun.COM 	errno = EINVAL;
1059663SMark.Logan@Sun.COM 	return NULL;
1069663SMark.Logan@Sun.COM }
1079663SMark.Logan@Sun.COM 
1089663SMark.Logan@Sun.COM /**
1099663SMark.Logan@Sun.COM  * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
1109663SMark.Logan@Sun.COM  * @sid:	[IN]  SID for which to determine the maximum string size
1119663SMark.Logan@Sun.COM  *
1129663SMark.Logan@Sun.COM  * Determine the maximum multi byte string size in bytes which is needed to
1139663SMark.Logan@Sun.COM  * store the standard textual representation of the SID pointed to by @sid.
1149663SMark.Logan@Sun.COM  * See ntfs_sid_to_mbs(), below.
1159663SMark.Logan@Sun.COM  *
1169663SMark.Logan@Sun.COM  * On success return the maximum number of bytes needed to store the multi byte
1179663SMark.Logan@Sun.COM  * string and on failure return -1 with errno set to the error code.
1189663SMark.Logan@Sun.COM  */
ntfs_sid_to_mbs_size(const SID * sid)1199663SMark.Logan@Sun.COM int ntfs_sid_to_mbs_size(const SID *sid)
1209663SMark.Logan@Sun.COM {
1219663SMark.Logan@Sun.COM 	int size, i;
1229663SMark.Logan@Sun.COM 
1239663SMark.Logan@Sun.COM 	if (!ntfs_sid_is_valid(sid)) {
1249663SMark.Logan@Sun.COM 		errno = EINVAL;
1259663SMark.Logan@Sun.COM 		return -1;
1269663SMark.Logan@Sun.COM 	}
1279663SMark.Logan@Sun.COM 	/* Start with "S-". */
1289663SMark.Logan@Sun.COM 	size = 2;
1299663SMark.Logan@Sun.COM 	/*
1309663SMark.Logan@Sun.COM 	 * Add the SID_REVISION.  Hopefully the compiler will optimize this
1319663SMark.Logan@Sun.COM 	 * away as SID_REVISION is a constant.
1329663SMark.Logan@Sun.COM 	 */
1339663SMark.Logan@Sun.COM 	for (i = SID_REVISION; i > 0; i /= 10)
1349663SMark.Logan@Sun.COM 		size++;
1359663SMark.Logan@Sun.COM 	/* Add the "-". */
1369663SMark.Logan@Sun.COM 	size++;
1379663SMark.Logan@Sun.COM 	/*
1389663SMark.Logan@Sun.COM 	 * Add the identifier authority.  If it needs to be in decimal, the
1399663SMark.Logan@Sun.COM 	 * maximum is 2^32-1 = 4294967295 = 10 characters.  If it needs to be
1409663SMark.Logan@Sun.COM 	 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
1419663SMark.Logan@Sun.COM 	 */
1429663SMark.Logan@Sun.COM 	if (!sid->identifier_authority.s.high_part)
1439663SMark.Logan@Sun.COM 		size += 10;
1449663SMark.Logan@Sun.COM 	else
1459663SMark.Logan@Sun.COM 		size += 14;
1469663SMark.Logan@Sun.COM 	/*
1479663SMark.Logan@Sun.COM 	 * Finally, add the sub authorities.  For each we have a "-" followed
1489663SMark.Logan@Sun.COM 	 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
1499663SMark.Logan@Sun.COM 	 */
1509663SMark.Logan@Sun.COM 	size += (1 + 10) * sid->sub_authority_count;
1519663SMark.Logan@Sun.COM 	/* We need the zero byte at the end, too. */
1529663SMark.Logan@Sun.COM 	size++;
1539663SMark.Logan@Sun.COM 	return size * sizeof(char);
1549663SMark.Logan@Sun.COM }
1559663SMark.Logan@Sun.COM 
1569663SMark.Logan@Sun.COM /**
1579663SMark.Logan@Sun.COM  * ntfs_sid_to_mbs - convert a SID to a multi byte string
1589663SMark.Logan@Sun.COM  * @sid:		[IN]  SID to convert
1599663SMark.Logan@Sun.COM  * @sid_str:		[OUT] string in which to return the SID (optional)
1609663SMark.Logan@Sun.COM  * @sid_str_size:	[IN]  size in bytes of @sid_str
1619663SMark.Logan@Sun.COM  *
1629663SMark.Logan@Sun.COM  * Convert the SID pointed to by @sid to its standard textual representation.
1639663SMark.Logan@Sun.COM  * @sid_str (if not NULL) needs to be able to store at least
1649663SMark.Logan@Sun.COM  * ntfs_sid_to_mbs_size() bytes.  @sid_str_size is the size in bytes of
1659663SMark.Logan@Sun.COM  * @sid_str if @sid_str is not NULL.
1669663SMark.Logan@Sun.COM  *
1679663SMark.Logan@Sun.COM  * The standard textual representation of the SID is of the form:
1689663SMark.Logan@Sun.COM  *	S-R-I-S-S...
1699663SMark.Logan@Sun.COM  * Where:
1709663SMark.Logan@Sun.COM  *    - The first "S" is the literal character 'S' identifying the following
1719663SMark.Logan@Sun.COM  *	digits as a SID.
1729663SMark.Logan@Sun.COM  *    - R is the revision level of the SID expressed as a sequence of digits
1739663SMark.Logan@Sun.COM  *	in decimal.
1749663SMark.Logan@Sun.COM  *    - I is the 48-bit identifier_authority, expressed as digits in decimal,
1759663SMark.Logan@Sun.COM  *	if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
1769663SMark.Logan@Sun.COM  *    - S... is one or more sub_authority values, expressed as digits in
1779663SMark.Logan@Sun.COM  *	decimal.
1789663SMark.Logan@Sun.COM  *
1799663SMark.Logan@Sun.COM  * If @sid_str is not NULL it will contain the converted SUID on return.  If it
1809663SMark.Logan@Sun.COM  * is NULL a string will be allocated and this will be returned.  The caller is
1819663SMark.Logan@Sun.COM  * responsible for free()ing the string in that case.
1829663SMark.Logan@Sun.COM  *
1839663SMark.Logan@Sun.COM  * On success return the converted string and on failure return NULL with errno
1849663SMark.Logan@Sun.COM  * set to the error code.
1859663SMark.Logan@Sun.COM  */
ntfs_sid_to_mbs(const SID * sid,char * sid_str,size_t sid_str_size)1869663SMark.Logan@Sun.COM char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
1879663SMark.Logan@Sun.COM {
1889663SMark.Logan@Sun.COM 	u64 u;
1899663SMark.Logan@Sun.COM 	char *s;
1909663SMark.Logan@Sun.COM 	int i, j, cnt;
1919663SMark.Logan@Sun.COM 
1929663SMark.Logan@Sun.COM 	/*
1939663SMark.Logan@Sun.COM 	 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
1949663SMark.Logan@Sun.COM 	 * check @sid, too.  8 is the minimum SID string size.
1959663SMark.Logan@Sun.COM 	 */
1969663SMark.Logan@Sun.COM 	if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
1979663SMark.Logan@Sun.COM 		errno = EINVAL;
1989663SMark.Logan@Sun.COM 		return NULL;
1999663SMark.Logan@Sun.COM 	}
2009663SMark.Logan@Sun.COM 	/* Allocate string if not provided. */
2019663SMark.Logan@Sun.COM 	if (!sid_str) {
2029663SMark.Logan@Sun.COM 		cnt = ntfs_sid_to_mbs_size(sid);
2039663SMark.Logan@Sun.COM 		if (cnt < 0)
2049663SMark.Logan@Sun.COM 			return NULL;
2059663SMark.Logan@Sun.COM 		s = ntfs_malloc(cnt);
2069663SMark.Logan@Sun.COM 		if (!s)
2079663SMark.Logan@Sun.COM 			return s;
2089663SMark.Logan@Sun.COM 		sid_str = s;
2099663SMark.Logan@Sun.COM 		/* So we know we allocated it. */
2109663SMark.Logan@Sun.COM 		sid_str_size = 0;
2119663SMark.Logan@Sun.COM 	} else {
2129663SMark.Logan@Sun.COM 		s = sid_str;
2139663SMark.Logan@Sun.COM 		cnt = sid_str_size;
2149663SMark.Logan@Sun.COM 	}
2159663SMark.Logan@Sun.COM 	/* Start with "S-R-". */
2169663SMark.Logan@Sun.COM 	i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
2179663SMark.Logan@Sun.COM 	if (i < 0 || i >= cnt)
2189663SMark.Logan@Sun.COM 		goto err_out;
2199663SMark.Logan@Sun.COM 	s += i;
2209663SMark.Logan@Sun.COM 	cnt -= i;
2219663SMark.Logan@Sun.COM 	/* Add the identifier authority. */
2229663SMark.Logan@Sun.COM 	for (u = i = 0, j = 40; i < 6; i++, j -= 8)
2239663SMark.Logan@Sun.COM 		u += (u64)sid->identifier_authority.value[i] << j;
2249663SMark.Logan@Sun.COM 	if (!sid->identifier_authority.s.high_part)
2259663SMark.Logan@Sun.COM 		i = snprintf(s, cnt, "%lu", (unsigned long)u);
2269663SMark.Logan@Sun.COM 	else
2279663SMark.Logan@Sun.COM 		i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
2289663SMark.Logan@Sun.COM 	if (i < 0 || i >= cnt)
2299663SMark.Logan@Sun.COM 		goto err_out;
2309663SMark.Logan@Sun.COM 	s += i;
2319663SMark.Logan@Sun.COM 	cnt -= i;
2329663SMark.Logan@Sun.COM 	/* Finally, add the sub authorities. */
2339663SMark.Logan@Sun.COM 	for (j = 0; j < sid->sub_authority_count; j++) {
2349663SMark.Logan@Sun.COM 		i = snprintf(s, cnt, "-%u", (unsigned int)
2359663SMark.Logan@Sun.COM 				le32_to_cpu(sid->sub_authority[j]));
2369663SMark.Logan@Sun.COM 		if (i < 0 || i >= cnt)
2379663SMark.Logan@Sun.COM 			goto err_out;
2389663SMark.Logan@Sun.COM 		s += i;
2399663SMark.Logan@Sun.COM 		cnt -= i;
2409663SMark.Logan@Sun.COM 	}
2419663SMark.Logan@Sun.COM 	return sid_str;
2429663SMark.Logan@Sun.COM err_out:
2439663SMark.Logan@Sun.COM 	if (i >= cnt)
2449663SMark.Logan@Sun.COM 		i = EMSGSIZE;
2459663SMark.Logan@Sun.COM 	else
2469663SMark.Logan@Sun.COM 		i = errno;
2479663SMark.Logan@Sun.COM 	if (!sid_str_size)
2489663SMark.Logan@Sun.COM 		free(sid_str);
2499663SMark.Logan@Sun.COM 	errno = i;
2509663SMark.Logan@Sun.COM 	return NULL;
2519663SMark.Logan@Sun.COM }
2529663SMark.Logan@Sun.COM 
2539663SMark.Logan@Sun.COM /**
2549663SMark.Logan@Sun.COM  * ntfs_generate_guid - generatates a random current guid.
2559663SMark.Logan@Sun.COM  * @guid:	[OUT]   pointer to a GUID struct to hold the generated guid.
2569663SMark.Logan@Sun.COM  *
2579663SMark.Logan@Sun.COM  * perhaps not a very good random number generator though...
2589663SMark.Logan@Sun.COM  */
ntfs_generate_guid(GUID * guid)2599663SMark.Logan@Sun.COM void ntfs_generate_guid(GUID *guid)
2609663SMark.Logan@Sun.COM {
2619663SMark.Logan@Sun.COM 	unsigned int i;
2629663SMark.Logan@Sun.COM 	u8 *p = (u8 *)guid;
2639663SMark.Logan@Sun.COM 
2649663SMark.Logan@Sun.COM 	for (i = 0; i < sizeof(GUID); i++) {
2659663SMark.Logan@Sun.COM 		p[i] = (u8)(random() & 0xFF);
2669663SMark.Logan@Sun.COM 		if (i == 7)
2679663SMark.Logan@Sun.COM 			p[7] = (p[7] & 0x0F) | 0x40;
2689663SMark.Logan@Sun.COM 		if (i == 8)
2699663SMark.Logan@Sun.COM 			p[8] = (p[8] & 0x3F) | 0x80;
2709663SMark.Logan@Sun.COM 	}
2719663SMark.Logan@Sun.COM }
2729663SMark.Logan@Sun.COM 
273