| 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 | return NULL;
|
|---|
| 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 | }
|
|---|