r14709: allways use the unicast socket of the interface, when reply to DGRAM
[sfrench/samba-autobuild/.git] / source4 / nbt_server / dgram / netlogon.c
index e013742f0a929d37580022b96475f1e82fe4fd86..c50c0ba1c0bb2c2c4610ed66d422d067471fe70e 100644 (file)
 */
 
 #include "includes.h"
-#include "dlinklist.h"
 #include "nbt_server/nbt_server.h"
-#include "smbd/service_task.h"
 #include "lib/socket/socket.h"
+#include "lib/ldb/include/ldb.h"
+#include "dsdb/samdb/samdb.h"
+#include "auth/auth.h"
+#include "db_wrap.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
 
 /*
   reply to a GETDC request
  */
 static void nbtd_netlogon_getdc(struct dgram_mailslot_handler *dgmslot, 
+                               struct nbtd_interface *iface,
                                struct nbt_dgram_packet *packet, 
-                               const char *src_address, int src_port,
+                               const struct socket_address *src,
                                struct nbt_netlogon_packet *netlogon)
 {
        struct nbt_name *name = &packet->data.msg.dest_name;
+       struct nbtd_interface *reply_iface = nbtd_find_reply_iface(iface, src->addr, False);
        struct nbt_netlogon_packet reply;
        struct nbt_netlogon_response_from_pdc *pdc;
+       const char *ref_attrs[] = {"nETBIOSName", NULL};
+       struct ldb_message **ref_res;
+       struct ldb_context *samctx;
+       int ret;
 
        /* only answer getdc requests on the PDC or LOGON names */
        if (name->type != NBT_NAME_PDC && name->type != NBT_NAME_LOGON) {
                return;
        }
 
+       samctx = samdb_connect(packet, anonymous_session(packet));
+       if (samctx == NULL) {
+               DEBUG(2,("Unable to open sam in getdc reply\n"));
+               return;
+       }
+
+       ret = gendb_search(samctx, samctx, NULL, &ref_res, ref_attrs,
+                          "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
+                          name->name);
+       
+       if (ret != 1) {
+               DEBUG(2,("Unable to find domain reference '%s' in sam\n", name->name));
+               return;
+       }
+
        /* setup a GETDC reply */
+       ZERO_STRUCT(reply);
        reply.command = NETLOGON_RESPONSE_FROM_PDC;
        pdc = &reply.req.response;
 
        pdc->pdc_name         = lp_netbios_name();
        pdc->unicode_pdc_name = pdc->pdc_name;
-       pdc->domain_name      = lp_workgroup();
+       pdc->domain_name      = samdb_result_string(ref_res[0], "nETBIOSName", name->name);;
        pdc->nt_version       = 1;
        pdc->lmnt_token       = 0xFFFF;
        pdc->lm20_token       = 0xFFFF;
@@ -57,19 +82,136 @@ static void nbtd_netlogon_getdc(struct dgram_mailslot_handler *dgmslot,
 
        packet->data.msg.dest_name.type = 0;
 
-       dgram_mailslot_netlogon_reply(dgmslot->dgmsock, 
+       dgram_mailslot_netlogon_reply(reply_iface->dgmsock, 
                                      packet, 
                                      netlogon->req.pdc.mailslot_name,
                                      &reply);
 }
 
 
+/*
+  reply to a ADS style GETDC request
+ */
+static void nbtd_netlogon_getdc2(struct dgram_mailslot_handler *dgmslot,
+                                struct nbtd_interface *iface,
+                                struct nbt_dgram_packet *packet, 
+                                const struct socket_address *src,
+                                struct nbt_netlogon_packet *netlogon)
+{
+       struct nbt_name *name = &packet->data.msg.dest_name;
+       struct nbtd_interface *reply_iface = nbtd_find_reply_iface(iface, src->addr, False);
+       struct nbt_netlogon_packet reply;
+       struct nbt_netlogon_response_from_pdc2 *pdc;
+       struct ldb_context *samctx;
+       const char *ref_attrs[] = {"nETBIOSName", "ncName", NULL};
+       const char *dom_attrs[] = {"dnsDomain", "objectGUID", NULL};
+       struct ldb_message **ref_res, **dom_res;
+       int ret;
+       const char **services = lp_server_services();
+       const char *my_ip = reply_iface->ip_address; 
+       if (!my_ip) {
+               DEBUG(0, ("Could not obtain own IP address for datagram socket\n"));
+               return;
+       }
+
+       /* only answer getdc requests on the PDC or LOGON names */
+       if (name->type != NBT_NAME_PDC && name->type != NBT_NAME_LOGON) {
+               return;
+       }
+
+       samctx = samdb_connect(packet, anonymous_session(packet));
+       if (samctx == NULL) {
+               DEBUG(2,("Unable to open sam in getdc reply\n"));
+               return;
+       }
+
+       ret = gendb_search(samctx, samctx, NULL, &ref_res, ref_attrs,
+                                 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
+                                 name->name);
+       
+       if (ret != 1) {
+               DEBUG(2,("Unable to find domain reference '%s' in sam\n", name->name));
+               return;
+       }
+
+       /* try and find the domain */
+       ret = gendb_search_dn(samctx, samctx, 
+                             samdb_result_dn(samctx, ref_res[0], "ncName", NULL), 
+                             &dom_res, dom_attrs);
+       if (ret != 1) {
+               DEBUG(2,("Unable to find domain from reference '%s' in sam\n",
+                        ldb_dn_linearize(samctx, ref_res[0]->dn)));
+               return;
+       }
+
+       /* setup a GETDC reply */
+       ZERO_STRUCT(reply);
+       reply.command = NETLOGON_RESPONSE_FROM_PDC2;
+
+#if 0
+       /* newer testing shows that the reply command type is not
+          changed based on whether a username is given in the
+          reply. This was what was causing the w2k join to be so
+          slow */
+       if (netlogon->req.pdc2.user_name[0]) {
+               reply.command = NETLOGON_RESPONSE_FROM_PDC_USER;
+       }
+#endif
+
+       pdc = &reply.req.response2;
+
+       /* TODO: accurately depict which services we are running */
+       pdc->server_type      = 
+               NBT_SERVER_PDC | NBT_SERVER_GC | 
+               NBT_SERVER_DS | NBT_SERVER_TIMESERV |
+               NBT_SERVER_CLOSEST | NBT_SERVER_WRITABLE | 
+               NBT_SERVER_GOOD_TIMESERV;
+
+       /* hmm, probably a better way to do this */
+       if (str_list_check(services, "ldap")) {
+               pdc->server_type |= NBT_SERVER_LDAP;
+       }
+
+       if (str_list_check(services, "kdc")) {
+               pdc->server_type |= NBT_SERVER_KDC;
+       }
+
+       pdc->domain_uuid      = samdb_result_guid(dom_res[0], "objectGUID");
+       pdc->forest           = samdb_result_string(dom_res[0], "dnsDomain", lp_realm());
+       pdc->dns_domain       = samdb_result_string(dom_res[0], "dnsDomain", lp_realm());
+
+       /* TODO: get our full DNS name from somewhere else */
+       pdc->pdc_dns_name     = talloc_asprintf(packet, "%s.%s", 
+                                               strlower_talloc(packet, lp_netbios_name()), 
+                                               pdc->dns_domain);
+       pdc->domain           = samdb_result_string(dom_res[0], "nETBIOSName", name->name);;
+       pdc->pdc_name         = lp_netbios_name();
+       pdc->user_name        = netlogon->req.pdc2.user_name;
+       /* TODO: we need to make sure these are in our DNS zone */
+       pdc->site_name        = "Default-First-Site-Name";
+       pdc->site_name2       = "Default-First-Site-Name";
+       pdc->unknown          = 0x10; /* what is this? */
+       pdc->unknown2         = 2; /* and this ... */
+       pdc->pdc_ip           = my_ip;
+       pdc->nt_version       = 13;
+       pdc->lmnt_token       = 0xFFFF;
+       pdc->lm20_token       = 0xFFFF;
+
+       packet->data.msg.dest_name.type = 0;
+
+       dgram_mailslot_netlogon_reply(reply_iface->dgmsock, 
+                                     packet, 
+                                     netlogon->req.pdc2.mailslot_name,
+                                     &reply);
+}
+
+
 /*
   handle incoming netlogon mailslot requests
 */
 void nbtd_mailslot_netlogon_handler(struct dgram_mailslot_handler *dgmslot, 
                                    struct nbt_dgram_packet *packet, 
-                                   const char *src_address, int src_port)
+                                   struct socket_address *src)
 {
        NTSTATUS status = NT_STATUS_NO_MEMORY;
        struct nbtd_interface *iface = 
@@ -91,19 +233,21 @@ void nbtd_mailslot_netlogon_handler(struct dgram_mailslot_handler *dgmslot,
        }
 
        DEBUG(2,("netlogon request to %s from %s:%d\n", 
-                nbt_name_string(netlogon, name), src_address, src_port));
+                nbt_name_string(netlogon, name), src->addr, src->port));
        status = dgram_mailslot_netlogon_parse(dgmslot, netlogon, packet, netlogon);
        if (!NT_STATUS_IS_OK(status)) goto failed;
 
