LCOV - code coverage report
Current view: top level - source4/ntvfs/ipc - vfs_ipc.c (source / functions) Hit Total Coverage
Test: coverage report for master 469b22b8 Lines: 452 665 68.0 %
Date: 2024-06-10 12:05:21 Functions: 26 47 55.3 %

          Line data    Source code
       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-2005
       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 3 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, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : /*
      22             :   this implements the IPC$ backend, called by the NTVFS subsystem to
      23             :   handle requests on IPC$ shares
      24             : */
      25             : 
      26             : 
      27             : #include "includes.h"
      28             : #include "../lib/util/dlinklist.h"
      29             : #include "ntvfs/ntvfs.h"
      30             : #include "../librpc/gen_ndr/rap.h"
      31             : #include "ntvfs/ipc/proto.h"
      32             : #include "../libcli/smb/smb_constants.h"
      33             : #include "param/param.h"
      34             : #include "../lib/tsocket/tsocket.h"
      35             : #include "../libcli/named_pipe_auth/npa_tstream.h"
      36             : #include "auth/auth.h"
      37             : #include "auth/auth_sam_reply.h"
      38             : #include "lib/socket/socket.h"
      39             : #include "auth/credentials/credentials.h"
      40             : #include "auth/credentials/credentials_krb5.h"
      41             : #include "system/kerberos.h"
      42             : #include "system/gssapi.h"
      43             : #include "system/locale.h"
      44             : #include "system/filesys.h"
      45             : 
      46             : #undef strncasecmp
      47             : 
      48             : /* this is the private structure used to keep the state of an open
      49             :    ipc$ connection. It needs to keep information about all open
      50             :    pipes */
      51             : struct ipc_private {
      52             :         struct ntvfs_module_context *ntvfs;
      53             : 
      54             :         /* a list of open pipes */
      55             :         struct pipe_state {
      56             :                 struct pipe_state *next, *prev;
      57             :                 struct ipc_private *ipriv;
      58             :                 const char *pipe_name;
      59             :                 struct ntvfs_handle *handle;
      60             :                 struct tstream_context *npipe;
      61             :                 uint16_t file_type;
      62             :                 uint16_t device_state;
      63             :                 uint64_t allocation_size;
      64             :                 struct tevent_queue *write_queue;
      65             :                 struct tevent_queue *read_queue;
      66             :         } *pipe_list;
      67             : };
      68             : 
      69             : 
      70             : /*
      71             :   find a open pipe give a file handle
      72             : */
      73       50988 : static struct pipe_state *pipe_state_find(struct ipc_private *ipriv, struct ntvfs_handle *handle)
      74             : {
      75           0 :         struct pipe_state *s;
      76           0 :         void *p;
      77             : 
      78       50988 :         p = ntvfs_handle_get_backend_data(handle, ipriv->ntvfs);
      79       50988 :         if (!p) return NULL;
      80             : 
      81       50988 :         s = talloc_get_type(p, struct pipe_state);
      82       50988 :         if (!s) return NULL;
      83             : 
      84       50988 :         return s;
      85             : }
      86             : 
      87             : /*
      88             :   find a open pipe give a wire fnum
      89             : */
      90          42 : static struct pipe_state *pipe_state_find_key(struct ipc_private *ipriv, struct ntvfs_request *req, const DATA_BLOB *key)
      91             : {
      92           0 :         struct ntvfs_handle *h;
      93             : 
      94          42 :         h = ntvfs_handle_search_by_wire_key(ipriv->ntvfs, req, key);
      95          42 :         if (!h) return NULL;
      96             : 
      97          33 :         return pipe_state_find(ipriv, h);
      98             : }
      99             : 
     100             : 
     101             : /*
     102             :   connect to a share - always works 
     103             : */
     104        1005 : static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
     105             :                             struct ntvfs_request *req,
     106             :                             union smb_tcon* tcon)
     107             : {
     108           0 :         struct ipc_private *ipriv;
     109           0 :         const char *sharename;
     110             : 
     111        1005 :         switch (tcon->generic.level) {
     112           0 :         case RAW_TCON_TCON:
     113           0 :                 sharename = tcon->tcon.in.service;
     114           0 :                 break;
     115          35 :         case RAW_TCON_TCONX:
     116          35 :                 sharename = tcon->tconx.in.path;
     117          35 :                 break;
     118         970 :         case RAW_TCON_SMB2:
     119         970 :                 sharename = tcon->smb2.in.path;
     120         970 :                 break;
     121           0 :         default:
     122           0 :                 return NT_STATUS_INVALID_LEVEL;
     123             :         }
     124             : 
     125        1005 :         if (strncmp(sharename, "\\\\", 2) == 0) {
     126         999 :                 char *p = strchr(sharename+2, '\\');
     127         999 :                 if (p) {
     128         999 :                         sharename = p + 1;
     129             :                 }
     130             :         }
     131             : 
     132        1005 :         ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "IPC");
     133        1005 :         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
     134             : 
     135        1005 :         ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "IPC");
     136        1005 :         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
     137             : 
     138        1005 :         if (tcon->generic.level == RAW_TCON_TCONX) {
     139          35 :                 tcon->tconx.out.fs_type = ntvfs->ctx->fs_type;
     140          35 :                 tcon->tconx.out.dev_type = ntvfs->ctx->dev_type;
     141             :         }
     142             : 
     143             :         /* prepare the private state for this connection */
     144        1005 :         ipriv = talloc(ntvfs, struct ipc_private);
     145        1005 :         NT_STATUS_HAVE_NO_MEMORY(ipriv);
     146             : 
     147        1005 :         ntvfs->private_data = ipriv;
     148             : 
     149        1005 :         ipriv->ntvfs = ntvfs;
     150        1005 :         ipriv->pipe_list = NULL;
     151             : 
     152        1005 :         return NT_STATUS_OK;
     153             : }
     154             : 
     155             : /*
     156             :   disconnect from a share
     157             : */
     158        1005 : static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
     159             : {
     160        1005 :         return NT_STATUS_OK;
     161             : }
     162             : 
     163             : /*
     164             :   delete a file
     165             : */
     166           0 : static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
     167             :                            struct ntvfs_request *req,
     168             :                            union smb_unlink *unl)
     169             : {
     170           0 :         return NT_STATUS_ACCESS_DENIED;
     171             : }
     172             : 
     173             : /*
     174             :   check if a directory exists
     175             : */
     176           0 : static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
     177             :                             struct ntvfs_request *req,
     178             :                             union smb_chkpath *cp)
     179             : {
     180           0 :         return NT_STATUS_ACCESS_DENIED;
     181             : }
     182             : 
     183             : /*
     184             :   return info on a pathname
     185             : */
     186          59 : static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
     187             :                               struct ntvfs_request *req, union smb_fileinfo *info)
     188             : {
     189          59 :         switch (info->generic.level) {
     190          29 :         case  RAW_FILEINFO_GENERIC:
     191          29 :                 return NT_STATUS_INVALID_DEVICE_REQUEST;
     192           1 :         case RAW_FILEINFO_GETATTR:
     193           1 :                 return NT_STATUS_ACCESS_DENIED;
     194          29 :         default:
     195          29 :                 return ntvfs_map_qpathinfo(ntvfs, req, info);
     196             :         }
     197             : }
     198             : 
     199             : /*
     200             :   set info on a pathname
     201             : */
     202           0 : static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
     203             :                                 struct ntvfs_request *req, union smb_setfileinfo *st)
     204             : {
     205           0 :         return NT_STATUS_ACCESS_DENIED;
     206             : }
     207             : 
     208             : 
     209             : /*
     210             :   destroy a open pipe structure
     211             : */
     212        1182 : static int ipc_fd_destructor(struct pipe_state *p)
     213             : {
     214        1182 :         DLIST_REMOVE(p->ipriv->pipe_list, p);
     215        1182 :         ntvfs_handle_remove_backend_data(p->handle, p->ipriv->ntvfs);
     216        1182 :         return 0;
     217             : }
     218             : 
     219             : struct ipc_open_state {
     220             :         struct ipc_private *ipriv;
     221             :         struct pipe_state *p;
     222             :         struct ntvfs_request *req;
     223             :         union smb_open *oi;
     224             :         struct auth_session_info_transport *session_info_transport;
     225             : };
     226             : 
     227             : static void ipc_open_done(struct tevent_req *subreq);
     228             : 
     229             : /*
     230             :   check the pipename is valid
     231             :  */
     232        1266 : static NTSTATUS validate_pipename(const char *name)
     233             : {
     234        8757 :         while (*name) {
     235        7491 :                 if (!isalnum(*name) && *name != '_') {
     236           0 :                         return NT_STATUS_INVALID_PARAMETER;
     237             :                 }
     238        7491 :                 name++;
     239             :         }
     240        1266 :         return NT_STATUS_OK;
     241             : }
     242             : 
     243             : /*
     244             :   open a file - used for MSRPC pipes
     245             : */
     246        1266 : static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
     247             :                          struct ntvfs_request *req, union smb_open *oi)
     248             : {
     249           0 :         NTSTATUS status;
     250           0 :         struct pipe_state *p;
     251        1266 :         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
     252             :                                     struct ipc_private);
     253           0 :         struct ntvfs_handle *h;
     254           0 :         struct ipc_open_state *state;
     255           0 :         struct tevent_req *subreq;
     256           0 :         const char *fname;
     257           0 :         const char *directory;
     258           0 :         const struct tsocket_address *remote_client_addr;
     259           0 :         const struct tsocket_address *local_server_addr;
     260             : 
     261        1266 :         switch (oi->generic.level) {
     262          13 :         case RAW_OPEN_NTCREATEX:
     263             :         case RAW_OPEN_NTTRANS_CREATE:
     264          13 :                 fname = oi->ntcreatex.in.fname;
     265          26 :                 while (fname[0] == '\\') fname++;
     266          13 :                 break;
     267           0 :         case RAW_OPEN_OPENX:
     268           0 :                 fname = oi->openx.in.fname;
     269           0 :                 while (fname[0] == '\\') fname++;
     270           0 :                 if (strncasecmp(fname, "PIPE\\", 5) != 0) {
     271           0 :                         return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
     272             :                 }
     273           0 :                 while (fname[0] == '\\') fname++;
     274           0 :                 break;
     275        1253 :         case RAW_OPEN_SMB2:
     276        1253 :                 fname = oi->smb2.in.fname;
     277        1253 :                 break;
     278           0 :         default:
     279           0 :                 return NT_STATUS_NOT_SUPPORTED;
     280             :         }
     281             : 
     282        1266 :         directory = talloc_asprintf(req, "%s/np",
     283        1266 :                                     lpcfg_ncalrpc_dir(ipriv->ntvfs->ctx->lp_ctx));
     284        1266 :         NT_STATUS_HAVE_NO_MEMORY(directory);
     285             : 
     286        1266 :         state = talloc(req, struct ipc_open_state);
     287        1266 :         NT_STATUS_HAVE_NO_MEMORY(state);
     288             : 
     289        1266 :         status = ntvfs_handle_new(ntvfs, req, &h);
     290        1266 :         NT_STATUS_NOT_OK_RETURN(status);
     291             : 
     292        1266 :         p = talloc(h, struct pipe_state);
     293        1266 :         NT_STATUS_HAVE_NO_MEMORY(p);
     294             : 
     295             :         /* check for valid characters in name */
     296        1266 :         fname = strlower_talloc(p, fname);
     297             : 
     298        1266 :         status = validate_pipename(fname);
     299        1266 :         NT_STATUS_NOT_OK_RETURN(status);
     300             : 
     301        1266 :         p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
     302        1266 :         NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
     303             : 
     304        1266 :         p->handle = h;
     305        1266 :         p->ipriv = ipriv;
     306             : 
     307        1266 :         p->write_queue = tevent_queue_create(p, "ipc_write_queue");
     308        1266 :         NT_STATUS_HAVE_NO_MEMORY(p->write_queue);
     309             : 
     310        1266 :         p->read_queue = tevent_queue_create(p, "ipc_read_queue");
     311        1266 :         NT_STATUS_HAVE_NO_MEMORY(p->read_queue);
     312             : 
     313        1266 :         state->ipriv = ipriv;
     314        1266 :         state->p = p;
     315        1266 :         state->req = req;
     316        1266 :         state->oi = oi;
     317             : 
     318        1266 :         status = auth_session_info_transport_from_session(state,
     319             :                                                           req->session_info,
     320        1266 :                                                           ipriv->ntvfs->ctx->event_ctx,
     321        1266 :                                                           ipriv->ntvfs->ctx->lp_ctx,
     322             :                                                           &state->session_info_transport);
     323             : 
     324        1266 :         NT_STATUS_NOT_OK_RETURN(status);
     325             : 
     326        1266 :         local_server_addr = ntvfs_get_local_address(ipriv->ntvfs);
     327        1266 :         remote_client_addr = ntvfs_get_remote_address(ipriv->ntvfs);
     328             : 
     329        1266 :         subreq = tstream_npa_connect_send(p,
     330        1266 :                                           ipriv->ntvfs->ctx->event_ctx,
     331             :                                           directory,
     332             :                                           fname,
     333             :                                           NCACN_NP,
     334             :                                           remote_client_addr,
     335             :                                           NULL,
     336             :                                           local_server_addr,
     337             :                                           NULL,
     338        1266 :                                           state->session_info_transport);
     339        1266 :         NT_STATUS_HAVE_NO_MEMORY(subreq);
     340        1266 :         tevent_req_set_callback(subreq, ipc_open_done, state);
     341             : 
     342        1266 :         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
     343        1266 :         return NT_STATUS_OK;
     344             : }
     345             : 
     346        1266 : static void ipc_open_done(struct tevent_req *subreq)
     347             : {
     348        1266 :         struct ipc_open_state *state = tevent_req_callback_data(subreq,
     349             :                                        struct ipc_open_state);
     350        1266 :         struct ipc_private *ipriv = state->ipriv;
     351        1266 :         struct pipe_state *p = state->p;
     352        1266 :         struct ntvfs_request *req = state->req;
     353        1266 :         union smb_open *oi = state->oi;
     354           0 :         int ret;
     355           0 :         int sys_errno;
     356           0 :         NTSTATUS status;
     357             : 
     358        1266 :         ret = tstream_npa_connect_recv(subreq, &sys_errno,
     359             :                                        p, &p->npipe,
     360             :                                        &p->file_type,
     361             :                                        &p->device_state,
     362             :                                        &p->allocation_size);
     363        1266 :         TALLOC_FREE(subreq);
     364        1266 :         if (ret == -1) {
     365          84 :                 status = map_nt_error_from_unix_common(sys_errno);
     366          84 :                 goto reply;
     367             :         }
     368             : 
     369        1182 :         DLIST_ADD(ipriv->pipe_list, p);
     370        1182 :         talloc_set_destructor(p, ipc_fd_destructor);
     371             : 
     372        1182 :         status = ntvfs_handle_set_backend_data(p->handle, ipriv->ntvfs, p);
     373        1182 :         if (!NT_STATUS_IS_OK(status)) {
     374           0 :                 goto reply;
     375             :         }
     376             : 
     377        1182 :         switch (oi->generic.level) {
     378          13 :         case RAW_OPEN_NTCREATEX:
     379          13 :                 ZERO_STRUCT(oi->ntcreatex.out);
     380          13 :                 oi->ntcreatex.out.file.ntvfs = p->handle;
     381          13 :                 oi->ntcreatex.out.oplock_level       = 0;
     382          13 :                 oi->ntcreatex.out.create_action      = NTCREATEX_ACTION_EXISTED;
     383          13 :                 oi->ntcreatex.out.create_time        = 0;
     384          13 :                 oi->ntcreatex.out.access_time        = 0;
     385          13 :                 oi->ntcreatex.out.write_time = 0;
     386          13 :                 oi->ntcreatex.out.change_time        = 0;
     387          13 :                 oi->ntcreatex.out.attrib     = FILE_ATTRIBUTE_NORMAL;
     388          13 :                 oi->ntcreatex.out.alloc_size = p->allocation_size;
     389          13 :                 oi->ntcreatex.out.size               = 0;
     390          13 :                 oi->ntcreatex.out.file_type  = p->file_type;
     391          13 :                 oi->ntcreatex.out.ipc_state  = p->device_state;
     392          13 :                 oi->ntcreatex.out.is_directory       = 0;
     393          13 :                 break;
     394           0 :         case RAW_OPEN_OPENX:
     395           0 :                 ZERO_STRUCT(oi->openx.out);
     396           0 :                 oi->openx.out.file.ntvfs     = p->handle;
     397           0 :                 oi->openx.out.attrib         = FILE_ATTRIBUTE_NORMAL;
     398           0 :                 oi->openx.out.write_time     = 0;
     399           0 :                 oi->openx.out.size           = 0;
     400           0 :                 oi->openx.out.access         = 0;
     401           0 :                 oi->openx.out.ftype          = p->file_type;
     402           0 :                 oi->openx.out.devstate               = p->device_state;
     403           0 :                 oi->openx.out.action         = 0;
     404           0 :                 oi->openx.out.unique_fid     = 0;
     405           0 :                 oi->openx.out.access_mask    = 0;
     406           0 :                 oi->openx.out.unknown                = 0;
     407           0 :                 break;
     408        1169 :         case RAW_OPEN_SMB2:
     409        1169 :                 ZERO_STRUCT(oi->smb2.out);
     410        1169 :                 oi->smb2.out.file.ntvfs              = p->handle;
     411        1169 :                 oi->smb2.out.oplock_level    = oi->smb2.in.oplock_level;
     412        1169 :                 oi->smb2.out.create_action   = NTCREATEX_ACTION_EXISTED;
     413        1169 :                 oi->smb2.out.create_time     = 0;
     414        1169 :                 oi->smb2.out.access_time     = 0;
     415        1169 :                 oi->smb2.out.write_time              = 0;
     416        1169 :                 oi->smb2.out.change_time     = 0;
     417        1169 :                 oi->smb2.out.alloc_size              = p->allocation_size;
     418        1169 :                 oi->smb2.out.size            = 0;
     419        1169 :                 oi->smb2.out.file_attr               = FILE_ATTRIBUTE_NORMAL;
     420        1169 :                 oi->smb2.out.reserved2               = 0;
     421        1169 :                 break;
     422           0 :         default:
     423           0 :                 break;
     424             :         }
     425             : 
     426        1266 : reply:
     427        1266 :         req->async_states->status = status;
     428        1266 :         req->async_states->send_fn(req);
     429        1266 : }
     430             : 
     431             : /*
     432             :   create a directory
     433             : */
     434           0 : static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
     435             :                           struct ntvfs_request *req, union smb_mkdir *md)
     436             : {
     437           0 :         return NT_STATUS_ACCESS_DENIED;
     438             : }
     439             : 
     440             : /*
     441             :   remove a directory
     442             : */
     443           0 : static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
     444             :                           struct ntvfs_request *req, struct smb_rmdir *rd)
     445             : {
     446           0 :         return NT_STATUS_ACCESS_DENIED;
     447             : }
     448             : 
     449             : /*
     450             :   rename a set of files
     451             : */
     452           0 : static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
     453             :                            struct ntvfs_request *req, union smb_rename *ren)
     454             : {
     455           0 :         return NT_STATUS_ACCESS_DENIED;
     456             : }
     457             : 
     458             : /*
     459             :   copy a set of files
     460             : */
     461           0 : static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
     462             :                          struct ntvfs_request *req, struct smb_copy *cp)
     463             : {
     464           0 :         return NT_STATUS_ACCESS_DENIED;
     465             : }
     466             : 
     467             : struct ipc_readv_next_vector_state {
     468             :         uint8_t *buf;
     469             :         size_t len;
     470             :         off_t ofs;
     471             :         size_t remaining;
     472             : };
     473             : 
     474       48421 : static void ipc_readv_next_vector_init(struct ipc_readv_next_vector_state *s,
     475             :                                        uint8_t *buf, size_t len)
     476             : {
     477       48421 :         ZERO_STRUCTP(s);
     478             : 
     479       48421 :         s->buf = buf;
     480       48421 :         s->len = MIN(len, UINT16_MAX);
     481       48421 : }
     482             : 
     483      145263 : static int ipc_readv_next_vector(struct tstream_context *stream,
     484             :                                  void *private_data,
     485             :                                  TALLOC_CTX *mem_ctx,
     486             :                                  struct iovec **_vector,
     487             :                                  size_t *count)
     488             : {
     489      145263 :         struct ipc_readv_next_vector_state *state =
     490             :                 (struct ipc_readv_next_vector_state *)private_data;
     491           0 :         struct iovec *vector;
     492           0 :         ssize_t pending;
     493           0 :         size_t wanted;
     494             : 
     495      145263 :         if (state->ofs == state->len) {
     496         805 :                 *_vector = NULL;
     497         805 :                 *count = 0;
     498         805 :                 return 0;
     499             :         }
     500             : 
     501      144458 :         pending = tstream_pending_bytes(stream);
     502      144458 :         if (pending == -1) {
     503           0 :                 return -1;
     504             :         }
     505             : 
     506      144458 :         if (pending == 0 && state->ofs != 0) {
     507             :                 /* return a short read */
     508       47616 :                 *_vector = NULL;
     509       47616 :                 *count = 0;
     510       47616 :                 return 0;
     511             :         }
     512             : 
     513       96842 :         if (pending == 0) {
     514             :                 /* we want at least one byte and recheck again */
     515       48421 :                 wanted = 1;
     516             :         } else {
     517       48421 :                 size_t missing = state->len - state->ofs;
     518       48421 :                 if (pending > missing) {
     519             :                         /* there's more available */
     520           0 :                         state->remaining = pending - missing;
     521           0 :                         wanted = missing;
     522             :                 } else {
     523             :                         /* read what we can get and recheck in the next cycle */
     524       48421 :                         wanted = pending;
     525             :                 }
     526             :         }
     527             : 
     528       96842 :         vector = talloc_array(mem_ctx, struct iovec, 1);
     529       96842 :         if (!vector) {
     530           0 :                 return -1;
     531             :         }
     532             : 
     533       96842 :         vector[0].iov_base = (char *) (state->buf + state->ofs);
     534       96842 :         vector[0].iov_len = wanted;
     535             : 
     536       96842 :         state->ofs += wanted;
     537             : 
     538       96842 :         *_vector = vector;
     539       96842 :         *count = 1;
     540       96842 :         return 0;
     541             : }
     542             : 
     543             : struct ipc_read_state {
     544             :         struct ipc_private *ipriv;
     545             :         struct pipe_state *p;
     546             :         struct ntvfs_request *req;
     547             :         union smb_read *rd;
     548             :         struct ipc_readv_next_vector_state next_vector;
     549             : };
     550             : 
     551             : static void ipc_read_done(struct tevent_req *subreq);
     552             : 
     553             : /*
     554             :   read from a file
     555             : */
     556        2614 : static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
     557             :                          struct ntvfs_request *req, union smb_read *rd)
     558             : {
     559        2614 :         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
     560             :                                     struct ipc_private);
     561           0 :         struct pipe_state *p;
     562           0 :         struct ipc_read_state *state;
     563           0 :         struct tevent_req *subreq;
     564             : 
     565        2614 :         if (rd->generic.level != RAW_READ_GENERIC) {
     566        1307 :                 return ntvfs_map_read(ntvfs, req, rd);
     567             :         }
     568             : 
     569        1307 :         p = pipe_state_find(ipriv, rd->readx.in.file.ntvfs);
     570        1307 :         if (!p) {
     571           0 :                 return NT_STATUS_INVALID_HANDLE;
     572             :         }
     573             : 
     574        1307 :         state = talloc(req, struct ipc_read_state);
     575        1307 :         NT_STATUS_HAVE_NO_MEMORY(state);
     576             : 
     577        1307 :         state->ipriv = ipriv;
     578        1307 :         state->p = p;
     579        1307 :         state->req = req;
     580        1307 :         state->rd = rd;
     581             : 
     582             :         /* rd->readx.out.data is already allocated */
     583        1307 :         ipc_readv_next_vector_init(&state->next_vector,
     584             :                                    rd->readx.out.data,
     585        1307 :                                    rd->readx.in.maxcnt);
     586             : 
     587        1307 :         subreq = tstream_readv_pdu_queue_send(req,
     588        1307 :                                               ipriv->ntvfs->ctx->event_ctx,
     589             :                                               p->npipe,
     590             :                                               p->read_queue,
     591             :                                               ipc_readv_next_vector,
     592        1307 :                                               &state->next_vector);
     593        1307 :         NT_STATUS_HAVE_NO_MEMORY(subreq);
     594        1307 :         tevent_req_set_callback(subreq, ipc_read_done, state);
     595             : 
     596        1307 :         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
     597        1307 :         return NT_STATUS_OK;
     598             : }
     599             : 
     600        1307 : static void ipc_read_done(struct tevent_req *subreq)
     601             : {
     602           0 :         struct ipc_read_state *state =
     603        1307 :                 tevent_req_callback_data(subreq,
     604             :                 struct ipc_read_state);
     605        1307 :         struct ntvfs_request *req = state->req;
     606        1307 :         union smb_read *rd = state->rd;
     607           0 :         int ret;
     608           0 :         int sys_errno;
     609           0 :         NTSTATUS status;
     610             : 
     611        1307 :         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
     612        1307 :         TALLOC_FREE(subreq);
     613        1307 :         if (ret == -1) {
     614           0 :                 status = map_nt_error_from_unix_common(sys_errno);
     615           0 :                 goto reply;
     616             :         }
     617             : 
     618        1307 :         status = NT_STATUS_OK;
     619        1307 :         if (state->next_vector.remaining > 0) {
     620           0 :                 status = STATUS_BUFFER_OVERFLOW;
     621             :         }
     622             : 
     623        1307 :         rd->readx.out.remaining = state->next_vector.remaining;
     624        1307 :         rd->readx.out.compaction_mode = 0;
     625        1307 :         rd->readx.out.nread = ret;
     626             : 
     627        1307 : reply:
     628        1307 :         req->async_states->status = status;
     629        1307 :         req->async_states->send_fn(req);
     630        1307 : }
     631             : 
     632             : struct ipc_write_state {
     633             :         struct ipc_private *ipriv;
     634             :         struct pipe_state *p;
     635             :         struct ntvfs_request *req;
     636             :         union smb_write *wr;
     637             :         struct iovec iov;
     638             : };
     639             : 
     640             : static void ipc_write_done(struct tevent_req *subreq);
     641             : 
     642             : /*
     643             :   write to a file
     644             : */
     645        2790 : static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
     646             :                           struct ntvfs_request *req, union smb_write *wr)
     647             : {
     648        2790 :         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
     649             :                                     struct ipc_private);
     650           0 :         struct pipe_state *p;
     651           0 :         struct tevent_req *subreq;
     652           0 :         struct ipc_write_state *state;
     653             : 
     654        2790 :         if (wr->generic.level != RAW_WRITE_GENERIC) {
     655        1395 :                 return ntvfs_map_write(ntvfs, req, wr);
     656             :         }
     657             : 
     658        1395 :         p = pipe_state_find(ipriv, wr->writex.in.file.ntvfs);
     659        1395 :         if (!p) {
     660           0 :                 return NT_STATUS_INVALID_HANDLE;
     661             :         }
     662             : 
     663        1395 :         state = talloc(req, struct ipc_write_state);
     664        1395 :         NT_STATUS_HAVE_NO_MEMORY(state);
     665             : 
     666        1395 :         state->ipriv = ipriv;
     667        1395 :         state->p = p;
     668        1395 :         state->req = req;
     669        1395 :         state->wr = wr;
     670        1395 :         state->iov.iov_base = discard_const_p(void, wr->writex.in.data);
     671        1395 :         state->iov.iov_len = wr->writex.in.count;
     672             : 
     673        1395 :         subreq = tstream_writev_queue_send(state,
     674        1395 :                                            ipriv->ntvfs->ctx->event_ctx,
     675             :                                            p->npipe,
     676             :                                            p->write_queue,
     677        1395 :                                            &state->iov, 1);
     678        1395 :         NT_STATUS_HAVE_NO_MEMORY(subreq);
     679        1395 :         tevent_req_set_callback(subreq, ipc_write_done, state);
     680             : 
     681        1395 :         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
     682        1395 :         return NT_STATUS_OK;
     683             : }
     684             : 
     685        1395 : static void ipc_write_done(struct tevent_req *subreq)
     686             : {
     687           0 :         struct ipc_write_state *state =
     688        1395 :                 tevent_req_callback_data(subreq,
     689             :                 struct ipc_write_state);
     690        1395 :         struct ntvfs_request *req = state->req;
     691        1395 :         union smb_write *wr = state->wr;
     692           0 :         int ret;
     693           0 :         int sys_errno;
     694           0 :         NTSTATUS status;
     695             : 
     696        1395 :         ret = tstream_writev_queue_recv(subreq, &sys_errno);
     697        1395 :         TALLOC_FREE(subreq);
     698        1395 :         if (ret == -1) {
     699           0 :                 status = map_nt_error_from_unix_common(sys_errno);
     700           0 :                 goto reply;
     701             :         }
     702             : 
     703        1395 :         status = NT_STATUS_OK;
     704             : 
     705        1395 :         wr->writex.out.nwritten = ret;
     706        1395 :         wr->writex.out.remaining = 0;
     707             : 
     708        1395 : reply:
     709        1395 :         req->async_states->status = status;
     710        1395 :         req->async_states->send_fn(req);
     711        1395 : }
     712             : 
     713             : /*
     714             :   seek in a file
     715             : */
     716           0 : static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
     717             :                          struct ntvfs_request *req,
     718             :                          union smb_seek *io)
     719             : {
     720           0 :         return NT_STATUS_ACCESS_DENIED;
     721             : }
     722             : 
     723             : /*
     724             :   flush a file
     725             : */
     726           0 : static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
     727             :                           struct ntvfs_request *req,
     728             :                           union smb_flush *io)
     729             : {
     730           0 :         return NT_STATUS_ACCESS_DENIED;
     731             : }
     732             : 
     733             : /*
     734             :   close a file
     735             : */
     736        2246 : static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
     737             :                           struct ntvfs_request *req, union smb_close *io)
     738             : {
     739        2246 :         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
     740             :                                     struct ipc_private);
     741           0 :         struct pipe_state *p;
     742             : 
     743        2246 :         if (io->generic.level != RAW_CLOSE_GENERIC) {
     744        1123 :                 return ntvfs_map_close(ntvfs, req, io);
     745             :         }
     746             : 
     747        1123 :         ZERO_STRUCT(io->generic.out);
     748             : 
     749        1123 :         p = pipe_state_find(ipriv, io->generic.in.file.ntvfs);
     750        1123 :         if (!p) {
     751           0 :                 return NT_STATUS_INVALID_HANDLE;
     752             :         }
     753             : 
     754        1123 :         talloc_free(p);
     755             : 
     756        1123 :         return NT_STATUS_OK;
     757             : }
     758             : 
     759             : /*
     760             :   exit - closing files
     761             : */
     762           0 : static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
     763             :                          struct ntvfs_request *req)
     764             : {
     765           0 :         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
     766             :                                     struct ipc_private);
     767           0 :         struct pipe_state *p, *next;
     768             :         
     769           0 :         for (p=ipriv->pipe_list; p; p=next) {
     770           0 :                 next = p->next;
     771           0 :                 if (p->handle->session_info == req->session_info &&
     772           0 :                     p->handle->smbpid == req->smbpid) {
     773           0 :                         talloc_free(p);
     774             :                 }
     775             :         }
     776             : 
     777           0 :         return NT_STATUS_OK;
     778             : }
     779             : 
     780             : /*
     781             :   logoff - closing files open by the user
     782             : */
     783           0 : static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
     784             :                            struct ntvfs_request *req)
     785             : {
     786           0 :         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
     787             :                                     struct ipc_private);
     788           0 :         struct pipe_state *p, *next;
     789             :         
     790           0 :         for (p=ipriv->pipe_list; p; p=next) {
     791           0 :                 next = p->next;
     792           0 :                 if (p->handle->session_info == req->session_info) {
     793           0 :                         talloc_free(p);
     794             :                 }
     795             :         }
     796             : 
     797           0 :         return NT_STATUS_OK;
     798             : }
     799             : 
     800             : /*
     801             :   setup for an async call
     802             : */
     803           0 : static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
     804             :                                 struct ntvfs_request *req,
     805             :                                 void *private_data)
     806             : {
     807           0 :         return NT_STATUS_OK;
     808             : }
     809             : 
     810             : /*
     811             :   cancel an async call
     812             : */
     813           0 : static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
     814             :                            struct ntvfs_request *req)
     815             : {
     816           0 :         return NT_STATUS_UNSUCCESSFUL;
     817             : }
     818             : 
     819             : /*
     820             :   lock a byte range
     821             : */
     822           0 : static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
     823             :                          struct ntvfs_request *req, union smb_lock *lck)
     824             : {
     825           0 :         return NT_STATUS_ACCESS_DENIED;
     826             : }
     827             : 
     828             : /*
     829             :   set info on a open file
     830             : */
     831           0 : static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
     832             :                                 struct ntvfs_request *req, union smb_setfileinfo *info)
     833             : {
     834           0 :         return NT_STATUS_ACCESS_DENIED;
     835             : }
     836             : 
     837             : /*
     838             :   query info on a open file
     839             : */
     840          49 : static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
     841             :                               struct ntvfs_request *req, union smb_fileinfo *info)
     842             : {
     843          49 :         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
     844             :                                     struct ipc_private);
     845          49 :         struct pipe_state *p = pipe_state_find(ipriv, info->generic.in.file.ntvfs);
     846          49 :         if (!p) {
     847           0 :                 return NT_STATUS_INVALID_HANDLE;
     848             :         }
     849          49 :         switch (info->generic.level) {
     850          20 :         case RAW_FILEINFO_GENERIC: 
     851             :         {
     852          20 :                 ZERO_STRUCT(info->generic.out);
     853          20 :                 info->generic.out.attrib = FILE_ATTRIBUTE_NORMAL;
     854          20 :                 info->generic.out.fname.s = strrchr(p->pipe_name, '\\');
     855          20 :                 info->generic.out.alloc_size = 4096;
     856          20 :                 info->generic.out.nlink = 1;
     857             :                 /* What the heck?  Match Win2k3: IPC$ pipes are delete pending */
     858          20 :                 info->generic.out.delete_pending = 1;
     859          20 :                 return NT_STATUS_OK;
     860             :         }
     861           8 :         case RAW_FILEINFO_ALT_NAME_INFO:
     862             :         case RAW_FILEINFO_ALT_NAME_INFORMATION:
     863             :         case RAW_FILEINFO_STREAM_INFO:
     864             :         case RAW_FILEINFO_STREAM_INFORMATION:
     865             :         case RAW_FILEINFO_COMPRESSION_INFO:
     866             :         case RAW_FILEINFO_COMPRESSION_INFORMATION:
     867             :         case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
     868             :         case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
     869           8 :                 return NT_STATUS_INVALID_PARAMETER;
     870           1 :         case  RAW_FILEINFO_ALL_EAS:
     871           1 :                 return NT_STATUS_ACCESS_DENIED;
     872          20 :         default:
     873          20 :                 return ntvfs_map_qfileinfo(ntvfs, req, info);
     874             :         }
     875             : }
     876             : 
     877             : 
     878             : /*
     879             :   return filesystem info
     880             : */
     881           0 : static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
     882             :                            struct ntvfs_request *req, union smb_fsinfo *fs)
     883             : {
     884           0 :         return NT_STATUS_ACCESS_DENIED;
     885             : }
     886             : 
     887             : /*
     888             :   return print queue info
     889             : */
     890           0 : static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
     891             :                         struct ntvfs_request *req, union smb_lpq *lpq)
     892             : {
     893           0 :         return NT_STATUS_ACCESS_DENIED;
     894             : }
     895             : 
     896             : /* 
     897             :    list files in a directory matching a wildcard pattern
     898             : */
     899           0 : static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
     900             :                           struct ntvfs_request *req, union smb_search_first *io,
     901             :                           void *search_private, 
     902             :                           bool (*callback)(void *, const union smb_search_data *))
     903             : {
     904           0 :         return NT_STATUS_ACCESS_DENIED;
     905             : }
     906             : 
     907             : /* 
     908             :    continue listing files in a directory 
     909             : */
     910           0 : static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
     911             :                          struct ntvfs_request *req, union smb_search_next *io,
     912             :                          void *search_private, 
     913             :                          bool (*callback)(void *, const union smb_search_data *))
     914             : {
     915           0 :         return NT_STATUS_ACCESS_DENIED;
     916             : }
     917             : 
     918             : /* 
     919             :    end listing files in a directory 
     920             : */
     921           0 : static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
     922             :                           struct ntvfs_request *req, union smb_search_close *io)
     923             : {
     924           0 :         return NT_STATUS_ACCESS_DENIED;
     925             : }
     926             : 
     927             : struct ipc_trans_state {
     928             :         struct ipc_private *ipriv;
     929             :         struct pipe_state *p;
     930             :         struct ntvfs_request *req;
     931             :         struct smb_trans2 *trans;
     932             :         struct iovec writev_iov;
     933             :         struct ipc_readv_next_vector_state next_vector;
     934             : };
     935             : 
     936             : static void ipc_trans_writev_done(struct tevent_req *subreq);
     937             : static void ipc_trans_readv_done(struct tevent_req *subreq);
     938             : 
     939             : /* SMBtrans - handle a DCERPC command */
     940          42 : static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
     941             :                                struct ntvfs_request *req, struct smb_trans2 *trans)
     942             : {
     943          42 :         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
     944             :                                     struct ipc_private);
     945           0 :         struct pipe_state *p;
     946           0 :         DATA_BLOB fnum_key;
     947           0 :         uint16_t fnum;
     948           0 :         struct ipc_trans_state *state;
     949           0 :         struct tevent_req *subreq;
     950             : 
     951             :         /*
     952             :          * the fnum is in setup[1], a 16 bit value
     953             :          * the setup[*] values are already in host byteorder
     954             :          * but ntvfs_handle_search_by_wire_key() expects
     955             :          * network byteorder
     956             :          */
     957          42 :         SSVAL(&fnum, 0, trans->in.setup[1]);
     958          42 :         fnum_key = data_blob_const(&fnum, 2);
     959             : 
     960          42 :         p = pipe_state_find_key(ipriv, req, &fnum_key);
     961          42 :         if (!p) {
     962           9 :                 return NT_STATUS_INVALID_HANDLE;
     963             :         }
     964             : 
     965             :         /*
     966             :          * Trans requests are only allowed
     967             :          * if no other Trans or Read is active
     968             :          */
     969          33 :         if (tevent_queue_length(p->read_queue) > 0) {
     970           0 :                 return NT_STATUS_PIPE_BUSY;
     971             :         }
     972             : 
     973          33 :         state = talloc(req, struct ipc_trans_state);
     974          33 :         NT_STATUS_HAVE_NO_MEMORY(state);
     975             : 
     976          33 :         trans->out.setup_count = 0;
     977          33 :         trans->out.setup = NULL;
     978          33 :         trans->out.params = data_blob(NULL, 0);
     979          33 :         trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
     980          33 :         NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
     981             : 
     982          33 :         state->ipriv = ipriv;
     983          33 :         state->p = p;
     984          33 :         state->req = req;
     985          33 :         state->trans = trans;
     986          33 :         state->writev_iov.iov_base = (char *) trans->in.data.data;
     987          33 :         state->writev_iov.iov_len = trans->in.data.length;
     988             : 
     989          33 :         ipc_readv_next_vector_init(&state->next_vector,
     990             :                                    trans->out.data.data,
     991             :                                    trans->out.data.length);
     992             : 
     993          33 :         subreq = tstream_writev_queue_send(state,
     994          33 :                                            ipriv->ntvfs->ctx->event_ctx,
     995             :                                            p->npipe,
     996             :                                            p->write_queue,
     997          33 :                                            &state->writev_iov, 1);
     998          33 :         NT_STATUS_HAVE_NO_MEMORY(subreq);
     999          33 :         tevent_req_set_callback(subreq, ipc_trans_writev_done, state);
    1000             : 
    1001          33 :         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
    1002          33 :         return NT_STATUS_OK;
    1003             : }
    1004             : 
    1005          33 : static void ipc_trans_writev_done(struct tevent_req *subreq)
    1006             : {
    1007           0 :         struct ipc_trans_state *state =
    1008          33 :                 tevent_req_callback_data(subreq,
    1009             :                 struct ipc_trans_state);
    1010          33 :         struct ipc_private *ipriv = state->ipriv;
    1011          33 :         struct pipe_state *p = state->p;
    1012          33 :         struct ntvfs_request *req = state->req;
    1013           0 :         int ret;
    1014           0 :         int sys_errno;
    1015           0 :         NTSTATUS status;
    1016             : 
    1017          33 :         ret = tstream_writev_queue_recv(subreq, &sys_errno);
    1018          33 :         TALLOC_FREE(subreq);
    1019          33 :         if (ret == 0) {
    1020           0 :                 status = NT_STATUS_PIPE_DISCONNECTED;
    1021           0 :                 goto reply;
    1022          33 :         } else if (ret == -1) {
    1023           0 :                 status = map_nt_error_from_unix_common(sys_errno);
    1024           0 :                 goto reply;
    1025             :         }
    1026             : 
    1027          33 :         subreq = tstream_readv_pdu_queue_send(state,
    1028          33 :                                               ipriv->ntvfs->ctx->event_ctx,
    1029             :                                               p->npipe,
    1030             :                                               p->read_queue,
    1031             :                                               ipc_readv_next_vector,
    1032          33 :                                               &state->next_vector);
    1033          33 :         if (!subreq) {
    1034           0 :                 status = NT_STATUS_NO_MEMORY;
    1035           0 :                 goto reply;
    1036             :         }
    1037          33 :         tevent_req_set_callback(subreq, ipc_trans_readv_done, state);
    1038          33 :         return;
    1039             : 
    1040           0 : reply:
    1041           0 :         req->async_states->status = status;
    1042           0 :         req->async_states->send_fn(req);
    1043             : }
    1044             : 
    1045          33 : static void ipc_trans_readv_done(struct tevent_req *subreq)
    1046             : {
    1047           0 :         struct ipc_trans_state *state =
    1048          33 :                 tevent_req_callback_data(subreq,
    1049             :                 struct ipc_trans_state);
    1050          33 :         struct ntvfs_request *req = state->req;
    1051          33 :         struct smb_trans2 *trans = state->trans;
    1052           0 :         int ret;
    1053           0 :         int sys_errno;
    1054           0 :         NTSTATUS status;
    1055             : 
    1056          33 :         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
    1057          33 :         TALLOC_FREE(subreq);
    1058          33 :         if (ret == -1) {
    1059           0 :                 status = map_nt_error_from_unix_common(sys_errno);
    1060           0 :                 goto reply;
    1061             :         }
    1062             : 
    1063          33 :         status = NT_STATUS_OK;
    1064          33 :         if (state->next_vector.remaining > 0) {
    1065           0 :                 status = STATUS_BUFFER_OVERFLOW;
    1066             :         }
    1067             : 
    1068          33 :         trans->out.data.length = ret;
    1069             : 
    1070          33 : reply:
    1071          33 :         req->async_states->status = status;
    1072          33 :         req->async_states->send_fn(req);
    1073          33 : }
    1074             : 
    1075             : /* SMBtrans - set named pipe state */
    1076           0 : static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
    1077             :                                       struct ntvfs_request *req, struct smb_trans2 *trans)
    1078             : {
    1079           0 :         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
    1080             :                                     struct ipc_private);
    1081           0 :         struct pipe_state *p;
    1082           0 :         DATA_BLOB fnum_key;
    1083             : 
    1084             :         /* the fnum is in setup[1] */
    1085           0 :         fnum_key = data_blob_const(&trans->in.setup[1], sizeof(trans->in.setup[1]));
    1086             : 
    1087           0 :         p = pipe_state_find_key(ipriv, req, &fnum_key);
    1088           0 :         if (!p) {
    1089           0 :                 return NT_STATUS_INVALID_HANDLE;
    1090             :         }
    1091             : 
    1092           0 :         if (trans->in.params.length != 2) {
    1093           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1094             :         }
    1095             : 
    1096             :         /*
    1097             :          * TODO: pass this to the tstream_npa logic
    1098             :          */
    1099           0 :         p->device_state = SVAL(trans->in.params.data, 0);
    1100             : 
    1101           0 :         trans->out.setup_count = 0;
    1102           0 :         trans->out.setup = NULL;
    1103           0 :         trans->out.params = data_blob(NULL, 0);
    1104           0 :         trans->out.data = data_blob(NULL, 0);
    1105             : 
    1106           0 :         return NT_STATUS_OK;
    1107             : }
    1108             : 
    1109             : 
    1110             : /* SMBtrans - used to provide access to SMB pipes */
    1111          42 : static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
    1112             :                                 struct ntvfs_request *req, struct smb_trans2 *trans)
    1113             : {
    1114           0 :         NTSTATUS status;
    1115             : 
    1116          42 :         if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
    1117           0 :                 return ipc_rap_call(req, ntvfs->ctx->event_ctx, ntvfs->ctx->lp_ctx, trans);
    1118             : 
    1119          42 :         if (trans->in.setup_count != 2) {
    1120           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1121             :         }
    1122             : 
    1123          42 :         switch (trans->in.setup[0]) {
    1124           0 :         case TRANSACT_SETNAMEDPIPEHANDLESTATE:
    1125           0 :                 status = ipc_set_nm_pipe_state(ntvfs, req, trans);
    1126           0 :                 break;
    1127          42 :         case TRANSACT_DCERPCCMD:
    1128          42 :                 status = ipc_dcerpc_cmd(ntvfs, req, trans);
    1129          42 :                 break;
    1130           0 :         default:
    1131           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1132           0 :                 break;
    1133             :         }
    1134             : 
    1135          42 :         return status;
    1136             : }
    1137             : 
    1138             : struct ipc_ioctl_state {
    1139             :         struct ipc_private *ipriv;
    1140             :         struct pipe_state *p;
    1141             :         struct ntvfs_request *req;
    1142             :         union smb_ioctl *io;
    1143             :         struct iovec writev_iov;
    1144             :         struct ipc_readv_next_vector_state next_vector;
    1145             : };
    1146             : 
    1147             : static void ipc_ioctl_writev_done(struct tevent_req *subreq);
    1148             : static void ipc_ioctl_readv_done(struct tevent_req *subreq);
    1149             : 
    1150       47081 : static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
    1151             :                                struct ntvfs_request *req, union smb_ioctl *io)
    1152             : {
    1153       47081 :         struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
    1154             :                                     struct ipc_private);
    1155           0 :         struct pipe_state *p;
    1156           0 :         struct ipc_ioctl_state *state;
    1157           0 :         struct tevent_req *subreq;
    1158             : 
    1159       47081 :         switch (io->smb2.in.function) {
    1160       47081 :         case FSCTL_NAMED_PIPE_READ_WRITE:
    1161       47081 :                 break;
    1162             : 
    1163           0 :         default:
    1164           0 :                 return NT_STATUS_FS_DRIVER_REQUIRED;
    1165             :         }
    1166             : 
    1167       47081 :         p = pipe_state_find(ipriv, io->smb2.in.file.ntvfs);
    1168       47081 :         if (!p) {
    1169           0 :                 return NT_STATUS_INVALID_HANDLE;
    1170             :         }
    1171             : 
    1172             :         /*
    1173             :          * Trans requests are only allowed
    1174             :          * if no other Trans or Read is active
    1175             :          */
    1176       47081 :         if (tevent_queue_length(p->read_queue) > 0) {
    1177           0 :                 return NT_STATUS_PIPE_BUSY;
    1178             :         }
    1179             : 
    1180       47081 :         state = talloc(req, struct ipc_ioctl_state);
    1181       47081 :         NT_STATUS_HAVE_NO_MEMORY(state);
    1182             : 
    1183       47081 :         io->smb2.out.reserved        = 0;
    1184       47081 :         io->smb2.out.function        = io->smb2.in.function;
    1185       47081 :         io->smb2.out.flags   = 0;
    1186       47081 :         io->smb2.out.reserved2       = 0;
    1187       47081 :         io->smb2.out.in              = data_blob_null;
    1188       47081 :         io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_output_response);
    1189       47081 :         NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
    1190             : 
    1191       47081 :         state->ipriv = ipriv;
    1192       47081 :         state->p = p;
    1193       47081 :         state->req = req;
    1194       47081 :         state->io = io;
    1195       47081 :         state->writev_iov.iov_base = (char *) io->smb2.in.out.data;
    1196       47081 :         state->writev_iov.iov_len = io->smb2.in.out.length;
    1197             : 
    1198       47081 :         ipc_readv_next_vector_init(&state->next_vector,
    1199             :                                    io->smb2.out.out.data,
    1200             :                                    io->smb2.out.out.length);
    1201             : 
    1202       47081 :         subreq = tstream_writev_queue_send(state,
    1203       47081 :                                            ipriv->ntvfs->ctx->event_ctx,
    1204             :                                            p->npipe,
    1205             :                                            p->write_queue,
    1206       47081 :                                            &state->writev_iov, 1);
    1207       47081 :         NT_STATUS_HAVE_NO_MEMORY(subreq);
    1208       47081 :         tevent_req_set_callback(subreq, ipc_ioctl_writev_done, state);
    1209             : 
    1210       47081 :         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
    1211       47081 :         return NT_STATUS_OK;
    1212             : }
    1213             : 
    1214       47081 : static void ipc_ioctl_writev_done(struct tevent_req *subreq)
    1215             : {
    1216           0 :         struct ipc_ioctl_state *state =
    1217       47081 :                 tevent_req_callback_data(subreq,
    1218             :                 struct ipc_ioctl_state);
    1219       47081 :         struct ipc_private *ipriv = state->ipriv;
    1220       47081 :         struct pipe_state *p = state->p;
    1221       47081 :         struct ntvfs_request *req = state->req;
    1222           0 :         int ret;
    1223           0 :         int sys_errno;
    1224           0 :         NTSTATUS status;
    1225             : 
    1226       47081 :         ret = tstream_writev_queue_recv(subreq, &sys_errno);
    1227       47081 :         TALLOC_FREE(subreq);
    1228       47081 :         if (ret == -1) {
    1229           0 :                 status = map_nt_error_from_unix_common(sys_errno);
    1230           0 :                 goto reply;
    1231             :         }
    1232             : 
    1233       47081 :         subreq = tstream_readv_pdu_queue_send(state,
    1234       47081 :                                               ipriv->ntvfs->ctx->event_ctx,
    1235             :                                               p->npipe,
    1236             :                                               p->read_queue,
    1237             :                                               ipc_readv_next_vector,
    1238       47081 :                                               &state->next_vector);
    1239       47081 :         if (!subreq) {
    1240           0 :                 status = NT_STATUS_NO_MEMORY;
    1241           0 :                 goto reply;
    1242             :         }
    1243       47081 :         tevent_req_set_callback(subreq, ipc_ioctl_readv_done, state);
    1244       47081 :         return;
    1245             : 
    1246           0 : reply:
    1247           0 :         req->async_states->status = status;
    1248           0 :         req->async_states->send_fn(req);
    1249             : }
    1250             : 
    1251       47081 : static void ipc_ioctl_readv_done(struct tevent_req *subreq)
    1252             : {
    1253           0 :         struct ipc_ioctl_state *state =
    1254       47081 :                 tevent_req_callback_data(subreq,
    1255             :                 struct ipc_ioctl_state);
    1256       47081 :         struct ntvfs_request *req = state->req;
    1257       47081 :         union smb_ioctl *io = state->io;
    1258           0 :         int ret;
    1259           0 :         int sys_errno;
    1260           0 :         NTSTATUS status;
    1261             : 
    1262       47081 :         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
    1263       47081 :         TALLOC_FREE(subreq);
    1264       47081 :         if (ret == -1) {
    1265           0 :                 status = map_nt_error_from_unix_common(sys_errno);
    1266           0 :                 goto reply;
    1267             :         }
    1268             : 
    1269       47081 :         status = NT_STATUS_OK;
    1270       47081 :         if (state->next_vector.remaining > 0) {
    1271           0 :                 status = STATUS_BUFFER_OVERFLOW;
    1272             :         }
    1273             : 
    1274       47081 :         io->smb2.out.out.length = ret;
    1275             : 
    1276       47081 : reply:
    1277       47081 :         req->async_states->status = status;
    1278       47081 :         req->async_states->send_fn(req);
    1279       47081 : }
    1280             : 
    1281             : /*
    1282             :   ioctl interface
    1283             : */
    1284       48005 : static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
    1285             :                           struct ntvfs_request *req, union smb_ioctl *io)
    1286             : {
    1287       48005 :         switch (io->generic.level) {
    1288       47081 :         case RAW_IOCTL_SMB2:
    1289       47081 :                 return ipc_ioctl_smb2(ntvfs, req, io);
    1290             : 
    1291         924 :         case RAW_IOCTL_SMB2_NO_HANDLE:
    1292         924 :                 return NT_STATUS_FS_DRIVER_REQUIRED;
    1293             : 
    1294           0 :         default:
    1295           0 :                 return NT_STATUS_ACCESS_DENIED;
    1296             :         }
    1297             : }
    1298             : 
    1299             : 
    1300             : /*
    1301             :   initialise the IPC backend, registering ourselves with the ntvfs subsystem
    1302             :  */
    1303          68 : NTSTATUS ntvfs_ipc_init(TALLOC_CTX *ctx)
    1304             : {
    1305           3 :         NTSTATUS ret;
    1306           3 :         struct ntvfs_ops ops;
    1307          68 :         NTVFS_CURRENT_CRITICAL_SIZES(vers);
    1308             : 
    1309          68 :         ZERO_STRUCT(ops);
    1310             :         
    1311             :         /* fill in the name and type */
    1312          68 :         ops.name = "default";
    1313          68 :         ops.type = NTVFS_IPC;
    1314             : 
    1315             :         /* fill in all the operations */
    1316          68 :         ops.connect_fn = ipc_connect;
    1317          68 :         ops.disconnect_fn = ipc_disconnect;
    1318          68 :         ops.unlink_fn = ipc_unlink;
    1319          68 :         ops.chkpath_fn = ipc_chkpath;
    1320          68 :         ops.qpathinfo_fn = ipc_qpathinfo;
    1321          68 :         ops.setpathinfo_fn = ipc_setpathinfo;
    1322          68 :         ops.open_fn = ipc_open;
    1323          68 :         ops.mkdir_fn = ipc_mkdir;
    1324          68 :         ops.rmdir_fn = ipc_rmdir;
    1325          68 :         ops.rename_fn = ipc_rename;
    1326          68 :         ops.copy_fn = ipc_copy;
    1327          68 :         ops.ioctl_fn = ipc_ioctl;
    1328          68 :         ops.read_fn = ipc_read;
    1329          68 :         ops.write_fn = ipc_write;
    1330          68 :         ops.seek_fn = ipc_seek;
    1331          68 :         ops.flush_fn = ipc_flush;
    1332          68 :         ops.close_fn = ipc_close;
    1333          68 :         ops.exit_fn = ipc_exit;
    1334          68 :         ops.lock_fn = ipc_lock;
    1335          68 :         ops.setfileinfo_fn = ipc_setfileinfo;
    1336          68 :         ops.qfileinfo_fn = ipc_qfileinfo;
    1337          68 :         ops.fsinfo_fn = ipc_fsinfo;
    1338          68 :         ops.lpq_fn = ipc_lpq;
    1339          68 :         ops.search_first_fn = ipc_search_first;
    1340          68 :         ops.search_next_fn = ipc_search_next;
    1341          68 :         ops.search_close_fn = ipc_search_close;
    1342          68 :         ops.trans_fn = ipc_trans;
    1343          68 :         ops.logoff_fn = ipc_logoff;
    1344          68 :         ops.async_setup_fn = ipc_async_setup;
    1345          68 :         ops.cancel_fn = ipc_cancel;
    1346             : 
    1347             :         /* register ourselves with the NTVFS subsystem. */
    1348          68 :         ret = ntvfs_register(&ops, &vers);
    1349             : 
    1350          68 :         if (!NT_STATUS_IS_OK(ret)) {
    1351           0 :                 DEBUG(0,("Failed to register IPC backend!\n"));
    1352           0 :                 return ret;
    1353             :         }
    1354             : 
    1355          68 :         return ret;
    1356             : }

Generated by: LCOV version 1.14