diff options
Diffstat (limited to 'usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c')
-rw-r--r-- | usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c | 1463 |
1 files changed, 1463 insertions, 0 deletions
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c new file mode 100644 index 0000000000..3b51c05e71 --- /dev/null +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c @@ -0,0 +1,1463 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Security Accounts Manager RPC (SAMR) interface definition. + */ + +#include <strings.h> +#include <unistd.h> +#include <netdb.h> +#include <pwd.h> +#include <grp.h> + +#include <smbsrv/libsmb.h> +#include <smbsrv/ntstatus.h> +#include <smbsrv/ntsid.h> +#include <smbsrv/smbinfo.h> +#include <smbsrv/nmpipes.h> +#include <smbsrv/libmlsvc.h> +#include <smbsrv/mlsvc_util.h> +#include <smbsrv/ndl/samrpc.ndl> +#include <smbsrv/samlib.h> + +/* + * The keys associated with the various handles dispensed + * by the SAMR server. These keys can be used to validate + * client activity. These values are never passed over + * the network so security shouldn't be an issue. + */ +#define SAMR_CONNECT_KEY "SamrConnect" +#define SAMR_DOMAIN_KEY "SamrDomain" +#define SAMR_USER_KEY "SamrUser" +#define SAMR_GROUP_KEY "SamrGroup" +#define SAMR_ALIAS_KEY "SamrAlias" + +/* + * Domain discriminator values. Set the top bit to try + * to distinguish these values from user and group ids. + */ +#define SAMR_DATABASE_DOMAIN 0x80000001 +#define SAMR_LOCAL_DOMAIN 0x80000002 +#define SAMR_BUILTIN_DOMAIN 0x80000003 +#define SAMR_PRIMARY_DOMAIN 0x80000004 + +static DWORD samr_s_enum_local_domains(struct samr_EnumLocalDomain *, + struct mlrpc_xaction *); + +static mlrpc_stub_table_t samr_stub_table[]; + +static mlrpc_service_t samr_service = { + "SAMR", /* name */ + "Security Accounts Manager", /* desc */ + "\\samr", /* endpoint */ + PIPE_LSASS, /* sec_addr_port */ + "12345778-1234-abcd-ef000123456789ac", 1, /* abstract */ + "8a885d04-1ceb-11c9-9fe808002b104860", 2, /* transfer */ + 0, /* no bind_instance_size */ + 0, /* no bind_req() */ + 0, /* no unbind_and_close() */ + 0, /* use generic_call_stub() */ + &TYPEINFO(samr_interface), /* interface ti */ + samr_stub_table /* stub_table */ +}; + +/* + * samr_initialize + * + * This function registers the SAM RPC interface with the RPC runtime + * library. It must be called in order to use either the client side + * or the server side functions. + */ +void +samr_initialize(void) +{ + (void) mlrpc_register_service(&samr_service); +} + +/* + * samr_s_ConnectAnon + * + * This is a request to connect to the local SAM database. We don't + * support any form of update request and our database doesn't + * contain any private information, so there is little point in + * doing any access access checking here. + * + * Return a handle for use with subsequent SAM requests. + */ +/*ARGSUSED*/ +static int +samr_s_ConnectAnon(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_ConnectAnon *param = arg; + ms_handle_t *handle; + + handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, SAMR_CONNECT_KEY, + SAMR_DATABASE_DOMAIN); + bcopy(handle, ¶m->handle, sizeof (samr_handle_t)); + + param->status = 0; + return (MLRPC_DRC_OK); +} + +/* + * samr_s_CloseHandle + * + * This is a request to close the SAM interface specified by the handle. + * Free the handle and zero out the result handle for the client. + * + * We could do some checking here but it probably doesn't matter. + */ +/*ARGSUSED*/ +static int +samr_s_CloseHandle(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_CloseHandle *param = arg; + +#ifdef SAMR_S_DEBUG + if (mlsvc_lookup_handle((ms_handle_t *)¶m->handle) == 0) { + bzero(¶m->result_handle, sizeof (samr_handle_t)); + param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); + return (MLRPC_DRC_OK); + } +#endif /* SAMR_S_DEBUG */ + + (void) mlsvc_put_handle((ms_handle_t *)¶m->handle); + bzero(¶m->result_handle, sizeof (samr_handle_t)); + param->status = 0; + return (MLRPC_DRC_OK); +} + +/* + * samr_s_LookupDomain + * + * This is a request to map a domain name to a domain SID. We can map + * the primary domain name, our local domain name (hostname) and the + * builtin domain names to the appropriate SID. Anything else will be + * rejected. + */ +static int +samr_s_LookupDomain(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_LookupDomain *param = arg; + char resource_domain[MAXHOSTNAMELEN]; + char *domain_name; + char *p; + nt_sid_t *sid = NULL; + + if ((domain_name = (char *)param->domain_name.str) == NULL) { + bzero(param, sizeof (struct samr_LookupDomain)); + param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER); + return (MLRPC_DRC_OK); + } + + smb_config_rdlock(); + p = smb_config_getstr(SMB_CI_DOMAIN_NAME); + (void) strlcpy(resource_domain, p, MAXHOSTNAMELEN); + smb_config_unlock(); + + if (mlsvc_is_local_domain(domain_name) == 1) { + sid = nt_sid_dup(nt_domain_local_sid()); + } else if (strcasecmp(resource_domain, domain_name) == 0) { + /* + * We should not be asked to provide + * the domain SID for the primary domain. + */ + sid = NULL; + } else { + sid = nt_builtin_lookup_name(domain_name, 0); + } + + if (sid) { + param->sid = (struct samr_sid *)mlsvc_sid_save(sid, mxa); + free(sid); + + if (param->sid == NULL) { + bzero(param, sizeof (struct samr_LookupDomain)); + param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); + return (MLRPC_DRC_OK); + } + + param->status = NT_STATUS_SUCCESS; + } else { + param->sid = NULL; + param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_DOMAIN); + } + + return (MLRPC_DRC_OK); +} + +/* + * samr_s_EnumLocalDomains + * + * This is a request for the local domains supported by this server. + * All we do here is validate the handle and set the status. The real + * work is done in samr_s_enum_local_domains. + */ +static int +samr_s_EnumLocalDomains(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_EnumLocalDomain *param = arg; + ms_handle_t *handle; + DWORD status; + + handle = (ms_handle_t *)¶m->handle; + + if (mlsvc_validate_handle(handle, SAMR_CONNECT_KEY) == 0) + status = NT_STATUS_ACCESS_DENIED; + else + status = samr_s_enum_local_domains(param, mxa); + + if (status == NT_STATUS_SUCCESS) { + param->enum_context = param->info->entries_read; + param->total_entries = param->info->entries_read; + param->status = NT_STATUS_SUCCESS; + } else { + bzero(param, sizeof (struct samr_EnumLocalDomain)); + param->status = NT_SC_ERROR(status); + } + + return (MLRPC_DRC_OK); +} + + +/* + * samr_s_enum_local_domains + * + * This function should only be called via samr_s_EnumLocalDomains to + * ensure that the appropriate validation is performed. We will answer + * queries about two domains: the local domain, synonymous with the + * local hostname, and the BUILTIN domain. So we return these two + * strings. + * + * Returns NT status values. + */ +static DWORD +samr_s_enum_local_domains(struct samr_EnumLocalDomain *param, + struct mlrpc_xaction *mxa) +{ + struct samr_LocalDomainInfo *info; + struct samr_LocalDomainEntry *entry; + char *hostname; + + hostname = MLRPC_HEAP_MALLOC(mxa, MAXHOSTNAMELEN); + if (hostname == NULL) + return (NT_STATUS_NO_MEMORY); + + if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0) + return (NT_STATUS_NO_MEMORY); + + entry = MLRPC_HEAP_NEWN(mxa, struct samr_LocalDomainEntry, 2); + if (entry == NULL) + return (NT_STATUS_NO_MEMORY); + + bzero(entry, (sizeof (struct samr_LocalDomainEntry) * 2)); + (void) mlsvc_string_save((ms_string_t *)&entry[0].name, hostname, mxa); + (void) mlsvc_string_save((ms_string_t *)&entry[1].name, "Builtin", mxa); + + info = MLRPC_HEAP_NEW(mxa, struct samr_LocalDomainInfo); + if (info == NULL) + return (NT_STATUS_NO_MEMORY); + + info->entries_read = 2; + info->entry = entry; + param->info = info; + return (NT_STATUS_SUCCESS); +} + +/* + * samr_s_OpenDomain + * + * This is a request to open a domain within the local SAM database. + * The caller must supply a valid handle obtained via a successful + * connect. We return a handle to be used to access objects within + * this domain. + */ +/*ARGSUSED*/ +static int +samr_s_OpenDomain(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_OpenDomain *param = arg; + ms_handle_t *handle = 0; + nt_domain_t *domain; + + if (!mlsvc_validate_handle( + (ms_handle_t *)¶m->handle, SAMR_CONNECT_KEY)) { + bzero(¶m->domain_handle, sizeof (samr_handle_t)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); + } + + domain = nt_domain_lookup_sid((nt_sid_t *)param->sid); + if (domain == NULL) { + bzero(¶m->domain_handle, sizeof (samr_handle_t)); + param->status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO); + return (MLRPC_DRC_OK); + } + + switch (domain->type) { + case NT_DOMAIN_BUILTIN: + handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, + SAMR_DOMAIN_KEY, SAMR_BUILTIN_DOMAIN); + + bcopy(handle, ¶m->domain_handle, sizeof (samr_handle_t)); + param->status = 0; + break; + + case NT_DOMAIN_LOCAL: + handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, + SAMR_DOMAIN_KEY, SAMR_LOCAL_DOMAIN); + + bcopy(handle, ¶m->domain_handle, sizeof (samr_handle_t)); + param->status = 0; + break; + + default: + bzero(¶m->domain_handle, sizeof (samr_handle_t)); + param->status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO); + } + + return (MLRPC_DRC_OK); +} + +/* + * samr_s_QueryDomainInfo + * + * The caller should pass a domain handle. + * + * Windows 95 Server Manager sends requests for levels 6 and 7 when + * the services menu item is selected. Level 2 is basically for getting + * number of users, groups, and aliases in a domain. + * We have no information on what the various information levels mean. + */ +static int +samr_s_QueryDomainInfo(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_QueryDomainInfo *param = arg; + ms_handle_desc_t *desc; + char *hostname; + char *domain_str = ""; + int rc; + + desc = mlsvc_lookup_handle((ms_handle_t *)¶m->domain_handle); + if (desc == NULL || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) { + bzero(param, sizeof (struct samr_QueryDomainInfo)); + param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); + return (MLRPC_DRC_OK); + } + + switch (param->info_level) { + case SAMR_QUERY_DOMAIN_INFO_6: + param->ru.info6.unknown1 = 0x00000000; + param->ru.info6.unknown2 = 0x00147FB0; + param->ru.info6.unknown3 = 0x00000000; + param->ru.info6.unknown4 = 0x00000000; + param->ru.info6.unknown5 = 0x00000000; + param->status = NT_STATUS_SUCCESS; + break; + + case SAMR_QUERY_DOMAIN_INFO_7: + param->ru.info7.unknown1 = 0x00000003; + param->status = NT_STATUS_SUCCESS; + break; + + case SAMR_QUERY_DOMAIN_INFO_2: + if (desc->discrim == SAMR_LOCAL_DOMAIN) { + hostname = MLRPC_HEAP_MALLOC(mxa, MAXHOSTNAMELEN); + rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1); + if (rc != 0 || hostname == NULL) { + bzero(param, + sizeof (struct samr_QueryDomainInfo)); + param->status = + NT_SC_ERROR(NT_STATUS_NO_MEMORY); + return (MLRPC_DRC_OK); + } + + domain_str = hostname; + } else { + if (desc->discrim == SAMR_BUILTIN_DOMAIN) + domain_str = "Builtin"; + } + + param->ru.info2.unknown1 = 0x00000000; + param->ru.info2.unknown2 = 0x80000000; + + (void) mlsvc_string_save((ms_string_t *)&(param->ru.info2.s1), + "", mxa); + + (void) mlsvc_string_save( + (ms_string_t *)&(param->ru.info2.domain), domain_str, mxa); + + (void) mlsvc_string_save((ms_string_t *)&(param->ru.info2.s2), + "", mxa); + + param->ru.info2.sequence_num = 0x0000002B; + param->ru.info2.unknown3 = 0x00000000; + param->ru.info2.unknown4 = 0x00000001; + param->ru.info2.unknown5 = 0x00000003; + param->ru.info2.unknown6 = 0x00000001; + param->ru.info2.num_users = 0; + param->ru.info2.num_groups = 0; + param->ru.info2.num_aliases = + (desc->discrim == SAMR_BUILTIN_DOMAIN) ? + nt_groups_count(NT_GROUP_CNT_BUILTIN) : + nt_groups_count(NT_GROUP_CNT_LOCAL); + + param->status = NT_STATUS_SUCCESS; + break; + + default: + bzero(param, sizeof (struct samr_QueryDomainInfo)); + return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID); + }; + + param->address = (DWORD)¶m->ru; + param->switch_value = param->info_level; + return (MLRPC_DRC_OK); +} + +/* + * samr_s_LookupNames + * + * The definition for this interface is obviously wrong but I can't + * seem to get it to work the way I think it should. It should + * support multiple name lookup but I can only get one working for now. + */ +static int +samr_s_LookupNames(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_LookupNames *param = arg; + ms_handle_desc_t *desc; + struct passwd *pw; + struct group *gr; + nt_sid_t *sid; + nt_group_t *grp; + WORD rid_type; + + desc = mlsvc_lookup_handle((ms_handle_t *)¶m->handle); + if (desc == 0 || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) { + bzero(param, sizeof (struct samr_LookupNames)); + param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); + return (MLRPC_DRC_OK); + } + + if (param->n_entry != 1) { + bzero(param, sizeof (struct samr_LookupNames)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); + } + + if (param->name.str == NULL) { + bzero(param, sizeof (struct samr_LookupNames)); + /* + * Windows NT returns NT_STATUS_NONE_MAPPED when the + * name is NULL. + * Windows 2000 returns STATUS_INVALID_ACCOUNT_NAME. + */ + param->status = NT_SC_ERROR(NT_STATUS_NONE_MAPPED); + return (MLRPC_DRC_OK); + } + + param->rids.rid = MLRPC_HEAP_NEW(mxa, DWORD); + param->rid_types.rid_type = MLRPC_HEAP_NEW(mxa, DWORD); + + if (desc->discrim == SAMR_BUILTIN_DOMAIN) { + sid = nt_builtin_lookup_name((char *)param->name.str, + &rid_type); + + if (sid != 0) { + param->rids.n_entry = 1; + (void) nt_sid_get_rid(sid, ¶m->rids.rid[0]); + param->rid_types.n_entry = 1; + param->rid_types.rid_type[0] = rid_type; + param->status = NT_STATUS_SUCCESS; + free(sid); + return (MLRPC_DRC_OK); + } + } else if (desc->discrim == SAMR_LOCAL_DOMAIN) { + grp = nt_group_getinfo((char *)param->name.str, RWLOCK_READER); + + if (grp != NULL) { + param->rids.n_entry = 1; + (void) nt_sid_get_rid(grp->sid, ¶m->rids.rid[0]); + param->rid_types.n_entry = 1; + param->rid_types.rid_type[0] = *grp->sid_name_use; + param->status = NT_STATUS_SUCCESS; + nt_group_putinfo(grp); + return (MLRPC_DRC_OK); + } + + if ((pw = getpwnam((const char *)param->name.str)) != NULL) { + param->rids.n_entry = 1; + param->rids.rid[0] = SAM_ENCODE_UXUID(pw->pw_uid); + param->rid_types.n_entry = 1; + param->rid_types.rid_type[0] = SidTypeUser; + param->status = NT_STATUS_SUCCESS; + return (MLRPC_DRC_OK); + } + + if ((gr = getgrnam((const char *)param->name.str)) != NULL) { + param->rids.n_entry = 1; + param->rids.rid[0] = SAM_ENCODE_UXGID(gr->gr_gid); + param->rid_types.n_entry = 1; + param->rid_types.rid_type[0] = SidTypeAlias; + param->status = NT_STATUS_SUCCESS; + return (MLRPC_DRC_OK); + } + } + + param->rids.n_entry = 0; + param->rid_types.n_entry = 0; + param->status = NT_SC_ERROR(NT_STATUS_NONE_MAPPED); + return (MLRPC_DRC_OK); +} + +/* + * samr_s_OpenUser + * + * This is a request to open a user within a specified domain in the + * local SAM database. The caller must supply a valid domain handle, + * obtained via a successful domain open request. The user is + * specified by the rid in the request. + */ +/*ARGSUSED*/ +static int +samr_s_OpenUser(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_OpenUser *param = arg; + ms_handle_t *handle; + + if (!mlsvc_validate_handle( + (ms_handle_t *)¶m->handle, SAMR_DOMAIN_KEY)) { + bzero(¶m->user_handle, sizeof (samr_handle_t)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); + } + + handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, SAMR_USER_KEY, + param->rid); + bcopy(handle, ¶m->user_handle, sizeof (samr_handle_t)); + + /* + * Need QueryUserInfo(level 21). + */ + bzero(¶m->user_handle, sizeof (samr_handle_t)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); +} + +/* + * samr_s_DeleteUser + * + * This is a request to delete a user within a specified domain in the + * local SAM database. The caller should supply a valid user handle but + * we deny access regardless. + */ +/*ARGSUSED*/ +static int +samr_s_DeleteUser(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_DeleteUser *param = arg; + + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); +} + +/* + * samr_s_QueryUserInfo + * + * Returns: + * NT_STATUS_SUCCESS + * NT_STATUS_ACCESS_DENIED + * NT_STATUS_INVALID_INFO_CLASS + */ +/*ARGSUSED*/ +static int +samr_s_QueryUserInfo(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_QueryUserInfo *param = arg; + + if (!mlsvc_validate_handle( + (ms_handle_t *)¶m->user_handle, SAMR_USER_KEY)) { + bzero(param, sizeof (struct samr_QueryUserInfo)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); + } + + bzero(param, sizeof (struct samr_QueryUserInfo)); + param->status = 0; + return (MLRPC_DRC_OK); +} + +/* + * samr_s_QueryUserGroups + * + * This is a request to obtain a list of groups of which a user is a + * member. The user is identified from the handle, which contains an + * encoded uid in the discriminator field. + * + * Get complete list of groups and check for builtin domain. + */ +static int +samr_s_QueryUserGroups(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_QueryUserGroups *param = arg; + struct samr_UserGroupInfo *info; + ms_handle_desc_t *desc; + struct passwd *pw; + DWORD uid; + + desc = mlsvc_lookup_handle((ms_handle_t *)¶m->user_handle); + if (desc == 0 || strcmp(desc->key, SAMR_USER_KEY)) { + bzero(param, sizeof (struct samr_QueryUserGroups)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); + } + + info = MLRPC_HEAP_NEW(mxa, struct samr_UserGroupInfo); + info->groups = MLRPC_HEAP_NEW(mxa, struct samr_UserGroups); + + uid = SAM_DECODE_RID(desc->discrim); + + if ((pw = getpwuid(uid)) != 0) { + info->n_entry = 1; + info->groups->rid = SAM_ENCODE_UXGID(pw->pw_gid); + info->groups->attr = SE_GROUP_MANDATORY + | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; + param->info = info; + param->status = 0; + } else { + bzero(param, sizeof (struct samr_QueryUserGroups)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + } + + return (MLRPC_DRC_OK); +} + +/* + * samr_s_OpenGroup + * + * This is a request to open a group within the specified domain in the + * local SAM database. The caller must supply a valid domain handle, + * obtained via a successful domain open request. The group is + * specified by the rid in the request. If this is a local RID it + * should already be encoded with type information. + * + * We return a handle to be used to access information about this group. + */ +/*ARGSUSED*/ +static int +samr_s_OpenGroup(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_OpenGroup *param = arg; + ms_handle_t *handle; + + if (!mlsvc_validate_handle( + (ms_handle_t *)¶m->handle, SAMR_DOMAIN_KEY)) { + bzero(¶m->group_handle, sizeof (samr_handle_t)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); + } + + handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, SAMR_GROUP_KEY, + param->rid); + bcopy(handle, ¶m->group_handle, sizeof (samr_handle_t)); + + param->status = 0; + return (MLRPC_DRC_OK); +} + +/* + * samr_s_Connect + * + * This is a request to connect to the local SAM database. We don't + * support any form of update request and our database doesn't + * contain any private information, so there is little point in + * doing any access access checking here. + * + * Return a handle for use with subsequent SAM requests. + */ +/*ARGSUSED*/ +static int +samr_s_Connect(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_Connect *param = arg; + ms_handle_t *handle; + + handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, + SAMR_CONNECT_KEY, SAMR_DATABASE_DOMAIN); + bcopy(handle, ¶m->handle, sizeof (samr_handle_t)); + + param->status = 0; + return (MLRPC_DRC_OK); +} + +/* + * samr_s_GetUserPwInfo + * + * This is a request to get a user's password. + */ +/*ARGSUSED*/ +static int +samr_s_GetUserPwInfo(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_GetUserPwInfo *param = arg; + ms_handle_t *handle; + DWORD status = 0; + + handle = (ms_handle_t *)¶m->user_handle; + + if (!mlsvc_validate_handle(handle, SAMR_USER_KEY)) + status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + + bzero(param, sizeof (struct samr_GetUserPwInfo)); + param->status = status; + return (MLRPC_DRC_OK); +} + +/* + * samr_s_CreateUser + * + * This is a request to create a user within a specified domain in the + * local SAM database. We always deny access. + */ +/*ARGSUSED*/ +static int +samr_s_CreateUser(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_CreateUser *param = arg; + + bzero(¶m->user_handle, sizeof (samr_handle_t)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); +} + +/* + * samr_s_ChangeUserPasswd + */ +/*ARGSUSED*/ +static int +samr_s_ChangeUserPasswd(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_ChangeUserPasswd *param = arg; + + bzero(param, sizeof (struct samr_ChangeUserPasswd)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); +} + +/* + * samr_s_GetDomainPwInfo + */ +/*ARGSUSED*/ +static int +samr_s_GetDomainPwInfo(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_GetDomainPwInfo *param = arg; + + bzero(param, sizeof (struct samr_GetDomainPwInfo)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); +} + +/* + * samr_s_SetUserInfo + */ +/*ARGSUSED*/ +static int +samr_s_SetUserInfo(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_SetUserInfo *param = arg; + + bzero(param, sizeof (struct samr_SetUserInfo)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); +} + +/* + * samr_s_QueryDispInfo + * + * This function is supposed to return local users' information. + * As we don't support local users, this function dosen't send + * back any information. + * + * I added a peice of code that returns information for Administrator + * and Guest builtin users. All information are hard-coded which I get + * from packet captures. Currently, this peice of code is opt-out. + */ +/*ARGSUSED*/ +static int +samr_s_QueryDispInfo(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_QueryDispInfo *param = arg; + ms_handle_desc_t *desc; + DWORD status = 0; + + desc = mlsvc_lookup_handle((ms_handle_t *)¶m->domain_handle); + if (desc == NULL || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) + status = NT_STATUS_INVALID_HANDLE; + +#ifdef SAMR_SUPPORT_USER + if ((desc->discrim != SAMR_LOCAL_DOMAIN) || (param->start_idx != 0)) { + param->total_size = 0; + param->returned_size = 0; + param->switch_value = 1; + param->count = 0; + param->users = 0; + } else { + param->total_size = 328; + param->returned_size = 328; + param->switch_value = 1; + param->count = 2; + param->users = (struct user_disp_info *)MLRPC_HEAP_MALLOC(mxa, + sizeof (struct user_disp_info)); + + param->users->count = 2; + param->users->acct[0].index = 1; + param->users->acct[0].rid = 500; + param->users->acct[0].ctrl = 0x210; + + (void) mlsvc_string_save( + (ms_string_t *)¶m->users->acct[0].name, + "Administrator", mxa); + + (void) mlsvc_string_save( + (ms_string_t *)¶m->users->acct[0].fullname, + "Built-in account for administering the computer/domain", + mxa); + + bzero(¶m->users->acct[0].desc, sizeof (samr_string_t)); + + param->users->acct[1].index = 2; + param->users->acct[1].rid = 501; + param->users->acct[1].ctrl = 0x211; + + (void) mlsvc_string_save( + (ms_string_t *)¶m->users->acct[1].name, + "Guest", mxa); + + (void) mlsvc_string_save( + (ms_string_t *)¶m->users->acct[1].fullname, + "Built-in account for guest access to the computer/domain", + mxa); + + bzero(¶m->users->acct[1].desc, sizeof (samr_string_t)); + } +#else + param->total_size = 0; + param->returned_size = 0; + param->switch_value = 1; + param->count = 0; + param->users = 0; +#endif + param->status = status; + return (MLRPC_DRC_OK); +} + +/* + * samr_s_EnumDomainGroups + * + * + * This function is supposed to return local users' information. + * As we don't support local users, this function dosen't send + * back any information. + * + * I added a peice of code that returns information for a + * domain group as None. All information are hard-coded which I get + * from packet captures. Currently, this peice of code is opt-out. + */ +/*ARGSUSED*/ +static int +samr_s_EnumDomainGroups(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_EnumDomainGroups *param = arg; + ms_handle_desc_t *desc; + DWORD status = NT_STATUS_SUCCESS; + + desc = mlsvc_lookup_handle((ms_handle_t *)¶m->domain_handle); + if (desc == NULL || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) + status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); + + param->total_size = 0; + param->returned_size = 0; + param->switch_value = 3; + param->count = 0; + param->groups = 0; + param->status = status; + return (MLRPC_DRC_OK); + +#ifdef SAMR_SUPPORT_GROUPS + if ((desc->discrim != SAMR_LOCAL_DOMAIN) || (param->start_idx != 0)) { + param->total_size = 0; + param->returned_size = 0; + param->switch_value = 3; + param->count = 0; + param->groups = 0; + } else { + param->total_size = 64; + param->returned_size = 64; + param->switch_value = 3; + param->count = 1; + param->groups = (struct group_disp_info *)MLRPC_HEAP_MALLOC( + mxa, sizeof (struct group_disp_info)); + + param->groups->count = 1; + param->groups->acct[0].index = 1; + param->groups->acct[0].rid = 513; + param->groups->acct[0].ctrl = 0x7; + (void) mlsvc_string_save( + (ms_string_t *)¶m->groups->acct[0].name, "None", mxa); + + (void) mlsvc_string_save( + (ms_string_t *)¶m->groups->acct[0].desc, + "Ordinary users", mxa); + } + + param->status = NT_STATUS_SUCCESS; + return (MLRPC_DRC_OK); +#endif +} + +/* + * samr_s_OpenAlias + * + * Lookup for requested alias, if it exists return a handle + * for that alias. The alias domain sid should match with + * the passed domain handle. + */ +/*ARGSUSED*/ +static int +samr_s_OpenAlias(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_OpenAlias *param = arg; + ms_handle_desc_t *desc = 0; + ms_handle_t *handle; + nt_group_t *grp; + DWORD status = NT_STATUS_SUCCESS; + + desc = mlsvc_lookup_handle((ms_handle_t *)¶m->domain_handle); + if (desc == 0 || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) { + status = NT_STATUS_INVALID_HANDLE; + goto open_alias_err; + } + + if (param->access_mask != SAMR_ALIAS_ACCESS_GET_INFO) { + status = NT_STATUS_ACCESS_DENIED; + goto open_alias_err; + } + + grp = nt_groups_lookup_rid(param->rid); + if (grp == 0) { + status = NT_STATUS_NO_SUCH_ALIAS; + goto open_alias_err; + } + + if (((desc->discrim == SAMR_LOCAL_DOMAIN) && + !nt_sid_is_local(grp->sid)) || + ((desc->discrim == SAMR_BUILTIN_DOMAIN) && + !nt_sid_is_builtin(grp->sid))) { + status = NT_STATUS_NO_SUCH_ALIAS; + goto open_alias_err; + } + + handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, SAMR_ALIAS_KEY, + param->rid); + bcopy(handle, ¶m->alias_handle, sizeof (samr_handle_t)); + param->status = 0; + return (MLRPC_DRC_OK); + +open_alias_err: + bzero(¶m->alias_handle, sizeof (samr_handle_t)); + param->status = NT_SC_ERROR(status); + return (MLRPC_DRC_OK); +} + +/* + * samr_s_CreateDomainAlias + * + * Creates a local group in the security database, which is the + * security accounts manager (SAM) + * For more information you can look at MSDN page for NetLocalGroupAdd. + * This RPC is used by CMC and right now it returns access denied. + * The peice of code that creates a local group doesn't get compiled. + */ +/*ARGSUSED*/ +static int +samr_s_CreateDomainAlias(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_CreateDomainAlias *param = arg; + +#ifdef SAMR_SUPPORT_ADD_ALIAS + DWORD status = NT_STATUS_SUCCESS; + ms_handle_desc_t *desc = 0; + ms_handle_t *handle; + nt_group_t *grp; + char *alias_name; +#endif + bzero(¶m->alias_handle, sizeof (samr_handle_t)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); + +#ifdef SAMR_SUPPORT_ADD_ALIAS + alias_name = param->alias_name.str; + if (alias_name == 0) { + status = NT_STATUS_INVALID_PARAMETER; + goto create_alias_err; + } + + desc = mlsvc_lookup_handle((ms_handle_t *)¶m->domain_handle); + if (desc == 0 || + (desc->discrim != SAMR_LOCAL_DOMAIN) || + (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) { + status = NT_STATUS_INVALID_HANDLE; + goto create_alias_err; + } + + /* + * Check access mask. User should be member of + * Administrators or Account Operators local group. + */ + status = nt_group_add(alias_name, 0, + NT_GROUP_AF_ADD | NT_GROUP_AF_LOCAL); + + if (status != NT_STATUS_SUCCESS) + goto create_alias_err; + + grp = nt_group_getinfo(alias_name, RWLOCK_READER); + if (grp == NULL) { + status = NT_STATUS_INTERNAL_ERROR; + goto create_alias_err; + } + + (void) nt_sid_get_rid(grp->sid, ¶m->rid); + nt_group_putinfo(grp); + handle = mlsvc_get_handle(MLSVC_IFSPEC_SAMR, SAMR_ALIAS_KEY, + param->rid); + bcopy(handle, ¶m->alias_handle, sizeof (samr_handle_t)); + + param->status = 0; + return (MLRPC_DRC_OK); + +create_alias_err: + bzero(¶m->alias_handle, sizeof (samr_handle_t)); + param->status = NT_SC_ERROR(status); + return (MLRPC_DRC_OK); +#endif +} + +/* + * samr_s_SetAliasInfo + * + * For more information you can look at MSDN page for NetLocalGroupSetInfo. + */ +/*ARGSUSED*/ +static int +samr_s_SetAliasInfo(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_SetAliasInfo *param = arg; + DWORD status = NT_STATUS_SUCCESS; + + if (!mlsvc_validate_handle( + (ms_handle_t *)¶m->alias_handle, SAMR_ALIAS_KEY)) { + status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); + } + + param->status = status; + return (MLRPC_DRC_OK); +} + +/* + * samr_s_QueryAliasInfo + * + * Retrieves information about the specified local group account + * by given handle. + */ +static int +samr_s_QueryAliasInfo(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_QueryAliasInfo *param = arg; + ms_handle_desc_t *desc; + nt_group_t *grp; + DWORD status; + + desc = mlsvc_lookup_handle((ms_handle_t *)¶m->alias_handle); + if (desc == NULL || (strcmp(desc->key, SAMR_ALIAS_KEY) != 0)) { + status = NT_STATUS_INVALID_HANDLE; + goto query_alias_err; + } + + grp = nt_groups_lookup_rid(desc->discrim); + if (grp == NULL) { + status = NT_STATUS_NO_SUCH_ALIAS; + goto query_alias_err; + } + + switch (param->level) { + case SAMR_QUERY_ALIAS_INFO_1: + param->ru.info1.level = param->level; + (void) mlsvc_string_save( + (ms_string_t *)¶m->ru.info1.name, grp->name, mxa); + + (void) mlsvc_string_save( + (ms_string_t *)¶m->ru.info1.desc, grp->comment, mxa); + + param->ru.info1.unknown = 1; + break; + + case SAMR_QUERY_ALIAS_INFO_3: + param->ru.info3.level = param->level; + (void) mlsvc_string_save( + (ms_string_t *)¶m->ru.info3.desc, grp->comment, mxa); + + break; + + default: + status = NT_STATUS_INVALID_INFO_CLASS; + goto query_alias_err; + }; + + param->address = (DWORD)¶m->ru; + param->status = 0; + return (MLRPC_DRC_OK); + +query_alias_err: + param->status = NT_SC_ERROR(status); + return (MLRPC_DRC_OK); +} + +/* + * samr_s_DeleteDomainAlias + * + * Deletes a local group account and all its members from the + * security database, which is the security accounts manager (SAM) database. + * Only members of the Administrators or Account Operators local group can + * execute this function. + * For more information you can look at MSDN page for NetLocalGroupSetInfo. + * + * This RPC is used by CMC and right now it returns access denied. + * The peice of code that removes a local group doesn't get compiled. + */ +/*ARGSUSED*/ +static int +samr_s_DeleteDomainAlias(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_DeleteDomainAlias *param = arg; + +#ifdef SAMR_SUPPORT_DEL_ALIAS + ms_handle_desc_t *desc = 0; + nt_group_t *grp; + char *alias_name; + DWORD status; +#endif + + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (MLRPC_DRC_OK); + +#ifdef SAMR_SUPPORT_DEL_ALIAS + desc = mlsvc_lookup_handle((ms_handle_t *)¶m->alias_handle); + if (desc == 0 || (strcmp(desc->key, SAMR_ALIAS_KEY) != 0)) { + status = NT_STATUS_INVALID_HANDLE; + goto delete_alias_err; + } + + grp = nt_groups_lookup_rid(desc->discrim); + if (grp == 0) { + status = NT_STATUS_NO_SUCH_ALIAS; + goto delete_alias_err; + } + + alias_name = strdup(grp->name); + if (alias_name == 0) { + status = NT_STATUS_NO_MEMORY; + goto delete_alias_err; + } + + status = nt_group_delete(alias_name); + free(alias_name); + if (status != NT_STATUS_SUCCESS) + goto delete_alias_err; + + param->status = 0; + return (MLRPC_DRC_OK); + +delete_alias_err: + param->status = NT_SC_ERROR(status); + return (MLRPC_DRC_OK); +#endif +} + +/* + * samr_s_EnumDomainAliases + * + * This function sends back a list which contains all local groups' name. + */ +static int +samr_s_EnumDomainAliases(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_EnumDomainAliases *param = arg; + ms_handle_desc_t *desc; + nt_group_t *grp = NULL; + DWORD status; + nt_group_iterator_t *gi; + nt_sid_t *local_sid; + nt_sid_t *builtin_sid; + nt_sid_t *sid; + DWORD cnt, skip; + struct name_rid *info; + + desc = mlsvc_lookup_handle((ms_handle_t *)¶m->domain_handle); + if (desc == NULL || (strcmp(desc->key, SAMR_DOMAIN_KEY) != 0)) { + status = NT_STATUS_INVALID_HANDLE; + goto enum_alias_err; + } + + local_sid = nt_domain_local_sid(); + builtin_sid = nt_builtin_lookup_name("BUILTIN", 0); + + if (desc->discrim == SAMR_LOCAL_DOMAIN) { + sid = local_sid; + } else if (desc->discrim == SAMR_BUILTIN_DOMAIN) { + sid = builtin_sid; + } else { + status = NT_STATUS_INVALID_HANDLE; + goto enum_alias_err; + } + + cnt = skip = 0; + gi = nt_group_open_iterator(); + nt_group_ht_lock(RWLOCK_READER); + while ((grp = nt_group_iterate(gi)) != 0) { + if (skip++ < param->resume_handle) + continue; + if (nt_sid_is_indomain(sid, grp->sid)) + cnt++; + } + nt_group_ht_unlock(); + nt_group_close_iterator(gi); + + param->aliases = (struct aliases_info *)MLRPC_HEAP_MALLOC(mxa, + sizeof (struct aliases_info) + (cnt-1) * sizeof (struct name_rid)); + + param->aliases->count = cnt; + param->aliases->address = cnt; + info = param->aliases->info; + + skip = 0; + gi = nt_group_open_iterator(); + nt_group_ht_lock(RWLOCK_READER); + while ((grp = nt_group_iterate(gi)) != NULL) { + if (skip++ < param->resume_handle) + continue; + if (nt_sid_is_indomain(sid, grp->sid)) { + (void) nt_sid_get_rid(grp->sid, &info->rid); + (void) mlsvc_string_save((ms_string_t *)&info->name, + grp->name, mxa); + + info++; + } + } + nt_group_ht_unlock(); + nt_group_close_iterator(gi); + + param->out_resume = cnt; + param->entries = cnt; + param->status = 0; + return (MLRPC_DRC_OK); + +enum_alias_err: + param->status = NT_SC_ERROR(status); + return (MLRPC_DRC_OK); +} + +/* + * samr_s_Connect3 + * + * This is the connect3 form of the connect request. It contains an + * extra parameter over samr_Connect. See samr_s_Connect for other + * details. NT returns an RPC fault - so we can do the same for now. + * Doing it this way should avoid the unsupported opnum error message + * appearing in the log. + */ +/*ARGSUSED*/ +static int +samr_s_Connect3(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_Connect3 *param = arg; + + bzero(param, sizeof (struct samr_Connect3)); + return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID); +} + + +/* + * samr_s_Connect4 + * + * This is the connect4 form of the connect request used by Windows XP. + * Returns an RPC fault for now. + */ +/*ARGSUSED*/ +static int +samr_s_Connect4(void *arg, struct mlrpc_xaction *mxa) +{ + struct samr_Connect4 *param = arg; + + bzero(param, sizeof (struct samr_Connect4)); + return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID); +} + +static mlrpc_stub_table_t samr_stub_table[] = { + { samr_s_ConnectAnon, SAMR_OPNUM_ConnectAnon }, + { samr_s_CloseHandle, SAMR_OPNUM_CloseHandle }, + { samr_s_LookupDomain, SAMR_OPNUM_LookupDomain }, + { samr_s_EnumLocalDomains, SAMR_OPNUM_EnumLocalDomains }, + { samr_s_OpenDomain, SAMR_OPNUM_OpenDomain }, + { samr_s_QueryDomainInfo, SAMR_OPNUM_QueryDomainInfo }, + { samr_s_LookupNames, SAMR_OPNUM_LookupNames }, + { samr_s_OpenUser, SAMR_OPNUM_OpenUser }, + { samr_s_DeleteUser, SAMR_OPNUM_DeleteUser }, + { samr_s_QueryUserInfo, SAMR_OPNUM_QueryUserInfo }, + { samr_s_QueryUserGroups, SAMR_OPNUM_QueryUserGroups }, + { samr_s_OpenGroup, SAMR_OPNUM_OpenGroup }, + { samr_s_Connect, SAMR_OPNUM_Connect }, + { samr_s_GetUserPwInfo, SAMR_OPNUM_GetUserPwInfo }, + { samr_s_CreateUser, SAMR_OPNUM_CreateUser }, + { samr_s_ChangeUserPasswd, SAMR_OPNUM_ChangeUserPasswd }, + { samr_s_GetDomainPwInfo, SAMR_OPNUM_GetDomainPwInfo }, + { samr_s_SetUserInfo, SAMR_OPNUM_SetUserInfo }, + { samr_s_Connect3, SAMR_OPNUM_Connect3 }, + { samr_s_Connect4, SAMR_OPNUM_Connect4 }, + { samr_s_QueryDispInfo, SAMR_OPNUM_QueryDispInfo }, + { samr_s_OpenAlias, SAMR_OPNUM_OpenAlias }, + { samr_s_CreateDomainAlias, SAMR_OPNUM_CreateDomainAlias }, + { samr_s_SetAliasInfo, SAMR_OPNUM_SetAliasInfo }, + { samr_s_QueryAliasInfo, SAMR_OPNUM_QueryAliasInfo }, + { samr_s_DeleteDomainAlias, SAMR_OPNUM_DeleteDomainAlias }, + { samr_s_EnumDomainAliases, SAMR_OPNUM_EnumDomainAliases }, + { samr_s_EnumDomainGroups, SAMR_OPNUM_EnumDomainGroups }, + {0} +}; + +/* + * There is a bug in the way that midl and the marshalling code handles + * unions so we need to fix some of the data offsets at runtime. The + * following macros and the fixup functions handle the corrections. + */ +DECL_FIXUP_STRUCT(samr_QueryDomainInfo_ru); +DECL_FIXUP_STRUCT(samr_QueryDomainInfoRes); +DECL_FIXUP_STRUCT(samr_QueryDomainInfo); + +DECL_FIXUP_STRUCT(samr_QueryAliasInfo_ru); +DECL_FIXUP_STRUCT(samr_QueryAliasInfoRes); +DECL_FIXUP_STRUCT(samr_QueryAliasInfo); + +DECL_FIXUP_STRUCT(QueryUserInfo_result_u); +DECL_FIXUP_STRUCT(QueryUserInfo_result); +DECL_FIXUP_STRUCT(samr_QueryUserInfo); + +void +fixup_samr_QueryDomainInfo(struct samr_QueryDomainInfo *val) +{ + unsigned short size1 = 0; + unsigned short size2 = 0; + unsigned short size3 = 0; + + switch (val->switch_value) { + CASE_INFO_ENT(samr_QueryDomainInfo, 2); + CASE_INFO_ENT(samr_QueryDomainInfo, 6); + CASE_INFO_ENT(samr_QueryDomainInfo, 7); + + default: + return; + }; + + size2 = size1 + (2 * sizeof (DWORD)); + size3 = size2 + sizeof (mlrpcconn_request_hdr_t) + sizeof (DWORD); + + FIXUP_PDU_SIZE(samr_QueryDomainInfo_ru, size1); + FIXUP_PDU_SIZE(samr_QueryDomainInfoRes, size2); + FIXUP_PDU_SIZE(samr_QueryDomainInfo, size3); +} + +void +fixup_samr_QueryAliasInfo(struct samr_QueryAliasInfo *val) +{ + unsigned short size1 = 0; + unsigned short size2 = 0; + unsigned short size3 = 0; + + switch (val->level) { + CASE_INFO_ENT(samr_QueryAliasInfo, 1); + CASE_INFO_ENT(samr_QueryAliasInfo, 3); + + default: + return; + }; + + size2 = size1 + (2 * sizeof (DWORD)); + size3 = size2 + sizeof (mlrpcconn_request_hdr_t) + sizeof (DWORD); + + FIXUP_PDU_SIZE(samr_QueryAliasInfo_ru, size1); + FIXUP_PDU_SIZE(samr_QueryAliasInfoRes, size2); + FIXUP_PDU_SIZE(samr_QueryAliasInfo, size3); +} + +void +fixup_samr_QueryUserInfo(struct samr_QueryUserInfo *val) +{ + unsigned short size1 = 0; + unsigned short size2 = 0; + unsigned short size3 = 0; + + switch (val->switch_index) { + CASE_INFO_ENT(samr_QueryUserInfo, 1); + CASE_INFO_ENT(samr_QueryUserInfo, 6); + CASE_INFO_ENT(samr_QueryUserInfo, 7); + CASE_INFO_ENT(samr_QueryUserInfo, 8); + CASE_INFO_ENT(samr_QueryUserInfo, 9); + CASE_INFO_ENT(samr_QueryUserInfo, 16); + + default: + return; + }; + + size2 = size1 + (2 * sizeof (DWORD)); + size3 = size2 + sizeof (mlrpcconn_request_hdr_t) + sizeof (DWORD); + + FIXUP_PDU_SIZE(QueryUserInfo_result_u, size1); + FIXUP_PDU_SIZE(QueryUserInfo_result, size2); + FIXUP_PDU_SIZE(samr_QueryUserInfo, size3); +} + +/* + * As long as there is only one entry in the union, there is no need + * to patch anything. + */ +/*ARGSUSED*/ +void +fixup_samr_QueryGroupInfo(struct samr_QueryGroupInfo *val) +{ +} |