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