the next step in the dcerpc server code. Added the link between the
[metze/samba-autobuild/.git] / source4 / ntvfs / ipc / vfs_ipc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    default IPC$ NTVFS backend
4    Copyright (C) Andrew Tridgell 2003
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 /*
21   this implements the IPC$ backend, called by the NTVFS subsystem to
22   handle requests on IPC$ shares
23 */
24
25
26 #include "includes.h"
27
28 /* this is the private structure used to keep the state of an open
29    ipc$ connection. It needs to keep information about all open
30    pipes */
31 struct ipc_private {
32
33         uint16 next_fnum;
34         uint16 num_open;
35
36         /* a list of open pipes */
37         struct pipe_state {
38                 struct pipe_state *next, *prev;
39                 TALLOC_CTX *mem_ctx;
40                 const char *pipe_name;
41                 uint16 fnum;
42                 struct dcesrv_state *pipe_state;
43         } *pipe_list;
44
45 };
46
47
48 /*
49   find the next fnum available on this connection
50 */
51 static uint16 find_next_fnum(struct ipc_private *ipc)
52 {
53         struct pipe_state *p;
54         uint32 ret;
55
56         if (ipc->num_open == 0xFFFF) {
57                 return 0;
58         }
59
60 again:
61         ret = ipc->next_fnum++;
62
63         for (p=ipc->pipe_list; p; p=p->next) {
64                 if (p->fnum == ret) {
65                         goto again;
66                 }
67         }
68
69         return ret;
70 }
71
72
73 /*
74   shutdown a single pipe. Called on a close or disconnect
75 */
76 static void pipe_shutdown(struct ipc_private *private, struct pipe_state *p)
77 {
78         TALLOC_CTX *mem_ctx = private->pipe_list->mem_ctx;
79         dcesrv_endpoint_disconnect(private->pipe_list->pipe_state);
80         DLIST_REMOVE(private->pipe_list, private->pipe_list);
81         talloc_destroy(mem_ctx);
82 }
83
84
85 /*
86   find a open pipe give a file descriptor
87 */
88 static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16 fnum)
89 {
90         struct pipe_state *p;
91         
92         for (p=private->pipe_list; p; p=p->next) {
93                 if (p->fnum == fnum) {
94                         return p;
95                 }
96         }
97
98         return NULL;
99 }
100
101
102 /*
103   connect to a share - always works 
104 */
105 static NTSTATUS ipc_connect(struct request_context *req, const char *sharename)
106 {
107         struct tcon_context *conn = req->conn;
108         struct ipc_private *private;
109
110         conn->fs_type = talloc_strdup(conn->mem_ctx, "IPC");
111         conn->dev_type = talloc_strdup(conn->mem_ctx, "IPC");
112
113         /* prepare the private state for this connection */
114         private = talloc(conn->mem_ctx, sizeof(struct ipc_private));
115         if (!private) {
116                 return NT_STATUS_NO_MEMORY;
117         }
118         conn->ntvfs_private = (void *)private;
119
120         private->pipe_list = NULL;
121         private->next_fnum = 1;
122         private->num_open = 0;
123
124         return NT_STATUS_OK;
125 }
126
127 /*
128   disconnect from a share
129 */
130 static NTSTATUS ipc_disconnect(struct tcon_context *tcon)
131 {
132         struct ipc_private *private = tcon->ntvfs_private;
133
134         /* close any pipes that are open. Discard any unread data */
135         while (private->pipe_list) {
136                 pipe_shutdown(private, private->pipe_list);
137         }
138
139         return NT_STATUS_OK;
140 }
141
142 /*
143   delete a file
144 */
145 static NTSTATUS ipc_unlink(struct request_context *req, struct smb_unlink *unl)
146 {
147         return NT_STATUS_ACCESS_DENIED;
148 }
149
150
151 /*
152   ioctl interface - we don't do any
153 */
154 static NTSTATUS ipc_ioctl(struct request_context *req, union smb_ioctl *io)
155 {
156         return NT_STATUS_ACCESS_DENIED;
157 }
158
159 /*
160   check if a directory exists
161 */
162 static NTSTATUS ipc_chkpath(struct request_context *req, struct smb_chkpath *cp)
163 {
164         return NT_STATUS_ACCESS_DENIED;
165 }
166
167 /*
168   return info on a pathname
169 */
170 static NTSTATUS ipc_qpathinfo(struct request_context *req, union smb_fileinfo *info)
171 {
172         return NT_STATUS_ACCESS_DENIED;
173 }
174
175 /*
176   set info on a pathname
177 */
178 static NTSTATUS ipc_setpathinfo(struct request_context *req, union smb_setfileinfo *st)
179 {
180         return NT_STATUS_ACCESS_DENIED;
181 }
182
183 /*
184   open a file - used for MSRPC pipes
185 */
186 static NTSTATUS ipc_open(struct request_context *req, union smb_open *oi)
187 {
188         struct pipe_state *p;
189         TALLOC_CTX *mem_ctx;
190         NTSTATUS status;
191         struct dcesrv_endpoint endpoint;
192         struct ipc_private *private = req->conn->ntvfs_private;
193
194         /* for now only handle NTcreateX style opens */
195         if (oi->generic.level != RAW_OPEN_NTCREATEX) {
196                 return NT_STATUS_ACCESS_DENIED;
197         }
198
199         mem_ctx = talloc_init("ipc_open '%s'", oi->ntcreatex.in.fname);
200         if (!mem_ctx) {
201                 return NT_STATUS_NO_MEMORY;
202         }
203
204         p = talloc(mem_ctx, sizeof(struct pipe_state));
205         if (!p) {
206                 talloc_destroy(mem_ctx);
207                 return NT_STATUS_NO_MEMORY;
208         }
209         p->mem_ctx = mem_ctx;
210
211         p->pipe_name = talloc_strdup(mem_ctx, oi->ntcreatex.in.fname);
212         if (!p->pipe_name) {
213                 talloc_destroy(mem_ctx);
214                 return NT_STATUS_NO_MEMORY;
215         }
216
217         p->fnum = find_next_fnum(private);
218         if (p->fnum == 0) {
219                 talloc_destroy(mem_ctx);
220                 return NT_STATUS_TOO_MANY_OPENED_FILES;
221         }
222
223         while (p->pipe_name[0] == '\\') {
224                 p->pipe_name++;
225         }
226
227         /*
228           we're all set, now ask the dcerpc server subsystem to open the 
229           endpoint. At this stage the pipe isn't bound, so we don't
230           know what interface the user actually wants, just that they want
231           one of the interfaces attached to this pipe endpoint.
232
233           TODO: note that we aren't passing any credentials here. We
234           will need to do that once the credentials infrastructure is
235           finalised for Samba4
236         */
237
238         endpoint.type = ENDPOINT_SMB;
239         endpoint.info.smb_pipe = p->pipe_name;
240
241         status = dcesrv_endpoint_connect(req->smb, &endpoint, &p->pipe_state);
242         if (!NT_STATUS_IS_OK(status)) {
243                 talloc_destroy(mem_ctx);
244                 return status;
245         }
246
247         private->num_open++;
248
249         DLIST_ADD(private->pipe_list, p);
250
251         ZERO_STRUCT(oi->ntcreatex.out);
252         oi->ntcreatex.out.fnum = p->fnum;
253
254         return NT_STATUS_OK;
255 }
256
257 /*
258   create a directory
259 */
260 static NTSTATUS ipc_mkdir(struct request_context *req, union smb_mkdir *md)
261 {
262         return NT_STATUS_ACCESS_DENIED;
263 }
264
265 /*
266   remove a directory
267 */
268 static NTSTATUS ipc_rmdir(struct request_context *req, struct smb_rmdir *rd)
269 {
270         return NT_STATUS_ACCESS_DENIED;
271 }
272
273 /*
274   rename a set of files
275 */
276 static NTSTATUS ipc_rename(struct request_context *req, union smb_rename *ren)
277 {
278         return NT_STATUS_ACCESS_DENIED;
279 }
280
281 /*
282   copy a set of files
283 */
284 static NTSTATUS ipc_copy(struct request_context *req, struct smb_copy *cp)
285 {
286         return NT_STATUS_ACCESS_DENIED;
287 }
288
289 /*
290   read from a file
291 */
292 static NTSTATUS ipc_read(struct request_context *req, union smb_read *rd)
293 {
294         struct ipc_private *private = req->conn->ntvfs_private;
295         DATA_BLOB data;
296         uint16 fnum;
297         struct pipe_state *p;
298         NTSTATUS status;
299
300         switch (rd->generic.level) {
301         case RAW_READ_READ:
302                 fnum = rd->read.in.fnum;
303                 data.length = rd->read.in.count;
304                 data.data = rd->read.out.data;
305                 break;
306         case RAW_READ_READX:
307                 fnum = rd->readx.in.fnum;
308                 data.length = rd->readx.in.maxcnt;
309                 data.data = rd->readx.out.data;
310                 break;
311         default:
312                 return NT_STATUS_NOT_SUPPORTED;
313         }
314
315         p = pipe_state_find(private, fnum);
316         if (!p) {
317                 return NT_STATUS_INVALID_HANDLE;
318         }
319
320         status = dcesrv_output(p->pipe_state, &data);
321         if (!NT_STATUS_IS_OK(status)) {
322                 return status;
323         }
324
325         switch (rd->generic.level) {
326         case RAW_READ_READ:
327                 rd->read.out.nread = data.length;
328                 break;
329         case RAW_READ_READX:
330                 rd->readx.out.remaining = 0;
331                 rd->readx.out.compaction_mode = 0;
332                 rd->readx.out.nread = data.length;
333                 break;
334         default:
335                 return NT_STATUS_NOT_SUPPORTED;
336         }
337
338         return NT_STATUS_OK;
339 }
340
341 /*
342   write to a file
343 */
344 static NTSTATUS ipc_write(struct request_context *req, union smb_write *wr)
345 {
346         struct ipc_private *private = req->conn->ntvfs_private;
347         DATA_BLOB data;
348         uint16 fnum;
349         struct pipe_state *p;
350         NTSTATUS status;
351
352         switch (wr->generic.level) {
353         case RAW_WRITE_WRITE:
354                 fnum = wr->write.in.fnum;
355                 data.data = wr->write.in.data;
356                 data.length = wr->write.in.count;
357                 break;
358
359         case RAW_WRITE_WRITEX:
360                 fnum = wr->writex.in.fnum;
361                 data.data = wr->writex.in.data;
362                 data.length = wr->writex.in.count;
363                 break;
364
365         default:
366                 return NT_STATUS_NOT_SUPPORTED;
367         }
368
369         p = pipe_state_find(private, fnum);
370         if (!p) {
371                 return NT_STATUS_INVALID_HANDLE;
372         }
373
374         status = dcesrv_input(p->pipe_state, &data);
375         if (!NT_STATUS_IS_OK(status)) {
376                 return status;
377         }
378
379         switch (wr->generic.level) {
380         case RAW_WRITE_WRITE:
381                 wr->write.out.nwritten = data.length;
382                 break;
383         case RAW_WRITE_WRITEX:
384                 wr->writex.out.nwritten = data.length;
385                 wr->writex.out.remaining = 0;
386                 break;
387         default:
388                 return NT_STATUS_NOT_SUPPORTED;
389         }
390
391         return NT_STATUS_OK;
392 }
393
394 /*
395   seek in a file
396 */
397 static NTSTATUS ipc_seek(struct request_context *req, struct smb_seek *io)
398 {
399         return NT_STATUS_ACCESS_DENIED;
400 }
401
402 /*
403   flush a file
404 */
405 static NTSTATUS ipc_flush(struct request_context *req, struct smb_flush *io)
406 {
407         return NT_STATUS_ACCESS_DENIED;
408 }
409
410 /*
411   close a file
412 */
413 static NTSTATUS ipc_close(struct request_context *req, union smb_close *io)
414 {
415         struct ipc_private *private = req->conn->ntvfs_private;
416         struct pipe_state *p;
417
418         if (io->generic.level != RAW_CLOSE_CLOSE) {
419                 return NT_STATUS_ACCESS_DENIED;
420         }
421
422         p = pipe_state_find(private, io->close.in.fnum);
423         if (!p) {
424                 return NT_STATUS_INVALID_HANDLE;
425         }
426
427         pipe_shutdown(private, p);
428         private->num_open--;
429
430         return NT_STATUS_OK;
431 }
432
433 /*
434   exit - closing files?
435 */
436 static NTSTATUS ipc_exit(struct request_context *req)
437 {
438         return NT_STATUS_ACCESS_DENIED;
439 }
440
441 /*
442   lock a byte range
443 */
444 static NTSTATUS ipc_lock(struct request_context *req, union smb_lock *lck)
445 {
446         return NT_STATUS_ACCESS_DENIED;
447 }
448
449 /*
450   set info on a open file
451 */
452 static NTSTATUS ipc_setfileinfo(struct request_context *req, union smb_setfileinfo *info)
453 {
454         return NT_STATUS_ACCESS_DENIED;
455 }
456
457 /*
458   query info on a open file
459 */
460 static NTSTATUS ipc_qfileinfo(struct request_context *req, union smb_fileinfo *info)
461 {
462         return NT_STATUS_ACCESS_DENIED;
463 }
464
465
466 /*
467   return filesystem info
468 */
469 static NTSTATUS ipc_fsinfo(struct request_context *req, union smb_fsinfo *fs)
470 {
471         return NT_STATUS_ACCESS_DENIED;
472 }
473
474 /*
475   return print queue info
476 */
477 static NTSTATUS ipc_lpq(struct request_context *req, union smb_lpq *lpq)
478 {
479         return NT_STATUS_ACCESS_DENIED;
480 }
481
482 /* 
483    list files in a directory matching a wildcard pattern
484 */
485 NTSTATUS ipc_search_first(struct request_context *req, union smb_search_first *io,
486                           void *search_private, 
487                           BOOL (*callback)(void *, union smb_search_data *))
488 {
489         return NT_STATUS_ACCESS_DENIED;
490 }
491
492 /* 
493    continue listing files in a directory 
494 */
495 NTSTATUS ipc_search_next(struct request_context *req, union smb_search_next *io,
496                          void *search_private, 
497                          BOOL (*callback)(void *, union smb_search_data *))
498 {
499         return NT_STATUS_ACCESS_DENIED;
500 }
501
502 /* 
503    end listing files in a directory 
504 */
505 NTSTATUS ipc_search_close(struct request_context *req, union smb_search_close *io)
506 {
507         return NT_STATUS_ACCESS_DENIED;
508 }
509
510
511 /* SMBtrans - used to provide access to SMB pipes */
512 static NTSTATUS ipc_trans(struct request_context *req, struct smb_trans2 *trans)
513 {
514         struct pipe_state *p;
515         struct ipc_private *private = req->conn->ntvfs_private;
516         NTSTATUS status;
517         
518         if (trans->in.setup_count != 2 ||
519             trans->in.setup[0] != TRANSACT_DCERPCCMD) {
520                 return NT_STATUS_INVALID_PARAMETER;
521         }
522
523         /* the fnum is in setup[1] */
524         p = pipe_state_find(private, trans->in.setup[1]);
525         if (!p) {
526                 return NT_STATUS_INVALID_HANDLE;
527         }
528
529         /* pass the data to the dcerpc server. Note that we don't
530            expect this to fail, and things like NDR faults are not
531            reported at this stage. Those sorts of errors happen in the
532            dcesrv_output stage */
533         status = dcesrv_input(p->pipe_state, &trans->in.data);
534         if (!NT_STATUS_IS_OK(status)) {
535                 return status;
536         }
537
538         /*
539           now ask the dcerpc system for some output. This doesn't yet handle
540           async calls. Again, we only expect NT_STATUS_OK. If the call fails then
541           the error is encoded at the dcerpc level
542         */
543         status = dcesrv_output(p->pipe_state, &trans->out.data);
544         if (!NT_STATUS_IS_OK(status)) {
545                 return status;
546         }
547
548         trans->out.setup_count = 0;
549         trans->out.setup = NULL;
550         trans->out.params = data_blob(NULL, 0);
551
552         return NT_STATUS_OK;
553 }
554
555
556
557 /*
558   initialialise the IPC backend, registering ourselves with the ntvfs subsystem
559  */
560 NTSTATUS ntvfs_ipc_init(void)
561 {
562         NTSTATUS ret;
563         struct ntvfs_ops ops;
564
565         ZERO_STRUCT(ops);
566         
567         /* fill in all the operations */
568         ops.name = "ipc";
569         ops.type = NTVFS_IPC;
570         ops.connect = ipc_connect;
571         ops.disconnect = ipc_disconnect;
572         ops.unlink = ipc_unlink;
573         ops.chkpath = ipc_chkpath;
574         ops.qpathinfo = ipc_qpathinfo;
575         ops.setpathinfo = ipc_setpathinfo;
576         ops.open = ipc_open;
577         ops.mkdir = ipc_mkdir;
578         ops.rmdir = ipc_rmdir;
579         ops.rename = ipc_rename;
580         ops.copy = ipc_copy;
581         ops.ioctl = ipc_ioctl;
582         ops.read = ipc_read;
583         ops.write = ipc_write;
584         ops.seek = ipc_seek;
585         ops.flush = ipc_flush;  
586         ops.close = ipc_close;
587         ops.exit = ipc_exit;
588         ops.lock = ipc_lock;
589         ops.setfileinfo = ipc_setfileinfo;
590         ops.qfileinfo = ipc_qfileinfo;
591         ops.fsinfo = ipc_fsinfo;
592         ops.lpq = ipc_lpq;
593         ops.search_first = ipc_search_first;
594         ops.search_next = ipc_search_next;
595         ops.search_close = ipc_search_close;
596         ops.trans = ipc_trans;
597
598         /* register ourselves with the NTVFS subsystem. */
599         ret = register_backend("ntvfs", &ops);
600
601         if (!NT_STATUS_IS_OK(ret)) {
602                 DEBUG(0,("Failed to register IPC backend!\n"));
603                 return ret;
604         }
605
606         return ret;
607 }