-       NDR_PRINT_DEBUG(nbt_netlogon_packet, netlogon);
-
        switch (netlogon->command) {
        case NETLOGON_QUERY_FOR_PDC:
-               nbtd_netlogon_getdc(dgmslot, packet, src_address, src_port, netlogon);
+               nbtd_netlogon_getdc(dgmslot, iface, packet, src, netlogon);
+               break;
+       case NETLOGON_QUERY_FOR_PDC2:
+               nbtd_netlogon_getdc2(dgmslot, iface, packet, src, netlogon);
                break;
        default:
                DEBUG(2,("unknown netlogon op %d from %s:%d\n", 
-                        netlogon->command, src_address, src_port));
+                        netlogon->command, src->addr, src->port));
+               NDR_PRINT_DEBUG(nbt_netlogon_packet, netlogon);
                break;
        }
 
@@ -111,7 +255,8 @@ void nbtd_mailslot_netlogon_handler(struct dgram_mailslot_handler *dgmslot,
        return;
 
 failed:
-       DEBUG(2,("nbtd netlogon handler failed from %s:%d - %s\n",
-                src_address, src_port, nt_errstr(status)));
+       DEBUG(2,("nbtd netlogon handler failed from %s:%d to %s - %s\n",
+                src->addr, src->port, nbt_name_string(netlogon, name),
+                nt_errstr(status)));
        talloc_free(netlogon);
 }