s3: Remove use of iconv_convenience.
[samba.git] / source3 / nmbd / nmbd_processlogon.c
index 8a183c4d24a1b72c61c848fdda6cd96562db2f33..d591f7062cb9f1360ae735ca24e5f71f1dc9395b 100644 (file)
@@ -24,6 +24,9 @@
 */
 
 #include "includes.h"
+#include "../libcli/netlogon.h"
+#include "../libcli/cldap/cldap.h"
+#include "../lib/tsocket/tsocket.h"
 
 struct sam_database_info {
         uint32 index;
@@ -31,6 +34,269 @@ struct sam_database_info {
         uint32 date_lo, date_hi;
 };
 
+/**
+ * check whether the client belongs to the hosts
+ * for which initial logon should be delayed...
+ */
+static bool delay_logon(const char *peer_name, const char *peer_addr)
+{
+       const char **delay_list = lp_init_logon_delayed_hosts();
+       const char *peer[2];
+
+       if (delay_list == NULL) {
+               return False;
+       }
+
+       peer[0] = peer_name;
+       peer[1] = peer_addr;
+
+       return list_match(delay_list, (const char *)peer, client_match);
+}
+
+static void delayed_init_logon_handler(struct event_context *event_ctx,
+                                      struct timed_event *te,
+                                      struct timeval now,
+                                      void *private_data)
+{
+       struct packet_struct *p = (struct packet_struct *)private_data;
+
+       DEBUG(10, ("delayed_init_logon_handler (%lx): re-queuing packet.\n",
+                  (unsigned long)te));
+
+       queue_packet(p);
+
+       TALLOC_FREE(te);
+}
+
+struct nmbd_proxy_logon_context {
+       struct cldap_socket *cldap_sock;
+};
+
+static struct nmbd_proxy_logon_context *global_nmbd_proxy_logon;
+
+bool initialize_nmbd_proxy_logon(void)
+{
+       const char *cldap_server = lp_parm_const_string(-1, "nmbd_proxy_logon",
+                                                       "cldap_server", NULL);
+       struct nmbd_proxy_logon_context *ctx;
+       NTSTATUS status;
+       struct in_addr addr;
+       char addrstr[INET_ADDRSTRLEN];
+       const char *server_str;
+       int ret;
+       struct tsocket_address *server_addr;
+
+       if (!cldap_server) {
+               return true;
+       }
+
+       addr = interpret_addr2(cldap_server);
+       server_str = inet_ntop(AF_INET, &addr,
+                            addrstr, sizeof(addrstr));
+       if (!server_str || strcmp("0.0.0.0", server_str) == 0) {
+               DEBUG(0,("Failed to resolve[%s] for nmbd_proxy_logon\n",
+                        cldap_server));
+               return false;
+       }
+
+       ctx = talloc_zero(nmbd_event_context(),
+                         struct nmbd_proxy_logon_context);
+       if (!ctx) {
+               return false;
+       }
+
+       ret = tsocket_address_inet_from_strings(ctx, "ipv4",
+                                               server_str, LDAP_PORT,
+                                               &server_addr);
+       if (ret != 0) {
+               TALLOC_FREE(ctx);
+               status = map_nt_error_from_unix(errno);
+               DEBUG(0,("Failed to create cldap tsocket_address for %s - %s\n",
+                        server_str, nt_errstr(status)));
+               return false;
+       }
+
+       /* we create a connected udp socket */
+       status = cldap_socket_init(ctx, nmbd_event_context(), NULL,
+                                  server_addr, &ctx->cldap_sock);
+       TALLOC_FREE(server_addr);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(ctx);
+               DEBUG(0,("failed to create cldap socket for %s: %s\n",
+                       server_str, nt_errstr(status)));
+               return false;
+       }
+
+       global_nmbd_proxy_logon = ctx;
+       return true;
+}
+
+struct nmbd_proxy_logon_state {
+       struct in_addr local_ip;
+       struct packet_struct *p;
+       const char *remote_name;
+       uint8_t remote_name_type;
+       const char *remote_mailslot;
+       struct nbt_netlogon_packet req;
+       struct nbt_netlogon_response resp;
+       struct cldap_netlogon io;
+};
+
+static int nmbd_proxy_logon_state_destructor(struct nmbd_proxy_logon_state *s)
+{
+       s->p->locked = false;
+       free_packet(s->p);
+       return 0;
+}
+
+static void nmbd_proxy_logon_done(struct tevent_req *subreq);
+
+static void nmbd_proxy_logon(struct nmbd_proxy_logon_context *ctx,
+                            struct in_addr local_ip,
+                            struct packet_struct *p,
+                            uint8_t *buf,
+                            uint32_t len)
+{
+       struct nmbd_proxy_logon_state *state;
+       enum ndr_err_code ndr_err;
+       DATA_BLOB blob = data_blob_const(buf, len);
+       const char *computer_name = NULL;
+       const char *mailslot_name = NULL;
+       const char *user_name = NULL;
+       const char *domain_sid = NULL;
+       uint32_t acct_control = 0;
+       uint32_t nt_version = 0;
+       struct tevent_req *subreq;
+       fstring source_name;
+       struct dgram_packet *dgram = &p->packet.dgram;
+
+       state = TALLOC_ZERO_P(ctx, struct nmbd_proxy_logon_state);
+       if (!state) {
+               DEBUG(0,("failed to allocate nmbd_proxy_logon_state\n"));
+               return;
+       }
+
+       pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);
+       state->remote_name = talloc_strdup(state, source_name);
+       state->remote_name_type = dgram->source_name.name_type,
+       state->local_ip = local_ip;
+       state->p = p;
+
+       ndr_err = ndr_pull_struct_blob(
+               &blob, state, &state->req,
+               (ndr_pull_flags_fn_t)ndr_pull_nbt_netlogon_packet);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+               DEBUG(0,("failed parse nbt_netlogon_packet: %s\n",
+                       nt_errstr(status)));
+               TALLOC_FREE(state);
+               return;
+       }
+
+       if (DEBUGLEVEL >= 10) {
+               DEBUG(10, ("nmbd_proxy_logon:\n"));
+               NDR_PRINT_DEBUG(nbt_netlogon_packet, &state->req);
+       }
+
+       switch (state->req.command) {
+       case LOGON_SAM_LOGON_REQUEST:
+               computer_name   = state->req.req.logon.computer_name;
+               user_name       = state->req.req.logon.user_name;
+               mailslot_name   = state->req.req.logon.mailslot_name;
+               acct_control    = state->req.req.logon.acct_control;
+               if (state->req.req.logon.sid_size > 0) {
+                       domain_sid = dom_sid_string(state,
+                                                   &state->req.req.logon.sid);
+                       if (!domain_sid) {
+                               DEBUG(0,("failed to get a string for sid\n"));
+                               TALLOC_FREE(state);
+                               return;
+                       }
+               }
+               nt_version      = state->req.req.logon.nt_version;
+               break;
+
+       default:
+               /* this can't happen as the caller already checks the command */
+               break;
+       }
+
+       state->remote_mailslot = mailslot_name;
+
+       if (user_name && strlen(user_name) == 0) {
+               user_name = NULL;
+       }
+
+       if (computer_name && strlen(computer_name) == 0) {
+               computer_name = NULL;
+       }
+
+       /*
+        * as the socket is connected,
+        * we don't need to specify the destination
+        */
+       state->io.in.dest_address       = NULL;
+       state->io.in.dest_port          = 0;
+       state->io.in.realm              = NULL;
+       state->io.in.host               = computer_name;
+       state->io.in.user               = user_name;
+       state->io.in.domain_guid        = NULL;
+       state->io.in.domain_sid         = domain_sid;
+       state->io.in.acct_control       = acct_control;
+       state->io.in.version            = nt_version;
+       state->io.in.map_response       = false;
+
+       subreq = cldap_netlogon_send(state,
+                                    ctx->cldap_sock,
+                                    &state->io);
+       if (!subreq) {
+               DEBUG(0,("failed to send cldap netlogon call\n"));
+               TALLOC_FREE(state);
+               return;
+       }
+       tevent_req_set_callback(subreq, nmbd_proxy_logon_done, state);
+
+       /* we reply async */
+       state->p->locked = true;
+       talloc_set_destructor(state, nmbd_proxy_logon_state_destructor);
+}
+
+static void nmbd_proxy_logon_done(struct tevent_req *subreq)
+{
+       struct nmbd_proxy_logon_state *state =
+               tevent_req_callback_data(subreq,
+               struct nmbd_proxy_logon_state);
+       NTSTATUS status;
+       DATA_BLOB response = data_blob_null;
+
+       status = cldap_netlogon_recv(subreq, state, &state->io);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("failed to recv cldap netlogon call: %s\n",
+                       nt_errstr(status)));
+               TALLOC_FREE(state);
+               return;
+       }
+
+       status = push_netlogon_samlogon_response(&response, state, 
+                                                &state->io.out.netlogon);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("failed to push netlogon_samlogon_response: %s\n",
+                       nt_errstr(status)));
+               TALLOC_FREE(state);
+               return;
+       }
+
+       send_mailslot(true, state->remote_mailslot,
+                     (char *)response.data, response.length,
+                     global_myname(), 0x0,
+                     state->remote_name,
+                     state->remote_name_type,
+                     state->p->ip,
+                     state->local_ip,
+                     state->p->port);
+       TALLOC_FREE(state);
+}
+
 /****************************************************************************
 Process a domain logon packet
 **************************************************************************/
