ntfs-3g/libntfs-3g/security.c
2006-10-30 22:32:48 +00:00

341 lines
9.8 KiB
C

/**
* security.c - Handling security/ACLs in NTFS. Originated from the Linux-NTFS project.
*
* Copyright (c) 2004 Anton Altaparmakov
* Copyright (c) 2005-2006 Szabolcs Szakacsits
* Copyright (c) 2006 Yura Pakhuchiy
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include "types.h"
#include "layout.h"
#include "attrib.h"
#include "security.h"
#include "misc.h"
/*
* The zero GUID.
*/
static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0),
const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
const GUID *const zero_guid = &__zero_guid;
/**
* ntfs_guid_is_zero - check if a GUID is zero
* @guid: [IN] guid to check
*
* Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
* and FALSE otherwise.
*/
BOOL ntfs_guid_is_zero(const GUID *guid)
{
return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
}
/**
* ntfs_guid_to_mbs - convert a GUID to a multi byte string
* @guid: [IN] guid to convert
* @guid_str: [OUT] string in which to return the GUID (optional)
*
* Convert the GUID pointed to by @guid to a multi byte string of the form
* "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL)
* needs to be able to store at least 37 bytes.
*
* If @guid_str is not NULL it will contain the converted GUID on return. If
* it is NULL a string will be allocated and this will be returned. The caller
* is responsible for free()ing the string in that case.
*
* On success return the converted string and on failure return NULL with errno
* set to the error code.
*/
char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
{
char *_guid_str;
int res;
if (!guid) {
errno = EINVAL;
return NULL;
}
_guid_str = guid_str;
if (!_guid_str) {
_guid_str = ntfs_malloc(37);
if (!_guid_str)
return _guid_str;
}
res = snprintf(_guid_str, 37,
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
(unsigned int)le32_to_cpu(guid->data1),
le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
guid->data4[0], guid->data4[1],
guid->data4[2], guid->data4[3], guid->data4[4],
guid->data4[5], guid->data4[6], guid->data4[7]);
if (res == 36)
return _guid_str;
if (!guid_str)
free(_guid_str);
errno = EINVAL;
return NULL;
}
/**
* ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
* @sid: [IN] SID for which to determine the maximum string size
*
* Determine the maximum multi byte string size in bytes which is needed to
* store the standard textual representation of the SID pointed to by @sid.
* See ntfs_sid_to_mbs(), below.
*
* On success return the maximum number of bytes needed to store the multi byte
* string and on failure return -1 with errno set to the error code.
*/
int ntfs_sid_to_mbs_size(const SID *sid)
{
int size, i;
if (!ntfs_sid_is_valid(sid)) {
errno = EINVAL;
return -1;
}
/* Start with "S-". */
size = 2;
/*
* Add the SID_REVISION. Hopefully the compiler will optimize this
* away as SID_REVISION is a constant.
*/
for (i = SID_REVISION; i > 0; i /= 10)
size++;
/* Add the "-". */
size++;
/*
* Add the identifier authority. If it needs to be in decimal, the
* maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be
* in hexadecimal, then maximum is 0x665544332211 = 14 characters.
*/
if (!sid->identifier_authority.high_part)
size += 10;
else
size += 14;
/*
* Finally, add the sub authorities. For each we have a "-" followed
* by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
*/
size += (1 + 10) * sid->sub_authority_count;
/* We need the zero byte at the end, too. */
size++;
return size * sizeof(char);
}
/**
* ntfs_sid_to_mbs - convert a SID to a multi byte string
* @sid: [IN] SID to convert
* @sid_str: [OUT] string in which to return the SID (optional)
* @sid_str_size: [IN] size in bytes of @sid_str
*
* Convert the SID pointed to by @sid to its standard textual representation.
* @sid_str (if not NULL) needs to be able to store at least
* ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of
* @sid_str if @sid_str is not NULL.
*
* The standard textual representation of the SID is of the form:
* S-R-I-S-S...
* Where:
* - The first "S" is the literal character 'S' identifying the following
* digits as a SID.
* - R is the revision level of the SID expressed as a sequence of digits
* in decimal.
* - I is the 48-bit identifier_authority, expressed as digits in decimal,
* if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
* - S... is one or more sub_authority values, expressed as digits in
* decimal.
*
* If @sid_str is not NULL it will contain the converted SUID on return. If it
* is NULL a string will be allocated and this will be returned. The caller is
* responsible for free()ing the string in that case.
*
* On success return the converted string and on failure return NULL with errno
* set to the error code.
*/
char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
{
u64 u;
char *s;
int i, j, cnt;
/*
* No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
* check @sid, too. 8 is the minimum SID string size.
*/
if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
errno = EINVAL;
return NULL;
}
/* Allocate string if not provided. */
if (!sid_str) {
cnt = ntfs_sid_to_mbs_size(sid);
if (cnt < 0)
return NULL;
s = ntfs_malloc(cnt);
if (!s)
return s;
sid_str = s;
/* So we know we allocated it. */
sid_str_size = 0;
} else {
s = sid_str;
cnt = sid_str_size;
}
/* Start with "S-R-". */
i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
if (i < 0 || i >= cnt)
goto err_out;
s += i;
cnt -= i;
/* Add the identifier authority. */
for (u = i = 0, j = 40; i < 6; i++, j -= 8)
u += (u64)sid->identifier_authority.value[i] << j;
if (!sid->identifier_authority.high_part)
i = snprintf(s, cnt, "%lu", (unsigned long)u);
else
i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
if (i < 0 || i >= cnt)
goto err_out;
s += i;
cnt -= i;
/* Finally, add the sub authorities. */
for (j = 0; j < sid->sub_authority_count; j++) {
i = snprintf(s, cnt, "-%u", (unsigned int)
le32_to_cpu(sid->sub_authority[j]));
if (i < 0 || i >= cnt)
goto err_out;
s += i;
cnt -= i;
}
return sid_str;
err_out:
if (i >= cnt)
i = EMSGSIZE;
else
i = errno;
if (!sid_str_size)
free(sid_str);
errno = i;
return NULL;
}
/**
* ntfs_generate_guid - generatates a random current guid.
* @guid: [OUT] pointer to a GUID struct to hold the generated guid.
*
* perhaps not a very good random number generator though...
*/
void ntfs_generate_guid(GUID *guid)
{
unsigned int i;
u8 *p = (u8 *)guid;
for (i = 0; i < sizeof(GUID); i++) {
p[i] = (u8)(random() & 0xFF);
if (i == 7)
p[7] = (p[7] & 0x0F) | 0x40;
if (i == 8)
p[8] = (p[8] & 0x3F) | 0x80;
}
}
int ntfs_sd_add_everyone(ntfs_inode *ni)
{
SECURITY_DESCRIPTOR_ATTR *sd;
ACL *acl;
ACCESS_ALLOWED_ACE *ace;
SID *sid;
int ret, sd_len;
/* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
/*
* Calculate security descriptor length. We have 2 sub-authorities in
* owner and group SIDs, but structure SID contain only one, so add
* 4 bytes to every SID.
*/
sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
sd = ntfs_calloc(sd_len);
if (!sd)
return -1;
sd->revision = 1;
sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
sid = (SID *)((u8 *)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
sid->revision = 1;
sid->sub_authority_count = 2;
sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
sid->identifier_authority.value[5] = 5;
sd->owner = cpu_to_le32((u8 *)sid - (u8 *)sd);
sid = (SID *)((u8 *)sid + sizeof(SID) + 4);
sid->revision = 1;
sid->sub_authority_count = 2;
sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
sid->identifier_authority.value[5] = 5;
sd->group = cpu_to_le32((u8 *)sid - (u8 *)sd);
acl = (ACL *)((u8 *)sid + sizeof(SID) + 4);
acl->revision = 2;
acl->size = cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
acl->ace_count = cpu_to_le16(1);
sd->dacl = cpu_to_le32((u8 *)acl - (u8 *)sd);
ace = (ACCESS_ALLOWED_ACE *)((u8 *)acl + sizeof(ACL));
ace->type = ACCESS_ALLOWED_ACE_TYPE;
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
ace->size = cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
ace->mask = cpu_to_le32(0x1f01ff); /* FIXME */
ace->sid.revision = 1;
ace->sid.sub_authority_count = 1;
ace->sid.sub_authority[0] = 0;
ace->sid.identifier_authority.value[5] = 1;
ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8 *)sd,
sd_len);
if (ret)
ntfs_log_perror("Failed to add SECURITY_DESCRIPTOR\n");
free(sd);
return ret;
}