r3132: - fixed a type conflict found by talloc_array_p()
[gd/samba-autobuild/.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
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         struct idr_context *idtree_fnum;
35
36         /* a list of open pipes */
37         struct pipe_state {
38                 struct pipe_state *next, *prev;
39                 struct ipc_private *private;
40                 const char *pipe_name;
41                 uint16_t fnum;
42                 struct dcesrv_connection *dce_conn;
43                 uint16_t ipc_state;
44                 /* we need to remember the session it was opened on,
45                    as it is illegal to operate on someone elses fnum */
46                 struct smbsrv_session *session;
47
48                 /* we need to remember the client pid that 
49                    opened the file so SMBexit works */
50                 uint16_t smbpid;
51         } *pipe_list;
52
53 };
54
55
56 /*
57   find a open pipe give a file descriptor
58 */
59 static struct pipe_state *pipe_state_find(struct ipc_private *private, uint16_t fnum)
60 {
61         return idr_find(private->idtree_fnum, fnum);
62 }
63
64
65 /*
66   connect to a share - always works 
67 */
68 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
69                             struct smbsrv_request *req, const char *sharename)
70 {
71         struct smbsrv_tcon *tcon = req->tcon;
72         struct ipc_private *private;
73
74         tcon->fs_type = talloc_strdup(tcon, "IPC");
75         tcon->dev_type = talloc_strdup(tcon, "IPC");
76
77         /* prepare the private state for this connection */
78         private = talloc_p(tcon, struct ipc_private);
79         if (!private) {
80                 return NT_STATUS_NO_MEMORY;
81         }
82         ntvfs->private_data = private;
83
84         private->pipe_list = NULL;
85
86         private->idtree_fnum = idr_init(private);
87         if (private->idtree_fnum == NULL) {
88                 return NT_STATUS_NO_MEMORY;
89         }
90
91         return NT_STATUS_OK;
92 }
93
94 /*
95   disconnect from a share
96 */
97 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs,
98                                struct smbsrv_tcon *tcon)
99 {
100         struct ipc_private *private = ntvfs->private_data;
101
102         /* close any pipes that are open. Discard any unread data */
103         while (private->pipe_list) {
104                 talloc_free(private->pipe_list);
105         }
106
107         return NT_STATUS_OK;
108 }
109
110 /*
111   delete a file
112 */
113 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
114                            struct smbsrv_request *req, struct smb_unlink *unl)
115 {
116         return NT_STATUS_ACCESS_DENIED;
117 }
118
119
120 /*
121   ioctl interface - we don't do any
122 */
123 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
124                           struct smbsrv_request *req, union smb_ioctl *io)
125 {
126         return NT_STATUS_ACCESS_DENIED;
127 }
128
129 /*
130   check if a directory exists
131 */
132 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
133                             struct smbsrv_request *req, struct smb_chkpath *cp)
134 {
135         return NT_STATUS_ACCESS_DENIED;
136 }
137
138 /*
139   return info on a pathname
140 */
141 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
142                               struct smbsrv_request *req, union smb_fileinfo *info)
143 {
144         return NT_STATUS_ACCESS_DENIED;
145 }
146
147 /*
148   set info on a pathname
149 */
150 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
151                                 struct smbsrv_request *req, union smb_setfileinfo *st)
152 {
153         return NT_STATUS_ACCESS_DENIED;
154 }
155
156
157 /*
158   destroy a open pipe structure
159 */
160 static int ipc_fd_destructor(void *ptr)
161 {
162         struct pipe_state *p = ptr;
163         idr_remove(p->private->idtree_fnum, p->fnum);
164         DLIST_REMOVE(p->private->pipe_list, p);
165         talloc_free(p->dce_conn);
166         return 0;
167 }
168
169
170 /*
171   open a file backend - used for MSRPC pipes
172 */
173 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
174                                  struct smbsrv_request *req, const char *fname, 
175                                  struct pipe_state **ps)
176 {
177         struct pipe_state *p;
178         NTSTATUS status;
179         struct dcerpc_binding ep_description;
180         struct auth_session_info *session_info = NULL;
181         struct ipc_private *private = ntvfs->private_data;
182         int fnum;
183
184         p = talloc_p(req, struct pipe_state);
185         if (!p) {
186                 return NT_STATUS_NO_MEMORY;
187         }
188
189         while (fname[0] == '\\') fname++;
190
191         p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
192         if (!p->pipe_name) {
193                 return NT_STATUS_NO_MEMORY;
194         }
195
196         fnum = idr_get_new(private->idtree_fnum, p, UINT16_MAX);
197         if (fnum == -1) {
198                 return NT_STATUS_TOO_MANY_OPENED_FILES;
199         }
200
201         p->fnum = fnum;
202         p->ipc_state = 0x5ff;
203
204         /*
205           we're all set, now ask the dcerpc server subsystem to open the 
206           endpoint. At this stage the pipe isn't bound, so we don't
207           know what interface the user actually wants, just that they want
208           one of the interfaces attached to this pipe endpoint.
209
210           TODO: note that we aren't passing any credentials here. We
211           will need to do that once the credentials infrastructure is
212           finalised for Samba4
213         */
214         ep_description.transport = NCACN_NP;
215         ep_description.options = talloc_array_p(req, const char *, 2);
216         ep_description.options[0] = p->pipe_name;
217         ep_description.options[1] = NULL;
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         data.length = rd->readx.in.maxcnt;
371         data.data = rd->readx.out.data;
372
373         p = pipe_state_find(private, fnum);
374         if (!p) {
375                 return NT_STATUS_INVALID_HANDLE;
376         }
377
378         status = dcesrv_output_blob(p->dce_conn, &data);
379         if (NT_STATUS_IS_ERR(status)) {
380                 return status;
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   lock a byte range
517 */
518 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
519                          struct smbsrv_request *req, union smb_lock *lck)
520 {
521         return NT_STATUS_ACCESS_DENIED;
522 }
523
524 /*
525   set info on a open file
526 */
527 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
528                                 struct smbsrv_request *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 ntvfs_module_context *ntvfs,
537                               struct smbsrv_request *req, union smb_fileinfo *info)
538 {
539         return NT_STATUS_ACCESS_DENIED;
540 }
541
542
543 /*
544   return filesystem info
545 */
546 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
547                            struct smbsrv_request *req, union smb_fsinfo *fs)
548 {
549         return NT_STATUS_ACCESS_DENIED;
550 }
551
552 /*
553   return print queue info
554 */
555 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
556                         struct smbsrv_request *req, union smb_lpq *lpq)
557 {
558         return NT_STATUS_ACCESS_DENIED;
559 }
560
561 /* 
562    list files in a directory matching a wildcard pattern
563 */
564 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
565                           struct smbsrv_request *req, union smb_search_first *io,
566                           void *search_private, 
567                           BOOL (*callback)(void *, union smb_search_data *))
568 {
569         return NT_STATUS_ACCESS_DENIED;
570 }
571
572 /* 
573    continue listing files in a directory 
574 */
575 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
576                          struct smbsrv_request *req, union smb_search_next *io,
577                          void *search_private, 
578                          BOOL (*callback)(void *, union smb_search_data *))
579 {
580         return NT_STATUS_ACCESS_DENIED;
581 }
582
583 /* 
584    end listing files in a directory 
585 */
586 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
587                           struct smbsrv_request *req, union smb_search_close *io)
588 {
589         return NT_STATUS_ACCESS_DENIED;
590 }
591
592
593 /* SMBtrans - handle a DCERPC command */
594 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
595                                struct smbsrv_request *req, struct smb_trans2 *trans)
596 {
597         struct pipe_state *p;
598         struct ipc_private *private = ntvfs->private_data;
599         NTSTATUS status;
600
601         /* the fnum is in setup[1] */
602         p = pipe_state_find(private, trans->in.setup[1]);
603         if (!p) {
604                 return NT_STATUS_INVALID_HANDLE;
605         }
606
607         trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
608         if (!trans->out.data.data) {
609                 return NT_STATUS_NO_MEMORY;
610         }
611
612         /* pass the data to the dcerpc server. Note that we don't
613            expect this to fail, and things like NDR faults are not
614            reported at this stage. Those sorts of errors happen in the
615            dcesrv_output stage */
616         status = dcesrv_input(p->dce_conn, &trans->in.data);
617         if (!NT_STATUS_IS_OK(status)) {
618                 return status;
619         }
620
621         /*
622           now ask the dcerpc system for some output. This doesn't yet handle
623           async calls. Again, we only expect NT_STATUS_OK. If the call fails then
624           the error is encoded at the dcerpc level
625         */
626         status = dcesrv_output_blob(p->dce_conn, &trans->out.data);
627         if (NT_STATUS_IS_ERR(status)) {
628                 return status;
629         }
630
631         trans->out.setup_count = 0;
632         trans->out.setup = NULL;
633         trans->out.params = data_blob(NULL, 0);
634
635         return status;
636 }
637
638
639 /* SMBtrans - set named pipe state */
640 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
641                                 struct smbsrv_request *req, struct smb_trans2 *trans)
642 {
643         struct ipc_private *private = ntvfs->private_data;
644         struct pipe_state *p;
645
646         /* the fnum is in setup[1] */
647         p = pipe_state_find(private, trans->in.setup[1]);
648         if (!p) {
649                 return NT_STATUS_INVALID_HANDLE;
650         }
651
652         if (trans->in.params.length != 2) {
653                 return NT_STATUS_INVALID_PARAMETER;
654         }
655         p->ipc_state = SVAL(trans->in.params.data, 0);
656
657         trans->out.setup_count = 0;
658         trans->out.setup = NULL;
659         trans->out.params = data_blob(NULL, 0);
660         trans->out.data = data_blob(NULL, 0);
661
662         return NT_STATUS_OK;
663 }
664
665
666 /* SMBtrans - used to provide access to SMB pipes */
667 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
668                                 struct smbsrv_request *req, struct smb_trans2 *trans)
669 {
670         NTSTATUS status;
671
672         if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
673                 return ipc_rap_call(req, trans);
674
675         if (trans->in.setup_count != 2) {
676                 return NT_STATUS_INVALID_PARAMETER;
677         }
678
679         switch (trans->in.setup[0]) {
680         case TRANSACT_SETNAMEDPIPEHANDLESTATE:
681                 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
682                 break;
683         case TRANSACT_DCERPCCMD:
684                 status = ipc_dcerpc_cmd(ntvfs, req, trans);
685                 break;
686         default:
687                 status = NT_STATUS_INVALID_PARAMETER;
688                 break;
689         }
690
691         return status;
692 }
693
694
695
696 /*
697   initialialise the IPC backend, registering ourselves with the ntvfs subsystem
698  */
699 NTSTATUS ntvfs_ipc_init(void)
700 {
701         NTSTATUS ret;
702         struct ntvfs_ops ops;
703
704         ZERO_STRUCT(ops);
705         
706         /* fill in the name and type */
707         ops.name = "default";
708         ops.type = NTVFS_IPC;
709
710         /* fill in all the operations */
711         ops.connect = ipc_connect;
712         ops.disconnect = ipc_disconnect;
713         ops.unlink = ipc_unlink;
714         ops.chkpath = ipc_chkpath;
715         ops.qpathinfo = ipc_qpathinfo;
716         ops.setpathinfo = ipc_setpathinfo;
717         ops.open = ipc_open;
718         ops.mkdir = ipc_mkdir;
719         ops.rmdir = ipc_rmdir;
720         ops.rename = ipc_rename;
721         ops.copy = ipc_copy;
722         ops.ioctl = ipc_ioctl;
723         ops.read = ipc_read;
724         ops.write = ipc_write;
725         ops.seek = ipc_seek;
726         ops.flush = ipc_flush;  
727         ops.close = ipc_close;
728         ops.exit = ipc_exit;
729         ops.lock = ipc_lock;
730         ops.setfileinfo = ipc_setfileinfo;
731         ops.qfileinfo = ipc_qfileinfo;
732         ops.fsinfo = ipc_fsinfo;
733         ops.lpq = ipc_lpq;
734         ops.search_first = ipc_search_first;
735         ops.search_next = ipc_search_next;
736         ops.search_close = ipc_search_close;
737         ops.trans = ipc_trans;
738         ops.logoff = ipc_logoff;
739         ops.async_setup = ipc_async_setup;
740
741         /* register ourselves with the NTVFS subsystem. */
742         ret = register_backend("ntvfs", &ops);
743
744         if (!NT_STATUS_IS_OK(ret)) {
745                 DEBUG(0,("Failed to register IPC backend!\n"));
746                 return ret;
747         }
748
749         return ret;
750 }