diff options
Diffstat (limited to 'usr/src/lib/libads/common/dsgetdc.c')
-rw-r--r-- | usr/src/lib/libads/common/dsgetdc.c | 162 |
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); + } +} |