r6320: some minor netlogon datagram fixes - NT4 can now join a Samba4 domain without
[samba.git] / source / 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 #include "includes.h"
24 #include "lib/events/events.h"
25 #include "dlinklist.h"
26 #include "libcli/nbt/libnbt.h"
27 #include "libcli/dgram/libdgram.h"
28 #include "lib/socket/socket.h"
29
30 /*
31   destroy a mailslot handler
32 */
33 static int dgram_mailslot_destructor(void *ptr)
34 {
35         struct dgram_mailslot_handler *dgmslot = 
36                 talloc_get_type(ptr, struct dgram_mailslot_handler);
37         
38         DLIST_REMOVE(dgmslot->dgmsock->mailslot_handlers, dgmslot);
39         return 0;
40 }
41
42 /*
43   start listening on a mailslot. talloc_free() the handle to stop listening
44 */
45 struct dgram_mailslot_handler *dgram_mailslot_listen(struct nbt_dgram_socket *dgmsock,
46                                                      const char *mailslot_name,
47                                                      dgram_mailslot_handler_t handler,
48                                                      void *private)
49 {
50         struct dgram_mailslot_handler *dgmslot;
51
52         dgmslot = talloc(dgmsock, struct dgram_mailslot_handler);
53         if (dgmslot == NULL) return NULL;
54
55         dgmslot->dgmsock = dgmsock;
56         dgmslot->mailslot_name = talloc_strdup(dgmslot, mailslot_name);
57         if (dgmslot->mailslot_name == NULL) {
58                 talloc_free(dgmslot);
59                 return NULL;
60         }
61         dgmslot->handler = handler;
62         dgmslot->private = private;
63
64         DLIST_ADD(dgmsock->mailslot_handlers, dgmslot);
65         talloc_set_destructor(dgmslot, dgram_mailslot_destructor);
66
67         EVENT_FD_READABLE(dgmsock->fde);
68
69         return dgmslot;
70 }
71
72 /*
73   find the handler for a specific mailslot name
74 */
75 struct dgram_mailslot_handler *dgram_mailslot_find(struct nbt_dgram_socket *dgmsock,
76                                                    const char *mailslot_name)
77 {
78         struct dgram_mailslot_handler *h;
79         for (h=dgmsock->mailslot_handlers;h;h=h->next) {
80                 if (strcasecmp(h->mailslot_name, mailslot_name) == 0) {
81                         return h;
82                 }
83         }
84         return NULL;
85 }
86
87 /*
88   check that a datagram packet is a valid mailslot request, and return the 
89   mailslot name if it is, otherwise return NULL
90 */
91 const char *dgram_mailslot_name(struct nbt_dgram_packet *packet)
92 {
93         if (packet->msg_type != DGRAM_DIRECT_UNIQUE &&
94             packet->msg_type != DGRAM_DIRECT_GROUP &&
95             packet->msg_type != DGRAM_BCAST) {
96                 return NULL;
97         }
98         if (packet->data.msg.dgram_body_type != DGRAM_SMB) return NULL;
99         if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
100         if (packet->data.msg.body.smb.smb_command != SMB_TRANSACTION) return NULL;
101         return packet->data.msg.body.smb.body.trans.mailslot_name;
102 }
103
104
105 /*
106   create a temporary mailslot handler for a reply mailslot, allocating
107   a new mailslot name using the given base name and a random integer extension
108 */
109 struct dgram_mailslot_handler *dgram_mailslot_temp(struct nbt_dgram_socket *dgmsock,
110                                                    const char *mailslot_name,
111                                                    dgram_mailslot_handler_t handler,
112                                                    void *private)
113 {
114         char *name;
115         int i;
116         struct dgram_mailslot_handler *dgmslot;
117
118         /* try a 100 times at most */
119         for (i=0;i<100;i++) {
120                 name = talloc_asprintf(dgmsock, "%s%03u", 
121                                        mailslot_name,
122                                        generate_random() % 1000);
123                 if (name == NULL) return NULL;
124                 if (dgram_mailslot_find(dgmsock, name)) {
125                         talloc_free(name);
126                         return NULL;
127                 }
128                 dgmslot = dgram_mailslot_listen(dgmsock, name, handler, private);
129                 talloc_free(name);
130                 return dgmslot;
131         }
132         DEBUG(2,("Unable to create temporary mailslot from %s\n", mailslot_name));
133         return NULL;
134 }
135
136
137 /*
138   send a mailslot request
139 */
140 NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
141                              enum dgram_msg_type msg_type,
142                              const char *mailslot_name,
143                              struct nbt_name *dest_name,
144                              const char *dest_address,
145                              int dest_port,
146                              struct nbt_name *src_name,
147                              DATA_BLOB *request)
148 {
149         TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
150         struct nbt_dgram_packet packet;
151         struct dgram_message *msg;
152         struct dgram_smb_packet *smb;
153         struct smb_trans_body *trans;
154         NTSTATUS status;
155
156         if (dest_port == 0) {
157                 dest_port = lp_dgram_port();
158         }
159
160         ZERO_STRUCT(packet);
161         packet.msg_type = msg_type;
162         packet.flags = DGRAM_FLAG_FIRST | DGRAM_NODE_NBDD;
163         packet.dgram_id = generate_random() % UINT16_MAX;
164         packet.source = socket_get_my_addr(dgmsock->sock, tmp_ctx);
165         packet.src_port = socket_get_my_port(dgmsock->sock);
166
167         msg = &packet.data.msg;
168         /* this length calculation is very crude - it should be based on gensize
169            calls */
170         msg->length = 138 + strlen(mailslot_name) + request->length; 
171         msg->offset = 0;
172
173         msg->source_name = *src_name;
174         msg->dest_name = *dest_name;
175         msg->dgram_body_type = DGRAM_SMB;
176
177         smb = &msg->body.smb;
178         smb->smb_command = SMB_TRANSACTION;
179
180         trans = &smb->body.trans;
181         trans->total_data_count = request->length;
182         trans->timeout     = 1000;
183         trans->data_count  = request->length;
184         trans->data_offset = 70 + strlen(mailslot_name);
185         trans->opcode      = 1; /* write mail slot */
186         trans->priority    = 1;
187         trans->class       = 2;
188         trans->mailslot_name = mailslot_name;
189         trans->data = *request;
190
191         status = nbt_dgram_send(dgmsock, &packet, dest_address, dest_port);
192
193         talloc_free(tmp_ctx);
194
195         return status;
196 }