@@ -39,20 +305,34 @@ void process_logon_packet(struct packet_struct *p, char *buf,int len,
                           const char *mailslot)
 {
        struct dgram_packet *dgram = &p->packet.dgram;
-       pstring my_name;
+       fstring my_name;
        fstring reply_name;
-       pstring outbuf;
+       char outbuf[1024];
        int code;
        uint16 token = 0;
        uint32 ntversion = 0;
        uint16 lmnttoken = 0;
        uint16 lm20token = 0;
        uint32 domainsidsize;
-       BOOL short_request = False;
+       bool short_request = False;
        char *getdc;
        char *uniuser; /* Unicode user name. */
-       pstring ascuser;
+       fstring ascuser;
        char *unicomp; /* Unicode computer name. */
+       size_t size;
+       struct sockaddr_storage ss;
+       const struct sockaddr_storage *pss;
+       struct in_addr ip;
+
+       in_addr_to_sockaddr_storage(&ss, p->ip);
+       pss = iface_ip((struct sockaddr *)&ss);
+       if (!pss) {
+               DEBUG(5,("process_logon_packet:can't find outgoing interface "
+                       "for packet from IP %s\n",
+                       inet_ntoa(p->ip) ));
+               return;
+       }
+       ip = ((struct sockaddr_in *)pss)->sin_addr;
 
        memset(outbuf, 0, sizeof(outbuf));
 
@@ -62,7 +342,7 @@ logons are not enabled.\n", inet_ntoa(p->ip) ));
                return;
        }
 
