From d9723d2bedab2bdba3250cfd2e4bb74ad359bb23 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Wed, 20 Nov 2013 10:30:32 +0100 Subject: [PATCH] netapi32: Add support for info level 502 in NetShareAdd. --- dlls/netapi32/netapi32.c | 463 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 463 insertions(+) diff --git a/dlls/netapi32/netapi32.c b/dlls/netapi32/netapi32.c index e6f34590d29..d2516d84951 100644 --- a/dlls/netapi32/netapi32.c +++ b/dlls/netapi32/netapi32.c @@ -298,11 +298,474 @@ static NET_API_STATUS share_info_2_to_samba( const BYTE *buf, unsigned char **bu return NERR_Success; } +struct sid +{ + unsigned char sid_rev_num; + unsigned char num_auths; + unsigned char id_auth[6]; + unsigned int sub_auths[15]; +}; + +enum ace_type +{ + ACE_TYPE_ACCESS_ALLOWED, + ACE_TYPE_ACCESS_DENIED, + ACE_TYPE_SYSTEM_AUDIT, + ACE_TYPE_SYSTEM_ALARM, + ACE_TYPE_ALLOWED_COMPOUND, + ACE_TYPE_ACCESS_ALLOWED_OBJECT, + ACE_TYPE_ACCESS_DENIED_OBJECT, + ACE_TYPE_SYSTEM_AUDIT_OBJECT, + ACE_TYPE_SYSTEM_ALARM_OBJECT +}; + +#define SEC_ACE_FLAG_OBJECT_INHERIT 0x01 +#define SEC_ACE_FLAG_CONTAINER_INHERIT 0x02 +#define SEC_ACE_FLAG_NO_PROPAGATE_INHERIT 0x04 +#define SEC_ACE_FLAG_INHERIT_ONLY 0x08 +#define SEC_ACE_FLAG_INHERITED_ACE 0x10 +#define SEC_ACE_FLAG_SUCCESSFUL_ACCESS 0x40 +#define SEC_ACE_FLAG_FAILED_ACCESS 0x80 + +struct guid +{ + unsigned int time_low; + unsigned short time_mid; + unsigned short time_hi_and_version; + unsigned char clock_seq[2]; + unsigned char node[6]; +}; + +union ace_object_type +{ + struct guid type; +}; + +union ace_object_inherited_type +{ + struct guid inherited_type; +}; + +struct ace_object +{ + unsigned int flags; + union ace_object_type type; + union ace_object_inherited_type inherited_type; +}; + +union ace_object_ctr +{ + struct ace_object object; +}; + +struct ace +{ + enum ace_type type; + unsigned char flags; + unsigned short size; + unsigned int access_mask; + union ace_object_ctr object; + struct sid trustee; +}; + +enum acl_revision +{ + ACL_REVISION_NT4 = 2, + ACL_REVISION_ADS = 4 +}; + +struct acl +{ + enum acl_revision revision; + unsigned short size; + unsigned int num_aces; + struct ace *aces; +}; + +enum security_descriptor_revision +{ + SECURITY_DESCRIPTOR_REVISION_1 = 1 +}; + +#define SEC_DESC_OWNER_DEFAULTED 0x0001 +#define SEC_DESC_GROUP_DEFAULTED 0x0002 +#define SEC_DESC_DACL_PRESENT 0x0004 +#define SEC_DESC_DACL_DEFAULTED 0x0008 +#define SEC_DESC_SACL_PRESENT 0x0010 +#define SEC_DESC_SACL_DEFAULTED 0x0020 +#define SEC_DESC_DACL_TRUSTED 0x0040 +#define SEC_DESC_SERVER_SECURITY 0x0080 +#define SEC_DESC_DACL_AUTO_INHERIT_REQ 0x0100 +#define SEC_DESC_SACL_AUTO_INHERIT_REQ 0x0200 +#define SEC_DESC_DACL_AUTO_INHERITED 0x0400 +#define SEC_DESC_SACL_AUTO_INHERITED 0x0800 +#define SEC_DESC_DACL_PROTECTED 0x1000 +#define SEC_DESC_SACL_PROTECTED 0x2000 +#define SEC_DESC_RM_CONTROL_VALID 0x4000 +#define SEC_DESC_SELF_RELATIVE 0x8000 + +struct security_descriptor +{ + enum security_descriptor_revision revision; + unsigned short type; + struct sid *owner_sid; + struct sid *group_sid; + struct acl *sacl; + struct acl *dacl; +}; + +struct share_info_502 +{ + const char *shi502_netname; + unsigned int shi502_type; + const char *shi502_remark; + unsigned int shi502_permissions; + unsigned int shi502_max_uses; + unsigned int shi502_current_uses; + const char *shi502_path; + const char *shi502_passwd; + unsigned int shi502_reserved; + struct security_descriptor *shi502_security_descriptor; +}; + +static unsigned short sd_control_to_samba( SECURITY_DESCRIPTOR_CONTROL control ) +{ + unsigned short ret = 0; + + if (control & SE_OWNER_DEFAULTED) ret |= SEC_DESC_OWNER_DEFAULTED; + if (control & SE_GROUP_DEFAULTED) ret |= SEC_DESC_GROUP_DEFAULTED; + if (control & SE_DACL_PRESENT) ret |= SEC_DESC_DACL_PRESENT; + if (control & SE_DACL_DEFAULTED) ret |= SEC_DESC_DACL_DEFAULTED; + if (control & SE_SACL_PRESENT) ret |= SEC_DESC_SACL_PRESENT; + if (control & SE_SACL_DEFAULTED) ret |= SEC_DESC_SACL_DEFAULTED; + if (control & SE_DACL_AUTO_INHERIT_REQ) ret |= SEC_DESC_DACL_AUTO_INHERIT_REQ; + if (control & SE_SACL_AUTO_INHERIT_REQ) ret |= SEC_DESC_SACL_AUTO_INHERIT_REQ; + if (control & SE_DACL_AUTO_INHERITED) ret |= SEC_DESC_DACL_AUTO_INHERITED; + if (control & SE_SACL_AUTO_INHERITED) ret |= SEC_DESC_SACL_AUTO_INHERITED; + if (control & SE_DACL_PROTECTED) ret |= SEC_DESC_DACL_PROTECTED; + if (control & SE_SACL_PROTECTED) ret |= SEC_DESC_SACL_PROTECTED; + if (control & SE_RM_CONTROL_VALID) ret |= SEC_DESC_RM_CONTROL_VALID; + return ret; +} + +static NET_API_STATUS sid_to_samba( const SID *src, struct sid *dst ) +{ + unsigned int i; + + if (src->Revision != 1) + { + ERR( "unknown revision %u\n", src->Revision ); + return ERROR_UNKNOWN_REVISION; + } + if (src->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) + { + WARN( "invalid subauthority count %u\n", src->SubAuthorityCount ); + return ERROR_INVALID_PARAMETER; + } + dst->sid_rev_num = SECURITY_DESCRIPTOR_REVISION_1; + dst->num_auths = src->SubAuthorityCount; + for (i = 0; i < 6; i++) dst->id_auth[i] = src->IdentifierAuthority.Value[i]; + for (i = 0; i < dst->num_auths; i++) dst->sub_auths[i] = src->SubAuthority[i]; + return NERR_Success; +} + +static enum ace_type ace_type_to_samba( BYTE type ) +{ + switch (type) + { + case ACCESS_ALLOWED_ACE_TYPE: return ACE_TYPE_ACCESS_ALLOWED; + case ACCESS_DENIED_ACE_TYPE: return ACE_TYPE_ACCESS_DENIED; + case SYSTEM_AUDIT_ACE_TYPE: return ACE_TYPE_SYSTEM_AUDIT; + case SYSTEM_ALARM_ACE_TYPE: return ACE_TYPE_SYSTEM_ALARM; + default: + ERR( "unhandled type %u\n", type ); + return 0; + } +} + +static unsigned char ace_flags_to_samba( BYTE flags ) +{ + static const BYTE known_flags = + OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | NO_PROPAGATE_INHERIT_ACE | + INHERIT_ONLY_ACE | INHERITED_ACE | SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG; + unsigned char ret = 0; + + if (flags & ~known_flags) + { + ERR( "unknown flags %x\n", flags & ~known_flags ); + return 0; + } + if (flags & OBJECT_INHERIT_ACE) ret |= SEC_ACE_FLAG_OBJECT_INHERIT; + if (flags & CONTAINER_INHERIT_ACE) ret |= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT; + if (flags & NO_PROPAGATE_INHERIT_ACE) ret |= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT; + if (flags & INHERIT_ONLY_ACE) ret |= SEC_ACE_FLAG_INHERIT_ONLY; + if (flags & INHERITED_ACE) ret |= SEC_ACE_FLAG_INHERITED_ACE; + if (flags & SUCCESSFUL_ACCESS_ACE_FLAG) ret |= SEC_ACE_FLAG_SUCCESSFUL_ACCESS; + if (flags & FAILED_ACCESS_ACE_FLAG) ret |= SEC_ACE_FLAG_FAILED_ACCESS; + return ret; +} + +#define GENERIC_ALL_ACCESS (1 << 28) +#define GENERIC_EXECUTE_ACCESS (1 << 29) +#define GENERIC_WRITE_ACCESS (1 << 30) +#define GENERIC_READ_ACCESS (1 << 31) + +unsigned int access_mask_to_samba( DWORD mask ) +{ + static const DWORD known_rights = + GENERIC_ALL | GENERIC_EXECUTE | GENERIC_WRITE | GENERIC_READ; + unsigned int ret = 0; + + if (mask & ~known_rights) + { + ERR( "unknown rights %x\n", mask & ~known_rights ); + return 0; + } + if (mask & GENERIC_ALL) ret |= GENERIC_ALL_ACCESS; + if (mask & GENERIC_EXECUTE) ret |= GENERIC_EXECUTE_ACCESS; + if (mask & GENERIC_WRITE) ret |= GENERIC_WRITE_ACCESS; + if (mask & GENERIC_READ) ret |= GENERIC_READ_ACCESS; + return ret; +} + +static NET_API_STATUS ace_to_samba( const ACE_HEADER *src, struct ace *dst ) +{ + dst->type = ace_type_to_samba( src->AceType ); + dst->flags = ace_flags_to_samba( src->AceFlags ); + dst->size = sizeof(*dst); + switch (src->AceType) + { + case ACCESS_ALLOWED_ACE_TYPE: + { + ACCESS_ALLOWED_ACE *ace = (ACCESS_ALLOWED_ACE *)src; + dst->access_mask = access_mask_to_samba( ace->Mask ); + memset( &dst->object, 0, sizeof(dst->object) ); + sid_to_samba( (const SID *)&ace->SidStart, &dst->trustee ); + } + case ACCESS_DENIED_ACE_TYPE: + { + ACCESS_DENIED_ACE *ace = (ACCESS_DENIED_ACE *)src; + dst->access_mask = access_mask_to_samba( ace->Mask ); + memset( &dst->object, 0, sizeof(dst->object) ); + sid_to_samba( (const SID *)&ace->SidStart, &dst->trustee ); + } + case SYSTEM_AUDIT_ACE_TYPE: + { + SYSTEM_AUDIT_ACE *ace = (SYSTEM_AUDIT_ACE *)src; + dst->access_mask = access_mask_to_samba( ace->Mask ); + memset( &dst->object, 0, sizeof(dst->object) ); + sid_to_samba( (const SID *)&ace->SidStart, &dst->trustee ); + } + case SYSTEM_ALARM_ACE_TYPE: + { + SYSTEM_ALARM_ACE *ace = (SYSTEM_ALARM_ACE *)src; + dst->access_mask = access_mask_to_samba( ace->Mask ); + memset( &dst->object, 0, sizeof(dst->object) ); + sid_to_samba( (const SID *)&ace->SidStart, &dst->trustee ); + } + default: + ERR( "unhandled type %u\n", src->AceType ); + return ERROR_INVALID_PARAMETER; + } + return NERR_Success; +} + +static NET_API_STATUS acl_to_samba( const ACL *src, struct acl *dst ) +{ + NET_API_STATUS status; + ACE_HEADER *src_ace; + unsigned int i; + + switch (src->AclRevision) + { + case ACL_REVISION4: + dst->revision = ACL_REVISION_ADS; + break; + default: + ERR( "unkhandled revision %u\n", src->AclRevision ); + return ERROR_UNKNOWN_REVISION; + } + dst->size = sizeof(*dst); + src_ace = (ACE_HEADER *)(src + 1); + dst->aces = (struct ace *)(dst + 1); + for (i = 0; i < src->AceCount; i++) + { + if ((status = ace_to_samba( src_ace, &dst->aces[i] ))) return status; + src_ace = (ACE_HEADER *)((char *)src_ace + src_ace->AceSize); + dst->size += dst->aces[i].size; + } + return NERR_Success; +} + +#define SELF_RELATIVE_FIELD(sd,field)\ + ((char *)(sd) + ((SECURITY_DESCRIPTOR_RELATIVE *)(sd))->field) + +static NET_API_STATUS sd_to_samba( const SECURITY_DESCRIPTOR *src, struct security_descriptor *dst ) +{ + NET_API_STATUS status; + const SID *owner, *group; + const ACL *dacl, *sacl; + unsigned int offset = sizeof(*dst); + + if (src->Revision != SECURITY_DESCRIPTOR_REVISION1) + return ERROR_UNKNOWN_REVISION; + + dst->revision = SECURITY_DESCRIPTOR_REVISION_1; + dst->type = sd_control_to_samba( src->Control ); + + if (src->Control & SE_SELF_RELATIVE) + { + if (!src->Owner) dst->owner_sid = NULL; + else + { + dst->owner_sid = (struct sid *)((char *)dst + offset); + owner = (const SID *)SELF_RELATIVE_FIELD( src, Owner ); + if ((status = sid_to_samba( owner, dst->owner_sid ))) return status; + offset += sizeof(struct sid); + } + if (!src->Group) dst->group_sid = NULL; + else + { + dst->group_sid = (struct sid *)((char *)dst + offset); + group = (const SID *)SELF_RELATIVE_FIELD( src, Group ); + if ((status = sid_to_samba( group, dst->group_sid ))) return status; + offset += sizeof(struct sid); + } + if (!(src->Control & SE_SACL_PRESENT)) dst->sacl = NULL; + else + { + dst->sacl = (struct acl *)((char *)dst + offset); + sacl = (const ACL *)SELF_RELATIVE_FIELD( src, Sacl ); + if ((status = acl_to_samba( sacl, dst->sacl ))) return status; + offset += dst->sacl->size; + } + if (!(src->Control & SE_DACL_PRESENT)) dst->dacl = NULL; + else + { + dst->dacl = (struct acl *)((char *)dst + offset); + dacl = (const ACL *)SELF_RELATIVE_FIELD( src, Dacl ); + if ((status = acl_to_samba( dacl, dst->dacl ))) return status; + } + } + else + { + if (!src->Owner) dst->owner_sid = NULL; + else + { + dst->owner_sid = (struct sid *)((char *)dst + offset); + if ((status = sid_to_samba( src->Owner, dst->owner_sid ))) return status; + offset += sizeof(struct sid); + } + if (!src->Group) dst->group_sid = NULL; + else + { + dst->group_sid = (struct sid *)((char *)dst + offset); + if ((status = sid_to_samba( src->Group, dst->group_sid ))) return status; + offset += sizeof(struct sid); + } + if (!(src->Control & SE_SACL_PRESENT)) dst->sacl = NULL; + else + { + dst->sacl = (struct acl *)((char *)dst + offset); + if ((status = acl_to_samba( src->Sacl, dst->sacl ))) return status; + offset += dst->sacl->size; + } + if (!(src->Control & SE_DACL_PRESENT)) dst->dacl = NULL; + else + { + dst->dacl = (struct acl *)((char *)dst + offset); + if ((status = acl_to_samba( src->Dacl, dst->dacl ))) return status; + } + } + return NERR_Success; +} + +static unsigned int sd_to_samba_size( const SECURITY_DESCRIPTOR *sd ) +{ + unsigned int ret = sizeof(struct security_descriptor); + + if (sd->Owner) ret += sizeof(struct sid); + if (sd->Group) ret += sizeof(struct sid); + if (sd->Control & SE_SACL_PRESENT) + ret += sizeof(struct acl) + sd->Sacl->AceCount * sizeof(struct ace); + if (sd->Control & SE_DACL_PRESENT) + ret += sizeof(struct acl) + sd->Dacl->AceCount * sizeof(struct ace); + return ret; +} + +static NET_API_STATUS share_info_502_to_samba( const BYTE *buf, unsigned char **bufptr ) +{ + NET_API_STATUS status; + struct share_info_502 *ret; + SHARE_INFO_502 *info = (SHARE_INFO_502 *)buf; + DWORD len = 0, size = 0; + char *ptr; + + *bufptr = NULL; + if (info->shi502_netname) + len += WideCharToMultiByte( CP_UNIXCP, 0, info->shi502_netname, -1, NULL, 0, NULL, NULL ); + if (info->shi502_remark) + len += WideCharToMultiByte( CP_UNIXCP, 0, info->shi502_remark, -1, NULL, 0, NULL, NULL ); + if (info->shi502_path) + len += WideCharToMultiByte( CP_UNIXCP, 0, info->shi502_path, -1, NULL, 0, NULL, NULL ); + if (info->shi502_passwd) + len += WideCharToMultiByte( CP_UNIXCP, 0, info->shi502_passwd, -1, NULL, 0, NULL, NULL ); + if (info->shi502_security_descriptor) + size = sd_to_samba_size( info->shi502_security_descriptor ); + if (!(ret = HeapAlloc( GetProcessHeap(), 0, sizeof(*ret) + (len * sizeof(WCHAR)) + size ))) + return ERROR_OUTOFMEMORY; + + ptr = (char *)(ret + 1); + if (!info->shi502_netname) ret->shi502_netname = NULL; + else + { + ret->shi502_netname = ptr; + ptr += WideCharToMultiByte( CP_UNIXCP, 0, info->shi502_netname, -1, ptr, len, NULL, NULL ); + } + ret->shi502_type = info->shi502_type; + if (!info->shi502_remark) ret->shi502_remark = NULL; + else + { + ret->shi502_remark = ptr; + ptr += WideCharToMultiByte( CP_UNIXCP, 0, info->shi502_remark, -1, ptr, len, NULL, NULL ); + } + ret->shi502_permissions = info->shi502_permissions; + ret->shi502_max_uses = info->shi502_max_uses; + ret->shi502_current_uses = info->shi502_current_uses; + if (!info->shi502_path) ret->shi502_path = NULL; + else + { + ret->shi502_path = ptr; + ptr += WideCharToMultiByte( CP_UNIXCP, 0, info->shi502_path, -1, ptr, len, NULL, NULL ); + } + if (!info->shi502_passwd) ret->shi502_passwd = NULL; + else + { + ret->shi502_passwd = ptr; + ptr += WideCharToMultiByte( CP_UNIXCP, 0, info->shi502_passwd, -1, ptr, len, NULL, NULL ); + } + ret->shi502_reserved = info->shi502_reserved; + if (!info->shi502_security_descriptor) ret->shi502_security_descriptor = NULL; + else + { + status = sd_to_samba( info->shi502_security_descriptor, (struct security_descriptor *)ptr ); + if (status) + { + HeapFree( GetProcessHeap(), 0, ret ); + return status; + } + ret->shi502_security_descriptor = (struct security_descriptor *)ptr; + } + *bufptr = (unsigned char *)ret; + return NERR_Success; +} + static NET_API_STATUS share_info_to_samba( DWORD level, const BYTE *buf, unsigned char **bufptr ) { switch (level) { case 2: return share_info_2_to_samba( buf, bufptr ); + case 502: return share_info_502_to_samba( buf, bufptr ); default: FIXME( "level %u not supported\n", level ); return ERROR_NOT_SUPPORTED;