1c02e8fadc8498eb08dc2b57d28cedf1c8016b86
[nivanova/samba-autobuild/.git] / source / ntvfs / ipc / vfs_ipc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    default IPC$ NTVFS backend
4
5    Copyright (C) Andrew Tridgell 2003
6    Copyright (C) Stefan (metze) Metzmacher 2004
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   this implements the IPC$ backend, called by the NTVFS subsystem to
24   handle requests on IPC$ shares
25 */
26
27
28 #include "includes.h"
29
30 /* this is the private structure used to keep the state of an open
31    ipc$ connection. It needs to keep information about all open
32    pipes */
33 struct ipc_private {
34
35         uint16 next_fnum;
36         uint16 num_open;
37
38         /* a list of open pipes */
39         struct pipe_state {
40                 struct pipe_state *next, *prev;
41                 TALLOC_CTX *mem_ctx;
42                 const char *pipe_name;
43                 uint16 fnum;
44                 struct dcesrv_connection *dce_conn;
45                 uint16 ipc_state;
46         } *pipe_list;
47
48 };
49
50
51 /*
52   find the next fnum available on this connection
53 */
54 static uint16 find_next_fnum(struct ipc_private *ipc)
55 {
56         struct pipe_state *p;
57         uint32 ret;
58
59         if (ipc->num_open == 0xFFFF) {
60                 return 0;
61         }
62
63 again:
64         ret = ipc->next_fnum++;
65
66         for (p=ipc->pipe_list; p; p=p->next) {
67                 if (p->fnum == ret) {
68                         goto again;
69                 }
70         }
71
72         return ret;
73 }
74
75
76 /*
77   shutdown a single pipe. Called on a close or disconnect
78 */
79 static void pipe_shutdown(struct ipc_private *private, struct pipe_state *p)
80 {
81         TALLOC_CTX *mem_ctx = private->pipe_list->mem_ctx;
82         dcesrv_endpoint_disconnect(private->pipe_list->dce_conn);
83         DLIST_REMOVE(private->pipe_list, private->pipe_list);
84         talloc_destroy(mem_ctx);
85 }
86
87
88 /*
89   find a open pipe give a file descriptor
90 */
91 static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16 fnum)
92 {
93         struct pipe_state *p;
94         
95         for (p=private->pipe_list; p; p=p->next) {
96                 if (p->fnum == fnum) {
97                         return p;
98                 }
99         }
100
101         return NULL;
102 }
103
104
105 /*
106   connect to a share - always works 
107 */
108 static NTSTATUS ipc_connect(struct request_context *req, const char *sharename)
109 {
110         struct tcon_context *conn = req->conn;
111         struct ipc_private *private;
112
113         conn->fs_type = talloc_strdup(conn->mem_ctx, "IPC");
114         conn->dev_type = talloc_strdup(conn->mem_ctx, "IPC");
115
116         /* prepare the private state for this connection */
117         private = talloc(conn->mem_ctx, sizeof(struct ipc_private));
118         if (!private) {
119                 return NT_STATUS_NO_MEMORY;
120         }
121         conn->ntvfs_private = (void *)private;
122
123         private->pipe_list = NULL;
124         private->next_fnum = 1;
125         private->num_open = 0;
126
127         return NT_STATUS_OK;
128 }
129
130 /*
131   disconnect from a share
132 */
133 static NTSTATUS ipc_disconnect(struct tcon_context *tcon)
134 {
135         struct ipc_private *private = tcon->ntvfs_private;
136
137         /* close any pipes that are open. Discard any unread data */
138         while (private->pipe_list) {
139                 pipe_shutdown(private, private->pipe_list);
140         }
141
142         return NT_STATUS_OK;
143 }
144
145 /*
146   delete a file
147 */
148 static NTSTATUS ipc_unlink(struct request_context *req, struct smb_unlink *unl)
149 {
150         return NT_STATUS_ACCESS_DENIED;
151 }
152
153
154 /*
155   ioctl interface - we don't do any
156 */
157 static NTSTATUS ipc_ioctl(struct request_context *req, union smb_ioctl *io)
158 {
159         return NT_STATUS_ACCESS_DENIED;
160 }
161
162 /*
163   check if a directory exists
164 */
165 static NTSTATUS ipc_chkpath(struct request_context *req, struct smb_chkpath *cp)
166 {
167         return NT_STATUS_ACCESS_DENIED;
168 }
169
170 /*
171   return info on a pathname
172 */
173 static NTSTATUS ipc_qpathinfo(struct request_context *req, union smb_fileinfo *info)
174 {
175         return NT_STATUS_ACCESS_DENIED;
176 }
177
178 /*
179   set info on a pathname
180 */
181 static NTSTATUS ipc_setpathinfo(struct request_context *req, union smb_setfileinfo *st)
182 {
183         return NT_STATUS_ACCESS_DENIED;
184 }
185
186
187
188 /*
189   open a file backend - used for MSRPC pipes
190 */
191 static NTSTATUS ipc_open_generic(struct request_context *req, const char *fname, 
192                                  struct pipe_state **ps)
193 {
194         struct pipe_state *p;
195         TALLOC_CTX *mem_ctx;
196         NTSTATUS status;
197         struct dcesrv_ep_description ep_description;
198         struct ipc_private *private = req->conn->ntvfs_private;
199
200         mem_ctx = talloc_init("ipc_open '%s'", fname);
201         if (!mem_ctx) {
202                 return NT_STATUS_NO_MEMORY;
203         }
204
205         p = talloc(mem_ctx, sizeof(struct pipe_state));
206         if (!p) {
207                 talloc_destroy(mem_ctx);
208                 return NT_STATUS_NO_MEMORY;
209         }
210         p->mem_ctx = mem_ctx;
211
212         p->pipe_name = talloc_strdup(mem_ctx, fname);
213         if (!p->pipe_name) {
214                 talloc_destroy(mem_ctx);
215                 return NT_STATUS_NO_MEMORY;
216         }
217
218         p->fnum = find_next_fnum(private);
219         if (p->fnum == 0) {
220                 talloc_destroy(mem_ctx);
221                 return NT_STATUS_TOO_MANY_OPENED_FILES;
222         }
223
224         while (p->pipe_name[0] == '\\') {
225                 p->pipe_name++;
226         }
227         p->ipc_state = 0x5ff;
228
229         /*
230           we're all set, now ask the dcerpc server subsystem to open the 
231           endpoint. At this stage the pipe isn't bound, so we don't
232           know what interface the user actually wants, just that they want
233           one of the interfaces attached to this pipe endpoint.
234
235           TODO: note that we aren't passing any credentials here. We
236           will need to do that once the credentials infrastructure is
237           finalised for Samba4
238         */
239
240         ep_description.type = ENDPOINT_SMB;
241         ep_description.info.smb_pipe = p->pipe_name;
242
243         status = dcesrv_endpoint_search_connect(&req->smb->dcesrv, &ep_description, &p->dce_conn);
244         if (!NT_STATUS_IS_OK(status)) {
245                 talloc_destroy(mem_ctx);
246                 return status;
247         }
248
249         private->num_open++;
250
251         DLIST_ADD(private->pipe_list, p);
252
253         *ps = p;
254
255         /* tell the RPC layer the transport session key */
256         if (req->user_ctx->vuser) {
257                 dcesrv_set_session_key(p->dce_conn, req->user_ctx->vuser->session_key);
258         }
259
260         return NT_STATUS_OK;
261 }
262
263 /*
264   open a file with ntcreatex - used for MSRPC pipes
265 */
266 static NTSTATUS ipc_open_ntcreatex(struct request_context *req, union smb_open *oi)
267 {
268         struct pipe_state *p;
269         NTSTATUS status;
270
271         status = ipc_open_generic(req, oi->ntcreatex.in.fname, &p);
272         if (!NT_STATUS_IS_OK(status)) {
273                 return status;
274         }
275
276         ZERO_STRUCT(oi->ntcreatex.out);
277         oi->ntcreatex.out.fnum = p->fnum;
278         oi->ntcreatex.out.ipc_state = p->ipc_state;
279
280         return status;
281 }
282
283 /*
284   open a file with openx - used for MSRPC pipes
285 */
286 static NTSTATUS ipc_open_openx(struct request_context *req, union smb_open *oi)
287 {
288         struct pipe_state *p;
289         NTSTATUS status;
290         const char *fname = oi->openx.in.fname;
291
292         if (strncasecmp(fname, "PIPE\\", 5) != 0) {
293                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
294         }
295
296         fname += 4;
297
298         status = ipc_open_generic(req, fname, &p);
299         if (!NT_STATUS_IS_OK(status)) {
300                 return status;
301         }
302
303         ZERO_STRUCT(oi->openx.out);
304         oi->openx.out.fnum = p->fnum;
305         oi->openx.out.ftype = 2;
306         oi->openx.out.devstate = p->ipc_state;
307         
308         return status;
309 }
310
311 /*
312   open a file - used for MSRPC pipes
313 */
314 static NTSTATUS ipc_open(struct request_context *req, union smb_open *oi)
315 {
316         NTSTATUS status;
317
318         switch (oi->generic.level) {
319         case RAW_OPEN_NTCREATEX:
320                 status = ipc_open_ntcreatex(req, oi);
321                 break;
322         case RAW_OPEN_OPENX:
323                 status = ipc_open_openx(req, oi);
324                 break;
325         default:
326                 status = NT_STATUS_NOT_SUPPORTED;
327                 break;
328         }
329
330         return status;
331 }
332
333 /*
334   create a directory
335 */
336 static NTSTATUS ipc_mkdir(struct request_context *req, union smb_mkdir *md)
337 {
338         return NT_STATUS_ACCESS_DENIED;
339 }
340
341 /*
342   remove a directory
343 */
344 static NTSTATUS ipc_rmdir(struct request_context *req, struct smb_rmdir *rd)
345 {
346         return NT_STATUS_ACCESS_DENIED;
347 }
348
349 /*
350   rename a set of files
351 */
352 static NTSTATUS ipc_rename(struct request_context *req, union smb_rename *ren)
353 {
354         return NT_STATUS_ACCESS_DENIED;
355 }
356
357 /*
358   copy a set of files
359 */
360 static NTSTATUS ipc_copy(struct request_context *req, struct smb_copy *cp)
361 {
362         return NT_STATUS_ACCESS_DENIED;
363 }
364
365 /*
366   read from a file
367 */
368 static NTSTATUS ipc_read(struct request_context *req, union smb_read *rd)
369 {
370         struct ipc_private *private = req->conn->ntvfs_private;
371         DATA_BLOB data;
372         uint16 fnum;
373         struct pipe_state *p;
374         NTSTATUS status;
375
376         switch (rd->generic.level) {
377         case RAW_READ_READ:
378                 fnum = rd->read.in.fnum;
379                 data.length = rd->read.in.count;
380                 data.data = rd->read.out.data;
381                 break;
382         case RAW_READ_READX:
383                 fnum = rd->readx.in.fnum;
384                 data.length = rd->readx.in.maxcnt;
385                 data.data = rd->readx.out.data;
386                 break;
387         default:
388                 return NT_STATUS_NOT_SUPPORTED;
389         }
390
391         p = pipe_state_find(private, fnum);
392         if (!p) {
393                 return NT_STATUS_INVALID_HANDLE;
394         }
395
396         status = dcesrv_output_blob(p->dce_conn, &data);
397         if (!NT_STATUS_IS_OK(status)) {
398                 return status;
399         }
400
401         switch (rd->generic.level) {
402         case RAW_READ_READ:
403                 rd->read.out.nread = data.length;
404                 break;
405         case RAW_READ_READX:
406                 rd->readx.out.remaining = 0;
407                 rd->readx.out.compaction_mode = 0;
408                 rd->readx.out.nread = data.length;
409                 break;
410         default:
411                 return NT_STATUS_NOT_SUPPORTED;
412         }
413
414         return NT_STATUS_OK;
415 }
416
417 /*
418   write to a file
419 */
420 static NTSTATUS ipc_write(struct request_context *req, union smb_write *wr)
421 {
422         struct ipc_private *private = req->conn->ntvfs_private;
423         DATA_BLOB data;
424         uint16 fnum;
425         struct pipe_state *p;
426         NTSTATUS status;
427
428         switch (wr->generic.level) {
429         case RAW_WRITE_WRITE:
430                 fnum = wr->write.in.fnum;
431                 data.data = wr->write.in.data;
432                 data.length = wr->write.in.count;
433                 break;
434
435         case RAW_WRITE_WRITEX:
436                 fnum = wr->writex.in.fnum;
437                 data.data = wr->writex.in.data;
438                 data.length = wr->writex.in.count;
439                 break;
440
441         default:
442                 return NT_STATUS_NOT_SUPPORTED;
443         }
444
445         p = pipe_state_find(private, fnum);
446         if (!p) {
447                 return NT_STATUS_INVALID_HANDLE;
448         }
449
450         status = dcesrv_input(p->dce_conn, &data);
451         if (!NT_STATUS_IS_OK(status)) {
452                 return status;
453         }
454
455         switch (wr->generic.level) {
456         case RAW_WRITE_WRITE:
457                 wr->write.out.nwritten = data.length;
458                 break;
459         case RAW_WRITE_WRITEX:
460                 wr->writex.out.nwritten = data.length;
461                 wr->writex.out.remaining = 0;
462                 break;
463         default:
464                 return NT_STATUS_NOT_SUPPORTED;
465         }
466
467         return NT_STATUS_OK;
468 }
469
470 /*
471   seek in a file
472 */
473 static NTSTATUS ipc_seek(struct request_context *req, struct smb_seek *io)
474 {
475         return NT_STATUS_ACCESS_DENIED;
476 }
477
478 /*
479   flush a file
480 */
481 static NTSTATUS ipc_flush(struct request_context *req, struct smb_flush *io)
482 {
483         return NT_STATUS_ACCESS_DENIED;
484 }
485
486 /*
487   close a file
488 */
489 static NTSTATUS ipc_close(struct request_context *req, union smb_close *io)
490 {
491         struct ipc_private *private = req->conn->ntvfs_private;
492         struct pipe_state *p;
493
494         if (io->generic.level != RAW_CLOSE_CLOSE) {
495                 return NT_STATUS_ACCESS_DENIED;
496         }
497
498         p = pipe_state_find(private, io->close.in.fnum);
499         if (!p) {
500                 return NT_STATUS_INVALID_HANDLE;
501         }
502
503         pipe_shutdown(private, p);
504         private->num_open--;
505
506         return NT_STATUS_OK;
507 }
508
509 /*
510   exit - closing files?
511 */
512 static NTSTATUS ipc_exit(struct request_context *req)
513 {
514         return NT_STATUS_ACCESS_DENIED;
515 }
516
517 /*
518   lock a byte range
519 */
520 static NTSTATUS ipc_lock(struct request_context *req, union smb_lock *lck)
521 {
522         return NT_STATUS_ACCESS_DENIED;
523 }
524
525 /*
526   set info on a open file
527 */
528 static NTSTATUS ipc_setfileinfo(struct request_context *req, union smb_setfileinfo *info)
529 {
530         return NT_STATUS_ACCESS_DENIED;
531 }
532
533 /*
534   query info on a open file
535 */
536 static NTSTATUS ipc_qfileinfo(struct request_context *req, union smb_fileinfo *info)
537 {
538         return NT_STATUS_ACCESS_DENIED;
539 }
540
541
542 /*
543   return filesystem info
544 */
545 static NTSTATUS ipc_fsinfo(struct request_context *req, union smb_fsinfo *fs)
546 {
547         return NT_STATUS_ACCESS_DENIED;
548 }
549
550 /*
551   return print queue info
552 */
553 static NTSTATUS ipc_lpq(struct request_context *req, union smb_lpq *lpq)
554 {
555         return NT_STATUS_ACCESS_DENIED;
556 }
557
558 /* 
559    list files in a directory matching a wildcard pattern
560 */
561 NTSTATUS ipc_search_first(struct request_context *req, union smb_search_first *io,
562                           void *search_private, 
563                           BOOL (*callback)(void *, union smb_search_data *))
564 {
565         return NT_STATUS_ACCESS_DENIED;
566 }
567
568 /* 
569    continue listing files in a directory 
570 */
571 NTSTATUS ipc_search_next(struct request_context *req, union smb_search_next *io,
572                          void *search_private, 
573                          BOOL (*callback)(void *, union smb_search_data *))
574 {
575         return NT_STATUS_ACCESS_DENIED;
576 }
577
578 /* 
579    end listing files in a directory 
580 */
581 NTSTATUS ipc_search_close(struct request_context *req, union smb_search_close *io)
582 {
583         return NT_STATUS_ACCESS_DENIED;
584 }
585
586
587 /* SMBtrans - handle a DCERPC command */
588 static NTSTATUS ipc_dcerpc_cmd(struct request_context *req, struct smb_trans2 *trans)
589 {
590         struct pipe_state *p;
591         struct ipc_private *private = req->conn->ntvfs_private;
592         NTSTATUS status;
593
594         /* the fnum is in setup[1] */
595         p = pipe_state_find(private, trans->in.setup[1]);
596         if (!p) {
597                 return NT_STATUS_INVALID_HANDLE;
598         }
599
600         trans->out.data = data_blob_talloc(req->mem_ctx, NULL, trans->in.max_data);
601         if (!trans->out.data.data) {
602                 return NT_STATUS_NO_MEMORY;
603         }
604
605         /* pass the data to the dcerpc server. Note that we don't
606            expect this to fail, and things like NDR faults are not
607            reported at this stage. Those sorts of errors happen in the
608            dcesrv_output stage */
609         status = dcesrv_input(p->dce_conn, &trans->in.data);
610         if (!NT_STATUS_IS_OK(status)) {
611                 return status;
612         }
613
614         /*
615           now ask the dcerpc system for some output. This doesn't yet handle
616           async calls. Again, we only expect NT_STATUS_OK. If the call fails then
617           the error is encoded at the dcerpc level
618         */
619         status = dcesrv_output_blob(p->dce_conn, &trans->out.data);
620         if (!NT_STATUS_IS_OK(status)) {
621                 return status;
622         }
623
624         trans->out.setup_count = 0;
625         trans->out.setup = NULL;
626         trans->out.params = data_blob(NULL, 0);
627
628         return NT_STATUS_OK;
629 }
630
631
632 /* SMBtrans - set named pipe state */
633 static NTSTATUS ipc_set_nm_pipe_state(struct request_context *req, struct smb_trans2 *trans)
634 {
635         struct pipe_state *p;
636         struct ipc_private *private = req->conn->ntvfs_private;
637
638         /* the fnum is in setup[1] */
639         p = pipe_state_find(private, trans->in.setup[1]);
640         if (!p) {
641                 return NT_STATUS_INVALID_HANDLE;
642         }
643
644         if (trans->in.params.length != 2) {
645                 return NT_STATUS_INVALID_PARAMETER;
646         }
647         p->ipc_state = SVAL(trans->in.params.data, 0);
648
649         trans->out.setup_count = 0;
650         trans->out.setup = NULL;
651         trans->out.params = data_blob(NULL, 0);
652         trans->out.data = data_blob(NULL, 0);
653
654         return NT_STATUS_OK;
655 }
656
657
658 /* SMBtrans - used to provide access to SMB pipes */
659 static NTSTATUS ipc_trans(struct request_context *req, struct smb_trans2 *trans)
660 {
661         NTSTATUS status;
662
663         if (trans->in.setup_count != 2) {
664                 return NT_STATUS_INVALID_PARAMETER;
665         }
666
667         switch (trans->in.setup[0]) {
668         case TRANSACT_SETNAMEDPIPEHANDLESTATE:
669                 status = ipc_set_nm_pipe_state(req, trans);
670                 break;
671         case TRANSACT_DCERPCCMD:
672                 status = ipc_dcerpc_cmd(req, trans);
673                 break;
674         default:
675                 status = NT_STATUS_INVALID_PARAMETER;
676                 break;
677         }
678
679         return status;
680 }
681
682
683
684 /*
685   initialialise the IPC backend, registering ourselves with the ntvfs subsystem
686  */
687 NTSTATUS ntvfs_ipc_init(void)
688 {
689         NTSTATUS ret;
690         struct ntvfs_ops ops;
691
692         ZERO_STRUCT(ops);
693         
694         /* fill in the name and type */
695         ops.name = "default";
696         ops.type = NTVFS_IPC;
697
698         /* fill in all the operations */
699         ops.connect = ipc_connect;
700         ops.disconnect = ipc_disconnect;
701         ops.unlink = ipc_unlink;
702         ops.chkpath = ipc_chkpath;
703         ops.qpathinfo = ipc_qpathinfo;
704         ops.setpathinfo = ipc_setpathinfo;
705         ops.open = ipc_open;
706         ops.mkdir = ipc_mkdir;
707         ops.rmdir = ipc_rmdir;
708         ops.rename = ipc_rename;
709         ops.copy = ipc_copy;
710         ops.ioctl = ipc_ioctl;
711         ops.read = ipc_read;
712         ops.write = ipc_write;
713         ops.seek = ipc_seek;
714         ops.flush = ipc_flush;  
715         ops.close = ipc_close;
716         ops.exit = ipc_exit;
717         ops.lock = ipc_lock;
718         ops.setfileinfo = ipc_setfileinfo;
719         ops.qfileinfo = ipc_qfileinfo;
720         ops.fsinfo = ipc_fsinfo;
721         ops.lpq = ipc_lpq;
722         ops.search_first = ipc_search_first;
723         ops.search_next = ipc_search_next;
724         ops.search_close = ipc_search_close;
725         ops.trans = ipc_trans;
726
727         /* register ourselves with the NTVFS subsystem. */
728         ret = register_backend("ntvfs", &ops);
729
730         if (!NT_STATUS_IS_OK(ret)) {
731                 DEBUG(0,("Failed to register IPC backend!\n"));
732                 return ret;
733         }
734
735         return ret;
736 }