netapi32: Add support for info level 502 in NetShareAdd.

This commit is contained in:
Hans Leidekker 2013-11-20 10:30:32 +01:00 committed by Alexandre Julliard
parent 499eed087e
commit d9723d2bed
1 changed files with 463 additions and 0 deletions

View File

@ -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;