1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 14 * Copyright 2022 RackTop Systems, Inc. 15 */ 16 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <stdarg.h> 21 #include <string.h> 22 #include <syslog.h> 23 #include <rpc/rpc.h> 24 #include <sys/uuid.h> 25 #include <smb/ntstatus.h> 26 #include <synch.h> 27 #include <thread.h> 28 #include <arpa/inet.h> 29 #include <uuid/uuid.h> 30 31 #include "idmapd.h" 32 #include "libadutils.h" 33 #include "dsgetdc.h" 34 #include "ads_priv.h" 35 36 void adspriv_program_1(struct svc_req *, register SVCXPRT *); 37 38 SVCXPRT *dcl_xprt = NULL; 39 40 void 41 init_dc_locator(void) 42 { 43 int connmaxrec = 32 * 1024; 44 45 dcl_xprt = svc_door_create(adspriv_program_1, 46 ADSPRIV_PROGRAM, ADSPRIV_V1, connmaxrec); 47 if (dcl_xprt == NULL) { 48 syslog(LOG_ERR, "unable to create door RPC service"); 49 return; 50 } 51 52 if (!svc_control(dcl_xprt, SVCSET_CONNMAXREC, &connmaxrec)) { 53 syslog(LOG_ERR, "unable to limit RPC request size"); 54 } 55 } 56 57 void 58 fini_dc_locator(void) 59 { 60 if (dcl_xprt != NULL) 61 svc_destroy(dcl_xprt); 62 } 63 64 /* 65 * Functions called by the (generated) adspriv_srv.c 66 */ 67 68 /* ARGSUSED */ 69 bool_t 70 adspriv_null_1_svc(void *result, struct svc_req *rqstp) 71 { 72 return (TRUE); 73 } 74 75 /* ARGSUSED */ 76 bool_t 77 adspriv_forcerediscovery_1_svc( 78 DsForceRediscoveryArgs args, 79 int *res, 80 struct svc_req *sreq) 81 { 82 /* Ignoring args for now. */ 83 84 idmap_cfg_force_rediscovery(); 85 *res = 0; 86 87 return (TRUE); 88 } 89 90 91 /* ARGSUSED */ 92 bool_t 93 adspriv_getdcname_1_svc( 94 DsGetDcNameArgs args, 95 DsGetDcNameRes *res, 96 struct svc_req *sreq) 97 { 98 uuid_t uuid; 99 adspriv_dcinfo *dci; 100 idmap_pg_config_t *pgcfg; 101 ad_disc_ds_t *ds; 102 char *s; 103 104 /* Init */ 105 (void) memset(res, 0, sizeof (*res)); 106 res->status = 0; 107 dci = &res->DsGetDcNameRes_u.res0; 108 109 if (args.Flags & DS_FORCE_REDISCOVERY) 110 idmap_cfg_force_rediscovery(); 111 112 /* 113 * We normally should wait if discovery is running. 114 * Sort of mis-using the background flag as a way to 115 * skip the wait, until we really do background disc. 116 */ 117 if ((args.Flags & DS_BACKGROUND_ONLY) == 0) { 118 timespec_t tv = { 15, 0 }; 119 int rc = 0; 120 int waited = 0; 121 122 (void) mutex_lock(&_idmapdstate.addisc_lk); 123 124 if (_idmapdstate.addisc_st != 0) 125 idmapdlog(LOG_DEBUG, "getdcname wait begin"); 126 127 while (_idmapdstate.addisc_st != 0) { 128 waited++; 129 rc = cond_reltimedwait(&_idmapdstate.addisc_cv, 130 &_idmapdstate.addisc_lk, &tv); 131 if (rc == ETIME) 132 break; 133 } 134 (void) mutex_unlock(&_idmapdstate.addisc_lk); 135 136 if (rc == ETIME) { 137 /* Caller will replace this with DC not found. */ 138 idmapdlog(LOG_ERR, "getdcname timeout"); 139 res->status = NT_STATUS_CANT_WAIT; 140 return (TRUE); 141 } 142 if (waited) { 143 idmapdlog(LOG_DEBUG, "getdcname wait done"); 144 } 145 } 146 147 RDLOCK_CONFIG(); 148 pgcfg = &_idmapdstate.cfg->pgcfg; 149 150 if (pgcfg->domain_name == NULL) { 151 res->status = NT_STATUS_INVALID_SERVER_STATE; 152 goto out; 153 } 154 155 if (args.DomainName != NULL && args.DomainName[0] != '\0' && 156 0 != strcasecmp(args.DomainName, pgcfg->domain_name)) { 157 /* 158 * They asked for a specific domain not our primary, 159 * which is not supported (and not needed). 160 */ 161 res->status = NT_STATUS_NO_SUCH_DOMAIN; 162 goto out; 163 } 164 165 if ((ds = pgcfg->domain_controller) == NULL) { 166 res->status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; 167 goto out; 168 } 169 170 dci->dci_DcName = strdup(ds->host); 171 if (dci->dci_DcName == NULL) { 172 res->status = NT_STATUS_NO_MEMORY; 173 goto out; 174 } 175 176 dci->dci_DcAddr = calloc(1, INET6_ADDRSTRLEN); 177 if (dci->dci_DcAddr == NULL) { 178 res->status = NT_STATUS_NO_MEMORY; 179 goto out; 180 } 181 if (ad_disc_getnameinfo(dci->dci_DcAddr, INET6_ADDRSTRLEN, 182 &ds->addr) == 0) 183 dci->dci_AddrType = DS_INET_ADDRESS; 184 185 if ((s = pgcfg->domain_guid) != NULL && 186 0 == uuid_parse(s, uuid)) { 187 (void) memcpy(dci->dci_guid, uuid, sizeof (uuid)); 188 } 189 190 if ((s = pgcfg->domain_name) != NULL) { 191 dci->dci_DomainName = strdup(s); 192 if (dci->dci_DomainName == NULL) { 193 res->status = NT_STATUS_NO_MEMORY; 194 goto out; 195 } 196 } 197 198 if ((s = pgcfg->forest_name) != NULL) { 199 dci->dci_DnsForestName = strdup(s); 200 if (dci->dci_DnsForestName == NULL) { 201 res->status = NT_STATUS_NO_MEMORY; 202 goto out; 203 } 204 } 205 206 dci->dci_Flags = ds->flags; 207 dci->dci_DcSiteName = strdup(ds->site); 208 if (dci->dci_DcSiteName == NULL) { 209 res->status = NT_STATUS_NO_MEMORY; 210 goto out; 211 } 212 213 if ((s = pgcfg->site_name) != NULL) { 214 dci->dci_ClientSiteName = strdup(s); 215 if (dci->dci_ClientSiteName == NULL) { 216 res->status = NT_STATUS_NO_MEMORY; 217 goto out; 218 } 219 } 220 221 /* Address in binary form too. */ 222 (void) memcpy(&dci->dci_sockaddr, 223 &ds->addr, ADSPRIV_SOCKADDR_LEN); 224 225 out: 226 UNLOCK_CONFIG(); 227 228 if (res->status != 0) { 229 /* Caller will free only if status == 0 */ 230 xdr_free(xdr_adspriv_dcinfo, (char *)dci); 231 } 232 233 return (TRUE); 234 } 235 236 /* ARGSUSED */ 237 int 238 adspriv_program_1_freeresult(SVCXPRT *xprt, xdrproc_t fun, caddr_t res) 239 { 240 xdr_free(fun, res); 241 return (TRUE); 242 } 243