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