Coverage Report

Created: 2025-07-23 07:04

/src/samba/source4/libcli/dgram/mailslot.c
Line
Count
Source (jump to first uncovered line)
1
/* 
2
   Unix SMB/CIFS implementation.
3
4
   packet handling for mailslot requests. 
5
   
6
   Copyright (C) Andrew Tridgell 2005
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
/*
23
   This implements "Class 2 mailslots", i.e. the communication mechanism 
24
   used for all mailslot packets smaller than 425 bytes. 
25
26
   "Class 1 mailslots" (which use SMB) are used for messages larger 
27
   than 426 bytes and are supported on some systems. These are not implemented
28
   in Samba4 yet, as there don't appear to be any core services that use
29
   them.
30
31
   425 and 426-byte sized messages are not supported at all.
32
*/
33
34
#include "includes.h"
35
#include "lib/events/events.h"
36
#include "../lib/util/dlinklist.h"
37
#include "libcli/dgram/libdgram.h"
38
#include "lib/socket/socket.h"
39
40
#undef strcasecmp
41
42
/*
43
  destroy a mailslot handler
44
*/
45
static int dgram_mailslot_destructor(struct dgram_mailslot_handler *dgmslot)
46
0
{
47
0
  DLIST_REMOVE(dgmslot->dgmsock->mailslot_handlers, dgmslot);
48
0
  return 0;
49
0
}
50
51
/*
52
  start listening on a mailslot. talloc_free() the handle to stop listening
53
*/
54
struct dgram_mailslot_handler *dgram_mailslot_listen(struct nbt_dgram_socket *dgmsock,
55
                 const char *mailslot_name,
56
                 dgram_mailslot_handler_t handler,
57
                 void *private_data)
58
0
{
59
0
  struct dgram_mailslot_handler *dgmslot;
60
61
0
  dgmslot = talloc(dgmsock, struct dgram_mailslot_handler);
62
0
  if (dgmslot == NULL) return NULL;
63
64
0
  dgmslot->dgmsock = dgmsock;
65
0
  dgmslot->mailslot_name = talloc_strdup(dgmslot, mailslot_name);
66
0
  if (dgmslot->mailslot_name == NULL) {
67
0
    talloc_free(dgmslot);
68
0
    return NULL;
69
0
  }
70
0
  dgmslot->handler = handler;
71
0
  dgmslot->private_data = private_data;
72
73
0
  DLIST_ADD(dgmsock->mailslot_handlers, dgmslot);
74
0
  talloc_set_destructor(dgmslot, dgram_mailslot_destructor);
75
76
0
  TEVENT_FD_READABLE(dgmsock->fde);
77
78
0
  return dgmslot;
79
0
}
80
81
/*
82
  find the handler for a specific mailslot name
83
*/
84
struct dgram_mailslot_handler *dgram_mailslot_find(struct nbt_dgram_socket *dgmsock,
85
               const char *mailslot_name)
86
0
{
87
0
  struct dgram_mailslot_handler *h;
88
0
  for (h=dgmsock->mailslot_handlers;h;h=h->next) {
89
0
    if (strcasecmp(h->mailslot_name, mailslot_name) == 0) {
90
0
      return h;
91
0
    }
92
0
  }
93
0
  return NULL;
94
0
}
95
96
/*
97
  check that a datagram packet is a valid mailslot request, and return the 
98
  mailslot name if it is, otherwise return NULL
99
*/
100
const char *dgram_mailslot_name(struct nbt_dgram_packet *packet)
101
0
{
102
0
  if (packet->msg_type != DGRAM_DIRECT_UNIQUE &&
103
0
      packet->msg_type != DGRAM_DIRECT_GROUP &&
104
0
      packet->msg_type != DGRAM_BCAST) {
105
0
    return NULL;
106
0
  }
107
0
  if (packet->data.msg.dgram_body_type != DGRAM_SMB) return NULL;
108
0
  if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
109
0
  return packet->data.msg.body.smb.body.trans.mailslot_name;
110
0
}
111
112
113
/*
114
  create a temporary mailslot handler for a reply mailslot, allocating
115
  a new mailslot name using the given base name and a random integer extension
116
*/
117
struct dgram_mailslot_handler *dgram_mailslot_temp(struct nbt_dgram_socket *dgmsock,
118
               const char *mailslot_name,
119
               dgram_mailslot_handler_t handler,
120
               void *private_data)
