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
_DsGetDcName(const char * ComputerName,const char * DomainName,const struct uuid * DomainGuid,const char * SiteName,uint32_t Flags,DOMAIN_CONTROLLER_INFO ** dcinfo)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
DsGetDcName(const char * ComputerName,const char * DomainName,const struct uuid * DomainGuid,const char * SiteName,uint32_t Flags,DOMAIN_CONTROLLER_INFO ** dcinfo)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
DsFreeDcInfo(DOMAIN_CONTROLLER_INFO * dci)156 DsFreeDcInfo(DOMAIN_CONTROLLER_INFO *dci)
157 {
158 if (dci != NULL) {
159 xdr_free(xdr_DsGetDcNameRes, (char *)dci);
160 free(dci);
161 }
162 }
163