-       pstrcpy(my_name, global_myname());
+       fstrcpy(my_name, global_myname());
 
        code = get_safe_SVAL(buf,len,buf,0,-1);
        DEBUG(4,("process_logon_packet: Logon from %s: code = 0x%x\n", inet_ntoa(p->ip), code));
@@ -93,7 +373,7 @@ logons are not enabled.\n", inet_ntoa(p->ip) ));
                                }
                                token = SVAL(q,3);
 
-                               fstrcpy(reply_name,my_name); 
+                               fstrcpy(reply_name,my_name);
 
                                pull_ascii_fstring(mach_str, machine);
                                pull_ascii_fstring(user_str, user);
@@ -108,9 +388,12 @@ logons are not enabled.\n", inet_ntoa(p->ip) ));
 
                                fstrcpy(reply_name, "\\\\");
                                fstrcat(reply_name, my_name);
-                               push_ascii(q,reply_name,
+                               size = push_ascii(q,reply_name,
                                                sizeof(outbuf)-PTR_DIFF(q, outbuf),
                                                STR_TERMINATE);
+                               if (size == (size_t)-1) {
+                                       return;
+                               }
                                q = skip_string(outbuf,sizeof(outbuf),q); /* PDC name */
 
                                SSVAL(q, 0, token);
@@ -123,11 +406,11 @@ logons are not enabled.\n", inet_ntoa(p->ip) ));
                                                global_myname(), 0x0,
                                                mach_str,
                                                dgram->source_name.name_type,
-                                               p->ip, *iface_ip(p->ip), p->port);  
+                                               p->ip, ip, p->port);
                                break;
                        }
 
