LCOV - code coverage report
Current view: top level - source3/libsmb - clidgram.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 174 215 80.9 %
Date: 2021-09-23 10:06:22 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    client dgram calls
       4             :    Copyright (C) Andrew Tridgell 1994-1998
       5             :    Copyright (C) Richard Sharpe 2001
       6             :    Copyright (C) John Terpstra 2001
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "libsmb/libsmb.h"
      24             : #include "../lib/util/tevent_ntstatus.h"
      25             : #include "libsmb/clidgram.h"
      26             : #include "libsmb/nmblib.h"
      27             : #include "libsmb/unexpected.h"
      28             : #include "messages.h"
      29             : #include "librpc/gen_ndr/samr.h"
      30             : #include "../lib/util/pidfile.h"
      31             : #include "lib/util/string_wrappers.h"
      32             : 
      33             : /*
      34             :  * cli_send_mailslot, send a mailslot for client code ...
      35             :  */
      36             : 
      37           5 : static bool cli_prep_mailslot(bool unique, const char *mailslot,
      38             :                        uint16_t priority,
      39             :                        char *buf, int len,
      40             :                        const char *srcname, int src_type,
      41             :                        const char *dstname, int dest_type,
      42             :                        const struct sockaddr_storage *dest_ss,
      43             :                        int dgm_id,
      44             :                        struct packet_struct *p)
      45             : {
      46           5 :         struct dgram_packet *dgram = &p->packet.dgram;
      47             :         char *ptr, *p2;
      48             :         char tmp[4];
      49             :         char addr[INET6_ADDRSTRLEN];
      50             : 
      51           5 :         ZERO_STRUCTP(p);
      52             : 
      53             :         /*
      54             :          * Next, build the DGRAM ...
      55             :          */
      56             : 
      57             :         /* DIRECT GROUP or UNIQUE datagram. */
      58           5 :         dgram->header.msg_type = unique ? 0x10 : 0x11;
      59           5 :         dgram->header.flags.node_type = M_NODE;
      60           5 :         dgram->header.flags.first = True;
      61           5 :         dgram->header.flags.more = False;
      62           5 :         dgram->header.dgm_id = dgm_id;
      63             :         /* source ip is filled by nmbd */
      64           5 :         dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
      65           5 :         dgram->header.packet_offset = 0;
      66             : 
      67           5 :         make_nmb_name(&dgram->source_name,srcname,src_type);
      68           5 :         make_nmb_name(&dgram->dest_name,dstname,dest_type);
      69             : 
      70           5 :         ptr = &dgram->data[0];
      71             : 
      72             :         /* Setup the smb part. */
      73           5 :         ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
      74           5 :         memcpy(tmp,ptr,4);
      75             : 
      76           5 :         if (smb_size + 17*2 + strlen(mailslot) + 1 + len > MAX_DGRAM_SIZE) {
      77           0 :                 DEBUG(0, ("cli_send_mailslot: Cannot write beyond end of packet\n"));
      78           0 :                 return False;
      79             :         }
      80             : 
      81           5 :         cli_set_message(ptr,17,strlen(mailslot) + 1 + len,True);
      82           5 :         memcpy(ptr,tmp,4);
      83             : 
      84           5 :         SCVAL(ptr,smb_com,SMBtrans);
      85           5 :         SSVAL(ptr,smb_vwv1,len);
      86           5 :         SSVAL(ptr,smb_vwv11,len);
      87           5 :         SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
      88           5 :         SSVAL(ptr,smb_vwv13,3);
      89           5 :         SSVAL(ptr,smb_vwv14,1);
      90           5 :         SSVAL(ptr,smb_vwv15,priority);
      91           5 :         SSVAL(ptr,smb_vwv16,2);
      92           5 :         p2 = smb_buf(ptr);
      93           5 :         fstrcpy(p2,mailslot);
      94           5 :         p2 = skip_string(ptr,MAX_DGRAM_SIZE,p2);
      95           5 :         if (!p2) {
      96           0 :                 return False;
      97             :         }
      98             : 
      99           5 :         memcpy(p2,buf,len);
     100           5 :         p2 += len;
     101             : 
     102           5 :         dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
     103             : 
     104           5 :         p->packet_type = DGRAM_PACKET;
     105           5 :         p->ip = ((const struct sockaddr_in *)dest_ss)->sin_addr;
     106           5 :         p->timestamp = time(NULL);
     107             : 
     108           5 :         DEBUG(4,("send_mailslot: Sending to mailslot %s from %s ",
     109             :                  mailslot, nmb_namestr(&dgram->source_name)));
     110           5 :         print_sockaddr(addr, sizeof(addr), dest_ss);
     111             : 
     112           5 :         DEBUGADD(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), addr));
     113             : 
     114           5 :         return true;
     115             : }
     116             : 
     117          19 : static char *mailslot_name(TALLOC_CTX *mem_ctx, struct in_addr dc_ip)
     118             : {
     119          19 :         return talloc_asprintf(mem_ctx, "%s%X",
     120             :                                NBT_MAILSLOT_GETDC, dc_ip.s_addr);
     121             : }
     122             : 
     123           5 : static bool prep_getdc_request(const struct sockaddr_storage *dc_ss,
     124             :                                const char *account_name,
     125             :                                uint32_t account_flags,
     126             :                                const char *domain_name,
     127             :                                const struct dom_sid *sid,
     128             :                                uint32_t nt_version,
     129             :                                const char *my_mailslot,
     130             :                                int dgm_id,
     131             :                                struct packet_struct *p)
     132             : {
     133           5 :         TALLOC_CTX *frame = talloc_stackframe();
     134             :         struct nbt_netlogon_packet packet;
     135             :         struct NETLOGON_SAM_LOGON_REQUEST *s;
     136             :         enum ndr_err_code ndr_err;
     137           5 :         DATA_BLOB blob = data_blob_null;
     138             :         struct dom_sid my_sid;
     139           5 :         bool ret = false;
     140             : 
     141           5 :         ZERO_STRUCT(packet);
     142           5 :         ZERO_STRUCT(my_sid);
     143             : 
     144           5 :         if (sid != NULL) {
     145           0 :                 my_sid = *sid;
     146             :         }
     147             : 
     148           5 :         packet.command  = LOGON_SAM_LOGON_REQUEST;
     149           5 :         s               = &packet.req.logon;
     150             : 
     151           5 :         s->request_count     = 0;
     152           5 :         s->computer_name     = lp_netbios_name();
     153           5 :         s->user_name         = account_name;
     154           5 :         s->mailslot_name     = my_mailslot;
     155           5 :         s->acct_control              = account_flags;
     156           5 :         s->sid                       = my_sid;
     157           5 :         s->nt_version                = nt_version;
     158           5 :         s->lmnt_token                = 0xffff;
     159           5 :         s->lm20_token                = 0xffff;
     160             : 
     161           5 :         if (DEBUGLEVEL >= 10) {
     162           0 :                 NDR_PRINT_DEBUG(nbt_netlogon_packet, &packet);
     163             :         }
     164             : 
     165           5 :         ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &packet,
     166             :                        (ndr_push_flags_fn_t)ndr_push_nbt_netlogon_packet);
     167           5 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     168           0 :                 goto fail;
     169             :         }
     170             : 
     171          15 :         ret = cli_prep_mailslot(false, NBT_MAILSLOT_NTLOGON, 0,
     172          10 :                                 (char *)blob.data, blob.length,
     173             :                                 lp_netbios_name(), 0, domain_name, 0x1c,
     174             :                                 dc_ss, dgm_id, p);
     175           5 : fail:
     176           5 :         TALLOC_FREE(frame);
     177           5 :         return ret;
     178             : }
     179             : 
     180           3 : static bool parse_getdc_response(
     181             :         struct packet_struct *packet,
     182             :         TALLOC_CTX *mem_ctx,
     183             :         const char *domain_name,
     184             :         uint32_t *nt_version,
     185             :         const char **dc_name,
     186             :         struct netlogon_samlogon_response **samlogon_response)
     187             : {
     188             :         DATA_BLOB blob;
     189             :         struct netlogon_samlogon_response *r;
     190             :         union dgram_message_body p;
     191             :         enum ndr_err_code ndr_err;
     192             :         NTSTATUS status;
     193             : 
     194           3 :         const char *returned_dc = NULL;
     195           3 :         const char *returned_domain = NULL;
     196             : 
     197           3 :         blob = data_blob_const(packet->packet.dgram.data,
     198           3 :                                packet->packet.dgram.datasize);
     199           3 :         if (blob.length < 4) {
     200           0 :                 DEBUG(1, ("invalid length: %d\n", (int)blob.length));
     201           0 :                 return false;
     202             :         }
     203             : 
     204           3 :         if (RIVAL(blob.data,0) != DGRAM_SMB) {
     205           0 :                 DEBUG(1, ("invalid packet\n"));
     206           0 :                 return false;
     207             :         }
     208             : 
     209           3 :         blob.data += 4;
     210           3 :         blob.length -= 4;
     211             : 
     212           3 :         ndr_err = ndr_pull_union_blob_all(&blob, mem_ctx, &p, DGRAM_SMB,
     213             :                        (ndr_pull_flags_fn_t)ndr_pull_dgram_smb_packet);
     214           3 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     215           0 :                 DEBUG(1, ("failed to parse packet\n"));
     216           0 :                 return false;
     217             :         }
     218             : 
     219           3 :         if (p.smb.smb_command != SMB_TRANSACTION) {
     220           0 :                 DEBUG(1, ("invalid smb_command: %d\n", p.smb.smb_command));
     221           0 :                 return false;
     222             :         }
     223             : 
     224           3 :         if (DEBUGLEVEL >= 10) {
     225           0 :                 NDR_PRINT_DEBUG(dgram_smb_packet, &p);
     226             :         }
     227             : 
     228           3 :         blob = p.smb.body.trans.data;
     229             : 
     230           3 :         r = talloc_zero(mem_ctx, struct netlogon_samlogon_response);
     231           3 :         if (!r) {
     232           0 :                 return false;
     233             :         }
     234             : 
     235           3 :         status = pull_netlogon_samlogon_response(&blob, r, r);
     236           3 :         if (!NT_STATUS_IS_OK(status)) {
     237           0 :                 TALLOC_FREE(r);
     238           0 :                 return false;
     239             :         }
     240             : 
     241           3 :         map_netlogon_samlogon_response(r);
     242             : 
     243             :         /* do we still need this ? */
     244           3 :         *nt_version = r->ntver;
     245             : 
     246           3 :         returned_domain = r->data.nt5_ex.domain_name;
     247           3 :         returned_dc = r->data.nt5_ex.pdc_name;
     248             : 
     249           3 :         if (!strequal(returned_domain, domain_name)) {
     250           0 :                 DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
     251             :                           domain_name, returned_domain));
     252           0 :                 TALLOC_FREE(r);
     253           0 :                 return false;
     254             :         }
     255             : 
     256           3 :         if (*returned_dc == '\\') returned_dc += 1;
     257           3 :         if (*returned_dc == '\\') returned_dc += 1;
     258             : 
     259           3 :         *dc_name = talloc_strdup(mem_ctx, returned_dc);
     260           3 :         if (!*dc_name) {
     261           0 :                 TALLOC_FREE(r);
     262           0 :                 return false;
     263             :         }
     264             : 
     265           3 :         if (samlogon_response) {
     266           3 :                 *samlogon_response = r;
     267             :         } else {
     268           0 :                 TALLOC_FREE(r);
     269             :         }
     270             : 
     271           3 :         DEBUG(10, ("GetDC gave name %s for domain %s\n",
     272             :                    *dc_name, returned_domain));
     273             : 
     274           3 :         return True;
     275             : }
     276             : 
     277             : struct nbt_getdc_state {
     278             :         struct tevent_context *ev;
     279             :         struct messaging_context *msg_ctx;
     280             :         struct nb_packet_reader *reader;
     281             :         const char *my_mailslot;
     282             :         pid_t nmbd_pid;
     283             : 
     284             :         const struct sockaddr_storage *dc_addr;
     285             :         const char *domain_name;
     286             :         const struct dom_sid *sid;
     287             :         uint32_t nt_version;
     288             :         const char *dc_name;
     289             :         struct netlogon_samlogon_response *samlogon_response;
     290             : 
     291             :         struct packet_struct p;
     292             : };
     293             : 
     294             : static void nbt_getdc_got_reader(struct tevent_req *subreq);
     295             : static void nbt_getdc_got_response(struct tevent_req *subreq);
     296             : 
     297          19 : struct tevent_req *nbt_getdc_send(TALLOC_CTX *mem_ctx,
     298             :                                   struct tevent_context *ev,
     299             :                                   struct messaging_context *msg_ctx,
     300             :                                   const struct sockaddr_storage *dc_addr,
     301             :                                   const char *domain_name,
     302             :                                   const struct dom_sid *sid,
     303             :                                   const char *account_name,
     304             :                                   uint32_t account_flags,
     305             :                                   uint32_t nt_version)
     306             : {
     307             :         struct tevent_req *req, *subreq;
     308             :         struct nbt_getdc_state *state;
     309             :         uint16_t dgm_id;
     310             :         bool ok;
     311             : 
     312          19 :         req = tevent_req_create(mem_ctx, &state, struct nbt_getdc_state);
     313          19 :         if (req == NULL) {
     314           0 :                 return NULL;
     315             :         }
     316          19 :         state->ev = ev;
     317          19 :         state->msg_ctx = msg_ctx;
     318          19 :         state->dc_addr = dc_addr;
     319          19 :         state->domain_name = domain_name;
     320          19 :         state->sid = sid;
     321          19 :         state->nt_version = nt_version;
     322             : 
     323          19 :         if (dc_addr->ss_family != AF_INET) {
     324           0 :                 tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
     325           0 :                 return tevent_req_post(req, ev);
     326             :         }
     327          19 :         state->my_mailslot = mailslot_name(
     328             :                 state, ((const struct sockaddr_in *)dc_addr)->sin_addr);
     329          19 :         if (tevent_req_nomem(state->my_mailslot, req)) {
     330           0 :                 return tevent_req_post(req, ev);
     331             :         }
     332          19 :         state->nmbd_pid = pidfile_pid(lp_pid_directory(), "nmbd");
     333          19 :         if (state->nmbd_pid == 0) {
     334          14 :                 DEBUG(3, ("No nmbd found\n"));
     335          14 :                 tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
     336          14 :                 return tevent_req_post(req, ev);
     337             :         }
     338             : 
     339           5 :         generate_random_buffer((uint8_t *)(void *)&dgm_id, sizeof(dgm_id));
     340             : 
     341          10 :         ok = prep_getdc_request(dc_addr, account_name, account_flags,
     342             :                                 domain_name, sid, nt_version,
     343           5 :                                 state->my_mailslot, dgm_id & 0x7fff,
     344           5 :                                 &state->p);
     345             : 
     346           5 :         if (!ok) {
     347           0 :                 DEBUG(3, ("prep_getdc_request failed\n"));
     348           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     349           0 :                 return tevent_req_post(req, ev);
     350             :         }
     351             : 
     352           5 :         subreq = nb_packet_reader_send(state, ev, DGRAM_PACKET, -1,
     353           5 :                                        state->my_mailslot);
     354           5 :         if (tevent_req_nomem(subreq, req)) {
     355           0 :                 return tevent_req_post(req, ev);
     356             :         }
     357           5 :         tevent_req_set_callback(subreq, nbt_getdc_got_reader, req);
     358           5 :         return req;
     359             : }
     360             : 
     361           5 : static void nbt_getdc_got_reader(struct tevent_req *subreq)
     362             : {
     363           5 :         struct tevent_req *req = tevent_req_callback_data(
     364             :                 subreq, struct tevent_req);
     365           5 :         struct nbt_getdc_state *state = tevent_req_data(
     366             :                 req, struct nbt_getdc_state);
     367             :         NTSTATUS status;
     368             : 
     369           5 :         status = nb_packet_reader_recv(subreq, state, &state->reader);
     370           5 :         TALLOC_FREE(subreq);
     371           5 :         if (tevent_req_nterror(req, status)) {
     372           0 :                 DEBUG(10, ("nb_packet_reader_recv returned %s\n",
     373             :                            nt_errstr(status)));
     374           2 :                 return;
     375             :         }
     376             : 
     377           5 :         status = messaging_send_buf(
     378             :                 state->msg_ctx, pid_to_procid(state->nmbd_pid),
     379           5 :                 MSG_SEND_PACKET, (uint8_t *)&state->p, sizeof(state->p));
     380             : 
     381           5 :         if (tevent_req_nterror(req, status)) {
     382           2 :                 DEBUG(10, ("messaging_send_buf returned %s\n",
     383             :                            nt_errstr(status)));
     384           2 :                 return;
     385             :         }
     386           3 :         subreq = nb_packet_read_send(state, state->ev, state->reader);
     387           3 :         if (tevent_req_nomem(subreq, req)) {
     388           0 :                 return;
     389             :         }
     390           3 :         tevent_req_set_callback(subreq, nbt_getdc_got_response, req);
     391             : }
     392             : 
     393           3 : static void nbt_getdc_got_response(struct tevent_req *subreq)
     394             : {
     395           3 :         struct tevent_req *req = tevent_req_callback_data(
     396             :                 subreq, struct tevent_req);
     397           3 :         struct nbt_getdc_state *state = tevent_req_data(
     398             :                 req, struct nbt_getdc_state);
     399             :         struct packet_struct *p;
     400             :         NTSTATUS status;
     401             :         bool ret;
     402             : 
     403           3 :         status = nb_packet_read_recv(subreq, state, &p);
     404           3 :         TALLOC_FREE(subreq);
     405           3 :         if (tevent_req_nterror(req, status)) {
     406           0 :                 return;
     407             :         }
     408             : 
     409           3 :         ret = parse_getdc_response(p, state, state->domain_name,
     410             :                                    &state->nt_version, &state->dc_name,
     411             :                                    &state->samlogon_response);
     412           3 :         if (!ret) {
     413           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     414           0 :                 return;
     415             :         }
     416           3 :         tevent_req_done(req);
     417             : }
     418             : 
     419          19 : NTSTATUS nbt_getdc_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     420             :                         uint32_t *nt_version, const char **dc_name,
     421             :                         struct netlogon_samlogon_response **samlogon_response)
     422             : {
     423          19 :         struct nbt_getdc_state *state = tevent_req_data(
     424             :                 req, struct nbt_getdc_state);
     425             :         NTSTATUS status;
     426             : 
     427          19 :         if (tevent_req_is_nterror(req, &status)) {
     428          16 :                 return status;
     429             :         }
     430           3 :         if (nt_version != NULL) {
     431           3 :                 *nt_version = state->nt_version;
     432             :         }
     433           3 :         if (dc_name != NULL) {
     434           3 :                 *dc_name = talloc_move(mem_ctx, &state->dc_name);
     435             :         }
     436           3 :         if (samlogon_response != NULL) {
     437           3 :                 *samlogon_response = talloc_move(
     438             :                         mem_ctx, &state->samlogon_response);
     439             :         }
     440           3 :         return NT_STATUS_OK;
     441             : }
     442             : 
     443          19 : NTSTATUS nbt_getdc(struct messaging_context *msg_ctx,
     444             :                    uint32_t timeout_in_seconds,
     445             :                    const struct sockaddr_storage *dc_addr,
     446             :                    const char *domain_name,
     447             :                    const struct dom_sid *sid,
     448             :                    const char *account_name,
     449             :                    uint32_t account_flags,
     450             :                    uint32_t nt_version,
     451             :                    TALLOC_CTX *mem_ctx,
     452             :                    uint32_t *pnt_version,
     453             :                    const char **dc_name,
     454             :                    struct netlogon_samlogon_response **samlogon_response)
     455             : {
     456          19 :         TALLOC_CTX *frame = talloc_stackframe();
     457             :         struct tevent_context *ev;
     458             :         struct tevent_req *req;
     459          19 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     460             : 
     461          19 :         ev = samba_tevent_context_init(frame);
     462          19 :         if (ev == NULL) {
     463           0 :                 goto fail;
     464             :         }
     465          19 :         req = nbt_getdc_send(ev, ev, msg_ctx, dc_addr, domain_name,
     466             :                              sid, account_name, account_flags, nt_version);
     467          19 :         if (req == NULL) {
     468           0 :                 goto fail;
     469             :         }
     470          19 :         if (!tevent_req_set_endtime(req, ev,
     471             :                         timeval_current_ofs(timeout_in_seconds, 0))) {
     472           0 :                 goto fail;
     473             :         }
     474          19 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     475           0 :                 goto fail;
     476             :         }
     477          19 :         status = nbt_getdc_recv(req, mem_ctx, pnt_version, dc_name,
     478             :                                 samlogon_response);
     479          19 :  fail:
     480          19 :         TALLOC_FREE(frame);
     481          19 :         return status;
     482             : }

Generated by: LCOV version 1.13