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 */
dgram_mailslot_destructor(struct dgram_mailslot_handler * dgmslot)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 */
dgram_mailslot_listen(struct nbt_dgram_socket * dgmsock,const char * mailslot_name,dgram_mailslot_handler_t handler,void * private_data)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 	TEVENT_FD_READABLE(dgmsock->fde);
75 
76 	return dgmslot;
77 }
78 
79 /*
80   find the handler for a specific mailslot name
81 */
dgram_mailslot_find(struct nbt_dgram_socket * dgmsock,const char * mailslot_name)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 */
dgram_mailslot_name(struct nbt_dgram_packet * packet)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 */
dgram_mailslot_temp(struct nbt_dgram_socket * dgmsock,const char * mailslot_name,dgram_mailslot_handler_t handler,void * private_data)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 */
dgram_mailslot_send(struct nbt_dgram_socket * dgmsock,enum dgram_msg_type msg_type,const char * mailslot_name,struct nbt_name * dest_name,struct socket_address * dest,struct nbt_name * src_name,DATA_BLOB * request)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 		talloc_free(tmp_ctx);
175 		return NT_STATUS_NO_MEMORY;
176 	}
177 	packet.src_addr = src->addr;
178 	packet.src_port = src->port;
179 
180 	msg = &packet.data.msg;
181 	/* this length calculation is very crude - it should be based on gensize
182 	   calls */
183 	msg->length = 138 + strlen(mailslot_name) + request->length;
184 	msg->offset = 0;
185 
186 	msg->source_name = *src_name;
187 	msg->dest_name = *dest_name;
188 	msg->dgram_body_type = DGRAM_SMB;
189 
190 	smb = &msg->body.smb;
191 	smb->smb_command = SMB_TRANSACTION;
192 
193 	trans = &smb->body.trans;
194 	trans->total_data_count = request->length;
195 	trans->timeout     = 1000;
196 	trans->data_count  = request->length;
197 	trans->data_offset = 70 + strlen(mailslot_name);
198 	trans->opcode      = 1; /* write mail slot */
199 	trans->priority    = 1;
200 	trans->_class      = 2;
201 	trans->mailslot_name = mailslot_name;
202 	trans->data = *request;
203 
204 	status = nbt_dgram_send(dgmsock, &packet, dest);
205 
206 	talloc_free(tmp_ctx);
207 
208 	return status;
209 }
210 
211 /*
212   return the mailslot data portion from a mailslot packet
213 */
dgram_mailslot_data(struct nbt_dgram_packet * dgram)214 DATA_BLOB dgram_mailslot_data(struct nbt_dgram_packet *dgram)
215 {
216 	struct smb_trans_body *trans = &dgram->data.msg.body.smb.body.trans;
217 	DATA_BLOB ret = trans->data;
218 	int pad = trans->data_offset - (70 + strlen(trans->mailslot_name));
219 
220 	if (pad < 0 || pad > ret.length) {
221 		DEBUG(2,("Badly formatted data in mailslot - pad = %d\n", pad));
222 		return data_blob(NULL, 0);
223 	}
224 	ret.data += pad;
225 	ret.length -= pad;
226 	return ret;
227 }
228