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