summaryrefslogtreecommitdiff
path: root/source3/libads/cldap.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libads/cldap.c')
-rw-r--r--source3/libads/cldap.c303
1 files changed, 237 insertions, 66 deletions
diff --git a/source3/libads/cldap.c b/source3/libads/cldap.c
index 5cefd6ccc1..ae087d976c 100644
--- a/source3/libads/cldap.c
+++ b/source3/libads/cldap.c
@@ -4,7 +4,6 @@
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)
- Copyright (C) 2009 Stefan Metzmacher (metze@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
@@ -21,8 +20,226 @@
*/
#include "includes.h"
-#include "../libcli/cldap/cldap.h"
-#include "../lib/tsocket/tsocket.h"
+
+/*
+ do a cldap netlogon query
+*/
+static int send_cldap_netlogon(TALLOC_CTX *mem_ctx, int sock, const char *domain,
+ const char *hostname, unsigned ntversion)
+{
+ ASN1_DATA *data;
+ char ntver[4];
+#ifdef CLDAP_USER_QUERY
+ char aac[4];
+
+ SIVAL(aac, 0, 0x00000180);
+#endif
+ SIVAL(ntver, 0, ntversion);
+
+ data = asn1_init(mem_ctx);
+ if (data == NULL) {
+ return -1;
+ }
+
+ asn1_push_tag(data,ASN1_SEQUENCE(0));
+ asn1_write_Integer(data, 4);
+ asn1_push_tag(data, ASN1_APPLICATION(3));
+ asn1_write_OctetString(data, NULL, 0);
+ asn1_write_enumerated(data, 0);
+ asn1_write_enumerated(data, 0);
+ asn1_write_Integer(data, 0);
+ asn1_write_Integer(data, 0);
+ asn1_write_BOOLEAN(data, False);
+ asn1_push_tag(data, ASN1_CONTEXT(0));
+
+ if (domain) {
+ asn1_push_tag(data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(data, "DnsDomain", 9);
+ asn1_write_OctetString(data, domain, strlen(domain));
+ asn1_pop_tag(data);
+ }
+
+ asn1_push_tag(data, ASN1_CONTEXT(3));
+ asn1_write_OctetString(data, "Host", 4);
+ 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);
+ asn1_pop_tag(data);
+
+ asn1_pop_tag(data);
+
+ asn1_push_tag(data,ASN1_SEQUENCE(0));
+ asn1_write_OctetString(data, "NetLogon", 8);
+ asn1_pop_tag(data);
+ asn1_pop_tag(data);
+ asn1_pop_tag(data);
+
+ if (data->has_error) {
+ DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data->ofs));
+ asn1_free(data);
+ return -1;
+ }
+
+ 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);
+
+ return 0;
+}
+
+/*
+ receive a cldap netlogon 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_null;
+ DATA_BLOB os1 = data_blob_null;
+ DATA_BLOB os2 = data_blob_null;
+ DATA_BLOB os3 = data_blob_null;
+ int i1;
+ struct netlogon_samlogon_response *r = NULL;
+ NTSTATUS status;
+
+ fd_set r_fds;
+ struct timeval timeout;
+
+ blob = data_blob(NULL, 8192);
+ if (blob.data == NULL) {
+ DEBUG(1, ("data_blob failed\n"));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ FD_ZERO(&r_fds);
+ FD_SET(sock, &r_fds);
+
+ /*
+ * half the time of a regular ldap timeout, not less than 3 seconds.
+ */
+ timeout.tv_sec = MAX(3,lp_ldap_timeout()/2);
+ timeout.tv_usec = 0;
+
+ ret = sys_select(sock+1, &r_fds, NULL, NULL, &timeout);
+ if (ret == -1) {
+ DEBUG(10, ("select failed: %s\n", strerror(errno)));
+ data_blob_free(&blob);
+ return -1;
+ }
+
+ if (ret == 0) {
+ DEBUG(1,("no reply received to cldap netlogon "
+ "(select timeout %u sec)\n",
+ (unsigned int)timeout.tv_sec));
+ data_blob_free(&blob);
+ return -1;
+ }
+
+ ret = read(sock, blob.data, blob.length);
+ if (ret <= 0) {
+ DEBUG(1,("no reply received to cldap netlogon "
+ "(ret = %d: Error = %s)\n",
+ ret,
+ ret == -1 ? strerror(errno) : "" ));
+ data_blob_free(&blob);
+ return -1;
+ }
+ blob.length = ret;
+
+ data = asn1_init(mem_ctx);
+ if (data == NULL) {
+ data_blob_free(&blob);
+ return -1;
+ }
+
+ asn1_load(data, blob);
+ asn1_start_tag(data, ASN1_SEQUENCE(0));
+ asn1_read_Integer(data, &i1);
+ asn1_start_tag(data, ASN1_APPLICATION(4));
+ asn1_read_OctetString(data, NULL, &os1);
+ asn1_start_tag(data, ASN1_SEQUENCE(0));
+ asn1_start_tag(data, ASN1_SEQUENCE(0));
+ asn1_read_OctetString(data, NULL, &os2);
+ asn1_start_tag(data, ASN1_SET);
+ asn1_read_OctetString(data, NULL, &os3);
+ asn1_end_tag(data);
+ asn1_end_tag(data);
+ asn1_end_tag(data);
+ asn1_end_tag(data);
+ asn1_end_tag(data);
+
+ 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;
+ }
+
+ 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);
+ asn1_free(data);
+ return -1;
+ }
+
+ 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);
+ asn1_free(data);
+ TALLOC_FREE(r);
+ return -1;
+ }
+
+ map_netlogon_samlogon_response(r);
+
+ data_blob_free(&os1);
+ data_blob_free(&os2);
+ data_blob_free(&os3);
+ data_blob_free(&blob);
+
+ asn1_free(data);
+
+ if (reply) {
+ *reply = r;
+ } else {
+ TALLOC_FREE(r);
+ }
+
+ return 0;
+}
/*******************************************************************
do a cldap netlogon query. Always 389/udp
@@ -32,79 +249,33 @@ bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
const char *server,
const char *realm,
uint32_t nt_version,
- struct netlogon_samlogon_response **_reply)
+ struct netlogon_samlogon_response **reply)
{
- struct cldap_socket *cldap;
- struct cldap_netlogon io;
- struct netlogon_samlogon_response *reply;
- NTSTATUS status;
- struct sockaddr_storage ss;
- char addrstr[INET6_ADDRSTRLEN];
- const char *dest_str;
+ int sock;
int ret;
- struct tsocket_address *dest_addr;
- if (!interpret_string_addr_prefer_ipv4(&ss, server, 0)) {
- DEBUG(2,("Failed to resolve[%s] into an address for cldap\n",
- server));
- return false;
+ sock = open_udp_socket(server, LDAP_PORT );
+ if (sock == -1) {
+ DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s. "
+ "Error %s\n",
+ server,
+ strerror(errno) ));
+ return False;
}
- dest_str = print_sockaddr(addrstr, sizeof(addrstr), &ss);
- ret = tsocket_address_inet_from_strings(mem_ctx, "ip",
- dest_str, LDAP_PORT,
- &dest_addr);
+ ret = send_cldap_netlogon(mem_ctx, sock, realm, global_myname(), nt_version);
if (ret != 0) {
- status = map_nt_error_from_unix(errno);
- DEBUG(2,("Failed to create cldap tsocket_address for %s - %s\n",
- dest_str, nt_errstr(status)));
- return false;
- }
-
- /*
- * as we use a connected udp socket
- */
- status = cldap_socket_init(mem_ctx, NULL, NULL, dest_addr, &cldap);
- TALLOC_FREE(dest_addr);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(2,("Failed to create cldap socket to %s: %s\n",
- dest_str, nt_errstr(status)));
- return false;
+ close(sock);
+ return False;
}
+ ret = recv_cldap_netlogon(mem_ctx, sock, nt_version, reply);
+ close(sock);
- reply = talloc(cldap, struct netlogon_samlogon_response);
- if (!reply) {
- goto failed;
+ if (ret == -1) {
+ return False;
}
- /*
- * as we use a connected socket, so we don't need to specify the
- * destination
- */
- io.in.dest_address = NULL;
- io.in.dest_port = 0;
- io.in.realm = realm;
- io.in.host = NULL;
- io.in.user = NULL;
- io.in.domain_guid = NULL;
- io.in.domain_sid = NULL;
- io.in.acct_control = 0;
- io.in.version = nt_version;
- io.in.map_response = false;
-
- status = cldap_netlogon(cldap, NULL, reply, &io);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(2,("cldap_netlogon() failed: %s\n", nt_errstr(status)));
- goto failed;
- }
-
- *reply = io.out.netlogon;
- *_reply = talloc_move(mem_ctx, &reply);
- TALLOC_FREE(cldap);
- return true;
-failed:
- TALLOC_FREE(cldap);
- return false;
+ return True;
}
/*******************************************************************