1/* 2 Samba Unix/Linux SMB client library 3 net ads cldap functions 4 Copyright (C) 2001 Andrew Tridgell (tridge@samba.org) 5 Copyright (C) 2003 Jim McDonough (jmcd@us.ibm.com) 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*/ 21 22#include "includes.h" 23 24/* 25 These seem to be strings as described in RFC1035 4.1.4 and can be: 26 27 - a sequence of labels ending in a zero octet 28 - a pointer 29 - a sequence of labels ending with a pointer 30 31 A label is a byte where the first two bits must be zero and the remaining 32 bits represent the length of the label followed by the label itself. 33 Therefore, the length of a label is at max 64 bytes. Under RFC1035, a 34 sequence of labels cannot exceed 255 bytes. 35 36 A pointer consists of a 14 bit offset from the beginning of the data. 37 38 struct ptr { 39 unsigned ident:2; // must be 11 40 unsigned offset:14; // from the beginning of data 41 }; 42 43 This is used as a method to compress the packet by eliminated duplicate 44 domain components. Since a UDP packet should probably be < 512 bytes and a 45 DNS name can be up to 255 bytes, this actually makes a lot of sense. 46*/ 47static unsigned pull_netlogon_string(char *ret, const char *ptr, 48 const char *data) 49{ 50 char *pret = ret; 51 int followed_ptr = 0; 52 unsigned ret_len = 0; 53 54 memset(pret, 0, MAX_DNS_LABEL); 55 do { 56 if ((*ptr & 0xc0) == 0xc0) { 57 uint16 len; 58 59 if (!followed_ptr) { 60 ret_len += 2; 61 followed_ptr = 1; 62 } 63 len = ((ptr[0] & 0x3f) << 8) | ptr[1]; 64 ptr = data + len; 65 } else if (*ptr) { 66 uint8 len = (uint8)*(ptr++); 67 68 if ((pret - ret + len + 1) >= MAX_DNS_LABEL) { 69 DEBUG(1,("DC returning too long DNS name\n")); 70 return 0; 71 } 72 73 if (pret != ret) { 74 *pret = '.'; 75 pret++; 76 } 77 memcpy(pret, ptr, len); 78 pret += len; 79 ptr += len; 80 81 if (!followed_ptr) { 82 ret_len += (len + 1); 83 } 84 } 85 } while (*ptr); 86 87 return followed_ptr ? ret_len : ret_len + 1; 88} 89 90/* 91 do a cldap netlogon query 92*/ 93static int send_cldap_netlogon(int sock, const char *domain, 94 const char *hostname, unsigned ntversion) 95{ 96 ASN1_DATA data; 97 char ntver[4]; 98#ifdef CLDAP_USER_QUERY 99 char aac[4]; 100 101 SIVAL(aac, 0, 0x00000180); 102#endif 103 SIVAL(ntver, 0, ntversion); 104 105 memset(&data, 0, sizeof(data)); 106 107 asn1_push_tag(&data,ASN1_SEQUENCE(0)); 108 asn1_write_Integer(&data, 4); 109 asn1_push_tag(&data, ASN1_APPLICATION(3)); 110 asn1_write_OctetString(&data, NULL, 0); 111 asn1_write_enumerated(&data, 0); 112 asn1_write_enumerated(&data, 0); 113 asn1_write_Integer(&data, 0); 114 asn1_write_Integer(&data, 0); 115 asn1_write_BOOLEAN2(&data, False); 116 asn1_push_tag(&data, ASN1_CONTEXT(0)); 117 118 if (domain) { 119 asn1_push_tag(&data, ASN1_CONTEXT(3)); 120 asn1_write_OctetString(&data, "DnsDomain", 9); 121 asn1_write_OctetString(&data, domain, strlen(domain)); 122 asn1_pop_tag(&data); 123 } 124 125 asn1_push_tag(&data, ASN1_CONTEXT(3)); 126 asn1_write_OctetString(&data, "Host", 4); 127 asn1_write_OctetString(&data, hostname, strlen(hostname)); 128 asn1_pop_tag(&data); 129 130#ifdef CLDAP_USER_QUERY 131 asn1_push_tag(&data, ASN1_CONTEXT(3)); 132 asn1_write_OctetString(&data, "User", 4); 133 asn1_write_OctetString(&data, "SAMBA$", 6); 134 asn1_pop_tag(&data); 135 136 asn1_push_tag(&data, ASN1_CONTEXT(3)); 137 asn1_write_OctetString(&data, "AAC", 4); 138 asn1_write_OctetString(&data, aac, 4); 139 asn1_pop_tag(&data); 140#endif 141 142 asn1_push_tag(&data, ASN1_CONTEXT(3)); 143 asn1_write_OctetString(&data, "NtVer", 5); 144 asn1_write_OctetString(&data, ntver, 4); 145 asn1_pop_tag(&data); 146 147 asn1_pop_tag(&data); 148 149 asn1_push_tag(&data,ASN1_SEQUENCE(0)); 150 asn1_write_OctetString(&data, "NetLogon", 8); 151 asn1_pop_tag(&data); 152 asn1_pop_tag(&data); 153 asn1_pop_tag(&data); 154 155 if (data.has_error) { 156 DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data.ofs)); 157 asn1_free(&data); 158 return -1; 159 } 160 161 if (write(sock, data.data, data.length) != (ssize_t)data.length) { 162 DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno))); 163 asn1_free(&data); 164 return -1; 165 } 166 167 asn1_free(&data); 168 169 return 0; 170} 171 172static SIG_ATOMIC_T gotalarm; 173 174/*************************************************************** 175 Signal function to tell us we timed out. 176****************************************************************/ 177 178static void gotalarm_sig(void) 179{ 180 gotalarm = 1; 181} 182 183/* 184 receive a cldap netlogon reply 185*/ 186static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply) 187{ 188 int ret; 189 ASN1_DATA data; 190 DATA_BLOB blob = data_blob(NULL, 0); 191 DATA_BLOB os1 = data_blob(NULL, 0); 192 DATA_BLOB os2 = data_blob(NULL, 0); 193 DATA_BLOB os3 = data_blob(NULL, 0); 194 int i1; 195 /* half the time of a regular ldap timeout, not less than 3 seconds. */ 196 unsigned int al_secs = MAX(3,lp_ldap_timeout()/2); 197 char *p; 198 199 blob = data_blob(NULL, 8192); 200 if (blob.data == NULL) { 201 DEBUG(1, ("data_blob failed\n")); 202 errno = ENOMEM; 203 return -1; 204 } 205 206 /* Setup timeout */ 207 gotalarm = 0; 208 CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig); 209 alarm(al_secs); 210 /* End setup timeout. */ 211 212 ret = read(sock, blob.data, blob.length); 213 214 /* Teardown timeout. */ 215 CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN); 216 alarm(0); 217 218 if (ret <= 0) { 219 DEBUG(1,("no reply received to cldap netlogon\n")); 220 data_blob_free(&blob); 221 return -1; 222 } 223 blob.length = ret; 224 225 asn1_load(&data, blob); 226 asn1_start_tag(&data, ASN1_SEQUENCE(0)); 227 asn1_read_Integer(&data, &i1); 228 asn1_start_tag(&data, ASN1_APPLICATION(4)); 229 asn1_read_OctetString(&data, &os1); 230 asn1_start_tag(&data, ASN1_SEQUENCE(0)); 231 asn1_start_tag(&data, ASN1_SEQUENCE(0)); 232 asn1_read_OctetString(&data, &os2); 233 asn1_start_tag(&data, ASN1_SET); 234 asn1_read_OctetString(&data, &os3); 235 asn1_end_tag(&data); 236 asn1_end_tag(&data); 237 asn1_end_tag(&data); 238 asn1_end_tag(&data); 239 asn1_end_tag(&data); 240 241 if (data.has_error) { 242 data_blob_free(&blob); 243 data_blob_free(&os1); 244 data_blob_free(&os2); 245 data_blob_free(&os3); 246 asn1_free(&data); 247 DEBUG(1,("Failed to parse cldap reply\n")); 248 return -1; 249 } 250 251 p = (char *)os3.data; 252 253 reply->type = IVAL(p, 0); p += 4; 254 reply->flags = IVAL(p, 0); p += 4; 255 256 memcpy(&reply->guid.info, p, UUID_FLAT_SIZE); 257 p += UUID_FLAT_SIZE; 258 259 p += pull_netlogon_string(reply->forest, p, (const char *)os3.data); 260 p += pull_netlogon_string(reply->domain, p, (const char *)os3.data); 261 p += pull_netlogon_string(reply->hostname, p, (const char *)os3.data); 262 p += pull_netlogon_string(reply->netbios_domain, p, (const char *)os3.data); 263 p += pull_netlogon_string(reply->netbios_hostname, p, (const char *)os3.data); 264 p += pull_netlogon_string(reply->unk, p, (const char *)os3.data); 265 266 if (reply->type == SAMLOGON_AD_R) { 267 p += pull_netlogon_string(reply->user_name, p, (const char *)os3.data); 268 } else { 269 *reply->user_name = 0; 270 } 271 272 p += pull_netlogon_string(reply->server_site_name, p, (const char *)os3.data); 273 p += pull_netlogon_string(reply->client_site_name, p, (const char *)os3.data); 274 275 reply->version = IVAL(p, 0); 276 reply->lmnt_token = SVAL(p, 4); 277 reply->lm20_token = SVAL(p, 6); 278 279 data_blob_free(&os1); 280 data_blob_free(&os2); 281 data_blob_free(&os3); 282 data_blob_free(&blob); 283 284 asn1_free(&data); 285 286 return 0; 287} 288 289/******************************************************************* 290 do a cldap netlogon query. Always 389/udp 291*******************************************************************/ 292 293BOOL ads_cldap_netlogon(const char *server, const char *realm, struct cldap_netlogon_reply *reply) 294{ 295 int sock; 296 int ret; 297 298 sock = open_udp_socket(server, LDAP_PORT ); 299 if (sock == -1) { 300 DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n", 301 server)); 302 return False; 303 } 304 305 ret = send_cldap_netlogon(sock, realm, global_myname(), 6); 306 if (ret != 0) { 307 close(sock); 308 return False; 309 } 310 ret = recv_cldap_netlogon(sock, reply); 311 close(sock); 312 313 if (ret == -1) { 314 return False; 315 } 316 317 return True; 318} 319