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