r1499: combine struct user_struct and struct smbsrv_user
[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
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 smbsrv_request *req, const char *sharename)
109 {
110         struct smbsrv_tcon *tcon = req->tcon;
111         struct ipc_private *private;
112
113         tcon->fs_type = talloc_strdup(tcon->mem_ctx, "IPC");
114         tcon->dev_type = talloc_strdup(tcon->mem_ctx, "IPC");
115
116         /* prepare the private state for this connection */
117         private = talloc(tcon->mem_ctx, sizeof(struct ipc_private));
118         if (!private) {
119                 return NT_STATUS_NO_MEMORY;
120         }
121         tcon->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 smbsrv_tcon *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 smbsrv_request *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 smbsrv_request *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 smbsrv_request *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 smbsrv_request *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 smbsrv_request *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 smbsrv_request *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 auth_session_info *session_info = NULL;
199         struct ipc_private *private = req->tcon->ntvfs_private;
200
201         mem_ctx = talloc_init("ipc_open '%s'", fname);
202         if (!mem_ctx) {
203                 return NT_STATUS_NO_MEMORY;
204         }
205
206         p = talloc(mem_ctx, sizeof(struct pipe_state));
207         if (!p) {
208                 talloc_destroy(mem_ctx);
209                 return NT_STATUS_NO_MEMORY;
210         }
211         p->mem_ctx = mem_ctx;
212
213         p->pipe_name = talloc_strdup(mem_ctx, fname);
214         if (!p->pipe_name) {
215                 talloc_destroy(mem_ctx);
216                 return NT_STATUS_NO_MEMORY;
217         }
218
219         p->fnum = find_next_fnum(private);
220         if (p->fnum == 0) {
221                 talloc_destroy(mem_ctx);
222                 return NT_STATUS_TOO_MANY_OPENED_FILES;
223         }
224
225         while (p->pipe_name[0] == '\\') {
226                 p->pipe_name++;
227         }
228         p->ipc_state = 0x5ff;
229
230         /*
231           we're all set, now ask the dcerpc server subsystem to open the 
232           endpoint. At this stage the pipe isn't bound, so we don't
233           know what interface the user actually wants, just that they want
234           one of the interfaces attached to this pipe endpoint.
235
236           TODO: note that we aren't passing any credentials here. We
237           will need to do that once the credentials infrastructure is
238           finalised for Samba4
239         */
240
241         ep_description.type = ENDPOINT_SMB;
242         ep_description.info.smb_pipe = p->pipe_name;
243
244         /* tell the RPC layer the session_info */
245         if (req->session) {
246                 /* The session info is refcount-increased in the 
247                    dcesrv_endpoint_search_connect() function */
248
249                 session_info = req->session->session_info;
250         }
251
252         status = dcesrv_endpoint_search_connect(&req->smb_conn->dcesrv, 
253                                                 &ep_description, 
254                                                 session_info,
255                                                 &p->dce_conn);
256         if (!NT_STATUS_IS_OK(status)) {
257                 talloc_destroy(mem_ctx);
258                 return status;
259         }
260
261         private->num_open++;
262
263         DLIST_ADD(private->pipe_list, p);
264
265         *ps = p;
266
267         return NT_STATUS_OK;
268 }
269
270 /*
271   open a file with ntcreatex - used for MSRPC pipes
272 */
273 static NTSTATUS ipc_open_ntcreatex(struct smbsrv_request *req, union smb_open *oi)
274 {
275         struct pipe_state *p;
276         NTSTATUS status;
277
278         status = ipc_open_generic(req, oi->ntcreatex.in.fname, &p);
279         if (!NT_STATUS_IS_OK(status)) {
280                 return status;
281         }
282
283         ZERO_STRUCT(oi->ntcreatex.out);
284         oi->ntcreatex.out.fnum = p->fnum;
285         oi->ntcreatex.out.ipc_state = p->ipc_state;
286
287         return status;
288 }
289
290 /*
291   open a file with openx - used for MSRPC pipes
292 */
293 static NTSTATUS ipc_open_openx(struct smbsrv_request *req, union smb_open *oi)
294 {
295         struct pipe_state *p;
296         NTSTATUS status;
297         const char *fname = oi->openx.in.fname;
298
299         if (strncasecmp(fname, "PIPE\\", 5) != 0) {
300                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
301         }
302
303         fname += 4;
304
305         status = ipc_open_generic(req, fname, &p);
306         if (!NT_STATUS_IS_OK(status)) {
307                 return status;
308         }
309
310         ZERO_STRUCT(oi->openx.out);
311         oi->openx.out.fnum = p->fnum;
312         oi->openx.out.ftype = 2;
313         oi->openx.out.devstate = p->ipc_state;
314         
315         return status;
316 }
317
318 /*
319   open a file - used for MSRPC pipes
320 */
321 static NTSTATUS ipc_open(struct smbsrv_request *req, union smb_open *oi)
322 {
323         NTSTATUS status;
324
325         switch (oi->generic.level) {
326         case RAW_OPEN_NTCREATEX:
327                 status = ipc_open_ntcreatex(req, oi);
328                 break;
329         case RAW_OPEN_OPENX:
330                 status = ipc_open_openx(req, oi);
331                 break;
332         default:
333                 status = NT_STATUS_NOT_SUPPORTED;
334                 break;
335         }
336
337         return status;
338 }
339
340 /*
341   create a directory
342 */
343 static NTSTATUS ipc_mkdir(struct smbsrv_request *req, union smb_mkdir *md)
344 {
345         return NT_STATUS_ACCESS_DENIED;
346 }
347
348 /*
349   remove a directory
350 */
351 static NTSTATUS ipc_rmdir(struct smbsrv_request *req, struct smb_rmdir *rd)
352 {
353         return NT_STATUS_ACCESS_DENIED;
354 }
355
356 /*
357   rename a set of files
358 */
359 static NTSTATUS ipc_rename(struct smbsrv_request *req, union smb_rename *ren)
360 {
361         return NT_STATUS_ACCESS_DENIED;
362 }
363
364 /*
365   copy a set of files
366 */
367 static NTSTATUS ipc_copy(struct smbsrv_request *req, struct smb_copy *cp)
368 {
369         return NT_STATUS_ACCESS_DENIED;
370 }
371
372 /*
373   read from a file
374 */
375 static NTSTATUS ipc_read(struct smbsrv_request *req, union smb_read *rd)
376 {
377         struct ipc_private *private = req->tcon->ntvfs_private;
378         DATA_BLOB data;
379         uint16_t fnum;
380         struct pipe_state *p;
381         NTSTATUS status;
382
383         switch (rd->generic.level) {
384         case RAW_READ_READ:
385                 fnum = rd->read.in.fnum;
386                 data.length = rd->read.in.count;
387                 data.data = rd->read.out.data;
388                 break;
389         case RAW_READ_READX:
390                 fnum = rd->readx.in.fnum;
391                 data.length = rd->readx.in.maxcnt;
392                 data.data = rd->readx.out.data;
393                 break;
394         default:
395                 return NT_STATUS_NOT_SUPPORTED;
396         }
397
398         p = pipe_state_find(private, fnum);
399         if (!p) {
400                 return NT_STATUS_INVALID_HANDLE;
401         }
402
403         status = dcesrv_output_blob(p->dce_conn, &data);
404         if (NT_STATUS_IS_ERR(status)) {
405                 return status;
406         }
407
408         switch (rd->generic.level) {
409         case RAW_READ_READ:
410                 rd->read.out.nread = data.length;
411                 break;
412         case RAW_READ_READX:
413                 rd->readx.out.remaining = 0;
414                 rd->readx.out.compaction_mode = 0;
415                 rd->readx.out.nread = data.length;
416                 break;
417         default:
418                 return NT_STATUS_NOT_SUPPORTED;
419         }
420
421         return status;
422 }
423
424 /*
425   write to a file
426 */
427 static NTSTATUS ipc_write(struct smbsrv_request *req, union smb_write *wr)
428 {
429         struct ipc_private *private = req->tcon->ntvfs_private;
430         DATA_BLOB data;
431         uint16_t fnum;
432         struct pipe_state *p;
433         NTSTATUS status;
434
435         switch (wr->generic.level) {
436         case RAW_WRITE_WRITE:
437                 fnum = wr->write.in.fnum;
438                 data.data = wr->write.in.data;
439                 data.length = wr->write.in.count;
440                 break;
441
442         case RAW_WRITE_WRITEX:
443                 fnum = wr->writex.in.fnum;
444                 data.data = wr->writex.in.data;
445                 data.length = wr->writex.in.count;
446                 break;
447
448         default:
449                 return NT_STATUS_NOT_SUPPORTED;
450         }
451
452         p = pipe_state_find(private, fnum);
453         if (!p) {
454                 return NT_STATUS_INVALID_HANDLE;
455         }
456
457         status = dcesrv_input(p->dce_conn, &data);
458         if (!NT_STATUS_IS_OK(status)) {
459                 return status;
460         }
461
462         switch (wr->generic.level) {
463         case RAW_WRITE_WRITE:
464                 wr->write.out.nwritten = data.length;
465                 break;
466         case RAW_WRITE_WRITEX:
467                 wr->writex.out.nwritten = data.length;
468                 wr->writex.out.remaining = 0;
469                 break;
470         default:
471                 return NT_STATUS_NOT_SUPPORTED;
472         }
473
474         return NT_STATUS_OK;
475 }
476
477 /*
478   seek in a file
479 */
480 static NTSTATUS ipc_seek(struct smbsrv_request *req, struct smb_seek *io)
481 {
482         return NT_STATUS_ACCESS_DENIED;
483 }
484
485 /*
486   flush a file
487 */
488 static NTSTATUS ipc_flush(struct smbsrv_request *req, struct smb_flush *io)
489 {
490         return NT_STATUS_ACCESS_DENIED;
491 }
492
493 /*
494   close a file
495 */
496 static NTSTATUS ipc_close(struct smbsrv_request *req, union smb_close *io)
497 {
498         struct ipc_private *private = req->tcon->ntvfs_private;
499         struct pipe_state *p;
500
501         if (io->generic.level != RAW_CLOSE_CLOSE) {
502                 return NT_STATUS_ACCESS_DENIED;
503         }
504
505         p = pipe_state_find(private, io->close.in.fnum);
506         if (!p) {
507                 return NT_STATUS_INVALID_HANDLE;
508         }
509
510         pipe_shutdown(private, p);
511         private->num_open--;
512
513         return NT_STATUS_OK;
514 }
515
516 /*
517   exit - closing files?
518 */
519 static NTSTATUS ipc_exit(struct smbsrv_request *req)
520 {
521         return NT_STATUS_ACCESS_DENIED;
522 }
523
524 /*
525   lock a byte range
526 */
527 static NTSTATUS ipc_lock(struct smbsrv_request *req, union smb_lock *lck)
528 {
529         return NT_STATUS_ACCESS_DENIED;
530 }
531
532 /*
533   set info on a open file
534 */
535 static NTSTATUS ipc_setfileinfo(struct smbsrv_request *req, union smb_setfileinfo *info)
536 {
537         return NT_STATUS_ACCESS_DENIED;
538 }
539
540 /*
541   query info on a open file
542 */
543 static NTSTATUS ipc_qfileinfo(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 smbsrv_request *req, union smb_fsinfo *fs)
553 {
554         return NT_STATUS_ACCESS_DENIED;
555 }
556
557 /*
558   return print queue info
559 */
560 static NTSTATUS ipc_lpq(struct smbsrv_request *req, union smb_lpq *lpq)
561 {
562         return NT_STATUS_ACCESS_DENIED;
563 }
564
565 /* 
566    list files in a directory matching a wildcard pattern
567 */
568 NTSTATUS ipc_search_first(struct smbsrv_request *req, union smb_search_first *io,
569                           void *search_private, 
570                           BOOL (*callback)(void *, union smb_search_data *))
571 {
572         return NT_STATUS_ACCESS_DENIED;
573 }
574
575 /* 
576    continue listing files in a directory 
577 */
578 NTSTATUS ipc_search_next(struct smbsrv_request *req, union smb_search_next *io,
579                          void *search_private, 
580                          BOOL (*callback)(void *, union smb_search_data *))
581 {
582         return NT_STATUS_ACCESS_DENIED;
583 }
584
585 /* 
586    end listing files in a directory 
587 */
588 NTSTATUS ipc_search_close(struct smbsrv_request *req, union smb_search_close *io)
589 {
590         return NT_STATUS_ACCESS_DENIED;
591 }
592
593
594 /* SMBtrans - handle a DCERPC command */
595 static NTSTATUS ipc_dcerpc_cmd(struct smbsrv_request *req, struct smb_trans2 *trans)
596 {
597         struct pipe_state *p;
598         struct ipc_private *private = req->tcon->ntvfs_private;
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->mem_ctx, 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 smbsrv_request *req, struct smb_trans2 *trans)
641 {
642         struct pipe_state *p;
643         struct ipc_private *private = req->tcon->ntvfs_private;
644
645         /* the fnum is in setup[1] */
646         p = pipe_state_find(private, trans->in.setup[1]);
647         if (!p) {
648                 return NT_STATUS_INVALID_HANDLE;
649         }
650
651         if (trans->in.params.length != 2) {
652                 return NT_STATUS_INVALID_PARAMETER;
653         }
654         p->ipc_state = SVAL(trans->in.params.data, 0);
655
656         trans->out.setup_count = 0;
657         trans->out.setup = NULL;
658         trans->out.params = data_blob(NULL, 0);
659         trans->out.data = data_blob(NULL, 0);
660
661         return NT_STATUS_OK;
662 }
663
664
665 /* SMBtrans - used to provide access to SMB pipes */
666 static NTSTATUS ipc_trans(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(req, trans);
680                 break;
681         case TRANSACT_DCERPCCMD:
682                 status = ipc_dcerpc_cmd(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
737         /* register ourselves with the NTVFS subsystem. */
738         ret = register_backend("ntvfs", &ops);
739
740         if (!NT_STATUS_IS_OK(ret)) {
741                 DEBUG(0,("Failed to register IPC backend!\n"));
742                 return ret;
743         }
744
745         return ret;
746 }