r10997: r11980@SERNOX (orig r10037): metze | 2005-09-05 14:21:40 +0200
[garming/samba-autobuild/.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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /*
24    This implements "Class 2 mailslots", i.e. the communication mechanism 
25    used for all mailslot packets smaller then 425 bytes. 
26
27    "Class 1 mailslots" (which use SMB) are used for messages larger 
28    then 426 bytes and are supported on some systems. These are not implemented
29    in Samba4 yet, as there don't appear to be any core services that use
30    them.
31
32    425 and 426-byte sized messages are not supported at all.
33 */
34
35 #include "includes.h"
36 #include "lib/events/events.h"
37 #include "dlinklist.h"
38 #include "libcli/nbt/libnbt.h"
39 #include "libcli/dgram/libdgram.h"
40 #include "lib/socket/socket.h"
41
42 /*
43   destroy a mailslot handler
44 */
45 static int dgram_mailslot_destructor(void *ptr)
46 {
47         struct dgram_mailslot_handler *dgmslot = 
48                 talloc_get_type(ptr, struct dgram_mailslot_handler);
49         
50         DLIST_REMOVE(dgmslot->dgmsock->mailslot_handlers, dgmslot);
51         return 0;
52 }
53
54 /*
55   start listening on a mailslot. talloc_free() the handle to stop listening
56 */
57 struct dgram_mailslot_handler *dgram_mailslot_listen(struct nbt_dgram_socket *dgmsock,
58                                                      const char *mailslot_name,
59                                                      dgram_mailslot_handler_t handler,
60                                                      void *private)
61 {
62         struct dgram_mailslot_handler *dgmslot;
63
64         dgmslot = talloc(dgmsock, struct dgram_mailslot_handler);
65         if (dgmslot == NULL) return NULL;
66
67         dgmslot->dgmsock = dgmsock;
68         dgmslot->mailslot_name = talloc_strdup(dgmslot, mailslot_name);
69         if (dgmslot->mailslot_name == NULL) {
70                 talloc_free(dgmslot);
71                 return NULL;
72         }
73         dgmslot->handler = handler;
74         dgmslot->private = private;
75
76         DLIST_ADD(dgmsock->mailslot_handlers, dgmslot);
77         talloc_set_destructor(dgmslot, dgram_mailslot_destructor);
78
79         EVENT_FD_READABLE(dgmsock->fde);
80
81         return dgmslot;
82 }
83
84 /*
85   find the handler for a specific mailslot name
86 */
87 struct dgram_mailslot_handler *dgram_mailslot_find(struct nbt_dgram_socket *dgmsock,
88                                                    const char *mailslot_name)
89 {
90         struct dgram_mailslot_handler *h;
91         for (h=dgmsock->mailslot_handlers;h;h=h->next) {
92                 if (strcasecmp(h->mailslot_name, mailslot_name) == 0) {
93                         return h;
94                 }
95         }
96         return NULL;
97 }
98
99 /*
100   check that a datagram packet is a valid mailslot request, and return the 
101   mailslot name if it is, otherwise return NULL
102 */
103 const char *dgram_mailslot_name(struct nbt_dgram_packet *packet)
104 {
105         if (packet->msg_type != DGRAM_DIRECT_UNIQUE &&
106             packet->msg_type != DGRAM_DIRECT_GROUP &&
107             packet->msg_type != DGRAM_BCAST) {
108                 return NULL;
109         }
110         if (packet->data.msg.dgram_body_type != DGRAM_SMB) return NULL;
111         if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
112         return packet->data.msg.body.smb.body.trans.mailslot_name;
113 }
114
115
116 /*
117   create a temporary mailslot handler for a reply mailslot, allocating
118   a new mailslot name using the given base name and a random integer extension
119 */
120 struct dgram_mailslot_handler *dgram_mailslot_temp(struct nbt_dgram_socket *dgmsock,
121                                                    const char *mailslot_name,
122                                                    dgram_mailslot_handler_t handler,
123                                                    void *private)
124 {
125         char *name;
126         int i;
127         struct dgram_mailslot_handler *dgmslot;
128
129         /* try a 100 times at most */
130         for (i=0;i<100;i++) {
131                 name = talloc_asprintf(dgmsock, "%s%03u", 
132                                        mailslot_name,
133                                        generate_random() % 1000);
134                 if (name == NULL) return NULL;
135                 if (dgram_mailslot_find(dgmsock, name)) {
136                         talloc_free(name);
137                         return NULL;
138                 }
139                 dgmslot = dgram_mailslot_listen(dgmsock, name, handler, private);
140                 talloc_free(name);
141                 return dgmslot;
142         }
143         DEBUG(2,("Unable to create temporary mailslot from %s\n", mailslot_name));
144         return NULL;
145 }
146
147
148 /*
149   send a mailslot request
150 */
151 NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
152                              enum dgram_msg_type msg_type,
153                              const char *mailslot_name,
154                              struct nbt_name *dest_name,
155                              const struct nbt_peer_socket *_dest,
156                              struct nbt_name *src_name,
157                              DATA_BLOB *request)
158 {
159         TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
160         struct nbt_dgram_packet packet;
161         struct nbt_peer_socket dest = *_dest;
162         struct dgram_message *msg;
163         struct dgram_smb_packet *smb;
164         struct smb_trans_body *trans;
165         NTSTATUS status;
166
167         if (dest.port == 0) {
168                 dest.port = lp_dgram_port();
169         }
170
171         ZERO_STRUCT(packet);
172         packet.msg_type = msg_type;
173         packet.flags = DGRAM_FLAG_FIRST | DGRAM_NODE_NBDD;
174         packet.dgram_id = generate_random() % UINT16_MAX;
175         packet.src_addr = socket_get_my_addr(dgmsock->sock, tmp_ctx);
176         packet.src_port = socket_get_my_port(dgmsock->sock);
177
178         msg = &packet.data.msg;
179         /* this length calculation is very crude - it should be based on gensize
180            calls */
181         msg->length = 138 + strlen(mailslot_name) + request->length;
182         msg->offset = 0;
183
184         msg->source_name = *src_name;
185         msg->dest_name = *dest_name;
186         msg->dgram_body_type = DGRAM_SMB;
187
188         smb = &msg->body.smb;
189         smb->smb_command = SMB_TRANSACTION;
190
191         trans = &smb->body.trans;
192         trans->total_data_count = request->length;
193         trans->timeout     = 1000;
194         trans->data_count  = request->length;
195         trans->data_offset = 70 + strlen(mailslot_name);
196         trans->opcode      = 1; /* write mail slot */
197         trans->priority    = 1;
198         trans->class       = 2;
199         trans->mailslot_name = mailslot_name;
200         trans->data = *request;
201
202         status = nbt_dgram_send(dgmsock, &packet, &dest);
203
204         talloc_free(tmp_ctx);
205
206         return status;
207 }
208
209 /*
210   return the mailslot data portion from a mailslot packet
211 */
212 DATA_BLOB dgram_mailslot_data(struct nbt_dgram_packet *dgram)
213 {
214         struct smb_trans_body *trans = &dgram->data.msg.body.smb.body.trans;
215         DATA_BLOB ret = trans->data;
216         int pad = trans->data_offset - (70 + strlen(trans->mailslot_name));
217
218         if (pad < 0 || pad > ret.length) {
219                 DEBUG(2,("Badly formatted data in mailslot - pad = %d\n", pad));
220                 return data_blob(NULL, 0);
221         }
222         ret.data += pad;
223         ret.length -= pad;
224         return ret;     
225 }