Fix include paths to new location of libutil.
[tprouty/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 #include "param/param.h"
40
41 /*
42   destroy a mailslot handler
43 */
44 static int dgram_mailslot_destructor(struct dgram_mailslot_handler *dgmslot)
45 {
46         DLIST_REMOVE(dgmslot->dgmsock->mailslot_handlers, dgmslot);
47         return 0;
48 }
49
50 /*
51   start listening on a mailslot. talloc_free() the handle to stop listening
52 */
53 struct dgram_mailslot_handler *dgram_mailslot_listen(struct nbt_dgram_socket *dgmsock,
54                                                      const char *mailslot_name,
55                                                      dgram_mailslot_handler_t handler,
56                                                      void *private)
57 {
58         struct dgram_mailslot_handler *dgmslot;
59
60         dgmslot = talloc(dgmsock, struct dgram_mailslot_handler);
61         if (dgmslot == NULL) return NULL;
62
63         dgmslot->dgmsock = dgmsock;
64         dgmslot->mailslot_name = talloc_strdup(dgmslot, mailslot_name);
65         if (dgmslot->mailslot_name == NULL) {
66                 talloc_free(dgmslot);
67                 return NULL;
68         }
69         dgmslot->handler = handler;
70         dgmslot->private = private;
71
72         DLIST_ADD(dgmsock->mailslot_handlers, dgmslot);
73         talloc_set_destructor(dgmslot, dgram_mailslot_destructor);
74
75         EVENT_FD_READABLE(dgmsock->fde);
76
77         return dgmslot;
78 }
79
80 /*
81   find the handler for a specific mailslot name
82 */
83 struct dgram_mailslot_handler *dgram_mailslot_find(struct nbt_dgram_socket *dgmsock,
84                                                    const char *mailslot_name)
85 {
86         struct dgram_mailslot_handler *h;
87         for (h=dgmsock->mailslot_handlers;h;h=h->next) {
88                 if (strcasecmp(h->mailslot_name, mailslot_name) == 0) {
89                         return h;
90                 }
91         }
92         return NULL;
93 }
94
95 /*
96   check that a datagram packet is a valid mailslot request, and return the 
97   mailslot name if it is, otherwise return NULL
98 */
99 const char *dgram_mailslot_name(struct nbt_dgram_packet *packet)
100 {
101         if (packet->msg_type != DGRAM_DIRECT_UNIQUE &&
102             packet->msg_type != DGRAM_DIRECT_GROUP &&
103             packet->msg_type != DGRAM_BCAST) {
104                 return NULL;
105         }
106         if (packet->data.msg.dgram_body_type != DGRAM_SMB) return NULL;
107         if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
108         return packet->data.msg.body.smb.body.trans.mailslot_name;
109 }
110
111
112 /*
113   create a temporary mailslot handler for a reply mailslot, allocating
114   a new mailslot name using the given base name and a random integer extension
115 */
116 struct dgram_mailslot_handler *dgram_mailslot_temp(struct nbt_dgram_socket *dgmsock,
117                                                    const char *mailslot_name,
118                                                    dgram_mailslot_handler_t handler,
119                                                    void *private)
120 {
121         char *name;
122         int i;
123         struct dgram_mailslot_handler *dgmslot;
124
125         /* try a 100 times at most */
126         for (i=0;i<100;i++) {
127                 name = talloc_asprintf(dgmsock, "%s%03u", 
128                                        mailslot_name,
129                                        generate_random() % 1000);
130                 if (name == NULL) return NULL;
131                 if (dgram_mailslot_find(dgmsock, name)) {
132                         talloc_free(name);
133                         return NULL;
134                 }
135                 dgmslot = dgram_mailslot_listen(dgmsock, name, handler, private);
136                 talloc_free(name);
137                 if (dgmslot != NULL) {
138                         return dgmslot;
139                 }
140         }
141         DEBUG(2,("Unable to create temporary mailslot from %s\n", mailslot_name));
142         return NULL;
143 }
144
145
146 /*
147   send a mailslot request
148 */
149 NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
150                              enum dgram_msg_type msg_type,
151                              const char *mailslot_name,
152                              struct nbt_name *dest_name,
153                              struct socket_address *dest,
154                              struct nbt_name *src_name,
155                              DATA_BLOB *request)
156 {
157         TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
158         struct nbt_dgram_packet packet;
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                 return NT_STATUS_INVALID_PARAMETER;
167         }
168
169         ZERO_STRUCT(packet);
170         packet.msg_type = msg_type;
171         packet.flags = DGRAM_FLAG_FIRST | DGRAM_NODE_NBDD;
172         packet.dgram_id = generate_random() % UINT16_MAX;
173         src = socket_get_my_addr(dgmsock->sock, tmp_ctx);
174         if (!src) {
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 */
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 }