Standardize License information
[openafs.git] / src / WINNT / afsd / smb_ioctl.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <windows.h>
14 #include <stdlib.h>
15 #include <malloc.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <time.h>
19
20 #include <osi.h>
21
22 #include "afsd.h"
23
24 #include "smb.h"
25
26 smb_ioctlProc_t *smb_ioctlProcsp[SMB_IOCTL_MAXPROCS];
27
28 void smb_InitIoctl(void)
29 {
30         smb_ioctlProcsp[VIOCGETAL] = cm_IoctlGetACL;
31         smb_ioctlProcsp[VIOC_FILE_CELL_NAME] = cm_IoctlGetFileCellName;
32         smb_ioctlProcsp[VIOCSETAL] = cm_IoctlSetACL;
33         smb_ioctlProcsp[VIOC_FLUSHVOLUME] = cm_IoctlFlushVolume;
34         smb_ioctlProcsp[VIOCFLUSH] = cm_IoctlFlushFile;
35         smb_ioctlProcsp[VIOCSETVOLSTAT] = cm_IoctlSetVolumeStatus;
36         smb_ioctlProcsp[VIOCGETVOLSTAT] = cm_IoctlGetVolumeStatus;
37         smb_ioctlProcsp[VIOCWHEREIS] = cm_IoctlWhereIs;
38         smb_ioctlProcsp[VIOC_AFS_STAT_MT_PT] = cm_IoctlStatMountPoint;
39         smb_ioctlProcsp[VIOC_AFS_DELETE_MT_PT] = cm_IoctlDeleteMountPoint;
40         smb_ioctlProcsp[VIOCCKSERV] = cm_IoctlCheckServers;
41         smb_ioctlProcsp[VIOC_GAG] = cm_IoctlGag;
42         smb_ioctlProcsp[VIOCCKBACK] = cm_IoctlCheckVolumes;
43         smb_ioctlProcsp[VIOCSETCACHESIZE] = cm_IoctlSetCacheSize;
44         smb_ioctlProcsp[VIOCGETCACHEPARMS] = cm_IoctlGetCacheParms;
45         smb_ioctlProcsp[VIOCGETCELL] = cm_IoctlGetCell;
46         smb_ioctlProcsp[VIOCNEWCELL] = cm_IoctlNewCell;
47         smb_ioctlProcsp[VIOC_GET_WS_CELL] = cm_IoctlGetWsCell;
48         smb_ioctlProcsp[VIOC_AFS_SYSNAME] = cm_IoctlSysName;
49         smb_ioctlProcsp[VIOC_GETCELLSTATUS] = cm_IoctlGetCellStatus;
50         smb_ioctlProcsp[VIOC_SETCELLSTATUS] = cm_IoctlSetCellStatus;
51         smb_ioctlProcsp[VIOC_SETSPREFS] = cm_IoctlSetSPrefs;
52         smb_ioctlProcsp[VIOC_GETSPREFS] = cm_IoctlGetSPrefs;
53         smb_ioctlProcsp[VIOC_STOREBEHIND] = cm_IoctlStoreBehind;
54         smb_ioctlProcsp[VIOC_AFS_CREATE_MT_PT] = cm_IoctlCreateMountPoint;
55         smb_ioctlProcsp[VIOC_TRACECTL] = cm_IoctlTraceControl;
56         smb_ioctlProcsp[VIOCSETTOK] = cm_IoctlSetToken;
57         smb_ioctlProcsp[VIOCGETTOK] = cm_IoctlGetTokenIter;
58         smb_ioctlProcsp[VIOCNEWGETTOK] = cm_IoctlGetToken;
59         smb_ioctlProcsp[VIOCDELTOK] = cm_IoctlDelToken;
60         smb_ioctlProcsp[VIOCDELALLTOK] = cm_IoctlDelAllToken;
61         smb_ioctlProcsp[VIOC_SYMLINK] = cm_IoctlSymlink;
62         smb_ioctlProcsp[VIOC_LISTSYMLINK] = cm_IoctlListlink;
63         smb_ioctlProcsp[VIOC_DELSYMLINK] = cm_IoctlDeletelink;
64         smb_ioctlProcsp[VIOC_MAKESUBMOUNT] = cm_IoctlMakeSubmount;
65 }
66
67 /* called to make a fid structure into an IOCTL fid structure */
68 void smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
69 {
70         smb_ioctl_t *iop;
71         cm_space_t *copyPrefix;
72
73         lock_ObtainMutex(&fidp->mx);
74         fidp->flags |= SMB_FID_IOCTL;
75         fidp->scp = &cm_fakeSCache;
76         if (fidp->ioctlp == NULL) {
77                 iop = malloc(sizeof(*iop));
78                 memset(iop, 0, sizeof(*iop));
79                 fidp->ioctlp = iop;
80         }
81         if (prefix) {
82                 copyPrefix = cm_GetSpace();
83                 strcpy(copyPrefix->data, prefix->data);
84                 fidp->ioctlp->prefix = copyPrefix;
85         }
86         lock_ReleaseMutex(&fidp->mx);
87 }
88
89 /* called when we receive a read call, does the send of the received data if
90  * this is the first read call.  This is the function that actually makes the
91  * call to the ioctl code.
92  */
93 smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
94 {
95         long opcode;
96         smb_ioctlProc_t *procp;
97         long code;
98
99         if (ioctlp->flags & SMB_IOCTLFLAG_DATAIN) {
100                 ioctlp->flags &= ~SMB_IOCTLFLAG_DATAIN;
101                 
102                 /* do the call now, or fail if we didn't get an opcode, or
103                  * enough of an opcode.
104                  */
105                 if (ioctlp->inCopied < sizeof(long)) return CM_ERROR_INVAL;
106                 memcpy(&opcode, ioctlp->inDatap, sizeof(long));
107                 ioctlp->inDatap += sizeof(long);
108
109                 osi_Log1(afsd_logp, "Ioctl opcode %d", opcode);
110
111                 /* check for opcode out of bounds */
112                 if (opcode < 0 || opcode >= SMB_IOCTL_MAXPROCS)
113                         return CM_ERROR_TOOBIG;
114                 
115                 /* check for no such proc */
116                 procp = smb_ioctlProcsp[opcode];
117                 if (procp == NULL) return CM_ERROR_BADOP;
118
119                 /* otherwise, make the call */
120                 ioctlp->outDatap += sizeof(long);       /* reserve room for return code */
121                 code = (*procp)(ioctlp, userp);
122
123                 osi_Log1(afsd_logp, "Ioctl return code %d", code);
124
125                 /* copy in return code */
126                 memcpy(ioctlp->outAllocp, &code, sizeof(long));
127         }
128         return 0;
129 }
130
131 /* called when we receive a write call.  If this is the first write call after
132  * a series of reads (or the very first call), then we start a new call.
133  * We also ensure that things are properly initialized for the start of a call.
134  */
135 void smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
136 {
137         /* make sure the buffer(s) are allocated */
138         if (!ioctlp->inAllocp) ioctlp->inAllocp = malloc(SMB_IOCTL_MAXDATA);
139         if (!ioctlp->outAllocp) ioctlp->outAllocp = malloc(SMB_IOCTL_MAXDATA);
140
141         /* and make sure that we've reset our state for the new incoming request */
142         if (!(ioctlp->flags & SMB_IOCTLFLAG_DATAIN)) {
143                 ioctlp->inCopied = 0;
144                 ioctlp->outCopied = 0;
145                 ioctlp->inDatap = ioctlp->inAllocp;
146                 ioctlp->outDatap = ioctlp->outAllocp;
147                 ioctlp->flags |= SMB_IOCTLFLAG_DATAIN;
148         }
149 }
150
151 /* called from smb_ReceiveCoreRead when we receive a read on the ioctl fid */
152 long smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
153         smb_packet_t *outp)
154 {
155         smb_ioctl_t *iop;
156         long count;
157         long leftToCopy;
158         char *op;
159         long code;
160         cm_user_t *userp;
161
162         iop = fidp->ioctlp;
163         count = smb_GetSMBParm(inp, 1);
164         userp = smb_GetUser(vcp, inp);
165
166         /* Identify tree */
167         iop->tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
168
169         /* turn the connection around, if required */
170         code = smb_IoctlPrepareRead(fidp, iop, userp);
171
172         if (code) {
173                 cm_ReleaseUser(userp);
174                 return code;
175         }
176
177         if (iop->flags & SMB_IOCTLFLAG_LOGON) {
178                 vcp->logonDLLUser = userp;
179                 userp->flags |= CM_USERFLAG_WASLOGON;
180         }
181
182         leftToCopy = (iop->outDatap - iop->outAllocp) - iop->outCopied;
183         if (count > leftToCopy) count = leftToCopy;
184         
185         /* now set the parms for a read of count bytes */
186         smb_SetSMBParm(outp, 0, count);
187         smb_SetSMBParm(outp, 1, 0);
188         smb_SetSMBParm(outp, 2, 0);
189         smb_SetSMBParm(outp, 3, 0);
190         smb_SetSMBParm(outp, 4, 0);
191
192         smb_SetSMBDataLength(outp, count+3);
193
194         op = smb_GetSMBData(outp, NULL);
195         *op++ = 1;
196         *op++ = count & 0xff;
197         *op++ = (count >> 8) & 0xff;
198         
199         /* now copy the data into the response packet */
200         memcpy(op, iop->outCopied + iop->outAllocp, count);
201
202         /* and adjust the counters */
203         iop->outCopied += count;
204         
205         cm_ReleaseUser(userp);
206         smb_ReleaseFID(fidp);
207
208         return 0;
209 }
210
211 /* called from smb_ReceiveCoreWrite when we receive a write call on the IOCTL
212  * file descriptor.
213  */
214 long smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
215 {
216         smb_ioctl_t *iop;
217         long count;
218         long code;
219         char *op;
220         long inDataBlockCount;
221
222         code = 0;
223         count = smb_GetSMBParm(inp, 1);
224         iop = fidp->ioctlp;
225         
226         smb_IoctlPrepareWrite(fidp, iop);
227
228         op = smb_GetSMBData(inp, NULL);
229         op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
230         
231         if (count + iop->inCopied > SMB_IOCTL_MAXDATA) {
232                 code = CM_ERROR_TOOBIG;
233                 goto done;
234         }
235         
236         /* copy data */
237         memcpy(iop->inDatap + iop->inCopied, op, count);
238         
239         /* adjust counts */
240         iop->inCopied += count;
241
242 done:
243         /* return # of bytes written */
244         if (code == 0) {
245                 smb_SetSMBParm(outp, 0, count);
246                 smb_SetSMBDataLength(outp, 0);
247         }
248
249         smb_ReleaseFID(fidp);
250         return code;
251 }
252
253 /* called from V3 read to handle IOCTL descriptor reads */
254 long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
255 {
256         smb_ioctl_t *iop;
257         long count;
258         long code;
259         long leftToCopy;
260         char *op;
261         cm_user_t *userp;
262
263         iop = fidp->ioctlp;
264         count = smb_GetSMBParm(inp, 5);
265         
266         userp = smb_GetUser(vcp, inp);
267
268         {
269                 smb_user_t *uidp;
270
271                 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
272                 osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
273                          uidp->userID, userp,
274                          osi_LogSaveString(afsd_logp, uidp->name));
275                 smb_ReleaseUID(uidp);
276         }
277
278         iop->tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
279
280         code = smb_IoctlPrepareRead(fidp, iop, userp);
281         if (code) {
282                 cm_ReleaseUser(userp);
283                 smb_ReleaseFID(fidp);
284                 return code;
285         }
286
287         if (iop->flags & SMB_IOCTLFLAG_LOGON) {
288                 vcp->logonDLLUser = userp;
289                 userp->flags |= CM_USERFLAG_WASLOGON;
290         }
291
292         leftToCopy = (iop->outDatap - iop->outAllocp) - iop->outCopied;
293         if (count > leftToCopy) count = leftToCopy;
294         
295         /* 0 and 1 are reserved for request chaining, were setup by our caller,
296          * and will be further filled in after we return.
297          */
298         smb_SetSMBParm(outp, 2, 0);     /* remaining bytes, for pipes */
299         smb_SetSMBParm(outp, 3, 0);     /* resvd */
300         smb_SetSMBParm(outp, 4, 0);     /* resvd */
301         smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
302         /* fill in #6 when we have all the parameters' space reserved */
303         smb_SetSMBParm(outp, 7, 0);     /* resv'd */
304         smb_SetSMBParm(outp, 8, 0);     /* resv'd */
305         smb_SetSMBParm(outp, 9, 0);     /* resv'd */
306         smb_SetSMBParm(outp, 10, 0);    /* resv'd */
307         smb_SetSMBParm(outp, 11, 0);    /* reserved */
308
309         /* get op ptr after putting in the last parm, since otherwise we don't
310          * know where the data really is.
311          */
312         op = smb_GetSMBData(outp, NULL);
313         
314         /* now fill in offset from start of SMB header to first data byte (to op) */
315         smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
316
317         /* set the packet data length the count of the # of bytes */
318         smb_SetSMBDataLength(outp, count);
319         
320         /* now copy the data into the response packet */
321         memcpy(op, iop->outCopied + iop->outAllocp, count);
322
323         /* and adjust the counters */
324         iop->outCopied += count;
325         
326         /* and cleanup things */
327         cm_ReleaseUser(userp);
328         smb_ReleaseFID(fidp);
329
330         return 0;
331 }
332
333 /* called from Read Raw to handle IOCTL descriptor reads */
334 long smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
335         smb_packet_t *outp)
336 {
337         smb_ioctl_t *iop;
338         long leftToCopy;
339         NCB *ncbp;
340         long code;
341         cm_user_t *userp;
342
343         iop = fidp->ioctlp;
344
345         userp = smb_GetUser(vcp, inp);
346
347         {
348                 smb_user_t *uidp;
349
350                 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
351                 osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
352                          uidp->userID, userp,
353                          osi_LogSaveString(afsd_logp, uidp->name));
354                 smb_ReleaseUID(uidp);
355         }
356
357         iop->tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
358
359         code = smb_IoctlPrepareRead(fidp, iop, userp);
360         if (code) {
361                 cm_ReleaseUser(userp);
362                 smb_ReleaseFID(fidp);
363                 return code;
364         }
365
366         if (iop->flags & SMB_IOCTLFLAG_LOGON) {
367                 vcp->logonDLLUser = userp;
368                 userp->flags |= CM_USERFLAG_WASLOGON;
369         }
370
371         leftToCopy = (iop->outDatap - iop->outAllocp) - iop->outCopied;
372
373         ncbp = outp->ncbp;
374         memset((char *)ncbp, 0, sizeof(NCB));
375
376         ncbp->ncb_length = (unsigned short) leftToCopy;
377         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
378         ncbp->ncb_command = NCBSEND;
379         ncbp->ncb_buffer = iop->outCopied + iop->outAllocp;
380
381         code = Netbios(ncbp);
382         if (code != 0)
383                 osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
384
385         cm_ReleaseUser(userp);
386         smb_ReleaseFID(fidp);
387
388         return 0;
389 }