summaryrefslogtreecommitdiff
path: root/usr/src/lib/libads/common/dsgetdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libads/common/dsgetdc.c')
-rw-r--r--usr/src/lib/libads/common/dsgetdc.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/usr/src/lib/libads/common/dsgetdc.c b/usr/src/lib/libads/common/dsgetdc.c
new file mode 100644
index 0000000000..a8b45707b9
--- /dev/null
+++ b/usr/src/lib/libads/common/dsgetdc.c
@@ -0,0 +1,162 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
+
+/*
+ * MS-compatible Directory Server Discovery API, DsGetDC...()
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <smb/nterror.h>
+#include <smb/ntstatus.h>
+#include <arpa/inet.h>
+#include "dsgetdc.h"
+#include "ads_priv.h"
+#include <assert.h>
+
+#define DSGETDC_VALID_FLAGS ( \
+ DS_FORCE_REDISCOVERY | \
+ DS_DIRECTORY_SERVICE_REQUIRED | \
+ DS_DIRECTORY_SERVICE_PREFERRED | \
+ DS_GC_SERVER_REQUIRED | \
+ DS_PDC_REQUIRED | \
+ DS_BACKGROUND_ONLY | \
+ DS_IP_REQUIRED | \
+ DS_KDC_REQUIRED | \
+ DS_TIMESERV_REQUIRED | \
+ DS_WRITABLE_REQUIRED | \
+ DS_GOOD_TIMESERV_PREFERRED | \
+ DS_AVOID_SELF | \
+ DS_ONLY_LDAP_NEEDED | \
+ DS_IS_FLAT_NAME | \
+ DS_IS_DNS_NAME | \
+ DS_RETURN_FLAT_NAME | \
+ DS_RETURN_DNS_NAME)
+
+static struct timeval TIMEOUT = { 15, 0 };
+
+/*
+ * The Windows version of this would return a single allocation,
+ * where any strings pointed to in the returned structure would be
+ * stored in space following the top-level returned structure.
+ * This allows NetApiBufferFree() to be the same as free().
+ *
+ * However, we don't have an easy way to do that right now, so
+ * the dcinfo returned here will be free'd with DsFreeDcInfo().
+ */
+uint32_t
+_DsGetDcName(const char *ComputerName,
+ const char *DomainName, const struct uuid *DomainGuid,
+ const char *SiteName, uint32_t Flags,
+ DOMAIN_CONTROLLER_INFO **dcinfo)
+{
+ DsGetDcNameArgs args;
+ DsGetDcNameRes res;
+ CLIENT *clnt = NULL;
+ enum clnt_stat clstat;
+
+ *dcinfo = NULL;
+ (void) memset(&args, 0, sizeof (args));
+ (void) memset(&res, 0, sizeof (res));
+
+ /*
+ * Later check for over constrained optional args here,
+ * and return (ERROR_INVALID_PARAMETER);
+ */
+
+ if (Flags & ~DSGETDC_VALID_FLAGS)
+ return (ERROR_INVALID_FLAGS);
+
+ /*
+ * Call the ADS deamon.
+ */
+ clnt = clnt_door_create(ADSPRIV_PROGRAM, ADSPRIV_V1, ADSPRIV_MAX_XFER);
+ if (clnt == NULL)
+ return (RPC_S_NOT_LISTENING);
+
+ args.ComputerName = (char *)ComputerName;
+ args.DomainName = (char *)DomainName;
+ if (DomainGuid != NULL)
+ (void) memcpy(&args.DomainGuid, DomainGuid,
+ sizeof (args.DomainGuid));
+ args.SiteName = (char *)SiteName;
+ args.Flags = Flags;
+
+ clstat = clnt_call(clnt, ADSPRIV_GetDcName,
+ (xdrproc_t)xdr_DsGetDcNameArgs, (caddr_t)&args,
+ (xdrproc_t)xdr_DsGetDcNameRes, (caddr_t)&res, TIMEOUT);
+
+ clnt_destroy(clnt);
+ if (clstat != RPC_SUCCESS)
+ return (RPC_S_CALL_FAILED);
+ if (res.status != 0)
+ return (res.status);
+
+ *dcinfo = malloc(sizeof (**dcinfo));
+ if (*dcinfo == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ /*
+ * We have taken pains to make these two the same.
+ * DOMAIN_CONTROLLER_INFO / struct adspriv_dcinfo
+ */
+ /* LINTED E_TRUE_LOGICAL_EXPR */
+ assert(sizeof (**dcinfo) == sizeof (res.DsGetDcNameRes_u.res0));
+ (void) memcpy(*dcinfo, &res.DsGetDcNameRes_u.res0, sizeof (**dcinfo));
+
+ /*
+ * NB: Do NOT xdr_free the result, because we're
+ * returning a copy of it to the caller.
+ */
+ return (0);
+}
+
+int
+DsGetDcName(const char *ComputerName,
+ const char *DomainName, const struct uuid *DomainGuid,
+ const char *SiteName, uint32_t Flags,
+ DOMAIN_CONTROLLER_INFO **dcinfo)
+{
+ uint32_t status;
+ int rc;
+
+ status = _DsGetDcName(ComputerName, DomainName, DomainGuid,
+ SiteName, Flags, dcinfo);
+
+ switch (status) {
+ case 0:
+ rc = 0;
+ break;
+ case NT_STATUS_NO_SUCH_DOMAIN: /* Specified domain unknown */
+ case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND:
+ case NT_STATUS_CANT_WAIT: /* or gave up waiting. */
+ case NT_STATUS_INVALID_SERVER_STATE: /* not in domain mode. */
+ rc = ERROR_NO_SUCH_DOMAIN;
+ break;
+ default:
+ rc = ERROR_INTERNAL_ERROR;
+ break;
+ }
+ return (rc);
+}
+
+void
+DsFreeDcInfo(DOMAIN_CONTROLLER_INFO *dci)
+{
+ if (dci != NULL) {
+ xdr_free(xdr_DsGetDcNameRes, (char *)dci);
+ free(dci);
+ }
+}