net ads cldap functions
Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
Copyright (C) 2003 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2008 Guenther Deschner (gd@samba.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
-/*
- These seem to be strings as described in RFC1035 4.1.4 and can be:
-
- - a sequence of labels ending in a zero octet
- - a pointer
- - a sequence of labels ending with a pointer
-
- A label is a byte where the first two bits must be zero and the remaining
- bits represent the length of the label followed by the label itself.
- Therefore, the length of a label is at max 64 bytes. Under RFC1035, a
- sequence of labels cannot exceed 255 bytes.
-
- A pointer consists of a 14 bit offset from the beginning of the data.
-
- struct ptr {
- unsigned ident:2; // must be 11
- unsigned offset:14; // from the beginning of data
- };
-
- This is used as a method to compress the packet by eliminated duplicate
- domain components. Since a UDP packet should probably be < 512 bytes and a
- DNS name can be up to 255 bytes, this actually makes a lot of sense.
-*/
-static unsigned pull_netlogon_string(char *ret, const char *ptr,
- const char *data)
-{
- char *pret = ret;
- int followed_ptr = 0;
- unsigned ret_len = 0;
-
- memset(pret, 0, MAX_DNS_LABEL);
- do {
- if ((*ptr & 0xc0) == 0xc0) {
- uint16 len;
-
- if (!followed_ptr) {
- ret_len += 2;
- followed_ptr = 1;
- }
- len = ((ptr[0] & 0x3f) << 8) | ptr[1];
- ptr = data + len;
- } else if (*ptr) {
- uint8 len = (uint8)*(ptr++);
-
- if ((pret - ret + len + 1) >= MAX_DNS_LABEL) {
- DEBUG(1,("DC returning too long DNS name\n"));
- return 0;
- }
-
- if (pret != ret) {
- *pret = '.';
- pret++;
- }
- memcpy(pret, ptr, len);
- pret += len;
- ptr += len;
-
- if (!followed_ptr) {
- ret_len += (len + 1);
- }
- }
- } while (*ptr);
-
- return followed_ptr ? ret_len : ret_len + 1;
-}
-
/*
do a cldap netlogon query
*/
if (write(sock, data.data, data.length) != (ssize_t)data.length) {
DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno)));
+ asn1_free(&data);
+ return -1;
}
asn1_free(&data);
/*
receive a cldap netlogon reply
*/
-static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
+static int recv_cldap_netlogon(TALLOC_CTX *mem_ctx,
+ int sock,
+ uint32_t nt_version,
+ struct netlogon_samlogon_response **reply)
{
int ret;
ASN1_DATA data;
- DATA_BLOB blob;
- DATA_BLOB os1, os2, os3;
+ DATA_BLOB blob = data_blob_null;
+ DATA_BLOB os1 = data_blob_null;
+ DATA_BLOB os2 = data_blob_null;
+ DATA_BLOB os3 = data_blob_null;
int i1;
/* half the time of a regular ldap timeout, not less than 3 seconds. */
unsigned int al_secs = MAX(3,lp_ldap_timeout()/2);
- char *p;
+ struct netlogon_samlogon_response *r = NULL;
+ NTSTATUS status;
blob = data_blob(NULL, 8192);
if (blob.data == NULL) {
if (data.has_error) {
data_blob_free(&blob);
+ data_blob_free(&os1);
+ data_blob_free(&os2);
+ data_blob_free(&os3);
asn1_free(&data);
DEBUG(1,("Failed to parse cldap reply\n"));
return -1;
}
- p = (char *)os3.data;
-
- reply->type = IVAL(p, 0); p += 4;
- reply->flags = IVAL(p, 0); p += 4;
-
- memcpy(&reply->guid.info, p, UUID_FLAT_SIZE);
- p += UUID_FLAT_SIZE;
-
- p += pull_netlogon_string(reply->forest, p, (const char *)os3.data);
- p += pull_netlogon_string(reply->domain, p, (const char *)os3.data);
- p += pull_netlogon_string(reply->hostname, p, (const char *)os3.data);
- p += pull_netlogon_string(reply->netbios_domain, p, (const char *)os3.data);
- p += pull_netlogon_string(reply->netbios_hostname, p, (const char *)os3.data);
- p += pull_netlogon_string(reply->unk, p, (const char *)os3.data);
-
- if (reply->type == SAMLOGON_AD_R) {
- p += pull_netlogon_string(reply->user_name, p, (const char *)os3.data);
- } else {
- *reply->user_name = 0;
+ r = TALLOC_ZERO_P(mem_ctx, struct netlogon_samlogon_response);
+ if (!r) {
+ errno = ENOMEM;
+ data_blob_free(&os1);
+ data_blob_free(&os2);
+ data_blob_free(&os3);
+ data_blob_free(&blob);
+ return -1;
}
- p += pull_netlogon_string(reply->server_site_name, p, (const char *)os3.data);
- p += pull_netlogon_string(reply->client_site_name, p, (const char *)os3.data);
+ status = pull_netlogon_samlogon_response(&os3, mem_ctx, NULL, r);
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_free(&os1);
+ data_blob_free(&os2);
+ data_blob_free(&os3);
+ data_blob_free(&blob);
+ TALLOC_FREE(r);
+ return -1;
+ }
- reply->version = IVAL(p, 0);
- reply->lmnt_token = SVAL(p, 4);
- reply->lm20_token = SVAL(p, 6);
+ map_netlogon_samlogon_response(r);
data_blob_free(&os1);
data_blob_free(&os2);
asn1_free(&data);
+ if (reply) {
+ *reply = r;
+ } else {
+ TALLOC_FREE(r);
+ }
+
return 0;
}
do a cldap netlogon query. Always 389/udp
*******************************************************************/
-BOOL ads_cldap_netlogon(const char *server, const char *realm, struct cldap_netlogon_reply *reply)
+bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
+ const char *server,
+ const char *realm,
+ uint32_t nt_version,
+ struct netlogon_samlogon_response **reply)
{
int sock;
int ret;
return False;
}
- ret = send_cldap_netlogon(sock, realm, global_myname(), 6);
+ ret = send_cldap_netlogon(sock, realm, global_myname(), nt_version);
if (ret != 0) {
+ close(sock);
return False;
}
- ret = recv_cldap_netlogon(sock, reply);
+ ret = recv_cldap_netlogon(mem_ctx, sock, nt_version, reply);
close(sock);
if (ret == -1) {
return True;
}
+
+/*******************************************************************
+ do a cldap netlogon query. Always 389/udp
+*******************************************************************/
+
+bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx,
+ const char *server,
+ const char *realm,
+ struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply5)
+{
+ uint32_t nt_version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
+ struct netlogon_samlogon_response *reply = NULL;
+ bool ret;
+
+ ret = ads_cldap_netlogon(mem_ctx, server, realm, nt_version, &reply);
+ if (!ret) {
+ return false;
+ }
+
+ if (reply->ntver != NETLOGON_NT_VERSION_5EX) {
+ DEBUG(0,("ads_cldap_netlogon_5: nt_version mismatch: 0x%08x\n",
+ reply->ntver));
+ return false;
+ }
+
+ *reply5 = reply->nt5_ex;
+
+ return true;
+}