-               case QUERYFORPDC:
+               case LOGON_PRIMARY_QUERY:
                        {
                                fstring mach_str, getdc_str;
                                fstring source_name;
@@ -202,13 +485,16 @@ logons are not enabled.\n", inet_ntoa(p->ip) ));
 
                                /* Construct reply. */
                                q = outbuf;
-                               SSVAL(q, 0, QUERYFORPDC_R);
+                               SSVAL(q, 0, NETLOGON_RESPONSE_FROM_PDC);
                                q += 2;
 
                                fstrcpy(reply_name,my_name);
-                               push_ascii(q, reply_name,
+                               size = push_ascii(q, reply_name,
                                                sizeof(outbuf)-PTR_DIFF(q, outbuf),
                                                STR_TERMINATE);
+                               if (size == (size_t)-1) {
+                                       return;
+                               }
                                q = skip_string(outbuf,sizeof(outbuf),q); /* PDC name */
 
                                /* PDC and domain name */
@@ -217,12 +503,12 @@ logons are not enabled.\n", inet_ntoa(p->ip) ));
                                        q = ALIGN2(q, outbuf);
 
                                        q += dos_PutUniCode(q, my_name,
-                                               sizeof(pstring) - PTR_DIFF(q, outbuf),
+                                               sizeof(outbuf) - PTR_DIFF(q, outbuf),
                                                True); /* PDC name */
                                        q += dos_PutUniCode(q, lp_workgroup(),
-                                               sizeof(pstring) - PTR_DIFF(q, outbuf),
+                                               sizeof(outbuf) - PTR_DIFF(q, outbuf),
                                                True); /* Domain name*/
-                                       if (sizeof(pstring) - PTR_DIFF(q, outbuf) < 8) {
+                                       if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 8) {
                                                return;
                                        }
                                        SIVAL(q, 0, 1); /* our nt version */
@@ -238,7 +524,7 @@ logons are not enabled.\n", inet_ntoa(p->ip) ));
                                DEBUG(5,("process_logon_packet: GETDC request from %s at IP %s, \
 reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                        mach_str,inet_ntoa(p->ip), reply_name, lp_workgroup(),
-                                       QUERYFORPDC_R, (uint32)ntversion, (uint32)lmnttoken,
+                                       NETLOGON_RESPONSE_FROM_PDC, (uint32)ntversion, (uint32)lmnttoken,
                                        (uint32)lm20token ));
 
                                dump_data(4, (uint8 *)outbuf, PTR_DIFF(q, outbuf));
@@ -251,18 +537,25 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                        global_myname(), 0x0,
                                        source_name,
                                        dgram->source_name.name_type,
-                                       p->ip, *iface_ip(p->ip), p->port);  
+                                       p->ip, ip, p->port);
                                return;
                        }
 
