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