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