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