static char *search_absolute(ntfs_volume *vol, ntfschar *path, int count, BOOL isdir) { ntfs_inode *ni; u64 inum; char *target; int start; int len; target = (char*)NULL; /* default return */ ni = ntfs_inode_open(vol, (MFT_REF)FILE_root); if (ni) { start = 0; /* * Examine and translate the path, until we reach either * - the end, * - an unknown item * - a non-directory * - another reparse point, * A reparse point is not dereferenced, it will be * examined later when the translated path is dereferenced, * however the final part of the path will not be adjusted * to correct case. */ do { len = 0; while (((start + len) < count) && (path[start + len] != const_cpu_to_le16('\\'))) len++; inum = ntfs_fix_file_name(ni, &path[start], len); ntfs_inode_close(ni); ni = (ntfs_inode*)NULL; if (inum != (u64)-1) { inum = MREF(inum); ni = ntfs_inode_open(vol, inum); start += len; if (start < count) path[start++] = const_cpu_to_le16('/'); } } while (ni && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) && !(ni->flags & FILE_ATTR_REPARSE_POINT) && (start < count)); if (ni && ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir) || (ni->flags & FILE_ATTR_REPARSE_POINT))) if (ntfs_ucstombs(path, count, &target, 0) < 0) { if (target) { free(target); target = (char*)NULL; } } if (ni) ntfs_inode_close(ni); } return (target); }
/** * change_label - change the current label on a device * @dev: device to change the label on * @mnt_flags: mount flags of the device or 0 if not mounted * @mnt_point: mount point of the device or NULL * @label: the new label * * Change the label on the device @dev to @label. */ static int change_label(ntfs_volume *vol, char *label) { ntfschar *new_label = NULL; int label_len; int result = 0; label_len = ntfs_mbstoucs(label, &new_label); if (label_len == -1) { ntfs_log_perror("Unable to convert label string to Unicode"); return 1; } else if (label_len*sizeof(ntfschar) > 0x100) { ntfs_log_warning("New label is too long. Maximum %u characters " "allowed. Truncating %u excess characters.\n", (unsigned)(0x100 / sizeof(ntfschar)), (unsigned)(label_len - (0x100 / sizeof(ntfschar)))); label_len = 0x100 / sizeof(ntfschar); label[label_len] = const_cpu_to_le16(0); } if(!opts.noaction) result = ntfs_volume_rename(vol, new_label, label_len) ? 1 : 0; free(new_label); return result; }
static char *search_absolute(ntfs_volume *vol, ntfschar *path, int count, BOOL isdir) { ntfs_inode *ni; u64 inum; char *target; int start; int len; target = (char*)NULL; /* default return */ ni = ntfs_inode_open(vol, (MFT_REF)FILE_root); if (ni) { start = 0; do { len = 0; while (((start + len) < count) && (path[start + len] != const_cpu_to_le16('\\'))) len++; inum = ntfs_fix_file_name(ni, &path[start], len); ntfs_inode_close(ni); ni = (ntfs_inode*)NULL; if (inum != (u64)-1) { inum = MREF(inum); ni = ntfs_inode_open(vol, inum); start += len; if (start < count) path[start++] = const_cpu_to_le16('/'); } } while (ni && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) && (start < count)); if (ni && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? isdir : !isdir)) if (ntfs_ucstombs(path, count, &target, 0) < 0) { if (target) { free(target); target = (char*)NULL; } } if (ni) ntfs_inode_close(ni); } return (target); }
static void erase_callback(struct erase_info *erase) { struct partition *part; u16 magic; int i, rc; size_t retlen; part = (struct partition*)erase->priv; i = erase->addr / part->block_size; if (i >= part->total_blocks || part->blocks[i].offset != erase->addr) { printk(KERN_ERR PREFIX "erase callback for unknown offset %x " "on '%s'\n", erase->addr, part->mbd.mtd->name); return; } if (erase->state != MTD_ERASE_DONE) { printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', " "state %d\n", erase->addr, part->mbd.mtd->name, erase->state); part->blocks[i].state = BLOCK_FAILED; part->blocks[i].free_sectors = 0; part->blocks[i].used_sectors = 0; kfree(erase); return; } magic = const_cpu_to_le16(RFD_MAGIC); part->blocks[i].state = BLOCK_ERASED; part->blocks[i].free_sectors = part->data_sectors_per_block; part->blocks[i].used_sectors = 0; part->blocks[i].erases++; rc = part->mbd.mtd->write(part->mbd.mtd, part->blocks[i].offset, sizeof(magic), &retlen, (u_char*)&magic); if (!rc && retlen != sizeof(magic)) rc = -EIO; if (rc) { printk(KERN_NOTICE PREFIX "'%s': unable to write RFD " "header at 0x%lx\n", part->mbd.mtd->name, part->blocks[i].offset); part->blocks[i].state = BLOCK_FAILED; } else part->blocks[i].state = BLOCK_OK; kfree(erase); }
static int set_reparse_index(ntfs_inode *ni, ntfs_index_context *xr, le32 reparse_tag) { struct REPARSE_INDEX indx; u64 file_id_cpu; le64 file_id; le16 seqn; seqn = ni->mrec->sequence_number; file_id_cpu = MK_MREF(ni->mft_no,le16_to_cpu(seqn)); file_id = cpu_to_le64(file_id_cpu); indx.header.data_offset = const_cpu_to_le16( sizeof(INDEX_ENTRY_HEADER) + sizeof(REPARSE_INDEX_KEY)); indx.header.data_length = const_cpu_to_le16(0); indx.header.reservedV = const_cpu_to_le32(0); indx.header.length = const_cpu_to_le16( sizeof(struct REPARSE_INDEX)); indx.header.key_length = const_cpu_to_le16( sizeof(REPARSE_INDEX_KEY)); indx.header.flags = const_cpu_to_le16(0); indx.header.reserved = const_cpu_to_le16(0); indx.key.reparse_tag = reparse_tag; /* danger on processors which require proper alignment ! */ memcpy(&indx.key.file_id, &file_id, 8); indx.filling = const_cpu_to_le32(0); ntfs_index_ctx_reinit(xr); return (ntfs_ie_add(xr,(INDEX_ENTRY*)&indx)); }
int cpu_to_le_acl(const struct POSIX_ACL *acl, size_t size, struct LE_POSIX_ACL *le_acl) { int i; int cnt; le_acl->version = acl->version; le_acl->flags = acl->flags; le_acl->filler = const_cpu_to_le16(0); cnt = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE); for (i=0; i<cnt; i++) { le_acl->ace[i].tag = cpu_to_le16(acl->ace[i].tag); le_acl->ace[i].perms = cpu_to_le16(acl->ace[i].perms); le_acl->ace[i].id = cpu_to_le32(acl->ace[i].id); } return (0); }
/** * change_label - change the current label on a device * @dev: device to change the label on * @mnt_flags: mount flags of the device or 0 if not mounted * @mnt_point: mount point of the device or NULL * @label: the new label * * Change the label on the device @dev to @label. */ static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, BOOL force) { ntfschar *new_label = NULL; int label_len; int result = 0; //XXX significant? if (mnt_flags & NTFS_MF_MOUNTED) { /* If not the root fs or mounted read/write, refuse change. */ if (!(mnt_flags & NTFS_MF_ISROOT) || !(mnt_flags & NTFS_MF_READONLY)) { if (!force) { ntfs_log_error("Refusing to change label on " "read-%s mounted device %s.\n", mnt_flags & NTFS_MF_READONLY ? "only" : "write", opts.device); return 1; } } } label_len = ntfs_mbstoucs(label, &new_label); if (label_len == -1) { ntfs_log_perror("Unable to convert label string to Unicode"); return 1; } else if (label_len*sizeof(ntfschar) > 0x100) { ntfs_log_warning("New label is too long. Maximum %u characters " "allowed. Truncating %u excess characters.\n", (unsigned)(0x100 / sizeof(ntfschar)), (unsigned)(label_len - (0x100 / sizeof(ntfschar)))); label_len = 0x100 / sizeof(ntfschar); label[label_len] = const_cpu_to_le16(0); } if(!opts.noaction) result = ntfs_volume_rename(vol, new_label, label_len) ? 1 : 0; free(new_label); return result; }
static int mark_sector_deleted(struct partition *part, u_long old_addr) { int block, offset, rc; u_long addr; size_t retlen; u16 del = const_cpu_to_le16(SECTOR_DELETED); block = old_addr / part->block_size; offset = (old_addr % part->block_size) / SECTOR_SIZE - part->header_sectors_per_block; addr = part->blocks[block].offset + (HEADER_MAP_OFFSET + offset) * sizeof(u16); rc = part->mbd.mtd->write(part->mbd.mtd, addr, sizeof(del), &retlen, (u_char*)&del); if (!rc && retlen != sizeof(del)) rc = -EIO; if (rc) { printk(KERN_WARNING PREFIX "error writing '%s' at " "0x%lx\n", part->mbd.mtd->name, addr); if (rc) goto err; } if (block == part->current_block) part->header_cache[offset + HEADER_MAP_OFFSET] = del; part->blocks[block].used_sectors--; if (!part->blocks[block].used_sectors && !part->blocks[block].free_sectors) rc = erase_block(part, block); err: return rc; }
static int set_object_id_index(ntfs_inode *ni, ntfs_index_context *xo, const OBJECT_ID_ATTR *object_id) { struct OBJECT_ID_INDEX indx; u64 file_id_cpu; le64 file_id; le16 seqn; seqn = ni->mrec->sequence_number; file_id_cpu = MK_MREF(ni->mft_no,le16_to_cpu(seqn)); file_id = cpu_to_le64(file_id_cpu); indx.header.data_offset = const_cpu_to_le16( sizeof(INDEX_ENTRY_HEADER) + sizeof(OBJECT_ID_INDEX_KEY)); indx.header.data_length = const_cpu_to_le16( sizeof(OBJECT_ID_INDEX_DATA)); indx.header.reservedV = const_cpu_to_le32(0); indx.header.length = const_cpu_to_le16( sizeof(struct OBJECT_ID_INDEX)); indx.header.key_length = const_cpu_to_le16( sizeof(OBJECT_ID_INDEX_KEY)); indx.header.flags = const_cpu_to_le16(0); indx.header.reserved = const_cpu_to_le16(0); memcpy(&indx.key.object_id,object_id,sizeof(GUID)); indx.data.file_id = file_id; memcpy(&indx.data.birth_volume_id, &object_id->birth_volume_id,sizeof(GUID)); memcpy(&indx.data.birth_object_id, &object_id->birth_object_id,sizeof(GUID)); memcpy(&indx.data.domain_id, &object_id->domain_id,sizeof(GUID)); ntfs_index_ctx_reinit(xo); return (ntfs_ie_add(xo,(INDEX_ENTRY*)&indx)); }
static char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction, int count, const char *mnt_point, BOOL isdir) { char *target; char *fulltarget; int sz; char *q; enum { FULL_PATH, ABS_PATH, REJECTED_PATH } kind; target = (char*)NULL; fulltarget = (char*)NULL; /* * For a full valid path we want x:\ * where \ is an individual char and x a non-null char */ if ((count >= 3) && junction[0] && (junction[1] == const_cpu_to_le16(':')) && (junction[2] == const_cpu_to_le16('\\'))) kind = FULL_PATH; else /* * For an absolute path we want an initial \ */ if ((count >= 0) && (junction[0] == const_cpu_to_le16('\\'))) kind = ABS_PATH; else kind = REJECTED_PATH; /* * Full path, with a drive letter and * no specific definition for the drive letter : * try to interpret as a target on the same volume. * Do the same for an abs path with no drive letter. */ if (((kind == FULL_PATH) && (count >= 3) && junction[3] && !ntfs_drive_letter(vol, junction[0])) || (kind == ABS_PATH)) { if (kind == ABS_PATH) target = search_absolute(vol, &junction[1], count - 1, isdir); else target = search_absolute(vol, &junction[3], count - 3, isdir); if (target) { fulltarget = (char*)ntfs_malloc(strlen(mnt_point) + strlen(target) + 2); if (fulltarget) { strcpy(fulltarget,mnt_point); strcat(fulltarget,"/"); strcat(fulltarget,target); } free(target); } } /* * full path with target not found on current volume : * link to /.NTFS-3G/target which the user can * define as a symbolic link to the real target */ if ((kind == FULL_PATH) && !fulltarget) { sz = ntfs_ucstombs(&junction[0], count,&target, 0); if ((sz > 0) && target) { /* reverse slashes */ for (q=target; *q; q++) if (*q == '\\') *q = '/'; /* force uppercase drive letter */ if ((target[1] == ':') && (target[0] >= 'a') && (target[0] <= 'z')) target[0] += 'A' - 'a'; fulltarget = (char*)ntfs_malloc(strlen(mnt_point) + sizeof(mappingdir) + strlen(target) + 1); if (fulltarget) { strcpy(fulltarget,mnt_point); strcat(fulltarget,"/"); strcat(fulltarget,mappingdir); strcat(fulltarget,target); } } if (target) free(target); } return (fulltarget); }
static char *search_relative(ntfs_inode *ni, ntfschar *path, int count) { char *target = (char*)NULL; ntfs_inode *curni; ntfs_inode *newni; u64 inum; int pos; int lth; BOOL ok; int max = 32; /* safety */ pos = 0; ok = TRUE; curni = ntfs_dir_parent_inode(ni); while (curni && ok && (pos < (count - 1)) && --max) { if ((count >= (pos + 2)) && (path[pos] == const_cpu_to_le16('.')) && (path[pos+1] == const_cpu_to_le16('\\'))) { path[1] = const_cpu_to_le16('/'); pos += 2; } else { if ((count >= (pos + 3)) && (path[pos] == const_cpu_to_le16('.')) &&(path[pos+1] == const_cpu_to_le16('.')) && (path[pos+2] == const_cpu_to_le16('\\'))) { path[2] = const_cpu_to_le16('/'); pos += 3; newni = ntfs_dir_parent_inode(curni); if (curni != ni) ntfs_inode_close(curni); curni = newni; if (!curni) ok = FALSE; } else { lth = 0; while (((pos + lth) < count) && (path[pos + lth] != const_cpu_to_le16('\\'))) lth++; if (lth > 0) inum = ntfs_fix_file_name(curni,&path[pos],lth); else inum = (u64)-1; if (!lth || ((curni != ni) && ntfs_inode_close(curni)) || (inum == (u64)-1)) ok = FALSE; else { curni = ntfs_inode_open(ni->vol, MREF(inum)); if (!curni) ok = FALSE; else { if (ok && ((pos + lth) < count)) { path[pos + lth] = const_cpu_to_le16('/'); pos += lth + 1; } else { pos += lth; if ((ni->mrec->flags ^ curni->mrec->flags) & MFT_RECORD_IS_DIRECTORY) ok = FALSE; if (ntfs_inode_close(curni)) ok = FALSE; } } } } } } if (ok && (ntfs_ucstombs(path, count, &target, 0) < 0)) { free(target); // needed ? target = (char*)NULL; } return (target); }
struct options { char *keyfile; /* .pfx file containing the user's private key. */ char *device; /* Device/File to work with */ char *file; /* File to display */ s64 inode; /* Inode to work with */ ATTR_TYPES attr; /* Attribute type to display */ int force; /* Override common sense */ int quiet; /* Less output */ int verbose; /* Extra output */ }; static const char *EXEC_NAME = "ntfsdecrypt"; static struct options opts; static ntfschar EFS[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('E'), const_cpu_to_le16('F'), const_cpu_to_le16('S'), const_cpu_to_le16('\0') }; /** * version - Print version information about the program * * Print a copyright statement and a brief description of the program. * * Return: none */ static void version(void) { ntfs_log_info("\n%s v%s (libntfs-3g) - Decrypt files and print on the " "standard output.\n\n", EXEC_NAME, VERSION); ntfs_log_info("Copyright (c) 2005 Yuval Fledel\n");
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include "types.h" #include "layout.h" #include "attrib.h" #include "security.h" #include "misc.h" #include "bitmap.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))); }
/** * init_system_file_sd - * * NTFS 3.1 - System files security decriptors * ===================================================== * * Create the security descriptor for system file number @sys_file_no and * return a pointer to the descriptor. * * Note the root directory system file (".") is very different and handled by a * different function. * * The sd is returned in *@sd_val and has length *@sd_val_len. * * Do NOT free *@sd_val as it is static memory. This also means that you can * only use *@sd_val until the next call to this function. */ void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len) { static u8 sd_array[0x68]; SECURITY_DESCRIPTOR_RELATIVE *sd; ACL *acl; ACCESS_ALLOWED_ACE *aa_ace; SID *sid; le32 *sub_authorities; if (sys_file_no < 0) { *sd_val = NULL; *sd_val_len = 0; return; } *sd_val = sd_array; sd = (SECURITY_DESCRIPTOR_RELATIVE*)&sd_array; sd->revision = 1; sd->alignment = 0; sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; *sd_val_len = 0x64; sd->owner = const_cpu_to_le32(0x48); sd->group = const_cpu_to_le32(0x54); sd->sacl = const_cpu_to_le32(0); sd->dacl = const_cpu_to_le32(0x14); /* * Now at offset 0x14, as specified in the security descriptor, we have * the DACL. */ acl = (ACL*)((char*)sd + le32_to_cpu(sd->dacl)); acl->revision = 2; acl->alignment1 = 0; acl->size = const_cpu_to_le16(0x34); acl->ace_count = const_cpu_to_le16(2); acl->alignment2 = const_cpu_to_le16(0); /* * Now at offset 0x1c, just after the DACL's ACL, we have the first * ACE of the DACL. The type of the ACE is access allowed. */ aa_ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL)); aa_ace->type = ACCESS_ALLOWED_ACE_TYPE; aa_ace->flags = 0; aa_ace->size = const_cpu_to_le16(0x14); switch (sys_file_no) { case FILE_AttrDef: case FILE_Boot: aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA; break; default: aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_WRITE | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_WRITE_EA | FILE_READ_EA | FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA; break; } aa_ace->sid.revision = 1; aa_ace->sid.sub_authority_count = 1; aa_ace->sid.identifier_authority.value[0] = 0; aa_ace->sid.identifier_authority.value[1] = 0; aa_ace->sid.identifier_authority.value[2] = 0; aa_ace->sid.identifier_authority.value[3] = 0; aa_ace->sid.identifier_authority.value[4] = 0; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ aa_ace->sid.identifier_authority.value[5] = 5; aa_ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); /* * Now at offset 0x30 within security descriptor, just after the first * ACE of the DACL. All system files, except the root directory, have * a second ACE. */ /* The second ACE of the DACL. Type is access allowed. */ aa_ace = (ACCESS_ALLOWED_ACE*)((char*)aa_ace + le16_to_cpu(aa_ace->size)); aa_ace->type = ACCESS_ALLOWED_ACE_TYPE; aa_ace->flags = 0; aa_ace->size = const_cpu_to_le16(0x18); /* Only $AttrDef and $Boot behave differently to everything else. */ switch (sys_file_no) { case FILE_AttrDef: case FILE_Boot: aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA; break; default: aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_WRITE_EA | FILE_READ_EA | FILE_APPEND_DATA | FILE_WRITE_DATA | FILE_READ_DATA; break; } aa_ace->sid.revision = 1; aa_ace->sid.sub_authority_count = 2; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ aa_ace->sid.identifier_authority.value[0] = 0; aa_ace->sid.identifier_authority.value[1] = 0; aa_ace->sid.identifier_authority.value[2] = 0; aa_ace->sid.identifier_authority.value[3] = 0; aa_ace->sid.identifier_authority.value[4] = 0; aa_ace->sid.identifier_authority.value[5] = 5; sub_authorities = aa_ace->sid.sub_authority; *sub_authorities++ = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); *sub_authorities = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); /* * Now at offset 0x48 into the security descriptor, as specified in the * security descriptor, we now have the owner SID. */ sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); sid->revision = 1; sid->sub_authority_count = 1; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ sid->identifier_authority.value[0] = 0; sid->identifier_authority.value[1] = 0; sid->identifier_authority.value[2] = 0; sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); /* * Now at offset 0x54 into the security descriptor, as specified in the * security descriptor, we have the group SID. */ sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); sid->revision = 1; sid->sub_authority_count = 2; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ sid->identifier_authority.value[0] = 0; sid->identifier_authority.value[1] = 0; sid->identifier_authority.value[2] = 0; sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; sub_authorities = sid->sub_authority; *sub_authorities++ = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); *sub_authorities = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); }
static char *ntfs_get_fulllink(ntfs_volume *vol, ntfschar *junction, int count, const char *mnt_point, BOOL isdir) { char *target; char *fulltarget; int sz; char *q; enum { DIR_JUNCTION, VOL_JUNCTION, NO_JUNCTION } kind; target = (char*)NULL; fulltarget = (char*)NULL; /* * For a valid directory junction we want \??\x:\ * where \ is an individual char and x a non-null char */ if ((count >= 7) && !memcmp(junction,dir_junction_head,8) && junction[4] && (junction[5] == const_cpu_to_le16(':')) && (junction[6] == const_cpu_to_le16('\\'))) kind = DIR_JUNCTION; else /* * For a valid volume junction we want \\?\Volume{ * and a final \ (where \ is an individual char) */ if ((count >= 12) && !memcmp(junction,vol_junction_head,22) && (junction[count-1] == const_cpu_to_le16('\\'))) kind = VOL_JUNCTION; else kind = NO_JUNCTION; /* * Directory junction with an explicit path and * no specific definition for the drive letter : * try to interpret as a target on the same volume */ if ((kind == DIR_JUNCTION) && (count >= 7) && junction[7] && !ntfs_drive_letter(vol, junction[4])) { target = search_absolute(vol,&junction[7],count - 7, isdir); if (target) { fulltarget = (char*)ntfs_malloc(strlen(mnt_point) + strlen(target) + 2); if (fulltarget) { strcpy(fulltarget,mnt_point); strcat(fulltarget,"/"); strcat(fulltarget,target); } free(target); } } /* * Volume junctions or directory junctions with * target not found on current volume : * link to /.NTFS-3G/target which the user can * define as a symbolic link to the real target */ if (((kind == DIR_JUNCTION) && !fulltarget) || (kind == VOL_JUNCTION)) { sz = ntfs_ucstombs(&junction[4], (kind == VOL_JUNCTION ? count - 5 : count - 4), &target, 0); if ((sz > 0) && target) { /* reverse slashes */ for (q=target; *q; q++) if (*q == '\\') *q = '/'; /* force uppercase drive letter */ if ((target[1] == ':') && (target[0] >= 'a') && (target[0] <= 'z')) target[0] += 'A' - 'a'; fulltarget = (char*)ntfs_malloc(strlen(mnt_point) + sizeof(mappingdir) + strlen(target) + 1); if (fulltarget) { strcpy(fulltarget,mnt_point); strcat(fulltarget,"/"); strcat(fulltarget,mappingdir); strcat(fulltarget,target); } } if (target) free(target); } return (fulltarget); }
static char *search_relative(ntfs_inode *ni, ntfschar *path, int count) { char *target = (char*)NULL; ntfs_inode *curni; ntfs_inode *newni; u64 inum; int pos; int lth; BOOL ok; BOOL morelinks; int max = 32; /* safety */ pos = 0; ok = TRUE; morelinks = FALSE; curni = ntfs_dir_parent_inode(ni); /* * Examine and translate the path, until we reach either * - the end, * - an unknown item * - a non-directory * - another reparse point, * A reparse point is not dereferenced, it will be * examined later when the translated path is dereferenced, * however the final part of the path will not be adjusted * to correct case. */ while (curni && ok && !morelinks && (pos < (count - 1)) && --max) { if ((count >= (pos + 2)) && (path[pos] == const_cpu_to_le16('.')) && (path[pos+1] == const_cpu_to_le16('\\'))) { path[1] = const_cpu_to_le16('/'); pos += 2; } else { if ((count >= (pos + 3)) && (path[pos] == const_cpu_to_le16('.')) &&(path[pos+1] == const_cpu_to_le16('.')) && (path[pos+2] == const_cpu_to_le16('\\'))) { path[2] = const_cpu_to_le16('/'); pos += 3; newni = ntfs_dir_parent_inode(curni); if (curni != ni) ntfs_inode_close(curni); curni = newni; if (!curni) ok = FALSE; } else { lth = 0; while (((pos + lth) < count) && (path[pos + lth] != const_cpu_to_le16('\\'))) lth++; if (lth > 0) inum = ntfs_fix_file_name(curni,&path[pos],lth); else inum = (u64)-1; if (!lth || ((curni != ni) && ntfs_inode_close(curni)) || (inum == (u64)-1)) ok = FALSE; else { curni = ntfs_inode_open(ni->vol, MREF(inum)); if (!curni) ok = FALSE; else { if (curni->flags & FILE_ATTR_REPARSE_POINT) morelinks = TRUE; if (ok && ((pos + lth) < count)) { path[pos + lth] = const_cpu_to_le16('/'); pos += lth + 1; if (morelinks && ntfs_inode_close(curni)) ok = FALSE; } else { pos += lth; if (!morelinks && (ni->mrec->flags ^ curni->mrec->flags) & MFT_RECORD_IS_DIRECTORY) ok = FALSE; if (ntfs_inode_close(curni)) ok = FALSE; } } } } } } if (ok && (ntfs_ucstombs(path, count, &target, 0) < 0)) { free(target); // needed ? target = (char*)NULL; } return (target); }
/** * @attr_rec: The attribute record to check * @mft_rec: The parent FILE record. * @buflen: The size of the FILE record. * * Return: * NULL: Fatal error occured. Not sure where is the next record. * otherwise: pointer to the next attribute record. * * The function only check fields that are inside this attr record. * * Assumes mft_rec is current_mft_record. */ static ATTR_REC *check_attr_record(ATTR_REC *attr_rec, MFT_RECORD *mft_rec, u16 buflen) { u16 name_offset; u16 attrs_offset = le16_to_cpu(mft_rec->attrs_offset); u32 attr_type = le32_to_cpu(attr_rec->type); u32 length = le32_to_cpu(attr_rec->length); // Check that this attribute does not overflow the mft_record if ((u8*)attr_rec+length >= ((u8*)mft_rec)+buflen) { check_failed("Attribute (0x%x) is larger than FILE record (%lld).\n", (int)attr_type, (long long)current_mft_record); return NULL; } // Attr type must be a multiple of 0x10 and 0x10<=x<=0x100. if ((attr_type & ~0x0F0) && (attr_type != 0x100)) { check_failed("Unknown attribute type 0x%x.\n", (int)attr_type); goto check_attr_record_next_attr; } if (length<24) { check_failed("Attribute %lld:0x%x Length too short (%u).\n", (long long)current_mft_record, (int)attr_type, (int)length); goto check_attr_record_next_attr; } // If this is the first attribute: // todo: instance number must be smaller than next_instance. if ((u8*)attr_rec == ((u8*)mft_rec) + attrs_offset) { if (!mft_rec->base_mft_record) assert_u32_equal(attr_type, 0x10, "First attribute type"); // The following not always holds. // attr 0x10 becomes instance 1 and attr 0x40 becomes 0. //assert_u32_equal(attr_rec->instance, 0, // "First attribute instance number"); } else { assert_u32_noteq(attr_type, 0x10, "Not-first attribute type"); // The following not always holds. //assert_u32_noteq(attr_rec->instance, 0, // "Not-first attribute instance number"); } //if (current_mft_record==938 || current_mft_record==1683 || current_mft_record==3152 || current_mft_record==22410) //printf("Attribute %lld:0x%x instance: %u isbase:%d.\n", // current_mft_record, (int)attr_type, (int)le16_to_cpu(attr_rec->instance), (int)mft_rec->base_mft_record); // todo: instance is unique. // Check flags. if (attr_rec->flags & ~(const_cpu_to_le16(0xc0ff))) { check_failed("Attribute %lld:0x%x Unknown flags (0x%x).\n", (long long)current_mft_record, (int)attr_type, (int)le16_to_cpu(attr_rec->flags)); } if (attr_rec->non_resident>1) { check_failed("Attribute %lld:0x%x Unknown non-resident " "flag (0x%x).\n", (long long)current_mft_record, (int)attr_type, (int)attr_rec->non_resident); goto check_attr_record_next_attr; } name_offset = le16_to_cpu(attr_rec->name_offset); /* * todo: name must be legal unicode. * Not really, information below in urls is about filenames, but I * believe it also applies to attribute names. (Yura) * http://blogs.msdn.com/michkap/archive/2006/09/24/769540.aspx * http://blogs.msdn.com/michkap/archive/2006/09/10/748699.aspx */ if (attr_rec->non_resident) { // Non-Resident // Make sure all the fields exist. if (length<64) { check_failed("Non-resident attribute %lld:0x%x too short (%u).\n", (long long)current_mft_record, (int)attr_type, (int)length); goto check_attr_record_next_attr; } if (attr_rec->compression_unit && (length<72)) { check_failed("Compressed attribute %lld:0x%x too short (%u).\n", (long long)current_mft_record, (int)attr_type, (int)length); goto check_attr_record_next_attr; } // todo: name comes before mapping pairs, and after the header. // todo: length==mapping_pairs_offset+length of compressed mapping pairs. // todo: mapping_pairs_offset is 8-byte aligned. // todo: lowest vcn <= highest_vcn // todo: if base record -> lowest vcn==0 // todo: lowest_vcn!=0 -> attribute list is used. // todo: lowest_vcn & highest_vcn are in the drive (0<=x<total clusters) // todo: mapping pairs agree with highest_vcn. // todo: compression unit == 0 or 4. // todo: reserved1 == 0. // todo: if not compressed nor sparse, initialized_size <= allocated_size and data_size <= allocated_size. // todo: if compressed or sparse, allocated_size <= initialized_size and allocated_size <= data_size // todo: if mft_no!=0 and not compressed/sparse, data_size==initialized_size. // todo: if mft_no!=0 and compressed/sparse, allocated_size==initialized_size. // todo: what about compressed_size if compressed? // todo: attribute must not be 0x10, 0x30, 0x40, 0x60, 0x70, 0x90, 0xd0 (not sure about 0xb0, 0xe0, 0xf0) } else { u16 value_offset = le16_to_cpu(attr_rec->value_offset); u32 value_length = le32_to_cpu(attr_rec->value_length); // Resident if (attr_rec->name_length) { if (name_offset < 24) check_failed("Resident attribute with " "name intersecting header.\n"); if (value_offset < name_offset + attr_rec->name_length) check_failed("Named resident attribute " "with value before name.\n"); } // if resident, length==value_length+value_offset //assert_u32_equal(le32_to_cpu(attr_rec->value_length)+ // value_offset, length, // "length==value_length+value_offset"); // if resident, length==value_length+value_offset if (value_length+value_offset > length) { check_failed("value_length(%d)+value_offset(%d)>length(%d) for attribute 0x%x.\n", (int)value_length, (int)value_offset, (int)length, (int)attr_type); return NULL; } // Check resident_flags. if (attr_rec->resident_flags>0x01) { check_failed("Unknown resident flags (0x%x) for attribute 0x%x.\n", (int)attr_rec->resident_flags, (int)attr_type); } else if (attr_rec->resident_flags && (attr_type!=0x30)) { check_failed("Resident flags mark attribute 0x%x as indexed.\n", (int)attr_type); } // reservedR is 0. assert_u32_equal(attr_rec->reservedR, 0, "Resident Reserved"); // todo: attribute must not be 0xa0 (not sure about 0xb0, 0xe0, 0xf0) // todo: check content well-formness per attr_type. } return 0; check_attr_record_next_attr: return (ATTR_REC *)(((u8 *)attr_rec) + length); }
le16 subst_name_offset; le16 subst_name_length; le16 print_name_offset; le16 print_name_length; le32 flags; /* 1 for full target, otherwise 0 */ char path_buffer[0]; /* above data assume this is char array */ } ; struct REPARSE_INDEX { /* index entry in $Extend/$Reparse */ INDEX_ENTRY_HEADER header; REPARSE_INDEX_KEY key; le32 filling; } ; static const ntfschar dir_junction_head[] = { const_cpu_to_le16('\\'), const_cpu_to_le16('?'), const_cpu_to_le16('?'), const_cpu_to_le16('\\') } ; static const ntfschar vol_junction_head[] = { const_cpu_to_le16('\\'), const_cpu_to_le16('?'), const_cpu_to_le16('?'), const_cpu_to_le16('\\'), const_cpu_to_le16('V'), const_cpu_to_le16('o'), const_cpu_to_le16('l'), const_cpu_to_le16('u'), const_cpu_to_le16('m'),
/** * init_root_sd - * * Creates the security_descriptor for the root folder on ntfs 3.1 as created * by Windows Vista (when the format is done from the disk management MMC * snap-in, note this is different from the format done from the disk * properties in Windows Explorer). */ void init_root_sd(u8 **sd_val, int *sd_val_len) { SECURITY_DESCRIPTOR_RELATIVE *sd; ACL *acl; ACCESS_ALLOWED_ACE *ace; SID *sid; le32 *sub_authorities; static char sd_array[0x102c]; *sd_val_len = 0x102c; *sd_val = (u8*)&sd_array; //security descriptor relative sd = (SECURITY_DESCRIPTOR_RELATIVE*)sd_array; sd->revision = SECURITY_DESCRIPTOR_REVISION; sd->alignment = 0; sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; sd->owner = const_cpu_to_le32(0x1014); sd->group = const_cpu_to_le32(0x1020); sd->sacl = 0; sd->dacl = const_cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE)); //acl acl = (ACL*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE)); acl->revision = ACL_REVISION; acl->alignment1 = 0; acl->size = const_cpu_to_le16(0x1000); acl->ace_count = const_cpu_to_le16(0x08); acl->alignment2 = 0; //ace1 ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL)); ace->type = ACCESS_ALLOWED_ACE_TYPE; ace->flags = 0; ace->size = const_cpu_to_le16(0x18); ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | FILE_LIST_DIRECTORY | FILE_WRITE_DATA | FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA | FILE_TRAVERSE | FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES; ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; sub_authorities = ace->sid.sub_authority; *sub_authorities++ = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); *sub_authorities = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); //ace2 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); ace->type = ACCESS_ALLOWED_ACE_TYPE; ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; ace->size = const_cpu_to_le16(0x18); ace->mask = GENERIC_ALL; ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; sub_authorities = ace->sid.sub_authority; *sub_authorities++ = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); *sub_authorities = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); //ace3 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); ace->type = ACCESS_ALLOWED_ACE_TYPE; ace->flags = 0; ace->size = const_cpu_to_le16(0x14); ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | FILE_LIST_DIRECTORY | FILE_WRITE_DATA | FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA | FILE_TRAVERSE | FILE_DELETE_CHILD | FILE_READ_ATTRIBUTES; ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x01; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); //ace4 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); ace->type = ACCESS_ALLOWED_ACE_TYPE; ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; ace->size = const_cpu_to_le16(0x14); ace->mask = GENERIC_ALL; ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x01; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); //ace5 ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size)); ace->type = ACCESS_ALLOWED_ACE_TYPE; ace->flags = 0; ace->size = const_cpu_to_le16(0x14); ace->mask = SYNCHRONIZE | READ_CONTROL | DELETE | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_TRAVERSE | FILE_WRITE_EA | FILE_READ_EA | FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | FILE_LIST_DIRECTORY; ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x01; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_AUTHENTICATED_USER_RID); //ace6 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); ace->type = ACCESS_ALLOWED_ACE_TYPE; ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; ace->size = const_cpu_to_le16(0x14); ace->mask = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE; ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x01; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_AUTHENTICATED_USER_RID); //ace7 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); ace->type = ACCESS_ALLOWED_ACE_TYPE; ace->flags = 0; ace->size = const_cpu_to_le16(0x18); ace->mask = SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_TRAVERSE | FILE_READ_EA | FILE_LIST_DIRECTORY; ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; sub_authorities = ace->sid.sub_authority; *sub_authorities++ = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); *sub_authorities = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); //ace8 ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size)); ace->type = ACCESS_ALLOWED_ACE_TYPE; ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE; ace->size = const_cpu_to_le16(0x18); ace->mask = GENERIC_READ | GENERIC_EXECUTE; ace->sid.revision = SID_REVISION; ace->sid.sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; sub_authorities = ace->sid.sub_authority; *sub_authorities++ = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); *sub_authorities = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS); //owner sid sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); sid->revision = 0x01; sid->sub_authority_count = 0x01; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ sid->identifier_authority.value[0] = 0; sid->identifier_authority.value[1] = 0; sid->identifier_authority.value[2] = 0; sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); //group sid sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); sid->revision = 0x01; sid->sub_authority_count = 0x01; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ sid->identifier_authority.value[0] = 0; sid->identifier_authority.value[1] = 0; sid->identifier_authority.value[2] = 0; sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); }
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point, int *pattr_size) { s64 attr_size = 0; char *target; unsigned int offs; unsigned int lth; ntfs_volume *vol; REPARSE_POINT *reparse_attr; struct MOUNT_POINT_REPARSE_DATA *mount_point_data; struct SYMLINK_REPARSE_DATA *symlink_data; enum { FULL_TARGET, ABS_TARGET, REL_TARGET } kind; ntfschar *p; BOOL bad; BOOL isdir; target = (char*)NULL; bad = TRUE; isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0); vol = ni->vol; reparse_attr = (REPARSE_POINT*)ntfs_attr_readall(ni, AT_REPARSE_POINT,(ntfschar*)NULL, 0, &attr_size); if (reparse_attr && attr_size && valid_reparse_data(ni, reparse_attr, attr_size)) { switch (reparse_attr->reparse_tag) { case IO_REPARSE_TAG_MOUNT_POINT : mount_point_data = (struct MOUNT_POINT_REPARSE_DATA*) reparse_attr->reparse_data; offs = le16_to_cpu(mount_point_data->subst_name_offset); lth = le16_to_cpu(mount_point_data->subst_name_length); /* reparse data consistency has been checked */ target = ntfs_get_fulllink(vol, (ntfschar*)&mount_point_data->path_buffer[offs], lth/2, mnt_point, isdir); if (target) bad = FALSE; break; case IO_REPARSE_TAG_SYMLINK : symlink_data = (struct SYMLINK_REPARSE_DATA*) reparse_attr->reparse_data; offs = le16_to_cpu(symlink_data->subst_name_offset); lth = le16_to_cpu(symlink_data->subst_name_length); p = (ntfschar*)&symlink_data->path_buffer[offs]; /* * Predetermine the kind of target, * the called function has to make a full check */ if (*p++ == const_cpu_to_le16('\\')) { if ((*p == const_cpu_to_le16('?')) || (*p == const_cpu_to_le16('\\'))) kind = FULL_TARGET; else kind = ABS_TARGET; } else if (*p == const_cpu_to_le16(':')) kind = ABS_TARGET; else kind = REL_TARGET; p--; /* reparse data consistency has been checked */ switch (kind) { case FULL_TARGET : if (!(symlink_data->flags & const_cpu_to_le32(1))) { target = ntfs_get_fulllink(vol, p, lth/2, mnt_point, isdir); if (target) bad = FALSE; } break; case ABS_TARGET : if (symlink_data->flags & const_cpu_to_le32(1)) { target = ntfs_get_abslink(vol, p, lth/2, mnt_point, isdir); if (target) bad = FALSE; } break; case REL_TARGET : if (symlink_data->flags & const_cpu_to_le32(1)) { target = ntfs_get_rellink(ni, p, lth/2); if (target) bad = FALSE; } break; } break; } free(reparse_attr); } *pattr_size = attr_size; if (bad) errno = EOPNOTSUPP; return (target); }
/** * init_secure_sds - * * NTFS 3.1 - System files security decriptors * =========================================== * Create the security descriptor entries in $SDS data stream like they * are in a partition, newly formatted with windows 2003 */ void init_secure_sds(char *sd_val) { SECURITY_DESCRIPTOR_HEADER *sds; SECURITY_DESCRIPTOR_RELATIVE *sd; ACL *acl; ACCESS_ALLOWED_ACE *ace; SID *sid; /* * security descriptor #1 */ //header sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val); sds->hash = const_cpu_to_le32(0xF80312F0); sds->security_id = const_cpu_to_le32(0x0100); sds->offset = const_cpu_to_le64(0x00); sds->length = const_cpu_to_le32(0x7C); //security descriptor relative sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds + sizeof(SECURITY_DESCRIPTOR_HEADER)); sd->revision = 0x01; sd->alignment = 0x00; sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; sd->owner = const_cpu_to_le32(0x48); sd->group = const_cpu_to_le32(0x58); sd->sacl = const_cpu_to_le32(0x00); sd->dacl = const_cpu_to_le32(0x14); //acl acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE)); acl->revision = 0x02; acl->alignment1 = 0x00; acl->size = const_cpu_to_le16(0x34); acl->ace_count = const_cpu_to_le16(0x02); acl->alignment2 = 0x00; //ace1 ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL)); ace->type = 0x00; ace->flags = 0x00; ace->size = const_cpu_to_le16(0x14); ace->mask = const_cpu_to_le32(0x120089); ace->sid.revision = 0x01; ace->sid.sub_authority_count = 0x01; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); //ace2 ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size)); ace->type = 0x00; ace->flags = 0x00; ace->size = const_cpu_to_le16(0x18); ace->mask = const_cpu_to_le32(0x120089); ace->sid.revision = 0x01; ace->sid.sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); //owner sid sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); sid->revision = 0x01; sid->sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ sid->identifier_authority.value[0] = 0; sid->identifier_authority.value[1] = 0; sid->identifier_authority.value[2] = 0; sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); //group sid sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); sid->revision = 0x01; sid->sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ sid->identifier_authority.value[0] = 0; sid->identifier_authority.value[1] = 0; sid->identifier_authority.value[2] = 0; sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); /* * security descriptor #2 */ //header sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val + 0x80); sds->hash = const_cpu_to_le32(0xB32451); sds->security_id = const_cpu_to_le32(0x0101); sds->offset = const_cpu_to_le64(0x80); sds->length = const_cpu_to_le32(0x7C); //security descriptor relative sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds + sizeof(SECURITY_DESCRIPTOR_HEADER)); sd->revision = 0x01; sd->alignment = 0x00; sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT; sd->owner = const_cpu_to_le32(0x48); sd->group = const_cpu_to_le32(0x58); sd->sacl = const_cpu_to_le32(0x00); sd->dacl = const_cpu_to_le32(0x14); //acl acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE)); acl->revision = 0x02; acl->alignment1 = 0x00; acl->size = const_cpu_to_le16(0x34); acl->ace_count = const_cpu_to_le16(0x02); acl->alignment2 = 0x00; //ace1 ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL)); ace->type = 0x00; ace->flags = 0x00; ace->size = const_cpu_to_le16(0x14); ace->mask = const_cpu_to_le32(0x12019F); ace->sid.revision = 0x01; ace->sid.sub_authority_count = 0x01; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID); //ace2 ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size)); ace->type = 0x00; ace->flags = 0x00; ace->size = const_cpu_to_le16(0x18); ace->mask = const_cpu_to_le32(0x12019F); ace->sid.revision = 0x01; ace->sid.sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ ace->sid.identifier_authority.value[0] = 0; ace->sid.identifier_authority.value[1] = 0; ace->sid.identifier_authority.value[2] = 0; ace->sid.identifier_authority.value[3] = 0; ace->sid.identifier_authority.value[4] = 0; ace->sid.identifier_authority.value[5] = 5; ace->sid.sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); ace->sid.sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); //owner sid sid = (SID*)((char*)sd + le32_to_cpu(sd->owner)); sid->revision = 0x01; sid->sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ sid->identifier_authority.value[0] = 0; sid->identifier_authority.value[1] = 0; sid->identifier_authority.value[2] = 0; sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); //group sid sid = (SID*)((char*)sd + le32_to_cpu(sd->group)); sid->revision = 0x01; sid->sub_authority_count = 0x02; /* SECURITY_NT_SID_AUTHORITY (S-1-5) */ sid->identifier_authority.value[0] = 0; sid->identifier_authority.value[1] = 0; sid->identifier_authority.value[2] = 0; sid->identifier_authority.value[3] = 0; sid->identifier_authority.value[4] = 0; sid->identifier_authority.value[5] = 5; sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID); sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS); return; }
} OBJECT_ID_INDEX_KEY; typedef struct { le64 file_id; GUID birth_volume_id; GUID birth_object_id; GUID domain_id; } OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA struct OBJECT_ID_INDEX { /* index entry in $Extend/$ObjId */ INDEX_ENTRY_HEADER header; OBJECT_ID_INDEX_KEY key; OBJECT_ID_INDEX_DATA data; } ; static ntfschar objid_index_name[] = { const_cpu_to_le16('$'), const_cpu_to_le16('O') }; #ifdef HAVE_SETXATTR /* extended attributes interface required */ /* * Set the index for a new object id * * Returns 0 if success * -1 if failure, explained by errno */ static int set_object_id_index(ntfs_inode *ni, ntfs_index_context *xo, const OBJECT_ID_ATTR *object_id) { struct OBJECT_ID_INDEX indx; u64 file_id_cpu;