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
init_dc_locator(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
fini_dc_locator(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
adspriv_null_1_svc(void * result,struct svc_req * rqstp)70 adspriv_null_1_svc(void *result, struct svc_req *rqstp)
71 {
72 	return (TRUE);
73 }
74 
75 /* ARGSUSED */
76 bool_t
adspriv_forcerediscovery_1_svc(DsForceRediscoveryArgs args,int * res,struct svc_req * sreq)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
adspriv_getdcname_1_svc(DsGetDcNameArgs args,DsGetDcNameRes * res,struct svc_req * sreq)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
adspriv_program_1_freeresult(SVCXPRT * xprt,xdrproc_t fun,caddr_t res)238 adspriv_program_1_freeresult(SVCXPRT *xprt, xdrproc_t fun, caddr_t res)
239 {
240 	xdr_free(fun, res);
241 	return (TRUE);
242 }
243