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
35void adspriv_program_1(struct svc_req *, register SVCXPRT *);
36
37SVCXPRT *dcl_xprt = NULL;
38
39void
40init_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
56void
57fini_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 */
68bool_t
69adspriv_null_1_svc(void *result, struct svc_req *rqstp)
70{
71	return (TRUE);
72}
73
74/* ARGSUSED */
75bool_t
76adspriv_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 */
91bool_t
92adspriv_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
198out:
199	UNLOCK_CONFIG();
200
201	return (TRUE);
202}
203
204/* ARGSUSED */
205int
206adspriv_program_1_freeresult(SVCXPRT *xprt, xdrproc_t fun, caddr_t res)
207{
208	xdr_free(fun, res);
209	return (TRUE);
210}
211