r3167: Add a member 'endpoint' to the dcerpc_binding struct to use instead of
[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
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.endpoint = p->pipe_name;
216
217         /* tell the RPC layer the session_info */
218         if (req->session) {
219                 /* The session info is refcount-increased in the 
220                    dcesrv_endpoint_search_connect() function */
221                 session_info = req->session->session_info;
222         }
223
224         status = dcesrv_endpoint_search_connect(req->smb_conn->dcesrv, 
225                                                 &ep_description, 
226                                                 session_info,
227                                                 &p->dce_conn);
228         if (!NT_STATUS_IS_OK(status)) {
229                 idr_remove(private->idtree_fnum, p->fnum);
230                 return status;
231         }
232
233         DLIST_ADD(private->pipe_list, p);
234
235         p->smbpid = req->smbpid;
236         p->session = req->session;
237         p->private = private;
238
239         *ps = p;
240
241         talloc_steal(private, p);
242
243         talloc_set_destructor(p, ipc_fd_destructor);
244
245         return NT_STATUS_OK;
246 }
247
248 /*
249   open a file with ntcreatex - used for MSRPC pipes
250 */
251 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
252                                    struct smbsrv_request *req, union smb_open *oi)
253 {
254         struct pipe_state *p;
255         NTSTATUS status;
256
257         status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
258         if (!NT_STATUS_IS_OK(status)) {
259                 return status;
260         }
261
262         ZERO_STRUCT(oi->ntcreatex.out);
263         oi->ntcreatex.out.fnum = p->fnum;
264         oi->ntcreatex.out.ipc_state = p->ipc_state;
265
266         return status;
267 }
268
269 /*
270   open a file with openx - used for MSRPC pipes
271 */
272 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
273                                struct smbsrv_request *req, union smb_open *oi)
274 {
275         struct pipe_state *p;
276         NTSTATUS status;
277         const char *fname = oi->openx.in.fname;
278
279         status = ipc_open_generic(ntvfs, req, fname, &p);
280         if (!NT_STATUS_IS_OK(status)) {
281                 return status;
282         }
283
284         ZERO_STRUCT(oi->openx.out);
285         oi->openx.out.fnum = p->fnum;
286         oi->openx.out.ftype = 2;
287         oi->openx.out.devstate = p->ipc_state;
288         
289         return status;
290 }
291
292 /*
293   open a file - used for MSRPC pipes
294 */
295 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
296                                 struct smbsrv_request *req, union smb_open *oi)
297 {
298         NTSTATUS status;
299
300         switch (oi->generic.level) {
301         case RAW_OPEN_NTCREATEX:
302                 status = ipc_open_ntcreatex(ntvfs, req, oi);
303                 break;
304         case RAW_OPEN_OPENX:
305                 status = ipc_open_openx(ntvfs, req, oi);
306                 break;
307         default:
308                 status = NT_STATUS_NOT_SUPPORTED;
309                 break;
310         }
311
312         return status;
313 }
314
315 /*
316   create a directory
317 */
318 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
319                           struct smbsrv_request *req, union smb_mkdir *md)
320 {
321         return NT_STATUS_ACCESS_DENIED;
322 }
323
324 /*
325   remove a directory
326 */
327 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
328                           struct smbsrv_request *req, struct smb_rmdir *rd)
329 {
330         return NT_STATUS_ACCESS_DENIED;
331 }
332
333 /*
334   rename a set of files
335 */
336 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
337                            struct smbsrv_request *req, union smb_rename *ren)
338 {
339         return NT_STATUS_ACCESS_DENIED;
340 }
341
342 /*
343   copy a set of files
344 */
345 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
346                          struct smbsrv_request *req, struct smb_copy *cp)
347 {
348         return NT_STATUS_ACCESS_DENIED;
349 }
350
351 /*
352   read from a file
353 */
354 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
355                          struct smbsrv_request *req, union smb_read *rd)
356 {
357         struct ipc_private *private = ntvfs->private_data;
358         DATA_BLOB data;
359         uint16_t fnum;
360         struct pipe_state *p;
361         NTSTATUS status;
362
363         if (rd->generic.level != RAW_READ_GENERIC) {
364                 return ntvfs_map_read(req, rd, ntvfs);
365         }
366
367         fnum = rd->readx.in.fnum;
368         data.length = rd->readx.in.maxcnt;
369         data.data = rd->readx.out.data;
370
371         p = pipe_state_find(private, fnum);
372         if (!p) {
373                 return NT_STATUS_INVALID_HANDLE;
374         }
375
376         status = dcesrv_output_blob(p->dce_conn, &data);
377         if (NT_STATUS_IS_ERR(status)) {
378                 return status;
379         }
380
381         rd->readx.out.remaining = 0;
382         rd->readx.out.compaction_mode = 0;
383         rd->readx.out.nread = data.length;
384
385         return status;
386 }
387
388 /*
389   write to a file
390 */
391 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
392                           struct smbsrv_request *req, union smb_write *wr)
393 {
394         struct ipc_private *private = ntvfs->private_data;
395         DATA_BLOB data;
396         uint16_t fnum;
397         struct pipe_state *p;
398         NTSTATUS status;
399
400         if (wr->generic.level != RAW_WRITE_GENERIC) {
401                 return ntvfs_map_write(req, wr, ntvfs);
402         }
403
404         fnum = wr->writex.in.fnum;
405         data.data = discard_const_p(void, wr->writex.in.data);
406         data.length = wr->writex.in.count;
407
408         p = pipe_state_find(private, fnum);
409         if (!p) {
410                 return NT_STATUS_INVALID_HANDLE;
411         }
412
413         status = dcesrv_input(p->dce_conn, &data);
414         if (!NT_STATUS_IS_OK(status)) {
415                 return status;
416         }
417
418         wr->writex.out.nwritten = data.length;
419         wr->writex.out.remaining = 0;
420
421         return NT_STATUS_OK;
422 }
423
424 /*
425   seek in a file
426 */
427 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
428                          struct smbsrv_request *req, struct smb_seek *io)
429 {
430         return NT_STATUS_ACCESS_DENIED;
431 }
432
433 /*
434   flush a file
435 */
436 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
437                           struct smbsrv_request *req, struct smb_flush *io)
438 {
439         return NT_STATUS_ACCESS_DENIED;
440 }
441
442 /*
443   close a file
444 */
445 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
446                           struct smbsrv_request *req, union smb_close *io)
447 {
448         struct ipc_private *private = ntvfs->private_data;
449         struct pipe_state *p;
450
451         if (io->generic.level != RAW_CLOSE_CLOSE) {
452                 return ntvfs_map_close(req, io, ntvfs);
453         }
454
455         p = pipe_state_find(private, io->close.in.fnum);
456         if (!p) {
457                 return NT_STATUS_INVALID_HANDLE;
458         }
459
460         talloc_free(p);
461
462         return NT_STATUS_OK;
463 }
464
465 /*
466   exit - closing files
467 */
468 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
469                          struct smbsrv_request *req)
470 {
471         struct ipc_private *private = ntvfs->private_data;
472         struct pipe_state *p, *next;
473         
474         for (p=private->pipe_list; p; p=next) {
475                 next = p->next;
476                 if (p->smbpid == req->smbpid) {
477                         talloc_free(p);
478                 }
479         }
480
481         return NT_STATUS_OK;
482 }
483
484 /*
485   logoff - closing files open by the user
486 */
487 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
488                            struct smbsrv_request *req)
489 {
490         struct ipc_private *private = ntvfs->private_data;
491         struct pipe_state *p, *next;
492         
493         for (p=private->pipe_list; p; p=next) {
494                 next = p->next;
495                 if (p->session == req->session) {
496                         talloc_free(p);
497                 }
498         }
499
500         return NT_STATUS_OK;
501 }
502
503 /*
504   setup for an async call
505 */
506 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
507                                 struct smbsrv_request *req,
508                                 void *private)
509 {
510         return NT_STATUS_OK;
511 }
512
513 /*
514   lock a byte range
515 */
516 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
517                          struct smbsrv_request *req, union smb_lock *lck)
518 {
519         return NT_STATUS_ACCESS_DENIED;
520 }
521
522 /*
523   set info on a open file
524 */
525 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
526                                 struct smbsrv_request *req, union smb_setfileinfo *info)
527 {
528         return NT_STATUS_ACCESS_DENIED;
529 }
530
531 /*
532   query info on a open file
533 */
534 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
535                               struct smbsrv_request *req, union smb_fileinfo *info)
536 {
537         return NT_STATUS_ACCESS_DENIED;
538 }
539
540
541 /*
542   return filesystem info
543 */
544 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
545                            struct smbsrv_request *req, union smb_fsinfo *fs)
546 {
547         return NT_STATUS_ACCESS_DENIED;
548 }
549
550 /*
551   return print queue info
552 */
553 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
554                         struct smbsrv_request *req, union smb_lpq *lpq)
555 {
556         return NT_STATUS_ACCESS_DENIED;
557 }
558
559 /* 
560    list files in a directory matching a wildcard pattern
561 */
562 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
563                           struct smbsrv_request *req, union smb_search_first *io,
564                           void *search_private, 
565                           BOOL (*callback)(void *, union smb_search_data *))
566 {
567         return NT_STATUS_ACCESS_DENIED;
568 }
569
570 /* 
571    continue listing files in a directory 
572 */
573 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
574                          struct smbsrv_request *req, union smb_search_next *io,
575                          void *search_private, 
576                          BOOL (*callback)(void *, union smb_search_data *))
577 {
578         return NT_STATUS_ACCESS_DENIED;
579 }
580
581 /* 
582    end listing files in a directory 
583 */
584 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
585                           struct smbsrv_request *req, union smb_search_close *io)
586 {
587         return NT_STATUS_ACCESS_DENIED;
588 }
589
590
591 /* SMBtrans - handle a DCERPC command */
592 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
593                                struct smbsrv_request *req, struct smb_trans2 *trans)
594 {
595         struct pipe_state *p;
596         struct ipc_private *private = ntvfs->private_data;
597         NTSTATUS status;
598
599         /* the fnum is in setup[1] */
600         p = pipe_state_find(private, trans->in.setup[1]);
601         if (!p) {
602                 return NT_STATUS_INVALID_HANDLE;
603         }
604
605         trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
606         if (!trans->out.data.data) {
607                 return NT_STATUS_NO_MEMORY;
608         }
609
610         /* pass the data to the dcerpc server. Note that we don't
611            expect this to fail, and things like NDR faults are not
612            reported at this stage. Those sorts of errors happen in the
613            dcesrv_output stage */
614         status = dcesrv_input(p->dce_conn, &trans->in.data);
615         if (!NT_STATUS_IS_OK(status)) {
616                 return status;
617         }
618
619         /*
620           now ask the dcerpc system for some output. This doesn't yet handle
621           async calls. Again, we only expect NT_STATUS_OK. If the call fails then
622           the error is encoded at the dcerpc level
623         */
624         status = dcesrv_output_blob(p->dce_conn, &trans->out.data);
625         if (NT_STATUS_IS_ERR(status)) {
626                 return status;
627         }
628
629         trans->out.setup_count = 0;
630         trans->out.setup = NULL;
631         trans->out.params = data_blob(NULL, 0);
632
633         return status;
634 }
635
636
637 /* SMBtrans - set named pipe state */
638 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
639                                 struct smbsrv_request *req, struct smb_trans2 *trans)
640 {
641         struct ipc_private *private = ntvfs->private_data;
642         struct pipe_state *p;
643
644         /* the fnum is in setup[1] */
645         p = pipe_state_find(private, trans->in.setup[1]);
646         if (!p) {
647                 return NT_STATUS_INVALID_HANDLE;
648         }
649
650         if (trans->in.params.length != 2) {
651                 return NT_STATUS_INVALID_PARAMETER;
652         }
653         p->ipc_state = SVAL(trans->in.params.data, 0);
654
655         trans->out.setup_count = 0;
656         trans->out.setup = NULL;
657         trans->out.params = data_blob(NULL, 0);
658         trans->out.data = data_blob(NULL, 0);
659
660         return NT_STATUS_OK;
661 }
662
663
664 /* SMBtrans - used to provide access to SMB pipes */
665 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
666                                 struct smbsrv_request *req, struct smb_trans2 *trans)
667 {
668         NTSTATUS status;
669
670         if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
671                 return ipc_rap_call(req, trans);
672
673         if (trans->in.setup_count != 2) {
674                 return NT_STATUS_INVALID_PARAMETER;
675         }
676
677         switch (trans->in.setup[0]) {
678         case TRANSACT_SETNAMEDPIPEHANDLESTATE:
679                 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
680                 break;
681         case TRANSACT_DCERPCCMD:
682                 status = ipc_dcerpc_cmd(ntvfs, req, trans);
683                 break;
684         default:
685                 status = NT_STATUS_INVALID_PARAMETER;
686                 break;
687         }
688
689         return status;
690 }
691
692
693
694 /*
695   initialialise the IPC backend, registering ourselves with the ntvfs subsystem
696  */
697 NTSTATUS ntvfs_ipc_init(void)
698 {
699         NTSTATUS ret;
700         struct ntvfs_ops ops;
701
702         ZERO_STRUCT(ops);
703         
704         /* fill in the name and type */
705         ops.name = "default";
706         ops.type = NTVFS_IPC;
707
708         /* fill in all the operations */
709         ops.connect = ipc_connect;
710         ops.disconnect = ipc_disconnect;
711         ops.unlink = ipc_unlink;
712         ops.chkpath = ipc_chkpath;
713         ops.qpathinfo = ipc_qpathinfo;
714         ops.setpathinfo = ipc_setpathinfo;
715         ops.open = ipc_open;
716         ops.mkdir = ipc_mkdir;
717         ops.rmdir = ipc_rmdir;
718         ops.rename = ipc_rename;
719         ops.copy = ipc_copy;
720         ops.ioctl = ipc_ioctl;
721         ops.read = ipc_read;
722         ops.write = ipc_write;
723         ops.seek = ipc_seek;
724         ops.flush = ipc_flush;  
725         ops.close = ipc_close;
726         ops.exit = ipc_exit;
727         ops.lock = ipc_lock;
728         ops.setfileinfo = ipc_setfileinfo;
729         ops.qfileinfo = ipc_qfileinfo;
730         ops.fsinfo = ipc_fsinfo;
731         ops.lpq = ipc_lpq;
732         ops.search_first = ipc_search_first;
733         ops.search_next = ipc_search_next;
734         ops.search_close = ipc_search_close;
735         ops.trans = ipc_trans;
736         ops.logoff = ipc_logoff;
737         ops.async_setup = ipc_async_setup;
738
739         /* register ourselves with the NTVFS subsystem. */
740         ret = register_backend("ntvfs", &ops);
741
742         if (!NT_STATUS_IS_OK(ret)) {
743                 DEBUG(0,("Failed to register IPC backend!\n"));
744                 return ret;
745         }
746
747         return ret;
748 }