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