use the auto-generated UUID, version and name rather than listing them
[mat/samba.git] / source4 / librpc / rpc / dcerpc_smb.c
1 /* 
2    Unix SMB/CIFS implementation.
3    raw dcerpc operations
4
5    Copyright (C) Tim Potter 2003
6    Copyright (C) Andrew Tridgell 2003
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
25
26 /* 
27    open a rpc connection to a named pipe 
28 */
29 NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe *p, 
30                               const char *pipe_name,
31                               const char *pipe_uuid, 
32                               uint32 pipe_version)
33 {
34         NTSTATUS status;
35         char *name = NULL;
36         union smb_open io;
37         TALLOC_CTX *mem_ctx;
38
39         asprintf(&name, "\\%s", pipe_name);
40         if (!name) {
41                 return NT_STATUS_NO_MEMORY;
42         }
43
44         io.ntcreatex.level = RAW_OPEN_NTCREATEX;
45         io.ntcreatex.in.flags = 0;
46         io.ntcreatex.in.root_fid = 0;
47         io.ntcreatex.in.access_mask = 
48                 STD_RIGHT_READ_CONTROL_ACCESS | 
49                 SA_RIGHT_FILE_WRITE_ATTRIBUTES | 
50                 SA_RIGHT_FILE_WRITE_EA | 
51                 GENERIC_RIGHTS_FILE_READ |
52                 GENERIC_RIGHTS_FILE_WRITE;
53         io.ntcreatex.in.file_attr = 0;
54         io.ntcreatex.in.alloc_size = 0;
55         io.ntcreatex.in.share_access = 
56                 NTCREATEX_SHARE_ACCESS_READ |
57                 NTCREATEX_SHARE_ACCESS_WRITE;
58         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
59         io.ntcreatex.in.create_options = 0;
60         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
61         io.ntcreatex.in.security_flags = 0;
62         io.ntcreatex.in.fname = name;
63
64         mem_ctx = talloc_init("torture_rpc_connection");
65         if (!mem_ctx) {
66                 return NT_STATUS_NO_MEMORY;
67         }
68         status = smb_raw_open(p->tree, mem_ctx, &io);
69         free(name);
70         talloc_destroy(mem_ctx);
71
72         if (!NT_STATUS_IS_OK(status)) {
73                 return status;
74         }
75  
76         p->fnum = io.ntcreatex.out.fnum;
77
78         /* bind to the pipe, using the pipe_name as the key */
79         status = dcerpc_bind_byuuid(p, pipe_uuid, pipe_version);
80
81         if (!NT_STATUS_IS_OK(status)) {
82                 union smb_close c;
83                 c.close.level = RAW_CLOSE_CLOSE;
84                 c.close.in.fnum = p->fnum;
85                 c.close.in.write_time = 0;
86                 smb_raw_close(p->tree, &c);
87         }
88
89         return status;
90 }
91
92
93 struct cli_request *dcerpc_raw_send(struct dcerpc_pipe *p, DATA_BLOB *blob)
94 {
95         struct smb_trans2 trans;
96         uint16 setup[2];
97         struct cli_request *req;
98         TALLOC_CTX *mem_ctx;
99
100         mem_ctx = talloc_init("dcerpc_raw_send");
101         if (!mem_ctx) return NULL;
102
103         trans.in.data = *blob;
104         trans.in.params = data_blob(NULL, 0);
105         
106         setup[0] = TRANSACT_DCERPCCMD;
107         setup[1] = p->fnum;
108
109         trans.in.max_param = 0;
110         trans.in.max_data = 0x8000;
111         trans.in.max_setup = 0;
112         trans.in.setup_count = 2;
113         trans.in.flags = 0;
114         trans.in.timeout = 0;
115         trans.in.setup = setup;
116         trans.in.trans_name = "\\PIPE\\";
117
118         req = smb_raw_trans_send(p->tree, &trans);
119
120         talloc_destroy(mem_ctx);
121
122         return req;
123 }
124
125
126 NTSTATUS dcerpc_raw_recv(struct dcerpc_pipe *p, 
127                          struct cli_request *req,
128                          TALLOC_CTX *mem_ctx,
129                          DATA_BLOB *blob)
130 {
131         struct smb_trans2 trans;
132         NTSTATUS status;
133         uint16 frag_length;
134         DATA_BLOB payload;
135
136         status = smb_raw_trans_recv(req, mem_ctx, &trans);
137         /* STATUS_BUFFER_OVERFLOW means that there is more data
138            available via SMBreadX */
139         if (!NT_STATUS_IS_OK(status) && 
140             !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
141                 return status;
142         }
143
144         payload = trans.out.data;
145
146         if (trans.out.data.length < 16 || 
147             !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
148                 goto done;
149         }
150
151         /* we might have recieved a partial fragment, in which case we
152            need to pull the rest of it */
153         frag_length = SVAL(payload.data, 8);
154         if (frag_length <= payload.length) {
155                 goto done;
156         }
157
158         /* make sure the payload can hold the whole fragment */
159         payload.data = talloc_realloc(mem_ctx, payload.data, frag_length);
160         if (!payload.data) {
161                 return NT_STATUS_NO_MEMORY;
162         }
163
164         /* the rest of the data is available via SMBreadX */
165         while (frag_length > payload.length) {
166                 uint32 n;
167                 union smb_read io;
168
169                 n = frag_length - payload.length;
170                 if (n > 0xFF00) {
171                         n = 0xFF00;
172                 }
173
174                 io.generic.level = RAW_READ_READX;
175                 io.readx.in.fnum = p->fnum;
176                 io.readx.in.mincnt = n;
177                 io.readx.in.maxcnt = n;
178                 io.readx.in.offset = 0;
179                 io.readx.in.remaining = 0;
180                 io.readx.out.data = payload.data + payload.length;
181                 status = smb_raw_read(p->tree, &io);
182                 if (!NT_STATUS_IS_OK(status) &&
183                     !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
184                         break;
185                 }
186                 
187                 n = io.readx.out.nread;
188                 if (n == 0) {
189                         status = NT_STATUS_UNSUCCESSFUL;
190                         break;
191                 }
192                 
193                 payload.length += n;
194
195                 /* if the SMBreadX returns NT_STATUS_OK then there
196                    isn't any more data to be read */
197                 if (NT_STATUS_IS_OK(status)) {
198                         break;
199                 }
200         }
201
202 done:
203         if (blob) {
204                 *blob = payload;
205         }
206
207         return status;
208 }
209
210 NTSTATUS dcerpc_raw_packet(struct dcerpc_pipe *p, 
211                            TALLOC_CTX *mem_ctx,
212                            DATA_BLOB *request_blob,
213                            DATA_BLOB *reply_blob)
214 {
215         struct cli_request *req;
216         req = dcerpc_raw_send(p, request_blob);
217         return dcerpc_raw_recv(p, req, mem_ctx, reply_blob);
218 }
219               
220
221 /* 
222    retrieve a secondary pdu from a pipe 
223 */
224 NTSTATUS dcerpc_raw_packet_secondary(struct dcerpc_pipe *p, 
225                                      TALLOC_CTX *mem_ctx,
226                                      DATA_BLOB *blob)
227 {
228         union smb_read io;
229         uint32 n = 0x2000;
230         uint32 frag_length;
231         NTSTATUS status;
232
233         *blob = data_blob_talloc(mem_ctx, NULL, n);
234         if (!blob->data) {
235                 return NT_STATUS_NO_MEMORY;
236         }
237
238         io.generic.level = RAW_READ_READX;
239         io.readx.in.fnum = p->fnum;
240         io.readx.in.mincnt = n;
241         io.readx.in.maxcnt = n;
242         io.readx.in.offset = 0;
243         io.readx.in.remaining = 0;
244         io.readx.out.data = blob->data;
245
246         status = smb_raw_read(p->tree, &io);
247         if (!NT_STATUS_IS_OK(status) &&
248             !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
249                 return status;
250         }
251
252         blob->length = io.readx.out.nread;
253
254         if (blob->length < 16) {
255                 return status;
256         }
257
258         frag_length = SVAL(blob->data, 8);
259         if (frag_length <= blob->length) {
260                 return status;
261         }
262
263         blob->data = talloc_realloc(mem_ctx, blob->data, frag_length);
264         if (!blob->data) {
265                 return NT_STATUS_NO_MEMORY;
266         }
267
268         while (frag_length > blob->length &&
269                NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
270
271                 n = frag_length - blob->length;
272                 if (n > 0xFF00) {
273                         n = 0xFF00;
274                 }
275
276                 io.readx.in.mincnt = n;
277                 io.readx.in.maxcnt = n;
278                 io.readx.out.data = blob->data + blob->length;
279                 status = smb_raw_read(p->tree, &io);
280
281                 if (!NT_STATUS_IS_OK(status) &&
282                     !NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
283                         return status;
284                 }
285                 
286                 n = io.readx.out.nread;
287                 blob->length += n;
288         }
289
290         return status;
291 }
292
293
294 /* 
295    send an initial pdu in a multi-pdu sequence
296 */
297 NTSTATUS dcerpc_raw_packet_initial(struct dcerpc_pipe *p, 
298                                    TALLOC_CTX *mem_ctx,
299                                    DATA_BLOB *blob)
300 {
301         union smb_write io;
302         NTSTATUS status;
303
304         io.generic.level = RAW_WRITE_WRITEX;
305         io.writex.in.fnum = p->fnum;
306         io.writex.in.offset = 0;
307         io.writex.in.wmode = PIPE_START_MESSAGE;
308         io.writex.in.remaining = blob->length;
309         io.writex.in.count = blob->length;
310         io.writex.in.data = blob->data;
311
312         status = smb_raw_write(p->tree, &io);
313         if (NT_STATUS_IS_OK(status)) {
314                 return status;
315         }
316
317         /* make sure it accepted it all */
318         if (io.writex.out.nwritten != blob->length) {
319                 return NT_STATUS_UNSUCCESSFUL;
320         }
321
322         return status;
323 }