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 * Copyright 2021 RackTop Systems, Inc. 15 */ 16 17 /* 18 * MS-compatible Directory Server Discovery API, DsGetDC...() 19 */ 20 21 #include <stdlib.h> 22 #include <string.h> 23 #include <smb/nterror.h> 24 #include <smb/ntstatus.h> 25 #include <arpa/inet.h> 26 #include "dsgetdc.h" 27 #include "ads_priv.h" 28 #include <sys/debug.h> 29 30 #define DSGETDC_VALID_FLAGS ( \ 31 DS_FORCE_REDISCOVERY | \ 32 DS_DIRECTORY_SERVICE_REQUIRED | \ 33 DS_DIRECTORY_SERVICE_PREFERRED | \ 34 DS_GC_SERVER_REQUIRED | \ 35 DS_PDC_REQUIRED | \ 36 DS_BACKGROUND_ONLY | \ 37 DS_IP_REQUIRED | \ 38 DS_KDC_REQUIRED | \ 39 DS_TIMESERV_REQUIRED | \ 40 DS_WRITABLE_REQUIRED | \ 41 DS_GOOD_TIMESERV_PREFERRED | \ 42 DS_AVOID_SELF | \ 43 DS_ONLY_LDAP_NEEDED | \ 44 DS_IS_FLAT_NAME | \ 45 DS_IS_DNS_NAME | \ 46 DS_RETURN_FLAT_NAME | \ 47 DS_RETURN_DNS_NAME) 48 49 static struct timeval TIMEOUT = { 15, 0 }; 50 51 /* 52 * The Windows version of this would return a single allocation, 53 * where any strings pointed to in the returned structure would be 54 * stored in space following the top-level returned structure. 55 * This allows NetApiBufferFree() to be the same as free(). 56 * 57 * However, we don't have an easy way to do that right now, so 58 * the dcinfo returned here will be free'd with DsFreeDcInfo(). 59 */ 60 uint32_t 61 _DsGetDcName(const char *ComputerName, 62 const char *DomainName, const struct uuid *DomainGuid, 63 const char *SiteName, uint32_t Flags, 64 DOMAIN_CONTROLLER_INFO **dcinfo) 65 { 66 DsGetDcNameArgs args; 67 DsGetDcNameRes res; 68 CLIENT *clnt = NULL; 69 enum clnt_stat clstat; 70 71 *dcinfo = NULL; 72 (void) memset(&args, 0, sizeof (args)); 73 (void) memset(&res, 0, sizeof (res)); 74 75 /* 76 * Later check for over constrained optional args here, 77 * and return (ERROR_INVALID_PARAMETER); 78 */ 79 80 if (Flags & ~DSGETDC_VALID_FLAGS) 81 return (ERROR_INVALID_FLAGS); 82 83 /* 84 * Call the ADS deamon. 85 */ 86 clnt = clnt_door_create(ADSPRIV_PROGRAM, ADSPRIV_V1, ADSPRIV_MAX_XFER); 87 if (clnt == NULL) 88 return (RPC_S_NOT_LISTENING); 89 90 args.ComputerName = (char *)ComputerName; 91 args.DomainName = (char *)DomainName; 92 if (DomainGuid != NULL) 93 (void) memcpy(&args.DomainGuid, DomainGuid, 94 sizeof (args.DomainGuid)); 95 args.SiteName = (char *)SiteName; 96 args.Flags = Flags; 97 98 clstat = clnt_call(clnt, ADSPRIV_GetDcName, 99 (xdrproc_t)xdr_DsGetDcNameArgs, (caddr_t)&args, 100 (xdrproc_t)xdr_DsGetDcNameRes, (caddr_t)&res, TIMEOUT); 101 102 clnt_destroy(clnt); 103 if (clstat != RPC_SUCCESS) 104 return (RPC_S_CALL_FAILED); 105 if (res.status != 0) 106 return (res.status); 107 108 *dcinfo = malloc(sizeof (**dcinfo)); 109 if (*dcinfo == NULL) 110 return (ERROR_NOT_ENOUGH_MEMORY); 111 112 /* 113 * We have taken pains to make these two the same. 114 * DOMAIN_CONTROLLER_INFO / struct adspriv_dcinfo 115 */ 116 CTASSERT(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_adspriv_dcinfo, (char *)dci); 160 free(dci); 161 } 162 } 163