vlp: Move closer to the code tested.
[kai/samba.git] / source3 / smbd / pipes.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Pipe SMB reply routines
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Luke Kenneth Casson Leighton 1996-1998
6    Copyright (C) Paul Ashton  1997-1998.
7    Copyright (C) Jeremy Allison 2005.
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 /*
23    This file handles reply_ calls on named pipes that the server
24    makes to handle specific protocols
25 */
26
27
28 #include "includes.h"
29
30 #define PIPE            "\\PIPE\\"
31 #define PIPELEN         strlen(PIPE)
32
33 #define MAX_PIPE_NAME_LEN       24
34
35 /****************************************************************************
36  Reply to an open and X on a named pipe.
37  This code is basically stolen from reply_open_and_X with some
38  wrinkles to handle pipes.
39 ****************************************************************************/
40
41 void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req)
42 {
43         const char *fname = NULL;
44         char *pipe_name = NULL;
45         files_struct *fsp;
46         int size=0,fmode=0,mtime=0,rmode=0;
47         TALLOC_CTX *ctx = talloc_tos();
48         NTSTATUS status;
49
50         /* XXXX we need to handle passed times, sattr and flags */
51         srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2, &pipe_name,
52                         smb_buf(req->inbuf), STR_TERMINATE);
53         if (!pipe_name) {
54                 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
55                                 ERRDOS, ERRbadpipe);
56                 return;
57         }
58
59         /* If the name doesn't start \PIPE\ then this is directed */
60         /* at a mailslot or something we really, really don't understand, */
61         /* not just something we really don't understand. */
62         if ( strncmp(pipe_name,PIPE,PIPELEN) != 0 ) {
63                 reply_doserror(req, ERRSRV, ERRaccess);
64                 return;
65         }
66
67         DEBUG(4,("Opening pipe %s.\n", pipe_name));
68
69         /* See if it is one we want to handle. */
70         if (!is_known_pipename(pipe_name)) {
71                 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
72                                 ERRDOS, ERRbadpipe);
73                 return;
74         }
75
76         /* Strip \PIPE\ off the name. */
77         fname = pipe_name + PIPELEN;
78
79 #if 0
80         /*
81          * Hack for NT printers... JRA.
82          */
83         if(should_fail_next_srvsvc_open(fname)) {
84                 reply_doserror(req, ERRSRV, ERRaccess);
85                 return;
86         }
87 #endif
88
89         /* Known pipes arrive with DIR attribs. Remove it so a regular file */
90         /* can be opened and add it in after the open. */
91         DEBUG(3,("Known pipe %s opening.\n",fname));
92
93         status = np_open(req, conn, fname, &fsp);
94         if (!NT_STATUS_IS_OK(status)) {
95                 reply_nterror(req, status);
96                 return;
97         }
98
99         /* Prepare the reply */
100         reply_outbuf(req, 15, 0);
101
102         /* Mark the opened file as an existing named pipe in message mode. */
103         SSVAL(req->outbuf,smb_vwv9,2);
104         SSVAL(req->outbuf,smb_vwv10,0xc700);
105
106         if (rmode == 2) {
107                 DEBUG(4,("Resetting open result to open from create.\n"));
108                 rmode = 1;
109         }
110
111         SSVAL(req->outbuf,smb_vwv2, fsp->fnum);
112         SSVAL(req->outbuf,smb_vwv3,fmode);
113         srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
114         SIVAL(req->outbuf,smb_vwv6,size);
115         SSVAL(req->outbuf,smb_vwv8,rmode);
116         SSVAL(req->outbuf,smb_vwv11,0x0001);
117
118         chain_reply(req);
119         return;
120 }
121
122 /****************************************************************************
123  Reply to a write on a pipe.
124 ****************************************************************************/
125
126 void reply_pipe_write(struct smb_request *req)
127 {
128         files_struct *fsp = file_fsp(req, SVAL(req->inbuf,smb_vwv0));
129         size_t numtowrite = SVAL(req->inbuf,smb_vwv1);
130         ssize_t nwritten;
131         uint8_t *data;
132
133         if (!fsp_is_np(fsp)) {
134                 reply_doserror(req, ERRDOS, ERRbadfid);
135                 return;
136         }
137
138         if (fsp->vuid != req->vuid) {
139                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
140                 return;
141         }
142
143         data = (uint8_t *)smb_buf(req->inbuf) + 3;
144
145         if (numtowrite == 0) {
146                 nwritten = 0;
147         } else {
148                 NTSTATUS status;
149                 status = np_write(fsp, data, numtowrite, &nwritten);
150                 if (!NT_STATUS_IS_OK(status)) {
151                         reply_nterror(req, status);
152                         return;
153                 }
154         }
155
156         if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) {
157                 reply_unixerror(req, ERRDOS, ERRnoaccess);
158                 return;
159         }
160
161         reply_outbuf(req, 1, 0);
162
163         SSVAL(req->outbuf,smb_vwv0,nwritten);
164   
165         DEBUG(3,("write-IPC pnum=%04x nwritten=%d\n", fsp->fnum,
166                  (int)nwritten));
167
168         return;
169 }
170
171 /****************************************************************************
172  Reply to a write and X.
173
174  This code is basically stolen from reply_write_and_X with some
175  wrinkles to handle pipes.
176 ****************************************************************************/
177
178 void reply_pipe_write_and_X(struct smb_request *req)
179 {
180         files_struct *fsp = file_fsp(req, SVAL(req->inbuf, smb_vwv2));
181         size_t numtowrite = SVAL(req->inbuf,smb_vwv10);
182         ssize_t nwritten;
183         int smb_doff = SVAL(req->inbuf, smb_vwv11);
184         bool pipe_start_message_raw =
185                 ((SVAL(req->inbuf, smb_vwv7)
186                   & (PIPE_START_MESSAGE|PIPE_RAW_MODE))
187                  == (PIPE_START_MESSAGE|PIPE_RAW_MODE));
188         uint8_t *data;
189
190         if (!fsp_is_np(fsp)) {
191                 reply_doserror(req, ERRDOS, ERRbadfid);
192                 return;
193         }
194
195         if (fsp->vuid != req->vuid) {
196                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
197                 return;
198         }
199
200         data = (uint8_t *)smb_base(req->inbuf) + smb_doff;
201
202         if (numtowrite == 0) {
203                 nwritten = 0;
204         } else {
205                 NTSTATUS status;
206
207                 if(pipe_start_message_raw) {
208                         /*
209                          * For the start of a message in named pipe byte mode,
210                          * the first two bytes are a length-of-pdu field. Ignore
211                          * them (we don't trust the client). JRA.
212                          */
213                        if(numtowrite < 2) {
214                                 DEBUG(0,("reply_pipe_write_and_X: start of "
215                                          "message set and not enough data "
216                                          "sent.(%u)\n",
217                                          (unsigned int)numtowrite ));
218                                 reply_unixerror(req, ERRDOS, ERRnoaccess);
219                                 return;
220                         }
221
222                         data += 2;
223                         numtowrite -= 2;
224                 }                        
225                 status = np_write(fsp, data, numtowrite, &nwritten);
226                 if (!NT_STATUS_IS_OK(status)) {
227                         reply_nterror(req, status);
228                         return;
229                 }
230         }
231
232         if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) {
233                 reply_unixerror(req, ERRDOS,ERRnoaccess);
234                 return;
235         }
236
237         reply_outbuf(req, 6, 0);
238
239         nwritten = (pipe_start_message_raw ? nwritten + 2 : nwritten);
240         SSVAL(req->outbuf,smb_vwv2,nwritten);
241   
242         DEBUG(3,("writeX-IPC pnum=%04x nwritten=%d\n", fsp->fnum,
243                  (int)nwritten));
244
245         chain_reply(req);
246 }
247
248 /****************************************************************************
249  Reply to a read and X.
250  This code is basically stolen from reply_read_and_X with some
251  wrinkles to handle pipes.
252 ****************************************************************************/
253
254 void reply_pipe_read_and_X(struct smb_request *req)
255 {
256         files_struct *fsp = file_fsp(req, SVAL(req->inbuf,smb_vwv0));
257         int smb_maxcnt = SVAL(req->inbuf,smb_vwv5);
258         int smb_mincnt = SVAL(req->inbuf,smb_vwv6);
259         ssize_t nread;
260         uint8_t *data;
261         bool unused;
262         NTSTATUS status;
263
264         /* we don't use the offset given to use for pipe reads. This
265            is deliberate, instead we always return the next lump of
266            data on the pipe */
267 #if 0
268         uint32 smb_offs = IVAL(req->inbuf,smb_vwv3);
269 #endif
270
271         if (!fsp_is_np(fsp)) {
272                 reply_doserror(req, ERRDOS, ERRbadfid);
273                 return;
274         }
275
276         if (fsp->vuid != req->vuid) {
277                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
278                 return;
279         }
280
281         reply_outbuf(req, 12, smb_maxcnt);
282
283         data = (uint8_t *)smb_buf(req->outbuf);
284
285         status = np_read(fsp, data, smb_maxcnt, &nread, &unused);
286
287         if (!NT_STATUS_IS_OK(status)) {
288                 reply_doserror(req, ERRDOS, ERRnoaccess);
289                 return;
290         }
291
292         srv_set_message((char *)req->outbuf, 12, nread, False);
293   
294         SSVAL(req->outbuf,smb_vwv5,nread);
295         SSVAL(req->outbuf,smb_vwv6,smb_offset(data,req->outbuf));
296         SSVAL(smb_buf(req->outbuf),-2,nread);
297   
298         DEBUG(3,("readX-IPC pnum=%04x min=%d max=%d nread=%d\n",
299                  fsp->fnum, smb_mincnt, smb_maxcnt, (int)nread));
300
301         chain_reply(req);
302 }