0e0f742f3eb12e3880575d5ed311f43e1dda73ef
[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         smb_ioctlProcsp[VIOC_GETRXKCRYPT] = cm_IoctlGetRxkcrypt;
66         smb_ioctlProcsp[VIOC_SETRXKCRYPT] = cm_IoctlSetRxkcrypt;
67 }
68
69 /* called to make a fid structure into an IOCTL fid structure */
70 void smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
71 {
72         smb_ioctl_t *iop;
73         cm_space_t *copyPrefix;
74
75         lock_ObtainMutex(&fidp->mx);
76         fidp->flags |= SMB_FID_IOCTL;
77         fidp->scp = &cm_fakeSCache;
78         if (fidp->ioctlp == NULL) {
79                 iop = malloc(sizeof(*iop));
80                 memset(iop, 0, sizeof(*iop));
81                 fidp->ioctlp = iop;
82         }
83         if (prefix) {
84                 copyPrefix = cm_GetSpace();
85                 strcpy(copyPrefix->data, prefix->data);
86                 fidp->ioctlp->prefix = copyPrefix;
87         }
88         lock_ReleaseMutex(&fidp->mx);
89 }
90
91 /* called when we receive a read call, does the send of the received data if
92  * this is the first read call.  This is the function that actually makes the
93  * call to the ioctl code.
94  */
95 smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
96 {
97         long opcode;
98         smb_ioctlProc_t *procp;
99         long code;
100
101         if (ioctlp->flags & SMB_IOCTLFLAG_DATAIN) {
102                 ioctlp->flags &= ~SMB_IOCTLFLAG_DATAIN;
103                 
104                 /* do the call now, or fail if we didn't get an opcode, or
105                  * enough of an opcode.
106                  */
107                 if (ioctlp->inCopied < sizeof(long)) return CM_ERROR_INVAL;
108                 memcpy(&opcode, ioctlp->inDatap, sizeof(long));
109                 ioctlp->inDatap += sizeof(long);
110
111                 osi_Log1(afsd_logp, "Ioctl opcode %d", opcode);
112
113                 /* check for opcode out of bounds */
114                 if (opcode < 0 || opcode >= SMB_IOCTL_MAXPROCS)
115                         return CM_ERROR_TOOBIG;
116                 
117                 /* check for no such proc */
118                 procp = smb_ioctlProcsp[opcode];
119                 if (procp == NULL) return CM_ERROR_BADOP;
120
121                 /* otherwise, make the call */
122                 ioctlp->outDatap += sizeof(long);       /* reserve room for return code */
123                 code = (*procp)(ioctlp, userp);
124
125                 osi_Log1(afsd_logp, "Ioctl return code %d", code);
126
127                 /* copy in return code */
128                 memcpy(ioctlp->outAllocp, &code, sizeof(long));
129         }
130         return 0;
131 }
132
133 /* called when we receive a write call.  If this is the first write call after
134  * a series of reads (or the very first call), then we start a new call.
135  * We also ensure that things are properly initialized for the start of a call.
136  */
137 void smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
138 {
139         /* make sure the buffer(s) are allocated */
140         if (!ioctlp->inAllocp) ioctlp->inAllocp = malloc(SMB_IOCTL_MAXDATA);
141         if (!ioctlp->outAllocp) ioctlp->outAllocp = malloc(SMB_IOCTL_MAXDATA);
142
143         /* and make sure that we've reset our state for the new incoming request */
144         if (!(ioctlp->flags & SMB_IOCTLFLAG_DATAIN)) {
145                 ioctlp->inCopied = 0;
146                 ioctlp->outCopied = 0;
147                 ioctlp->inDatap = ioctlp->inAllocp;
148                 ioctlp->outDatap = ioctlp->outAllocp;
149                 ioctlp->flags |= SMB_IOCTLFLAG_DATAIN;
150         }
151 }
152
153 /* called from smb_ReceiveCoreRead when we receive a read on the ioctl fid */
154 long smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
155         smb_packet_t *outp)
156 {
157         smb_ioctl_t *iop;
158         long count;
159         long leftToCopy;
160         char *op;
161         long code;
162         cm_user_t *userp;
163
164         iop = fidp->ioctlp;
165         count = smb_GetSMBParm(inp, 1);
166         userp = smb_GetUser(vcp, inp);
167
168         /* Identify tree */
169         iop->tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
170
171         /* turn the connection around, if required */
172         code = smb_IoctlPrepareRead(fidp, iop, userp);
173
174         if (code) {
175                 cm_ReleaseUser(userp);
176                 return code;
177         }
178
179         if (iop->flags & SMB_IOCTLFLAG_LOGON) {
180                 vcp->logonDLLUser = userp;
181                 userp->flags |= CM_USERFLAG_WASLOGON;
182         }
183
184         leftToCopy = (iop->outDatap - iop->outAllocp) - iop->outCopied;
185         if (count > leftToCopy) count = leftToCopy;
186         
187         /* now set the parms for a read of count bytes */
188         smb_SetSMBParm(outp, 0, count);
189         smb_SetSMBParm(outp, 1, 0);
190         smb_SetSMBParm(outp, 2, 0);
191         smb_SetSMBParm(outp, 3, 0);
192         smb_SetSMBParm(outp, 4, 0);
193
194         smb_SetSMBDataLength(outp, count+3);
195
196         op = smb_GetSMBData(outp, NULL);
197         *op++ = 1;
198         *op++ = count & 0xff;
199         *op++ = (count >> 8) & 0xff;
200         
201         /* now copy the data into the response packet */
202         memcpy(op, iop->outCopied + iop->outAllocp, count);
203
204         /* and adjust the counters */
205         iop->outCopied += count;
206         
207         cm_ReleaseUser(userp);
208         smb_ReleaseFID(fidp);
209
210         return 0;
211 }
212
213 /* called from smb_ReceiveCoreWrite when we receive a write call on the IOCTL
214  * file descriptor.
215  */
216 long smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
217 {
218         smb_ioctl_t *iop;
219         long count;
220         long code;
221         char *op;
222         long inDataBlockCount;
223
224         code = 0;
225         count = smb_GetSMBParm(inp, 1);
226         iop = fidp->ioctlp;
227         
228         smb_IoctlPrepareWrite(fidp, iop);
229
230         op = smb_GetSMBData(inp, NULL);
231         op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
232         
233         if (count + iop->inCopied > SMB_IOCTL_MAXDATA) {
234                 code = CM_ERROR_TOOBIG;
235                 goto done;
236         }
237         
238         /* copy data */
239         memcpy(iop->inDatap + iop->inCopied, op, count);
240         
241         /* adjust counts */
242         iop->inCopied += count;
243
244 done:
245         /* return # of bytes written */
246         if (code == 0) {
247                 smb_SetSMBParm(outp, 0, count);
248                 smb_SetSMBDataLength(outp, 0);
249         }
250
251         smb_ReleaseFID(fidp);
252         return code;
253 }
254
255 /* called from V3 read to handle IOCTL descriptor reads */
256 long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
257 {
258         smb_ioctl_t *iop;
259         long count;
260         long code;
261         long leftToCopy;
262         char *op;
263         cm_user_t *userp;
264
265         iop = fidp->ioctlp;
266         count = smb_GetSMBParm(inp, 5);
267         
268         userp = smb_GetUser(vcp, inp);
269
270         {
271                 smb_user_t *uidp;
272
273                 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
274                 osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
275                          uidp->userID, userp,
276                          osi_LogSaveString(afsd_logp, uidp->name));
277                 smb_ReleaseUID(uidp);
278         }
279
280         iop->tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
281
282         code = smb_IoctlPrepareRead(fidp, iop, userp);
283         if (code) {
284                 cm_ReleaseUser(userp);
285                 smb_ReleaseFID(fidp);
286                 return code;
287         }
288
289         if (iop->flags & SMB_IOCTLFLAG_LOGON) {
290                 vcp->logonDLLUser = userp;
291                 userp->flags |= CM_USERFLAG_WASLOGON;
292         }
293
294         leftToCopy = (iop->outDatap - iop->outAllocp) - iop->outCopied;
295         if (count > leftToCopy) count = leftToCopy;
296         
297         /* 0 and 1 are reserved for request chaining, were setup by our caller,
298          * and will be further filled in after we return.
299          */
300         smb_SetSMBParm(outp, 2, 0);     /* remaining bytes, for pipes */
301         smb_SetSMBParm(outp, 3, 0);     /* resvd */
302         smb_SetSMBParm(outp, 4, 0);     /* resvd */
303         smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
304         /* fill in #6 when we have all the parameters' space reserved */
305         smb_SetSMBParm(outp, 7, 0);     /* resv'd */
306         smb_SetSMBParm(outp, 8, 0);     /* resv'd */
307         smb_SetSMBParm(outp, 9, 0);     /* resv'd */
308         smb_SetSMBParm(outp, 10, 0);    /* resv'd */
309         smb_SetSMBParm(outp, 11, 0);    /* reserved */
310
311         /* get op ptr after putting in the last parm, since otherwise we don't
312          * know where the data really is.
313          */
314         op = smb_GetSMBData(outp, NULL);
315         
316         /* now fill in offset from start of SMB header to first data byte (to op) */
317         smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
318
319         /* set the packet data length the count of the # of bytes */
320         smb_SetSMBDataLength(outp, count);
321         
322         /* now copy the data into the response packet */
323         memcpy(op, iop->outCopied + iop->outAllocp, count);
324
325         /* and adjust the counters */
326         iop->outCopied += count;
327         
328         /* and cleanup things */
329         cm_ReleaseUser(userp);
330         smb_ReleaseFID(fidp);
331
332         return 0;
333 }
334
335 /* called from Read Raw to handle IOCTL descriptor reads */
336 long smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
337         smb_packet_t *outp)
338 {
339         smb_ioctl_t *iop;
340         long leftToCopy;
341         NCB *ncbp;
342         long code;
343         cm_user_t *userp;
344
345         iop = fidp->ioctlp;
346
347         userp = smb_GetUser(vcp, inp);
348
349         {
350                 smb_user_t *uidp;
351
352                 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
353                 osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
354                          uidp->userID, userp,
355                          osi_LogSaveString(afsd_logp, uidp->name));
356                 smb_ReleaseUID(uidp);
357         }
358
359         iop->tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
360
361         code = smb_IoctlPrepareRead(fidp, iop, userp);
362         if (code) {
363                 cm_ReleaseUser(userp);
364                 smb_ReleaseFID(fidp);
365                 return code;
366         }
367
368         if (iop->flags & SMB_IOCTLFLAG_LOGON) {
369                 vcp->logonDLLUser = userp;
370                 userp->flags |= CM_USERFLAG_WASLOGON;
371         }
372
373         leftToCopy = (iop->outDatap - iop->outAllocp) - iop->outCopied;
374
375         ncbp = outp->ncbp;
376         memset((char *)ncbp, 0, sizeof(NCB));
377
378         ncbp->ncb_length = (unsigned short) leftToCopy;
379         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
380         ncbp->ncb_command = NCBSEND;
381         ncbp->ncb_buffer = iop->outCopied + iop->outAllocp;
382
383         code = Netbios(ncbp);
384         if (code != 0)
385                 osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
386
387         cm_ReleaseUser(userp);
388         smb_ReleaseFID(fidp);
389
390         return 0;
391 }