diff --git a/src/cmds/ntux_cmd_chmod.c b/src/cmds/ntux_cmd_chmod.c index 7be2bc8..773c8ea 100644 --- a/src/cmds/ntux_cmd_chmod.c +++ b/src/cmds/ntux_cmd_chmod.c @@ -6,12 +6,14 @@ #include #include +#include #include #include #include #include #include +#include #include #include @@ -32,9 +34,22 @@ #define NTUX_OPT_MODE_PLUS (2) #define NTUX_OPT_MODE_MINUS (3) +#define NTUX_BUF_SIZE_64K (64*1024) + static const nt_sid sid_system = __SID_SYSTEM; static const nt_sid_os sid_admins = __SID_ADMINISTRATORS; +struct ntux_sd_buffer { + nt_sd_common_buffer sd; + uint32_t exbuf[512]; +}; + +struct ntux_ace_any { + nt_ace_header header; + uint32_t mask; + uint32_t sid_start; +}; + static int ntux_cmd_chmod_ret(int fd, struct __ofd * ofd, void * hasync, int ret) { if (hasync) @@ -67,15 +82,22 @@ int ntux_cmd_chmod(const struct ntux_driver_ctx * dctx, const char * dunit) int32_t status; int fdout; int fdcwd; + int finherit; int optmode; const char * strmode; const char * chmode; const unsigned char * unit; - nt_sd * srcsd; - nt_sd_common_buffer dstsd; + char * ch; + struct ntux_sd_buffer sdbuf; + struct ntux_sd_buffer srcsd; + struct ntux_sd_buffer cntsd; + nt_sd_common_buffer * dstsd; nt_sd_common_meta meta; nt_sid * owner; nt_sid * group; + nt_acl * dacl; + struct ntux_ace_any * srcace; + struct ntux_ace_any * dstace; uint32_t access_owner; uint32_t access_group; uint32_t access_other; @@ -83,20 +105,34 @@ int ntux_cmd_chmod(const struct ntux_driver_ctx * dctx, const char * dunit) uint32_t ace_flags; uint32_t sec_mask; size_t size; + size_t addr; + size_t aceaddr; + size_t cntbufsize; + char * cntpath_utf8; + wchar16_t * cntpath_utf16; + int exacefilter; + size_t exacesize; + int exacecount; + int idx; int fd = -1; + int cntfd = -1; struct __ofd * ofd = 0; + struct __ofd * cntofd = 0; + void * cntbuf = 0; void * hasync = 0; - uint32_t buf[0x300] = {0}; + char dummy = 0; /* strmode */ - strmode = dctx->cctx->strmode ? dctx->cctx->strmode : (char *)buf; + strmode = dctx->cctx->strmode ? dctx->cctx->strmode : &dummy; optmode = NTUX_OPT_MODE_NEUTRAL; + finherit = false; ace_flags = 0; for (chmode=strmode; *chmode; chmode++) { switch (*chmode) { case '=': optmode = NTUX_OPT_MODE_EQUAL; + finherit = 0; ace_flags = 0; break; @@ -129,6 +165,27 @@ int ntux_cmd_chmod(const struct ntux_driver_ctx * dctx, const char * dunit) break; + case 'P': + switch (optmode) { + case NTUX_OPT_MODE_EQUAL: + case NTUX_OPT_MODE_PLUS: + finherit = true; + break; + + case NTUX_OPT_MODE_MINUS: + finherit = false; + break; + + default: + return ntux_cmd_chmod_ret( + 0,0,0, + NTUX_CUSTOM_ERROR( + dctx, + NTUX_ERR_FLEE_ERROR)); + } + + break; + default: return ntux_cmd_chmod_ret( 0,0,0, @@ -203,21 +260,19 @@ int ntux_cmd_chmod(const struct ntux_driver_ctx * dctx, const char * dunit) NTUX_SYSTEM_ERROR(dctx)); /* srcsd */ - srcsd = (nt_sd *)buf; - if ((status = __xfi_query_security_object( hasync, NT_OWNER_SECURITY_INFORMATION | NT_GROUP_SECURITY_INFORMATION | NT_DACL_SECURITY_INFORMATION, - srcsd,sizeof(buf),&size))) + &srcsd.sd.sd,sizeof(srcsd),&size))) if (ntux_errno_set(dctx,ENXIO)) return ntux_cmd_chmod_ret( fd,ofd,hasync, NTUX_SYSTEM_ERROR(dctx)); if ((status = __xfi_acl_init_common_descriptor_meta( - &meta,srcsd, + &meta,&srcsd.sd.sd, NT_ACL_INIT_COMMON_DESCRIPTION_META_STRICT_MODE))) if (ntux_errno_set(dctx,EBADF)) return ntux_cmd_chmod_ret( @@ -239,8 +294,10 @@ int ntux_cmd_chmod(const struct ntux_driver_ctx * dctx, const char * dunit) } /* updated dacl */ + dstsd = &sdbuf.sd; + __xfi_acl_init_common_descriptor( - &dstsd, + dstsd, owner ? owner : meta.owner, group ? group : meta.group, 0,0, @@ -248,11 +305,213 @@ int ntux_cmd_chmod(const struct ntux_driver_ctx * dctx, const char * dunit) access_admin,meta.system_acc, ace_flags); + if ((dstsd->sd.offset_dacl < dstsd->sd.offset_owner) + || (dstsd->sd.offset_dacl < dstsd->sd.offset_group) + || (dstsd->sd.offset_dacl < dstsd->sd.offset_sacl)) + return ntux_cmd_chmod_ret( + fd,0,0, + NTUX_CUSTOM_ERROR( + dctx, + NTUX_ERR_FLOW_ERROR)); + + /* inherited ace's */ + if (finherit) { + dstsd->sd.control = NT_SE_SELF_RELATIVE + | NT_SE_DACL_AUTO_INHERIT_REQ + | NT_SE_DACL_AUTO_INHERITED + | NT_SE_DACL_PRESENT; + + /* cntofd */ + cntbuf = 0; cntbufsize = NTUX_BUF_SIZE_64K; + + if (__xfi_allocate_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + &cntbuf, + 0, + &cntbufsize, + NT_MEM_COMMIT, + NT_PAGE_READWRITE)) + return ntux_cmd_chmod_ret( + fd,ofd,hasync, + NTUX_SYSTEM_ERROR(dctx)); + + if (__xfi_ofd_is_dir(ofd)) { + cntpath_utf16 = (wchar16_t *)cntbuf; + + __xfi_path_conv_ofdat_utf16( + ofd, + (const wchar16_t[]){'.','.','/',0}, + PSX_PATH_SYNTAX_ANY, + 4*sizeof(wchar16_t), + cntpath_utf16, + PSX_PATH_SYNTAX_POSIX_STRICT, + cntbufsize, + 0,0,PSX_PATH_CONV_RESOLVE_ELEMENT, + &cntofd); + } else { + cntpath_utf8 = cntbuf; + + status = __xfi_path_conv_utf8( + fdcwd, + unit, + PSX_PATH_SYNTAX_POSIX_STRICT, + ntux_strlen((const char *)unit), + cntpath_utf8, + PSX_PATH_SYNTAX_POSIX_STRICT, + cntbufsize, + 0,0,PSX_PATH_CONV_RESOLVE_ELEMENT, + 0); + + if (status) { + __xfi_free_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + &cntbuf, + &cntbufsize, + NT_MEM_RELEASE); + + return ntux_cmd_chmod_ret( + fd,ofd,hasync, + NTUX_CUSTOM_ERROR( + dctx, + NTUX_ERR_FLOW_ERROR)); + } + + if ((cntpath_utf8[0] == '/') && cntpath_utf8[1]) { + for (ch=cntpath_utf8; *ch; ch++) + (void)0; + + /* guard against an internal error */ + if (ch[-1] != '/') { + for (--ch; *ch != '/'; ch--) + (void)0; + + *ch = 0; + + cntfd = __sys_openat( + fdcwd, + (const unsigned char *)cntpath_utf8, + 0,0); + + if (cntfd >= 0) + if (!(cntofd = __xfi_ofd_ref_inc(cntfd))) + __sys_close(cntfd); + } + } + } + + __xfi_free_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + &cntbuf, + &cntbufsize, + NT_MEM_RELEASE); + + if (!cntofd) + return ntux_cmd_chmod_ret( + fd,ofd,hasync, + NTUX_CUSTOM_ERROR( + dctx, + NTUX_ERR_FLOW_ERROR)); + + status = __xfi_query_security_object( + cntofd->info.hfile, + NT_OWNER_SECURITY_INFORMATION + | NT_GROUP_SECURITY_INFORMATION + | NT_DACL_SECURITY_INFORMATION, + &cntsd.sd.sd,sizeof(cntsd),&size); + + if (status) { + __xfi_ofd_ref_dec(cntofd); + __sys_close(cntfd); + + return ntux_cmd_chmod_ret( + fd,ofd,hasync, + NTUX_SYSTEM_ERROR(dctx)); + } + + /* exacefilter */ + exacefilter = __xfi_ofd_is_dir(ofd) + ? NT_ACE_CONTAINER_INHERIT + : NT_ACE_OBJECT_INHERIT; + + /* exacecount, exacesize */ + if (cntsd.sd.sd.offset_dacl) { + addr = (size_t)&cntsd.sd.sd; + addr += cntsd.sd.sd.offset_dacl; + dacl = (nt_acl *)addr; + + addr += sizeof(*dacl); + + exacecount = 0; + exacesize = 0; + + for (idx=0; idxace_count; idx++) { + srcace = (struct ntux_ace_any *)addr; + + if (srcace->header.ace_flags & exacefilter) { + exacecount++; + exacesize += srcace->header.ace_size; + } + + addr += srcace->header.ace_size; + } + + + /* dstsd::dacl */ + addr = (size_t)dstsd; + addr += dstsd->sd.offset_dacl; + dacl = (nt_acl *)addr; + + if (dstsd->sd.offset_dacl + dacl->acl_size + exacesize > sizeof(sdbuf)) { + __xfi_ofd_ref_dec(cntofd); + __sys_close(cntfd); + + return ntux_cmd_chmod_ret( + fd,ofd,hasync, + NTUX_BUFFER_ERROR(dctx)); + } + + dacl->acl_size += exacesize; + dacl->ace_count += exacecount; + + /* pointer to dstsd's next ace */ + aceaddr = addr; + aceaddr += sizeof(*dacl); + + for (idx=0; idxace_count; idx++) { + dstace = (struct ntux_ace_any *)aceaddr; + aceaddr += dstace->header.ace_size; + } + + dstace = (struct ntux_ace_any *)aceaddr; + + /* copy container's ace's according to filter */ + addr = (size_t)&cntsd.sd.sd; + addr += cntsd.sd.sd.offset_dacl; + dacl = (nt_acl *)addr; + addr += sizeof(*dacl); + + for (idx=0; idxace_count; idx++) { + srcace = (struct ntux_ace_any *)addr; + + if (srcace->header.ace_flags & exacefilter) { + ntux_memcpy(dstace,srcace,srcace->header.ace_size); + dstace->header.ace_flags = NT_ACE_INHERITED; + + aceaddr += srcace->header.ace_size; + dstace = (struct ntux_ace_any *)aceaddr; + } + + addr += srcace->header.ace_size; + } + } + } + + /* finalize */ sec_mask = NT_DACL_SECURITY_INFORMATION; sec_mask |= owner ? NT_OWNER_SECURITY_INFORMATION : 0; if ((status = __xfi_set_security_object( - hasync,sec_mask,&dstsd.sd))) + hasync,sec_mask,&dstsd->sd))) if (ntux_errno_set(dctx,EPERM)) return ntux_cmd_chmod_ret( fd,ofd,hasync, @@ -261,6 +520,12 @@ int ntux_cmd_chmod(const struct ntux_driver_ctx * dctx, const char * dunit) /* changes */ (void)fdout; + /* cntofd */ + if (cntofd) { + __xfi_ofd_ref_dec(cntofd); + __sys_close(cntfd); + } + /* all done */ return ntux_cmd_chmod_ret(fd,ofd,hasync,0); }