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 | /*
|
---|
41 | destroy a mailslot handler
|
---|
42 | */
|
---|
43 | static int dgram_mailslot_destructor(struct dgram_mailslot_handler *dgmslot)
|
---|
44 | {
|
---|
45 | DLIST_REMOVE(dgmslot->dgmsock->mailslot_handlers, dgmslot);
|
---|
46 | return 0;
|
---|
47 | }
|
---|
48 |
|
---|
49 | /*
|
---|
50 | start listening on a mailslot. talloc_free() the handle to stop listening
|
---|
51 | */
|
---|
52 | struct dgram_mailslot_handler *dgram_mailslot_listen(struct nbt_dgram_socket *dgmsock,
|
---|
53 | const char *mailslot_name,
|
---|
54 | dgram_mailslot_handler_t handler,
|
---|
55 | void *private_data)
|
---|
56 | {
|
---|
57 | struct dgram_mailslot_handler *dgmslot;
|
---|
58 |
|
---|
59 | dgmslot = talloc(dgmsock, struct dgram_mailslot_handler);
|
---|
60 | if (dgmslot == NULL) return NULL;
|
---|
61 |
|
---|
62 | dgmslot->dgmsock = dgmsock;
|
---|
63 | dgmslot->mailslot_name = talloc_strdup(dgmslot, mailslot_name);
|
---|
64 | if (dgmslot->mailslot_name == NULL) {
|
---|
65 | talloc_free(dgmslot);
|
---|
66 | return NULL;
|
---|
67 | }
|
---|
68 | dgmslot->handler = handler;
|
---|
69 | dgmslot->private_data = private_data;
|
---|
70 |
|
---|
71 | DLIST_ADD(dgmsock->mailslot_handlers, dgmslot);
|
---|
72 | talloc_set_destructor(dgmslot, dgram_mailslot_destructor);
|
---|
73 |
|
---|
74 | EVENT_FD_READABLE(dgmsock->fde);
|
---|
75 |
|
---|
76 | return dgmslot;
|
---|
77 | }
|
---|
78 |
|
---|
79 | /*
|
---|
80 | find the handler for a specific mailslot name
|
---|
81 | */
|
---|
82 | struct dgram_mailslot_handler *dgram_mailslot_find(struct nbt_dgram_socket *dgmsock,
|
---|
83 | const char *mailslot_name)
|
---|
84 | {
|
---|
85 | struct dgram_mailslot_handler *h;
|
---|
86 | for (h=dgmsock->mailslot_handlers;h;h=h->next) {
|
---|
87 | if (strcasecmp(h->mailslot_name, mailslot_name) == 0) {
|
---|
88 | return h;
|
---|
89 | }
|
---|
90 | }
|
---|
91 | return NULL;
|
---|
92 | }
|
---|
93 |
|
---|
94 | /*
|
---|
95 | check that a datagram packet is a valid mailslot request, and return the
|
---|
96 | mailslot name if it is, otherwise return NULL
|
---|
97 | */
|
---|
98 | const char *dgram_mailslot_name(struct nbt_dgram_packet *packet)
|
---|
99 | {
|
---|
100 | if (packet->msg_type != DGRAM_DIRECT_UNIQUE &&
|
---|
101 | packet->msg_type != DGRAM_DIRECT_GROUP &&
|
---|
102 | packet->msg_type != DGRAM_BCAST) {
|
---|
103 | return NULL;
|
---|
104 | }
|
---|
105 | if (packet->data.msg.dgram_body_type != DGRAM_SMB) return NULL;
|
---|
106 | if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
|
---|
107 | return packet->data.msg.body.smb.body.trans.mailslot_name;
|
---|
108 | }
|
---|
109 |
|
---|
110 |
|
---|
111 | /*
|
---|
112 | create a temporary mailslot handler for a reply mailslot, allocating
|
---|
113 | a new mailslot name using the given base name and a random integer extension
|
---|
114 | */
|
---|
115 | struct dgram_mailslot_handler *dgram_mailslot_temp(struct nbt_dgram_socket *dgmsock,
|
---|
116 | const char *mailslot_name,
|
---|
117 | dgram_mailslot_handler_t handler,
|
---|
118 | void *private_data)
|
---|
119 | {
|
---|
120 | char *name;
|
---|
121 | int i;
|
---|
122 | struct dgram_mailslot_handler *dgmslot;
|
---|
123 |
|
---|
124 | /* try a 100 times at most */
|
---|
125 | for (i=0;i<100;i++) {
|
---|
126 | name = talloc_asprintf(dgmsock, "%s%03u",
|
---|
127 | mailslot_name,
|
---|
128 | generate_random() % 1000);
|
---|
129 | if (name == NULL) return NULL;
|
---|
130 | if (dgram_mailslot_find(dgmsock, name)) {
|
---|
131 | talloc_free(name);
|
---|
132 | continue;
|
---|
133 | }
|
---|
134 | dgmslot = dgram_mailslot_listen(dgmsock, name, handler, private_data);
|
---|
135 | talloc_free(name);
|
---|
136 | if (dgmslot != NULL) {
|
---|
137 | return dgmslot;
|
---|
138 | }
|
---|
139 | }
|
---|
140 | DEBUG(2,("Unable to create temporary mailslot from %s\n", mailslot_name));
|
---|
141 | return NULL;
|
---|
142 | }
|
---|
143 |
|
---|
144 |
|
---|
145 | /*
|
---|
146 | send a mailslot request
|
---|
147 | */
|
---|
148 | NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
|
---|
149 | enum dgram_msg_type msg_type,
|
---|
150 | const char *mailslot_name,
|
---|
151 | struct nbt_name *dest_name,
|
---|
152 | struct socket_address *dest,
|
---|
153 | struct nbt_name *src_name,
|
---|
154 | DATA_BLOB *request)
|
---|
155 | {
|
---|
156 | TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
|
---|
157 | struct nbt_dgram_packet packet;
|
---|
158 | struct dgram_message *msg;
|
---|
159 | struct dgram_smb_packet *smb;
|
---|
160 | struct smb_trans_body *trans;
|
---|
161 | struct socket_address *src;
|
---|
162 | NTSTATUS status;
|
---|
163 |
|
---|
164 | if (dest->port == 0) {
|
---|
165 | return NT_STATUS_INVALID_PARAMETER;
|
---|
166 | }
|
---|
167 |
|
---|
168 | ZERO_STRUCT(packet);
|
---|
169 | packet.msg_type = msg_type;
|
---|
170 | packet.flags = DGRAM_FLAG_FIRST | DGRAM_NODE_NBDD;
|
---|
171 | packet.dgram_id = generate_random() % UINT16_MAX;
|
---|
172 | src = socket_get_my_addr(dgmsock->sock, tmp_ctx);
|
---|
173 | if (!src) {
|
---|
174 | return NT_STATUS_NO_MEMORY;
|
---|
175 | }
|
---|
176 | packet.src_addr = src->addr;
|
---|
177 | packet.src_port = src->port;
|
---|
178 |
|
---|
179 | msg = &packet.data.msg;
|
---|
180 | /* this length calculation is very crude - it should be based on gensize
|
---|
181 | calls */
|
---|
182 | msg->length = 138 + strlen(mailslot_name) + request->length;
|
---|
183 | msg->offset = 0;
|
---|
184 |
|
---|
185 | msg->source_name = *src_name;
|
---|
186 | msg->dest_name = *dest_name;
|
---|
187 | msg->dgram_body_type = DGRAM_SMB;
|
---|
188 |
|
---|
189 | smb = &msg->body.smb;
|
---|
190 | smb->smb_command = SMB_TRANSACTION;
|
---|
191 |
|
---|
192 | trans = &smb->body.trans;
|
---|
193 | trans->total_data_count = request->length;
|
---|
194 | trans->timeout = 1000;
|
---|
195 | trans->data_count = request->length;
|
---|
196 | trans->data_offset = 70 + strlen(mailslot_name);
|
---|
197 | trans->opcode = 1; /* write mail slot */
|
---|
198 | trans->priority = 1;
|
---|
199 | trans->_class = 2;
|
---|
200 | trans->mailslot_name = mailslot_name;
|
---|
201 | trans->data = *request;
|
---|
202 |
|
---|
203 | status = nbt_dgram_send(dgmsock, &packet, dest);
|
---|
204 |
|
---|
205 | talloc_free(tmp_ctx);
|
---|
206 |
|
---|
207 | return status;
|
---|
208 | }
|
---|
209 |
|
---|
210 | /*
|
---|
211 | return the mailslot data portion from a mailslot packet
|
---|
212 | */
|
---|
213 | DATA_BLOB dgram_mailslot_data(struct nbt_dgram_packet *dgram)
|
---|
214 | {
|
---|
215 | struct smb_trans_body *trans = &dgram->data.msg.body.smb.body.trans;
|
---|
216 | DATA_BLOB ret = trans->data;
|
---|
217 | int pad = trans->data_offset - (70 + strlen(trans->mailslot_name));
|
---|
218 |
|
---|
219 | if (pad < 0 || pad > ret.length) {
|
---|
220 | DEBUG(2,("Badly formatted data in mailslot - pad = %d\n", pad));
|
---|
221 | return data_blob(NULL, 0);
|
---|
222 | }
|
---|
223 | ret.data += pad;
|
---|
224 | ret.length -= pad;
|
---|
225 | return ret;
|
---|
226 | }
|
---|