Blob Blame History Raw
/***********************************************************/
/*  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);
}