2 * security.c - Handling security/ACLs in NTFS. Originated from the Linux-NTFS project.
4 * Copyright (c) 2004 Anton Altaparmakov
5 * Copyright (c) 2005-2006 Szabolcs Szakacsits
6 * Copyright (c) 2006 Yura Pakhuchiy
8 * This program/include file is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program/include file is distributed in the hope that it will be
14 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program (in the main directory of the NTFS-3G
20 * distribution in the file COPYING); if not, write to the Free Software
21 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
51 static const GUID __zero_guid
= { const_cpu_to_le32(0), const_cpu_to_le16(0),
52 const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
53 const GUID
*const zero_guid
= &__zero_guid
;
56 * ntfs_guid_is_zero - check if a GUID is zero
57 * @guid: [IN] guid to check
59 * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
60 * and FALSE otherwise.
62 BOOL
ntfs_guid_is_zero(const GUID
*guid
)
64 return (memcmp(guid
, zero_guid
, sizeof(*zero_guid
)));
68 * ntfs_guid_to_mbs - convert a GUID to a multi byte string
69 * @guid: [IN] guid to convert
70 * @guid_str: [OUT] string in which to return the GUID (optional)
72 * Convert the GUID pointed to by @guid to a multi byte string of the form
73 * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL)
74 * needs to be able to store at least 37 bytes.
76 * If @guid_str is not NULL it will contain the converted GUID on return. If
77 * it is NULL a string will be allocated and this will be returned. The caller
78 * is responsible for free()ing the string in that case.
80 * On success return the converted string and on failure return NULL with errno
81 * set to the error code.
83 char *ntfs_guid_to_mbs(const GUID
*guid
, char *guid_str
)
94 _guid_str
= ntfs_malloc(37);
98 res
= snprintf(_guid_str
, 37,
99 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
100 (unsigned int)le32_to_cpu(guid
->data1
),
101 le16_to_cpu(guid
->data2
), le16_to_cpu(guid
->data3
),
102 guid
->data4
[0], guid
->data4
[1],
103 guid
->data4
[2], guid
->data4
[3], guid
->data4
[4],
104 guid
->data4
[5], guid
->data4
[6], guid
->data4
[7]);
114 * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
115 * @sid: [IN] SID for which to determine the maximum string size
117 * Determine the maximum multi byte string size in bytes which is needed to
118 * store the standard textual representation of the SID pointed to by @sid.
119 * See ntfs_sid_to_mbs(), below.
121 * On success return the maximum number of bytes needed to store the multi byte
122 * string and on failure return -1 with errno set to the error code.
124 int ntfs_sid_to_mbs_size(const SID
*sid
)
128 if (!ntfs_sid_is_valid(sid
)) {
132 /* Start with "S-". */
135 * Add the SID_REVISION. Hopefully the compiler will optimize this
136 * away as SID_REVISION is a constant.
138 for (i
= SID_REVISION
; i
> 0; i
/= 10)
143 * Add the identifier authority. If it needs to be in decimal, the
144 * maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be
145 * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
147 if (!sid
->identifier_authority
.high_part
)
152 * Finally, add the sub authorities. For each we have a "-" followed
153 * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
155 size
+= (1 + 10) * sid
->sub_authority_count
;
156 /* We need the zero byte at the end, too. */
158 return size
* sizeof(char);
162 * ntfs_sid_to_mbs - convert a SID to a multi byte string
163 * @sid: [IN] SID to convert
164 * @sid_str: [OUT] string in which to return the SID (optional)
165 * @sid_str_size: [IN] size in bytes of @sid_str
167 * Convert the SID pointed to by @sid to its standard textual representation.
168 * @sid_str (if not NULL) needs to be able to store at least
169 * ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of
170 * @sid_str if @sid_str is not NULL.
172 * The standard textual representation of the SID is of the form:
175 * - The first "S" is the literal character 'S' identifying the following
177 * - R is the revision level of the SID expressed as a sequence of digits
179 * - I is the 48-bit identifier_authority, expressed as digits in decimal,
180 * if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
181 * - S... is one or more sub_authority values, expressed as digits in
184 * If @sid_str is not NULL it will contain the converted SUID on return. If it
185 * is NULL a string will be allocated and this will be returned. The caller is
186 * responsible for free()ing the string in that case.
188 * On success return the converted string and on failure return NULL with errno
189 * set to the error code.
191 char *ntfs_sid_to_mbs(const SID
*sid
, char *sid_str
, size_t sid_str_size
)
198 * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
199 * check @sid, too. 8 is the minimum SID string size.
201 if (sid_str
&& (sid_str_size
< 8 || !ntfs_sid_is_valid(sid
))) {
205 /* Allocate string if not provided. */
207 cnt
= ntfs_sid_to_mbs_size(sid
);
210 s
= ntfs_malloc(cnt
);
214 /* So we know we allocated it. */
220 /* Start with "S-R-". */
221 i
= snprintf(s
, cnt
, "S-%hhu-", (unsigned char)sid
->revision
);
222 if (i
< 0 || i
>= cnt
)
226 /* Add the identifier authority. */
227 for (u
= i
= 0, j
= 40; i
< 6; i
++, j
-= 8)
228 u
+= (u64
)sid
->identifier_authority
.value
[i
] << j
;
229 if (!sid
->identifier_authority
.high_part
)
230 i
= snprintf(s
, cnt
, "%lu", (unsigned long)u
);
232 i
= snprintf(s
, cnt
, "0x%llx", (unsigned long long)u
);
233 if (i
< 0 || i
>= cnt
)
237 /* Finally, add the sub authorities. */
238 for (j
= 0; j
< sid
->sub_authority_count
; j
++) {
239 i
= snprintf(s
, cnt
, "-%u", (unsigned int)
240 le32_to_cpu(sid
->sub_authority
[j
]));
241 if (i
< 0 || i
>= cnt
)
259 * ntfs_generate_guid - generatates a random current guid.
260 * @guid: [OUT] pointer to a GUID struct to hold the generated guid.
262 * perhaps not a very good random number generator though...
264 void ntfs_generate_guid(GUID
*guid
)
269 for (i
= 0; i
< sizeof(GUID
); i
++) {
270 p
[i
] = (u8
)(random() & 0xFF);
272 p
[7] = (p
[7] & 0x0F) | 0x40;
274 p
[8] = (p
[8] & 0x3F) | 0x80;
278 int ntfs_sd_add_everyone(ntfs_inode
*ni
)
280 SECURITY_DESCRIPTOR_ATTR
*sd
;
282 ACCESS_ALLOWED_ACE
*ace
;
286 /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
288 * Calculate security descriptor length. We have 2 sub-authorities in
289 * owner and group SIDs, but structure SID contain only one, so add
290 * 4 bytes to every SID.
292 sd_len
= sizeof(SECURITY_DESCRIPTOR_ATTR
) + 2 * (sizeof(SID
) + 4) +
293 sizeof(ACL
) + sizeof(ACCESS_ALLOWED_ACE
);
294 sd
= ntfs_calloc(sd_len
);
299 sd
->control
= SE_DACL_PRESENT
| SE_SELF_RELATIVE
;
301 sid
= (SID
*)((u8
*)sd
+ sizeof(SECURITY_DESCRIPTOR_ATTR
));
303 sid
->sub_authority_count
= 2;
304 sid
->sub_authority
[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID
);
305 sid
->sub_authority
[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS
);
306 sid
->identifier_authority
.value
[5] = 5;
307 sd
->owner
= cpu_to_le32((u8
*)sid
- (u8
*)sd
);
309 sid
= (SID
*)((u8
*)sid
+ sizeof(SID
) + 4);
311 sid
->sub_authority_count
= 2;
312 sid
->sub_authority
[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID
);
313 sid
->sub_authority
[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS
);
314 sid
->identifier_authority
.value
[5] = 5;
315 sd
->group
= cpu_to_le32((u8
*)sid
- (u8
*)sd
);
317 acl
= (ACL
*)((u8
*)sid
+ sizeof(SID
) + 4);
319 acl
->size
= cpu_to_le16(sizeof(ACL
) + sizeof(ACCESS_ALLOWED_ACE
));
320 acl
->ace_count
= cpu_to_le16(1);
321 sd
->dacl
= cpu_to_le32((u8
*)acl
- (u8
*)sd
);
323 ace
= (ACCESS_ALLOWED_ACE
*)((u8
*)acl
+ sizeof(ACL
));
324 ace
->type
= ACCESS_ALLOWED_ACE_TYPE
;
325 ace
->flags
= OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
;
326 ace
->size
= cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE
));
327 ace
->mask
= cpu_to_le32(0x1f01ff); /* FIXME */
328 ace
->sid
.revision
= 1;
329 ace
->sid
.sub_authority_count
= 1;
330 ace
->sid
.sub_authority
[0] = 0;
331 ace
->sid
.identifier_authority
.value
[5] = 1;
333 ret
= ntfs_attr_add(ni
, AT_SECURITY_DESCRIPTOR
, AT_UNNAMED
, 0, (u8
*)sd
,
336 ntfs_log_perror("Failed to add SECURITY_DESCRIPTOR\n");
343 * ntfs_security_hash - calculate the hash of a security descriptor
344 * @sd: self-relative security descriptor whose hash to calculate
345 * @length: size in bytes of the security descritor @sd
347 * Calculate the hash of the self-relative security descriptor @sd of length
350 * This hash is used in the $Secure system file as the primary key for the $SDH
351 * index and is also stored in the header of each security descriptor in the
352 * $SDS data stream as well as in the index data of both the $SII and $SDH
353 * indexes. In all three cases it forms part of the SDS_ENTRY_HEADER
356 * Return the calculated security hash in little endian.
358 le32
ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE
*sd
, const u32 len
)
360 const le32
*pos
= (const le32
*)sd
;
361 const le32
*end
= pos
+ (len
>> 2);
365 hash
= le32_to_cpup(pos
) + ntfs_rol32(hash
, 3);
368 return cpu_to_le32(hash
);