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