1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * Active Directory Setup RPC interface used by Windows 2000. 29 */ 30 31 #include <synch.h> 32 #include <strings.h> 33 #include <stdlib.h> 34 #include <netdb.h> 35 36 #include <libmlrpc/libmlrpc.h> 37 #include <smbsrv/libsmb.h> 38 #include <smbsrv/libmlsvc.h> 39 #include <smbsrv/ndl/dssetup.ndl> 40 #include <smbsrv/smbinfo.h> 41 #include <smbsrv/nmpipes.h> 42 43 int dssetup_get_domain_info(ds_primary_domain_info_t *); 44 45 static int dssetup_DsRoleGetPrimaryDomainInfo(void *, ndr_xa_t *); 46 static uint32_t dssetup_member_server(ds_primary_domain_info_t *, ndr_xa_t *); 47 static uint32_t dssetup_standalone_server(ds_primary_domain_info_t *, 48 ndr_xa_t *); 49 50 static ndr_stub_table_t dssetup_stub_table[] = { 51 { dssetup_DsRoleGetPrimaryDomainInfo, 52 DSSETUP_OPNUM_DsRoleGetPrimaryDomainInfo }, 53 {0} 54 }; 55 56 static ndr_service_t dssetup_service = { 57 "DSSETUP", /* name */ 58 "Active Directory Setup", /* desc */ 59 "\\lsarpc", /* endpoint */ 60 PIPE_LSASS, /* sec_addr_port */ 61 "3919286a-b10c-11d0-9ba8-00c04fd92ef5", 0, /* abstract */ 62 NDR_TRANSFER_SYNTAX_UUID, 2, /* transfer */ 63 0, /* no bind_instance_size */ 64 0, /* no bind_req() */ 65 0, /* no unbind_and_close() */ 66 0, /* use generic_call_stub() */ 67 &TYPEINFO(dssetup_interface), /* interface ti */ 68 dssetup_stub_table /* stub_table */ 69 }; 70 71 static ds_primary_domain_info_t ds_info; 72 static mutex_t ds_info_mtx; 73 74 /* 75 * dssetup_initialize 76 * 77 * This function registers the DSSETUP interface with the RPC runtime 78 * library. It must be called in order to use either the client side 79 * or the server side functions. 80 */ 81 void 82 dssetup_initialize(void) 83 { 84 dssetup_clear_domain_info(); 85 (void) ndr_svc_register(&dssetup_service); 86 } 87 88 void 89 dssetup_clear_domain_info(void) 90 { 91 (void) mutex_lock(&ds_info_mtx); 92 93 free(ds_info.nt_domain); 94 free(ds_info.dns_domain); 95 free(ds_info.forest); 96 bzero(&ds_info, sizeof (ds_primary_domain_info_t)); 97 98 (void) mutex_unlock(&ds_info_mtx); 99 } 100 101 /* 102 * Request for machine role and primary domain information. 103 */ 104 static int 105 dssetup_DsRoleGetPrimaryDomainInfo(void *arg, ndr_xa_t *mxa) 106 { 107 dssetup_DsRoleGetPrimaryDomainInfo_t *param = arg; 108 dssetup_GetPrimaryDomainInfo_t *info; 109 ds_primary_domain_info_t *info1; 110 uint32_t status; 111 int security_mode; 112 113 info = NDR_MALLOC(mxa, sizeof (dssetup_GetPrimaryDomainInfo_t)); 114 if (info == NULL) { 115 status = NT_STATUS_NO_MEMORY; 116 } else if (param->level != DS_ROLE_BASIC_INFORMATION) { 117 status = NT_STATUS_INVALID_LEVEL; 118 } else { 119 info->switch_value = param->level; 120 info1 = &info->ru.info1; 121 122 security_mode = smb_config_get_secmode(); 123 124 if (security_mode == SMB_SECMODE_DOMAIN) 125 status = dssetup_member_server(info1, mxa); 126 else 127 status = dssetup_standalone_server(info1, mxa); 128 } 129 130 if (status != NT_STATUS_SUCCESS) { 131 bzero(param, sizeof (dssetup_DsRoleGetPrimaryDomainInfo_t)); 132 param->status = NT_SC_ERROR(status); 133 } else { 134 param->info = info; 135 param->status = NT_STATUS_SUCCESS; 136 } 137 138 return (NDR_DRC_OK); 139 } 140 141 /* 142 * When the machine role is domain member: 143 * nt_domain must contain the NetBIOS domain name 144 * dns_domain must contain the DNS domain name (cannot be NULL) 145 * forest must contain the forest name (cannot be NULL) 146 * 147 * If DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT is set in flags, the domain_guid 148 * must contain the domain UUID. Otherwise domain_guid is ignored. 149 */ 150 static uint32_t 151 dssetup_member_server(ds_primary_domain_info_t *info, ndr_xa_t *mxa) 152 { 153 char dns_domain[MAXHOSTNAMELEN]; 154 char nt_domain[MAXHOSTNAMELEN]; 155 156 (void) mutex_lock(&ds_info_mtx); 157 158 if ((ds_info.flags & DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT) == 0) { 159 /* 160 * If we don't have the domain GUID, try to get it from a 161 * domain controller. Otherwise, use local configuration. 162 */ 163 free(ds_info.nt_domain); 164 free(ds_info.dns_domain); 165 free(ds_info.forest); 166 (void) dssetup_get_domain_info(&ds_info); 167 } 168 169 if (ds_info.flags & DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT) { 170 info->flags = DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT; 171 info->nt_domain = NDR_STRDUP(mxa, (char *)ds_info.nt_domain); 172 info->dns_domain = NDR_STRDUP(mxa, (char *)ds_info.dns_domain); 173 info->forest = NDR_STRDUP(mxa, (char *)ds_info.forest); 174 bcopy(&ds_info.domain_guid, &info->domain_guid, 175 sizeof (ndr_uuid_t)); 176 } else { 177 if (smb_getdomainname(nt_domain, MAXHOSTNAMELEN) != 0) { 178 (void) mutex_unlock(&ds_info_mtx); 179 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 180 } 181 182 if (smb_getfqdomainname(dns_domain, MAXHOSTNAMELEN) != 0) { 183 (void) mutex_unlock(&ds_info_mtx); 184 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 185 } 186 187 (void) smb_strlwr(dns_domain); 188 189 info->flags = 0; 190 info->nt_domain = NDR_STRDUP(mxa, nt_domain); 191 info->dns_domain = NDR_STRDUP(mxa, dns_domain); 192 info->forest = NDR_STRDUP(mxa, dns_domain); 193 bzero(&info->domain_guid, sizeof (ndr_uuid_t)); 194 } 195 196 (void) mutex_unlock(&ds_info_mtx); 197 198 if (info->nt_domain == NULL || 199 info->dns_domain == NULL || 200 info->forest == NULL) 201 return (NT_STATUS_NO_MEMORY); 202 203 info->role = DS_ROLE_MEMBER_SERVER; 204 return (NT_STATUS_SUCCESS); 205 } 206 207 /* 208 * When the machine role is standalone: 209 * nt_domain must contain the NetBIOS workgroup name 210 * dns_domain must be NULL 211 * forest must be NULL 212 * 213 * We don't maintain a domain GUID. When DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT 214 * is not set in flags, domain_guid is ignored. 215 */ 216 static uint32_t 217 dssetup_standalone_server(ds_primary_domain_info_t *info, ndr_xa_t *mxa) 218 { 219 char nt_domain[MAXHOSTNAMELEN]; 220 221 if (smb_getdomainname(nt_domain, MAXHOSTNAMELEN) != 0) 222 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 223 224 info->nt_domain = NDR_STRDUP(mxa, nt_domain); 225 if (info->nt_domain == NULL) 226 return (NT_STATUS_NO_MEMORY); 227 228 info->role = DS_ROLE_STANDALONE_SERVER; 229 info->flags = 0; 230 info->dns_domain = NULL; 231 info->forest = NULL; 232 bzero(&info->domain_guid, sizeof (ndr_uuid_t)); 233 return (NT_STATUS_SUCCESS); 234 }