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