summaryrefslogtreecommitdiff
path: root/source3/utils/net_ads_cldap.c
diff options
context:
space:
mode:
authorJim McDonough <jmcd@samba.org>2003-05-20 13:51:43 +0000
committerJim McDonough <jmcd@samba.org>2003-05-20 13:51:43 +0000
commita3c5277a93a13432aaa90c6a5450f2c72c86948f (patch)
treeb00c00e8d6adf264008fd175a982f2ef2e470ce0 /source3/utils/net_ads_cldap.c
parent40c53cae2bd6f104bdd1ffe53a1cb58891824eac (diff)
downloadsamba-a3c5277a93a13432aaa90c6a5450f2c72c86948f.tar.gz
samba-a3c5277a93a13432aaa90c6a5450f2c72c86948f.tar.bz2
samba-a3c5277a93a13432aaa90c6a5450f2c72c86948f.zip
Fix bug #96: Use DNS decompression to properly parse cldap netlogon
packets, otherwise repeated components will not decode correctly. Thanks to aliguori@us.ibm.com for the fix, and lukeh@padl.com for pointing us to the right docs. (This used to be commit a8d5d74cf80c6cae3eac1daa3f88d56373789560)
Diffstat (limited to 'source3/utils/net_ads_cldap.c')
-rw-r--r--source3/utils/net_ads_cldap.c242
1 files changed, 132 insertions, 110 deletions
diff --git a/source3/utils/net_ads_cldap.c b/source3/utils/net_ads_cldap.c
index 86d5abea4b..e74e4b5a4c 100644
--- a/source3/utils/net_ads_cldap.c
+++ b/source3/utils/net_ads_cldap.c
@@ -24,28 +24,28 @@
#ifdef HAVE_ADS
-struct netlogon_string {
- uint32 comp_len;
- char **component;
- uint8 extra_flag;
-};
+#define MAX_DNS_LABEL 255 + 1
struct cldap_netlogon_reply {
uint32 type;
uint32 flags;
GUID guid;
- struct netlogon_string forest;
- struct netlogon_string domain;
- struct netlogon_string hostname;
-
- struct netlogon_string netbios_domain;
- struct netlogon_string netbios_hostname;
+ char forest[MAX_DNS_LABEL];
+ char unk0[MAX_DNS_LABEL];
+ char domain[MAX_DNS_LABEL];
+ char hostname[MAX_DNS_LABEL];
- struct netlogon_string user_name;
- struct netlogon_string site_name;
+ char netbios_domain[MAX_DNS_LABEL];
+ char unk1[MAX_DNS_LABEL];
+ char netbios_hostname[MAX_DNS_LABEL];
- struct netlogon_string unk0;
+ char unk2[MAX_DNS_LABEL];
+ char user_name[MAX_DNS_LABEL];
+ char unk3[MAX_DNS_LABEL];
+ char site_name[MAX_DNS_LABEL];
+ char unk4[MAX_DNS_LABEL];
+ char site_name_2[MAX_DNS_LABEL];
uint32 version;
uint16 lmnt_token;
@@ -53,38 +53,69 @@ struct cldap_netlogon_reply {
};
/*
- These strings are rather interesting... They are composed of a series of
- length encoded strings, terminated by either 1) a zero length string or 2)
- a 0xc0 byte with what appears to be a one byte flags immediately following.
+ 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(struct netlogon_string *ret,const char *d)
+static unsigned pull_netlogon_string(char *ret, const char *ptr,
+ const char *data)
{
- const char *p = (const char *)d;
-
- ZERO_STRUCTP(ret);
+ char *pret = ret;
+ int followed_ptr = 0;
+ unsigned ret_len = 0;
+ memset(pret, 0, MAX_DNS_LABEL);
do {
- unsigned len = (unsigned char)*p;
- p++;
-
- if (len > 0 && len != 0xc0) {
- ret->component = realloc(ret->component,
- ++ret->comp_len *
- sizeof(char *));
-
- ret->component[ret->comp_len - 1] =
- smb_xstrndup(p, len);
- p += len;
- } else {
- if (len == 0xc0) {
- ret->extra_flag = *p;
- p++;
- };
- break;
+ 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) {
+ d_printf("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 (1);
+ } while (*ptr);
- return (p - d);
+ return ret_len ? ret_len : 1;
}
/*
@@ -95,7 +126,11 @@ static int send_cldap_netlogon(int sock, const char *domain,
{
ASN1_DATA data;
char ntver[4];
+#ifdef CLDAP_USER_QUERY
+ char aac[4];
+ SIVAL(aac, 0, 0x00000180);
+#endif
SIVAL(ntver, 0, ntversion);
memset(&data, 0, sizeof(data));
@@ -121,6 +156,18 @@ static int send_cldap_netlogon(int sock, const char *domain,
asn1_write_OctetString(&data, hostname, strlen(hostname));
asn1_pop_tag(&data);
+#ifdef CLDAP_USER_QUERY
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "User", 4);
+ asn1_write_OctetString(&data, "SAMBA$", 6);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, "AAC", 4);
+ asn1_write_OctetString(&data, aac, 4);
+ asn1_pop_tag(&data);
+#endif
+
asn1_push_tag(&data, ASN1_CONTEXT(3));
asn1_write_OctetString(&data, "NtVer", 5);
asn1_write_OctetString(&data, ntver, 4);
@@ -144,7 +191,6 @@ static int send_cldap_netlogon(int sock, const char *domain,
d_printf("failed to send cldap query (%s)\n", strerror(errno));
}
- file_save("cldap_query.dat", data.data, data.length);
asn1_free(&data);
return 0;
@@ -173,8 +219,6 @@ static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
}
blob.length = ret;
- file_save("cldap_reply.dat", blob.data, blob.length);
-
asn1_load(&data, blob);
asn1_start_tag(&data, ASN1_SEQUENCE(0));
asn1_read_Integer(&data, &i1);
@@ -196,8 +240,6 @@ static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
return -1;
}
- file_save("cldap_reply_core.dat", os3.data, os3.length);
-
p = os3.data;
reply->type = IVAL(p, 0); p += 4;
@@ -206,15 +248,25 @@ static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
memcpy(&reply->guid.info, p, GUID_SIZE);
p += GUID_SIZE;
- p += pull_netlogon_string(&reply->forest, p);
- p += pull_netlogon_string(&reply->domain, p);
- p += pull_netlogon_string(&reply->hostname, p);
- p += pull_netlogon_string(&reply->netbios_domain, p);
- p += pull_netlogon_string(&reply->netbios_hostname, p);
- p += pull_netlogon_string(&reply->user_name, p);
- p += pull_netlogon_string(&reply->site_name, p);
+ p += pull_netlogon_string(reply->forest, p, os3.data);
+ p += pull_netlogon_string(reply->unk0, p, os3.data);
+ p += pull_netlogon_string(reply->domain, p, os3.data);
+ p += pull_netlogon_string(reply->hostname, p, os3.data);
+ p += pull_netlogon_string(reply->netbios_domain, p, os3.data);
+ p += pull_netlogon_string(reply->unk1, p, os3.data);
+ p += pull_netlogon_string(reply->netbios_hostname, p, os3.data);
+ p += pull_netlogon_string(reply->unk2, p, os3.data);
+
+ if (reply->type == SAMLOGON_AD_R) {
+ p += pull_netlogon_string(reply->user_name, p, os3.data);
+ } else {
+ *reply->user_name = 0;
+ }
- p += pull_netlogon_string(&reply->unk0, p);
+ p += pull_netlogon_string(reply->unk3, p, os3.data);
+ p += pull_netlogon_string(reply->site_name, p, os3.data);
+ p += pull_netlogon_string(reply->unk4, p, os3.data);
+ p += pull_netlogon_string(reply->site_name_2, p, os3.data);
reply->version = IVAL(p, 0);
reply->lmnt_token = SVAL(p, 4);
@@ -229,52 +281,6 @@ static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
}
/*
- free a netlogon string
-*/
-static void netlogon_string_free(struct netlogon_string *str)
-{
- unsigned int i;
-
- for (i = 0; i < str->comp_len; ++i) {
- SAFE_FREE(str->component[i]);
- }
- SAFE_FREE(str->component);
-}
-
-/*
- free a cldap reply packet
-*/
-static void cldap_reply_free(struct cldap_netlogon_reply *reply)
-{
- netlogon_string_free(&reply->forest);
- netlogon_string_free(&reply->domain);
- netlogon_string_free(&reply->hostname);
- netlogon_string_free(&reply->netbios_domain);
- netlogon_string_free(&reply->netbios_hostname);
- netlogon_string_free(&reply->user_name);
- netlogon_string_free(&reply->site_name);
- netlogon_string_free(&reply->unk0);
-}
-
-static void d_print_netlogon_string(const char *label,
- struct netlogon_string *str)
-{
- unsigned int i;
-
- if (str->comp_len) {
- d_printf("%s", label);
- if (str->extra_flag) {
- d_printf("[%d]", str->extra_flag);
- }
- d_printf(": ");
- for (i = 0; i < str->comp_len; ++i) {
- d_printf("%s%s", (i ? "." : ""), str->component[i]);
- }
- d_printf("\n");
- }
-}
-
-/*
do a cldap netlogon query
*/
int ads_cldap_netlogon(ADS_STRUCT *ads)
@@ -289,6 +295,7 @@ int ads_cldap_netlogon(ADS_STRUCT *ads)
inet_ntoa(ads->ldap_ip),
ads->ldap_port);
return -1;
+
}
ret = send_cldap_netlogon(sock, ads->config.realm, global_myname(), 6);
@@ -305,7 +312,18 @@ int ads_cldap_netlogon(ADS_STRUCT *ads)
d_printf("Information for Domain Controller: %s\n\n",
ads->config.ldap_server_name);
- d_printf("Response Type: 0x%x\n", reply.type);
+ d_printf("Response Type: ");
+ switch (reply.type) {
+ case SAMLOGON_AD_UNK_R:
+ d_printf("SAMLOGON\n");
+ break;
+ case SAMLOGON_AD_R:
+ d_printf("SAMLOGON_USER\n");
+ break;
+ default:
+ d_printf("0x%x\n", reply.type);
+ break;
+ }
d_printf("GUID: ");
print_guid(&reply.guid);
d_printf("Flags:\n"
@@ -330,23 +348,27 @@ int ads_cldap_netlogon(ADS_STRUCT *ads)
(reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
(reply.flags & ADS_NDNC) ? "yes" : "no");
- d_print_netlogon_string("Forest", &reply.forest);
- d_print_netlogon_string("Domain", &reply.domain);
- d_print_netlogon_string("Hostname", &reply.hostname);
+ printf("Forest:\t\t\t%s\n", reply.forest);
+ if (*reply.unk0) printf("Unk0:\t\t\t%s\n", reply.unk0);
+ printf("Domain:\t\t\t%s\n", reply.domain);
+ printf("Domain Controller:\t%s\n", reply.hostname);
- d_print_netlogon_string("Pre-Win2k Domain", &reply.netbios_domain);
- d_print_netlogon_string("Pre-Win2k Hostname", &reply.netbios_hostname);
+ printf("Pre-Win2k Domain:\t%s\n", reply.netbios_domain);
+ if (*reply.unk1) printf("Unk1:\t\t\t%s\n", reply.unk1);
+ printf("Pre-Win2k Hostname:\t%s\n", reply.netbios_hostname);
- d_print_netlogon_string("User name", &reply.user_name);
- d_print_netlogon_string("Site Name", &reply.site_name);
- d_print_netlogon_string("Unknown Field", &reply.unk0);
+ if (*reply.unk2) printf("Unk2:\t\t\t%s\n", reply.unk2);
+ if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
+
+ if (*reply.unk3) printf("Unk3:\t\t\t%s\n", reply.unk3);
+ printf("Site Name:\t\t%s\n", reply.site_name);
+ if (*reply.unk4) printf("Unk4:\t\t\t%s\n", reply.unk4);
+ printf("Site Name (2):\t\t%s\n", reply.site_name_2);
d_printf("NT Version: %d\n", reply.version);
d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
d_printf("LM20 Token: %.2x\n", reply.lm20_token);
- cldap_reply_free(&reply);
-
return ret;
}