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*/ 43static 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*/ 52struct 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*/ 82struct 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*/ 98const 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*/ 115struct 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*/ 148NTSTATUS 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*/ 213DATA_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} 227