121
0
{
122
0
  char *name;
123
0
  int i;
124
0
  struct dgram_mailslot_handler *dgmslot;
125
126
  /* try a 100 times at most */
127
0
  for (i=0;i<100;i++) {
128
0
    name = talloc_asprintf(dgmsock, "%s%03u", 
129
0
               mailslot_name,
130
0
               generate_random() % 1000);
131
0
    if (name == NULL) return NULL;
132
0
    if (dgram_mailslot_find(dgmsock, name)) {
133
0
      talloc_free(name);
134
0
      continue;
135
0
    }
136
0
    dgmslot = dgram_mailslot_listen(dgmsock, name, handler, private_data);
137
0
    talloc_free(name);
138
0
    if (dgmslot != NULL) {
139
0
      return dgmslot;
140
0
    }
141
0
  }
142
0
  DEBUG(2,("Unable to create temporary mailslot from %s\n", mailslot_name));
143
0
  return NULL;
144
0
}
145
146
147
/*
148
  send a mailslot request
149
*/
150
NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
151
           enum dgram_msg_type msg_type,
152
           const char *mailslot_name,
153
           struct nbt_name *dest_name,
154
           struct socket_address *dest,
155
           struct nbt_name *src_name,
156
           DATA_BLOB *request)
157
0
{
158
0
  TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
159
0
  struct nbt_dgram_packet packet;
160
0
  struct dgram_message *msg;
161
0
  struct dgram_smb_packet *smb;
162
0
  struct smb_trans_body *trans;
163
0
  struct socket_address *src;
164
0
  NTSTATUS status;
165
166
0
  if (dest->port == 0) {
167
0
    return NT_STATUS_INVALID_PARAMETER;
168
0
  }
169
170
0
  ZERO_STRUCT(packet);
171
0
  packet.msg_type = msg_type;
172
0
  packet.flags = DGRAM_FLAG_FIRST | DGRAM_NODE_NBDD;
173
0
  packet.dgram_id = generate_random() % UINT16_MAX;
174
0
  src = socket_get_my_addr(dgmsock->sock, tmp_ctx);
175
0
  if (!src) {
176
0
    talloc_free(tmp_ctx);
177
0
    return NT_STATUS_NO_MEMORY;
178
0
  }
179
0
  packet.src_addr = src->addr;
180
0
  packet.src_port = src->port;
181
182
0
  msg = &packet.data.msg;
183
  /* this length calculation is very crude - it should be based on gensize
184
     calls */
185
0
  msg->length = 138 + strlen(mailslot_name) + request->length;
186
0
  msg->offset = 0;
187
188
0
  msg->source_name = *src_name;
189
0
  msg->dest_name = *dest_name;
190
0
  msg->dgram_body_type = DGRAM_SMB;
191
192
0
  smb = &msg->body.smb;
193
0
  smb->smb_command = SMB_TRANSACTION;
194
195
0
  trans = &smb->body.trans;
196
0
  trans->total_data_count = request->length;
197
0
  trans->timeout     = 1000;
198
0
  trans->data_count  = request->length;
199
0
  trans->data_offset = 70 + strlen(mailslot_name);
200
0
  trans->opcode      = 1; /* write mail slot */
201
0
  trans->priority    = 1;
202
0
  trans->_class      = 2;
203
0
  trans->mailslot_name = mailslot_name;
204
0
  trans->data = *request;
205
206
0
  status = nbt_dgram_send(dgmsock, &packet, dest);
207
208
0
  talloc_free(tmp_ctx);
209
210
0
  return status;
211
0
}
212
213
/*
214
  return the mailslot data portion from a mailslot packet
215
*/
216
DATA_BLOB dgram_mailslot_data(struct nbt_dgram_packet *dgram)
217
0
{
218
0
  struct smb_trans_body *trans = &dgram->data.msg.body.smb.body.trans;
219
0
  DATA_BLOB ret = trans->data;
220
0
  int pad = trans->data_offset - (70 + strlen(trans->mailslot_name));
221
222
0
  if (pad < 0 || pad > ret.length) {
223
0
    DEBUG(2,("Badly formatted data in mailslot - pad = %d\n", pad));
224
0
    return data_blob(NULL, 0);
225
0
  }
226
0
  ret.data += pad;
227
0
  ret.length -= pad;
228
0
  return ret; 
229
0
}