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