r23792: convert Samba4 to GPLv3
[amitay/samba.git] / source4 / libcli / dgram / mailslot.c
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)
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 = private;
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)
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);
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 socket_address *dest;
159         struct dgram_message *msg;
160         struct dgram_smb_packet *smb;
161         struct smb_trans_body *trans;
162         struct socket_address *src;
163         NTSTATUS status;
164
165         if (_dest->port == 0) {
166                 dest = socket_address_from_strings(tmp_ctx, _dest->family, 
167                                                    _dest->addr, lp_dgram_port());
168         } else {
169                 dest = _dest;
170         }
171         if (!dest) {
172                 return NT_STATUS_NO_MEMORY;
173         }
174
175         ZERO_STRUCT(packet);
176         packet.msg_type = msg_type;
177         packet.flags = DGRAM_FLAG_FIRST | DGRAM_NODE_NBDD;
178         packet.dgram_id = generate_random() % UINT16_MAX;
179         src = socket_get_my_addr(dgmsock->sock, tmp_ctx);
180         if (!src) {
181                 return NT_STATUS_NO_MEMORY;
182         }
183         packet.src_addr = src->addr;
184         packet.src_port = src->port;
185
186         msg = &packet.data.msg;
187         /* this length calculation is very crude - it should be based on gensize
188            calls */
189         msg->length = 138 + strlen(mailslot_name) + request->length;
190         msg->offset = 0;
191
192         msg->source_name = *src_name;
193         msg->dest_name = *dest_name;
194         msg->dgram_body_type = DGRAM_SMB;
195
196         smb = &msg->body.smb;
197         smb->smb_command = SMB_TRANSACTION;
198
199         trans = &smb->body.trans;
200         trans->total_data_count = request->length;
201         trans->timeout     = 1000;
202         trans->data_count  = request->length;
203         trans->data_offset = 70 + strlen(mailslot_name);
204         trans->opcode      = 1; /* write mail slot */
205         trans->priority    = 1;
206         trans->class       = 2;
207         trans->mailslot_name = mailslot_name;
208         trans->data = *request;
209
210         status = nbt_dgram_send(dgmsock, &packet, dest);
211
212         talloc_free(tmp_ctx);
213
214         return status;
215 }
216
217 /*
218   return the mailslot data portion from a mailslot packet
219 */
220 DATA_BLOB dgram_mailslot_data(struct nbt_dgram_packet *dgram)
221 {
222         struct smb_trans_body *trans = &dgram->data.msg.body.smb.body.trans;
223         DATA_BLOB ret = trans->data;
224         int pad = trans->data_offset - (70 + strlen(trans->mailslot_name));
225
226         if (pad < 0 || pad > ret.length) {
227                 DEBUG(2,("Badly formatted data in mailslot - pad = %d\n", pad));
228                 return data_blob(NULL, 0);
229         }
230         ret.data += pad;
231         ret.length -= pad;
232         return ret;     
233 }