/***********************************************************/
/* ntux: native translation und extension */
/* Copyright (C) 2016--2018 Z. Gilboa */
/* Released under GPLv2 and GPLv3; see COPYING.NTUX. */
/***********************************************************/
#include <psxabi/sys_sysapi.h>
#include <psxabi/sys_stat.h>
#include <psxabi/sys_errno.h>
#include <psxxfi/xfi_base.h>
#include <psxxfi/xfi_acl.h>
#include <psxxfi/xfi_fs.h>
#include <psxxfi/xfi_ofd.h>
#include <psxxfi/xfi_unicode.h>
#include <ntapi/nt_object.h>
#include <ntapi/nt_acl.h>
#include <ntapi/nt_file.h>
#include <ntux/ntux.h>
#include "ntux_driver_impl.h"
#include "ntux_nolibc_impl.h"
#include "ntux_errinfo_impl.h"
#define __SID_SYSTEM {1,1,{{0,0,0,0,0,5}},{18}}
#define __SID_ADMINISTRATORS {1,2,{{0,0,0,0,0,5}},{32,544}}
static const nt_sid sid_system = __SID_SYSTEM;
static const nt_sid_os sid_admins = __SID_ADMINISTRATORS;
static int ntux_cmd_chmod_ret(int fd, struct __ofd * ofd, void * hasync, int ret)
{
if (hasync)
__xfi_close_handle(hasync);
if (ofd)
__xfi_ofd_ref_dec(ofd);
if (fd >= 0)
__sys_close(fd);
return ret;
}
static nt_sid * ntux_cmd_chmod_sid_from_name(const char * name)
{
if (!strcmp(name,"Administrators"))
return (nt_sid *)&sid_admins;
else if (!strcmp(name,"SYSTEM"))
return (nt_sid *)&sid_system;
else
return 0;
}
int ntux_cmd_chmod(const struct ntux_driver_ctx * dctx, const char * dunit)
{
intptr_t ret;
int32_t status;
int fdout;
int fdcwd;
const unsigned char * unit;
nt_sd * srcsd;
nt_sd_common_buffer dstsd;
nt_sd_common_meta meta;
nt_sid * owner;
nt_sid * group;
uint32_t access_owner;
uint32_t access_group;
uint32_t access_other;
uint32_t access_admin;
uint32_t ace_flags;
uint32_t sec_mask;
size_t size;
int fd = -1;
struct __ofd * ofd = 0;
void * hasync = 0;
uint32_t buf[0x300];
/* ACE propagation: +p, -p */
if (!dctx->cctx->strmode)
ace_flags = 0;
else if (!strcmp(dctx->cctx->strmode,"+p"))
ace_flags = NT_ACE_CONTAINER_INHERIT | NT_ACE_OBJECT_INHERIT;
else if (!strcmp(dctx->cctx->strmode,"-p"))
ace_flags = 0;
else
return ntux_cmd_chmod_ret(
0,0,0,
NTUX_CUSTOM_ERROR(
dctx,
NTUX_ERR_FLEE_ERROR));
/* initial --owner and --group support: Administrators, SYSTEM */
owner = 0;
group = 0;
if (dctx->cctx->owner)
if (!(owner = ntux_cmd_chmod_sid_from_name(dctx->cctx->owner)))
return ntux_cmd_chmod_ret(
0,0,0,
NTUX_CUSTOM_ERROR(
dctx,
NTUX_ERR_NOT_IMPLEMENTED));
if (dctx->cctx->group)
if (!(group = ntux_cmd_chmod_sid_from_name(dctx->cctx->group)))
return ntux_cmd_chmod_ret(
0,0,0,
NTUX_CUSTOM_ERROR(
dctx,
NTUX_ERR_NOT_IMPLEMENTED));
/* init */
ntux_driver_set_ectx(
dctx,0,dunit);
unit = (const unsigned char *)dunit;
/* fdctx */
fdout = ntux_driver_fdout(dctx);
fdcwd = ntux_driver_fdcwd(dctx);
/* fd */
if ((ret = __sys_openat(fdcwd,unit,0,0)) < 0)
if (ntux_errno_set(dctx,ret))
return ntux_cmd_chmod_ret(
0,0,0,
NTUX_SYSTEM_ERROR(dctx));
fd = ret;
/* ofd */
if (!(ofd = __xfi_ofd_ref_inc(fd)))
return ntux_cmd_chmod_ret(
fd,0,0,
NTUX_CUSTOM_ERROR(
dctx,
NTUX_ERR_FLOW_ERROR));
/* hasync */
sec_mask = NT_SEC_READ_CONTROL;
sec_mask |= NT_SEC_WRITE_DAC;
sec_mask |= owner ? NT_SEC_WRITE_OWNER : 0;
if ((status = __xfi_fs_open_async(
&hasync,
ofd->info.hfile,0,
sec_mask,
NT_FILE_SHARE_READ
| NT_FILE_SHARE_WRITE
| NT_FILE_SHARE_DELETE)))
if (ntux_errno_set(dctx,EACCES))
return ntux_cmd_chmod_ret(
fd,ofd,0,
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)))
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,
NT_ACL_INIT_COMMON_DESCRIPTION_META_STRICT_MODE)))
if (ntux_errno_set(dctx,EBADF))
return ntux_cmd_chmod_ret(
fd,ofd,hasync,
NTUX_SYSTEM_ERROR(dctx));
/* source permissions */
access_owner = meta.owner_ace ? meta.owner_ace->mask : 0;
access_group = meta.group_ace ? meta.group_ace->mask : 0;
access_other = meta.other_ace ? meta.other_ace->mask : 0;
access_admin = meta.admin_ace ? meta.admin_ace->mask : 0;
/* initial --strmode support, retaining previous options as needed */
if (!dctx->cctx->strmode) {
ace_flags |= meta.owner_ace ? meta.owner_ace->header.ace_flags : 0;
ace_flags |= meta.group_ace ? meta.group_ace->header.ace_flags : 0;
ace_flags |= meta.other_ace ? meta.other_ace->header.ace_flags : 0;
ace_flags |= meta.admin_ace ? meta.admin_ace->header.ace_flags : 0;
}
/* updated dacl */
__xfi_acl_init_common_descriptor(
&dstsd,
owner ? owner : meta.owner,
group ? group : meta.group,
0,0,
access_owner,access_group,access_other,
access_admin,meta.system_acc,
ace_flags);
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)))
if (ntux_errno_set(dctx,EPERM))
return ntux_cmd_chmod_ret(
fd,ofd,hasync,
NTUX_SYSTEM_ERROR(dctx));
/* changes */
(void)fdout;
/* all done */
return ntux_cmd_chmod_ret(fd,ofd,hasync,0);
}