-               case SAMLOGON:
+               case LOGON_SAM_LOGON_REQUEST:
 
                        {
                                fstring getdc_str;
                                fstring source_name;
+                               char *source_addr;
                                char *q = buf + 2;
                                fstring asccomp;
 
+                               if (global_nmbd_proxy_logon) {
+                                       nmbd_proxy_logon(global_nmbd_proxy_logon,
+                                                        ip, p, (uint8_t *)buf, len);
+                                       return;
+                               }
+
                                q += 2;
 
                                if (PTR_DIFF(q, buf) >= len) {
@@ -296,7 +589,7 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                domainsidsize = IVAL(q, 0);
                                q += 4;
 
-                               DEBUG(5,("process_logon_packet: SAMLOGON sidsize %d, len = %d\n", domainsidsize, len));
+                               DEBUG(5,("process_logon_packet: LOGON_SAM_LOGON_REQUEST sidsize %d, len = %d\n", domainsidsize, len));
 
                                if (domainsidsize < (len - PTR_DIFF(q, buf)) && (domainsidsize != 0)) {
                                        q += domainsidsize;
@@ -328,23 +621,23 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                lm20token = SVAL(q, 6);
                                q += 8;
 
-                               DEBUG(3,("process_logon_packet: SAMLOGON sidsize %d ntv %d\n", domainsidsize, ntversion));
+                               DEBUG(3,("process_logon_packet: LOGON_SAM_LOGON_REQUEST sidsize %d ntv %d\n", domainsidsize, ntversion));
 
                                /*
                                 * we respond regadless of whether the machine is in our password 
                                 * database. If it isn't then we let smbd send an appropriate error.
                                 * Let's ignore the SID.
                                 */
-                               pull_ucs2_pstring(ascuser, uniuser);
+                               pull_ucs2_fstring(ascuser, uniuser);
                                pull_ucs2_fstring(asccomp, unicomp);
-                               DEBUG(5,("process_logon_packet: SAMLOGON user %s\n", ascuser));
+                               DEBUG(5,("process_logon_packet: LOGON_SAM_LOGON_REQUEST user %s\n", ascuser));
 
                                fstrcpy(reply_name, "\\\\"); /* Here it wants \\LOGONSERVER. */
                                fstrcat(reply_name, my_name);
 
-                               DEBUG(5,("process_logon_packet: SAMLOGON request from %s(%s) for %s, returning logon svr %s domain %s code %x token=%x\n",
+                               DEBUG(5,("process_logon_packet: LOGON_SAM_LOGON_REQUEST request from %s(%s) for %s, returning logon svr %s domain %s code %x token=%x\n",
                                        asccomp,inet_ntoa(p->ip), ascuser, reply_name, lp_workgroup(),
-                               SAMLOGON_R ,lmnttoken));
+                               LOGON_SAM_LOGON_RESPONSE ,lmnttoken));
 
                                /* Construct reply. */
 
@@ -353,49 +646,59 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                /* never, at least for now */
                                if ((ntversion < 11) || (SEC_ADS != lp_security()) || (ROLE_DOMAIN_PDC != lp_server_role())) {
                                        if (SVAL(uniuser, 0) == 0) {
-                                               SSVAL(q, 0, SAMLOGON_UNK_R);    /* user unknown */
+                                               SSVAL(q, 0, LOGON_SAM_LOGON_USER_UNKNOWN);      /* user unknown */
                                        } else {
-                                               SSVAL(q, 0, SAMLOGON_R);
+                                               SSVAL(q, 0, LOGON_SAM_LOGON_RESPONSE);
                                        }
 
                                        q += 2;
 
                                        q += dos_PutUniCode(q, reply_name,
-                                               sizeof(pstring) - PTR_DIFF(q, outbuf),
+                                               sizeof(outbuf) - PTR_DIFF(q, outbuf),
                                                True);
                                        q += dos_PutUniCode(q, ascuser,
-                                               sizeof(pstring) - PTR_DIFF(q, outbuf),
+                                               sizeof(outbuf) - PTR_DIFF(q, outbuf),
                                                True);
                                        q += dos_PutUniCode(q, lp_workgroup(),
-                                               sizeof(pstring) - PTR_DIFF(q, outbuf),
+                                               sizeof(outbuf) - PTR_DIFF(q, outbuf),
                                                True);
                                }
 #ifdef HAVE_ADS
                                else {
                                        struct GUID domain_guid;
                                        UUID_FLAT flat_guid;
-                                       pstring domain;
-                                       pstring hostname;
+                                       char *domain;
+                                       char *hostname;
                                        char *component, *dc, *q1;
-                                       uint8 size;
                                        char *q_orig = q;
                                        int str_offset;
+                                       char *saveptr = NULL;
 
-                                       get_mydnsdomname(domain);
-                                       get_myname(hostname);
+                                       domain = get_mydnsdomname(talloc_tos());
+                                       if (!domain) {
+                                               DEBUG(2,
+                                               ("get_mydnsdomname failed.\n"));
+                                               return;
+                                       }
+                                       hostname = get_myname(talloc_tos());
+                                       if (!hostname) {
+                                               DEBUG(2,
+                                               ("get_myname failed.\n"));
+                                               return;
+                                       }
 
                                        if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 8) {
                                                return;
                                        }
                                        if (SVAL(uniuser, 0) == 0) {
-                                               SIVAL(q, 0, SAMLOGON_AD_UNK_R); /* user unknown */
+                                               SIVAL(q, 0, LOGON_SAM_LOGON_USER_UNKNOWN_EX);   /* user unknown */
                                        } else {
-                                               SIVAL(q, 0, SAMLOGON_AD_R);
+                                               SIVAL(q, 0, LOGON_SAM_LOGON_RESPONSE_EX);
                                        }
                                        q += 4;
 
-                                       SIVAL(q, 0, ADS_PDC|ADS_GC|ADS_LDAP|ADS_DS|
-                                               ADS_KDC|ADS_TIMESERV|ADS_CLOSEST|ADS_WRITABLE);
+                                       SIVAL(q, 0, NBT_SERVER_PDC|NBT_SERVER_GC|NBT_SERVER_LDAP|NBT_SERVER_DS|
+                                               NBT_SERVER_KDC|NBT_SERVER_TIMESERV|NBT_SERVER_CLOSEST|NBT_SERVER_WRITABLE);
                                        q += 4;
 
                                        /* Push Domain GUID */
@@ -415,7 +718,7 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                        str_offset = q - q_orig;
                                        dc = domain;
                                        q1 = q;
-                                       while ((component = strtok(dc, "."))) {
+                                       while ((component = strtok_r(dc, ".", &saveptr)) != NULL) {
                                                dc = NULL;
                                                if (sizeof(outbuf) - PTR_DIFF(q, outbuf) < 1) {
                                                        return;
@@ -423,6 +726,9 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                                size = push_ascii(&q[1], component,
                                                        sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
                                                        0);
+                                               if (size == (size_t)-1 || size > 0xff) {
+                                                       return;
+                                               }
                                                SCVAL(q, 0, size);
                                                q += (size + 1);
                                        }
@@ -443,6 +749,9 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                        size = push_ascii(&q[1], hostname,
                                                        sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
                                                        0);
+                                       if (size == (size_t)-1 || size > 0xff) {
+                                               return;
+                                       }
                                        SCVAL(q, 0, size);
                                        q += (size + 1);
 
@@ -458,6 +767,9 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                        size = push_ascii(&q[1], lp_workgroup(),
                                                        sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
                                                        STR_UPPER);
+                                       if (size == (size_t)-1 || size > 0xff) {
+                                               return;
+                                       }
                                        SCVAL(q, 0, size);
                                        q += (size + 1);
 
@@ -473,6 +785,9 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                        size = push_ascii(&q[1], my_name,
                                                        sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
                                                        0);
+                                       if (size == (size_t)-1 || size > 0xff) {
+                                               return;
+                                       }
                                        SCVAL(q, 0, size);
                                        q += (size + 1);
 
@@ -489,6 +804,9 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                                size = push_ascii(&q[1], ascuser,
                                                        sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
                                                        0);
+                                               if (size == (size_t)-1 || size > 0xff) {
+                                                       return;
+                                               }
                                                SCVAL(q, 0, size);
                                                q += (size + 1);
                                        }
@@ -501,6 +819,9 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                        size = push_ascii(&q[1], "Default-First-Site-Name",
                                                        sizeof(outbuf) - PTR_DIFF(q+1, outbuf),
                                                        0);
+                                       if (size == (size_t)-1 || size > 0xff) {
+                                               return;
+                                       }
                                        SCVAL(q, 0, size);
                                        q += (size + 1);
 
@@ -519,7 +840,7 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
 
                                        SIVAL(q, 0, 0x00000002);
                                        q += 4; /* unknown */
-                                       SIVAL(q, 0, (iface_ip(p->ip))->s_addr);
+                                       SIVAL(q, 0, ntohl(ip.s_addr));
                                        q += 4;
                                        SIVAL(q, 0, 0x00000000);
                                        q += 4; /* unknown */
@@ -543,21 +864,65 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
 
                                pull_ascii_fstring(getdc_str, getdc);
                                pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);
+                               source_addr = SMB_STRDUP(inet_ntoa(dgram->header.source_ip));
+                               if (source_addr == NULL) {
+                                       DEBUG(3, ("out of memory copying client"
+                                                 " address string\n"));
+                                       return;
+                               }
+
+                               /*
+                                * handle delay.
+                                * packets requeued after delay are marked as
+                                * locked.
+                                */
+                               if ((p->locked == False) &&
+                                   (strlen(ascuser) == 0) &&
+                                   delay_logon(source_name, source_addr))
+                               {
+                                       struct timeval when;
+
+                                       DEBUG(3, ("process_logon_packet: "
+                                                 "delaying initial logon "
+                                                 "reply for client %s(%s) for "
+                                                 "%u milliseconds\n",
+                                                 source_name, source_addr,
+                                                 lp_init_logon_delay()));
+
+                                       when = timeval_current_ofs(0,
+                                               lp_init_logon_delay() * 1000);
+                                       p->locked = true;
+                                       event_add_timed(nmbd_event_context(),
+                                                       NULL,
+                                                       when,
+                                                       delayed_init_logon_handler,
+                                                       p);
+                               } else {
+                                       DEBUG(3, ("process_logon_packet: "
+                                                 "processing delayed initial "
+                                                 "logon reply for client "
+                                                 "%s(%s)\n",
+                                                 source_name, source_addr));
+
+                                       p->locked = false;
+                                       send_mailslot(true, getdc,
+                                               outbuf,PTR_DIFF(q,outbuf),
+                                               global_myname(), 0x0,
+                                               source_name,
+                                               dgram->source_name.name_type,
+                                               p->ip, ip, p->port);
+                               }
+
+                               SAFE_FREE(source_addr);
 
-                               send_mailslot(True, getdc,
-                                       outbuf,PTR_DIFF(q,outbuf),
-                                       global_myname(), 0x0,
-                                       source_name,
-                                       dgram->source_name.name_type,
-                                       p->ip, *iface_ip(p->ip), p->port);
                                break;
                        }
 
                /* Announce change to UAS or SAM.  Send by the domain controller when a
                replication event is required. */
 
-               case SAM_UAS_CHANGE:
-                       DEBUG(5, ("Got SAM_UAS_CHANGE\n"));
+               case NETLOGON_ANNOUNCE_UAS:
+                       DEBUG(5, ("Got NETLOGON_ANNOUNCE_UAS\n"));
                        break;
 
                default: