xref: /illumos-gate/usr/src/lib/libads/common/dsgetdc.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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  * MS-compatible Directory Server Discovery API, DsGetDC...()
18  */
19 
20 #include <stdlib.h>
21 #include <string.h>
22 #include <smb/nterror.h>
23 #include <smb/ntstatus.h>
24 #include <arpa/inet.h>
25 #include "dsgetdc.h"
26 #include "ads_priv.h"
27 #include <assert.h>
28 
29 #define	DSGETDC_VALID_FLAGS ( \
30 	DS_FORCE_REDISCOVERY | \
31 	DS_DIRECTORY_SERVICE_REQUIRED | \
32 	DS_DIRECTORY_SERVICE_PREFERRED | \
33 	DS_GC_SERVER_REQUIRED | \
34 	DS_PDC_REQUIRED | \
35 	DS_BACKGROUND_ONLY | \
36 	DS_IP_REQUIRED | \
37 	DS_KDC_REQUIRED | \
38 	DS_TIMESERV_REQUIRED | \
39 	DS_WRITABLE_REQUIRED | \
40 	DS_GOOD_TIMESERV_PREFERRED | \
41 	DS_AVOID_SELF | \
42 	DS_ONLY_LDAP_NEEDED | \
43 	DS_IS_FLAT_NAME | \
44 	DS_IS_DNS_NAME | \
45 	DS_RETURN_FLAT_NAME | \
46 	DS_RETURN_DNS_NAME)
47 
48 static struct timeval TIMEOUT = { 15, 0 };
49 
50 /*
51  * The Windows version of this would return a single allocation,
52  * where any strings pointed to in the returned structure would be
53  * stored in space following the top-level returned structure.
54  * This allows NetApiBufferFree() to be the same as free().
55  *
56  * However, we don't have an easy way to do that right now, so
57  * the dcinfo returned here will be free'd with DsFreeDcInfo().
58  */
59 uint32_t
60 _DsGetDcName(const char *ComputerName,
61     const char *DomainName, const struct uuid *DomainGuid,
62     const char *SiteName, uint32_t Flags,
63     DOMAIN_CONTROLLER_INFO **dcinfo)
64 {
65 	DsGetDcNameArgs args;
66 	DsGetDcNameRes res;
67 	CLIENT *clnt = NULL;
68 	enum clnt_stat clstat;
69 
70 	*dcinfo = NULL;
71 	(void) memset(&args, 0, sizeof (args));
72 	(void) memset(&res, 0, sizeof (res));
73 
74 	/*
75 	 * Later check for over constrained optional args here,
76 	 * and return (ERROR_INVALID_PARAMETER);
77 	 */
78 
79 	if (Flags & ~DSGETDC_VALID_FLAGS)
80 		return (ERROR_INVALID_FLAGS);
81 
82 	/*
83 	 * Call the ADS deamon.
84 	 */
85 	clnt = clnt_door_create(ADSPRIV_PROGRAM, ADSPRIV_V1, ADSPRIV_MAX_XFER);
86 	if (clnt == NULL)
87 		return (RPC_S_NOT_LISTENING);
88 
89 	args.ComputerName = (char *)ComputerName;
90 	args.DomainName = (char *)DomainName;
91 	if (DomainGuid != NULL)
92 		(void) memcpy(&args.DomainGuid, DomainGuid,
93 		    sizeof (args.DomainGuid));
94 	args.SiteName = (char *)SiteName;
95 	args.Flags = Flags;
96 
97 	clstat = clnt_call(clnt, ADSPRIV_GetDcName,
98 	    (xdrproc_t)xdr_DsGetDcNameArgs, (caddr_t)&args,
99 	    (xdrproc_t)xdr_DsGetDcNameRes, (caddr_t)&res, TIMEOUT);
100 
101 	clnt_destroy(clnt);
102 	if (clstat != RPC_SUCCESS)
103 		return (RPC_S_CALL_FAILED);
104 	if (res.status != 0)
105 		return (res.status);
106 
107 	*dcinfo = malloc(sizeof (**dcinfo));
108 	if (*dcinfo == NULL)
109 		return (ERROR_NOT_ENOUGH_MEMORY);
110 
111 	/*
112 	 * We have taken pains to make these two the same.
113 	 * DOMAIN_CONTROLLER_INFO / struct adspriv_dcinfo
114 	 */
115 	/* LINTED E_TRUE_LOGICAL_EXPR */
116 	assert(sizeof (**dcinfo) == sizeof (res.DsGetDcNameRes_u.res0));
117 	(void) memcpy(*dcinfo, &res.DsGetDcNameRes_u.res0, sizeof (**dcinfo));
118 
119 	/*
120 	 * NB: Do NOT xdr_free the result, because we're
121 	 * returning a copy of it to the caller.
122 	 */
123 	return (0);
124 }
125 
126 int
127 DsGetDcName(const char *ComputerName,
128     const char *DomainName, const struct uuid *DomainGuid,
129     const char *SiteName, uint32_t Flags,
130     DOMAIN_CONTROLLER_INFO **dcinfo)
131 {
132 	uint32_t status;
133 	int rc;
134 
135 	status = _DsGetDcName(ComputerName, DomainName, DomainGuid,
136 	    SiteName, Flags, dcinfo);
137 
138 	switch (status) {
139 	case 0:
140 		rc = 0;
141 		break;
142 	case NT_STATUS_NO_SUCH_DOMAIN:	/* Specified domain unknown */
143 	case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND:
144 	case NT_STATUS_CANT_WAIT:		/* or gave up waiting. */
145 	case NT_STATUS_INVALID_SERVER_STATE:	/*  not in domain mode. */
146 		rc = ERROR_NO_SUCH_DOMAIN;
147 		break;
148 	default:
149 		rc = ERROR_INTERNAL_ERROR;
150 		break;
151 	}
152 	return (rc);
153 }
154 
155 void
156 DsFreeDcInfo(DOMAIN_CONTROLLER_INFO *dci)
157 {
158 	if (dci != NULL) {
159 		xdr_free(xdr_DsGetDcNameRes, (char *)dci);
160 		free(dci);
161 	}
162 }
163