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