1N/A/**
1N/A * security.c - Handling security/ACLs in NTFS. Part of the Linux-NTFS project.
1N/A *
1N/A * Copyright (c) 2004 Anton Altaparmakov
1N/A *
1N/A * This program/include file is free software; you can redistribute it and/or
1N/A * modify it under the terms of the GNU General Public License as published
1N/A * by the Free Software Foundation; either version 2 of the License, or
1N/A * (at your option) any later version.
1N/A *
1N/A * This program/include file is distributed in the hope that it will be
1N/A * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1N/A * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A * GNU General Public License for more details.
1N/A *
1N/A * You should have received a copy of the GNU General Public License
1N/A * along with this program (in the main directory of the Linux-NTFS
1N/A * distribution in the file COPYING); if not, write to the Free Software
1N/A * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1N/A */
1N/A
1N/A#ifdef HAVE_CONFIG_H
1N/A#include "config.h"
1N/A#endif
1N/A
1N/A#ifdef HAVE_STDIO_H
1N/A#include <stdio.h>
1N/A#endif
1N/A#ifdef HAVE_STDLIB_H
1N/A#include <stdlib.h>
1N/A#endif
1N/A#ifdef HAVE_STRING_H
1N/A#include <string.h>
1N/A#endif
1N/A#ifdef HAVE_ERRNO_H
1N/A#include <errno.h>
1N/A#endif
1N/A
1N/A#include "compat.h"
1N/A#include "types.h"
1N/A#include "layout.h"
1N/A#include "security.h"
1N/A
1N/A/*
1N/A * The zero GUID.
1N/A */
1N/Astatic const GUID __zero_guid = { { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } };
1N/Aconst GUID *const zero_guid = &__zero_guid;
1N/A
1N/A/**
1N/A * ntfs_guid_is_zero - check if a GUID is zero
1N/A * @guid: [IN] guid to check
1N/A *
1N/A * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
1N/A * and FALSE otherwise.
1N/A */
1N/ABOOL ntfs_guid_is_zero(const GUID *guid)
1N/A{
1N/A return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
1N/A}
1N/A
1N/A/**
1N/A * ntfs_guid_to_mbs - convert a GUID to a multi byte string
1N/A * @guid: [IN] guid to convert
1N/A * @guid_str: [OUT] string in which to return the GUID (optional)
1N/A *
1N/A * Convert the GUID pointed to by @guid to a multi byte string of the form
1N/A * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL)
1N/A * needs to be able to store at least 37 bytes.
1N/A *
1N/A * If @guid_str is not NULL it will contain the converted GUID on return. If
1N/A * it is NULL a string will be allocated and this will be returned. The caller
1N/A * is responsible for free()ing the string in that case.
1N/A *
1N/A * On success return the converted string and on failure return NULL with errno
1N/A * set to the error code.
1N/A */
1N/Achar *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
1N/A{
1N/A char *_guid_str;
1N/A int res;
1N/A
1N/A if (!guid) {
1N/A errno = EINVAL;
1N/A return NULL;
1N/A }
1N/A _guid_str = guid_str;
1N/A if (!_guid_str) {
1N/A _guid_str = ntfs_malloc(37);
1N/A if (!_guid_str)
1N/A return _guid_str;
1N/A }
1N/A res = snprintf(_guid_str, 37, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1N/A "%02x%02x-%02x%02x%02x%02x%02x%02x", guid->raw[0],
1N/A guid->raw[1], guid->raw[2], guid->raw[3], guid->raw[4],
1N/A guid->raw[5], guid->raw[6], guid->raw[7], guid->raw[8],
1N/A guid->raw[9], guid->raw[10], guid->raw[11],
1N/A guid->raw[12], guid->raw[13], guid->raw[14],
1N/A guid->raw[15]);
1N/A if (res == 36)
1N/A return _guid_str;
1N/A if (!guid_str)
1N/A free(_guid_str);
1N/A errno = EINVAL;
1N/A return NULL;
1N/A}
1N/A
1N/A/**
1N/A * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
1N/A * @sid: [IN] SID for which to determine the maximum string size
1N/A *
1N/A * Determine the maximum multi byte string size in bytes which is needed to
1N/A * store the standard textual representation of the SID pointed to by @sid.
1N/A * See ntfs_sid_to_mbs(), below.
1N/A *
1N/A * On success return the maximum number of bytes needed to store the multi byte
1N/A * string and on failure return -1 with errno set to the error code.
1N/A */
1N/Aint ntfs_sid_to_mbs_size(const SID *sid)
1N/A{
1N/A int size, i;
1N/A
1N/A if (!ntfs_sid_is_valid(sid)) {
1N/A errno = EINVAL;
1N/A return -1;
1N/A }
1N/A /* Start with "S-". */
1N/A size = 2;
1N/A /*
1N/A * Add the SID_REVISION. Hopefully the compiler will optimize this
1N/A * away as SID_REVISION is a constant.
1N/A */
1N/A for (i = SID_REVISION; i > 0; i /= 10)
1N/A size++;
1N/A /* Add the "-". */
1N/A size++;
1N/A /*
1N/A * Add the identifier authority. If it needs to be in decimal, the
1N/A * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be
1N/A * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
1N/A */
1N/A if (!sid->identifier_authority.s.high_part)
1N/A size += 10;
1N/A else
1N/A size += 14;
1N/A /*
1N/A * Finally, add the sub authorities. For each we have a "-" followed
1N/A * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
1N/A */
1N/A size += (1 + 10) * sid->sub_authority_count;
1N/A /* We need the zero byte at the end, too. */
1N/A size++;
1N/A return size * sizeof(char);
1N/A}
1N/A
1N/A/**
1N/A * ntfs_sid_to_mbs - convert a SID to a multi byte string
1N/A * @sid: [IN] SID to convert
1N/A * @sid_str: [OUT] string in which to return the SID (optional)
1N/A * @sid_str_size: [IN] size in bytes of @sid_str
1N/A *
1N/A * Convert the SID pointed to by @sid to its standard textual representation.
1N/A * @sid_str (if not NULL) needs to be able to store at least
1N/A * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of
1N/A * @sid_str if @sid_str is not NULL.
1N/A *
1N/A * The standard textual representation of the SID is of the form:
1N/A * S-R-I-S-S...
1N/A * Where:
1N/A * - The first "S" is the literal character 'S' identifying the following
1N/A * digits as a SID.
1N/A * - R is the revision level of the SID expressed as a sequence of digits
1N/A * in decimal.
1N/A * - I is the 48-bit identifier_authority, expressed as digits in decimal,
1N/A * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
1N/A * - S... is one or more sub_authority values, expressed as digits in
1N/A * decimal.
1N/A *
1N/A * If @sid_str is not NULL it will contain the converted SUID on return. If it
1N/A * is NULL a string will be allocated and this will be returned. The caller is
1N/A * responsible for free()ing the string in that case.
1N/A *
1N/A * On success return the converted string and on failure return NULL with errno
1N/A * set to the error code.
1N/A */
1N/Achar *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
1N/A{
1N/A u64 u;
1N/A char *s;
1N/A int i, j, cnt;
1N/A
1N/A /*
1N/A * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
1N/A * check @sid, too. 8 is the minimum SID string size.
1N/A */
1N/A if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
1N/A errno = EINVAL;
1N/A return NULL;
1N/A }
1N/A /* Allocate string if not provided. */
1N/A if (!sid_str) {
1N/A cnt = ntfs_sid_to_mbs_size(sid);
1N/A if (cnt < 0)
1N/A return NULL;
1N/A s = ntfs_malloc(cnt);
1N/A if (!s)
1N/A return s;
1N/A sid_str = s;
1N/A /* So we know we allocated it. */
1N/A sid_str_size = 0;
1N/A } else {
1N/A s = sid_str;
1N/A cnt = sid_str_size;
1N/A }
1N/A /* Start with "S-R-". */
1N/A i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
1N/A if (i < 0 || i >= cnt)
1N/A goto err_out;
1N/A s += i;
1N/A cnt -= i;
1N/A /* Add the identifier authority. */
1N/A for (u = i = 0, j = 40; i < 6; i++, j -= 8)
1N/A u += (u64)sid->identifier_authority.value[i] << j;
1N/A if (!sid->identifier_authority.s.high_part)
1N/A i = snprintf(s, cnt, "%lu", (unsigned long)u);
1N/A else
1N/A i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
1N/A if (i < 0 || i >= cnt)
1N/A goto err_out;
1N/A s += i;
1N/A cnt -= i;
1N/A /* Finally, add the sub authorities. */
1N/A for (j = 0; j < sid->sub_authority_count; j++) {
1N/A i = snprintf(s, cnt, "-%u", (unsigned int)
1N/A le32_to_cpu(sid->sub_authority[j]));
1N/A if (i < 0 || i >= cnt)
1N/A goto err_out;
1N/A s += i;
1N/A cnt -= i;
1N/A }
1N/A return sid_str;
1N/Aerr_out:
1N/A if (i >= cnt)
1N/A i = EMSGSIZE;
1N/A else
1N/A i = errno;
1N/A if (!sid_str_size)
1N/A free(sid_str);
1N/A errno = i;
1N/A return NULL;
1N/A}
1N/A
1N/A/**
1N/A * ntfs_generate_guid - generatates a random current guid.
1N/A * @guid: [OUT] pointer to a GUID struct to hold the generated guid.
1N/A *
1N/A * perhaps not a very good random number generator though...
1N/A */
1N/Avoid ntfs_generate_guid(GUID *guid)
1N/A{
1N/A unsigned int i;
1N/A u8 *p = (u8 *)guid;
1N/A
1N/A for (i = 0; i < sizeof(GUID); i++) {
1N/A p[i] = (u8)(random() & 0xFF);
1N/A if (i == 7)
1N/A p[7] = (p[7] & 0x0F) | 0x40;
1N/A if (i == 8)
1N/A p[8] = (p[8] & 0x3F) | 0x80;
1N/A }
1N/A}
1N/A