windows-cm_ioctl_query_opts-20080115
[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 /*extern unsigned char smb_LANadapter;*/
29
30 void smb_InitIoctl(void)
31 {
32         int i;
33         for (i=0; i<SMB_IOCTL_MAXPROCS; i++)
34             smb_ioctlProcsp[i] = NULL;
35
36         smb_ioctlProcsp[VIOCGETAL] = cm_IoctlGetACL;
37         smb_ioctlProcsp[VIOC_FILE_CELL_NAME] = cm_IoctlGetFileCellName;
38         smb_ioctlProcsp[VIOCSETAL] = cm_IoctlSetACL;
39         smb_ioctlProcsp[VIOC_FLUSHVOLUME] = cm_IoctlFlushVolume;
40         smb_ioctlProcsp[VIOCFLUSH] = cm_IoctlFlushFile;
41         smb_ioctlProcsp[VIOCSETVOLSTAT] = cm_IoctlSetVolumeStatus;
42         smb_ioctlProcsp[VIOCGETVOLSTAT] = cm_IoctlGetVolumeStatus;
43         smb_ioctlProcsp[VIOCWHEREIS] = cm_IoctlWhereIs;
44         smb_ioctlProcsp[VIOC_AFS_STAT_MT_PT] = cm_IoctlStatMountPoint;
45         smb_ioctlProcsp[VIOC_AFS_DELETE_MT_PT] = cm_IoctlDeleteMountPoint;
46         smb_ioctlProcsp[VIOCCKSERV] = cm_IoctlCheckServers;
47         smb_ioctlProcsp[VIOC_GAG] = cm_IoctlGag;
48         smb_ioctlProcsp[VIOCCKBACK] = cm_IoctlCheckVolumes;
49         smb_ioctlProcsp[VIOCSETCACHESIZE] = cm_IoctlSetCacheSize;
50         smb_ioctlProcsp[VIOCGETCACHEPARMS] = cm_IoctlGetCacheParms;
51         smb_ioctlProcsp[VIOCGETCELL] = cm_IoctlGetCell;
52         smb_ioctlProcsp[VIOCNEWCELL] = cm_IoctlNewCell;
53         smb_ioctlProcsp[VIOC_GET_WS_CELL] = cm_IoctlGetWsCell;
54         smb_ioctlProcsp[VIOC_AFS_SYSNAME] = cm_IoctlSysName;
55         smb_ioctlProcsp[VIOC_GETCELLSTATUS] = cm_IoctlGetCellStatus;
56         smb_ioctlProcsp[VIOC_SETCELLSTATUS] = cm_IoctlSetCellStatus;
57         smb_ioctlProcsp[VIOC_SETSPREFS] = cm_IoctlSetSPrefs;
58         smb_ioctlProcsp[VIOC_GETSPREFS] = cm_IoctlGetSPrefs;
59         smb_ioctlProcsp[VIOC_STOREBEHIND] = cm_IoctlStoreBehind;
60         smb_ioctlProcsp[VIOC_AFS_CREATE_MT_PT] = cm_IoctlCreateMountPoint;
61         smb_ioctlProcsp[VIOC_TRACECTL] = cm_IoctlTraceControl;
62         smb_ioctlProcsp[VIOCSETTOK] = cm_IoctlSetToken;
63         smb_ioctlProcsp[VIOCGETTOK] = cm_IoctlGetTokenIter;
64         smb_ioctlProcsp[VIOCNEWGETTOK] = cm_IoctlGetToken;
65         smb_ioctlProcsp[VIOCDELTOK] = cm_IoctlDelToken;
66         smb_ioctlProcsp[VIOCDELALLTOK] = cm_IoctlDelAllToken;
67         smb_ioctlProcsp[VIOC_SYMLINK] = cm_IoctlSymlink;
68         smb_ioctlProcsp[VIOC_LISTSYMLINK] = cm_IoctlListlink;
69         smb_ioctlProcsp[VIOC_DELSYMLINK] = cm_IoctlDeletelink;
70         smb_ioctlProcsp[VIOC_MAKESUBMOUNT] = cm_IoctlMakeSubmount;
71         smb_ioctlProcsp[VIOC_GETRXKCRYPT] = cm_IoctlGetRxkcrypt;
72         smb_ioctlProcsp[VIOC_SETRXKCRYPT] = cm_IoctlSetRxkcrypt;
73         smb_ioctlProcsp[VIOC_ISSYMLINK] = cm_IoctlIslink;
74         smb_ioctlProcsp[VIOC_TRACEMEMDUMP] = cm_IoctlMemoryDump;
75         smb_ioctlProcsp[VIOC_ISSYMLINK] = cm_IoctlIslink;
76         smb_ioctlProcsp[VIOC_FLUSHALL] = cm_IoctlFlushAllVolumes;
77         smb_ioctlProcsp[VIOCGETFID] = cm_IoctlGetFid;
78         smb_ioctlProcsp[VIOCGETOWNER] = cm_IoctlGetOwner;
79         smb_ioctlProcsp[VIOC_RXSTAT_PROC] = cm_IoctlRxStatProcess;
80         smb_ioctlProcsp[VIOC_RXSTAT_PEER] = cm_IoctlRxStatPeer;
81         smb_ioctlProcsp[VIOC_UUIDCTL] = cm_IoctlUUIDControl;
82         smb_ioctlProcsp[VIOC_PATH_AVAILABILITY] = cm_IoctlPathAvailability;
83         smb_ioctlProcsp[VIOC_GETFILETYPE] = cm_IoctlGetFileType;
84         smb_ioctlProcsp[VIOC_VOLSTAT_TEST] = cm_IoctlVolStatTest;
85 }
86
87 /* called to make a fid structure into an IOCTL fid structure */
88 void smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
89 {
90     smb_ioctl_t *iop;
91     cm_space_t *copyPrefix;
92
93     lock_ObtainMutex(&fidp->mx);
94     fidp->flags |= SMB_FID_IOCTL;
95     fidp->scp = &cm_data.fakeSCache;
96     cm_HoldSCache(fidp->scp);
97     if (fidp->ioctlp == NULL) {
98         iop = malloc(sizeof(*iop));
99         memset(iop, 0, sizeof(*iop));
100         fidp->ioctlp = iop;
101         iop->fidp = fidp;
102     }
103     if (prefix) {
104         copyPrefix = cm_GetSpace();
105         strcpy(copyPrefix->data, prefix->data);
106         fidp->ioctlp->prefix = copyPrefix;
107     }
108     lock_ReleaseMutex(&fidp->mx);
109 }
110
111 /* called when we receive a read call, does the send of the received data if
112  * this is the first read call.  This is the function that actually makes the
113  * call to the ioctl code.
114  */
115 long smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
116 {
117     long opcode;
118     smb_ioctlProc_t *procp = NULL;
119     long code;
120
121     if (ioctlp->flags & SMB_IOCTLFLAG_DATAIN) {
122         ioctlp->flags &= ~SMB_IOCTLFLAG_DATAIN;
123
124         /* do the call now, or fail if we didn't get an opcode, or
125          * enough of an opcode.
126          */
127         if (ioctlp->inCopied < sizeof(long)) 
128             return CM_ERROR_INVAL;
129         memcpy(&opcode, ioctlp->inDatap, sizeof(long));
130         ioctlp->inDatap += sizeof(long);
131
132         osi_Log1(afsd_logp, "Ioctl opcode 0x%x", opcode);
133
134         /* check for opcode out of bounds */
135         if (opcode < 0 || opcode >= SMB_IOCTL_MAXPROCS)
136             return CM_ERROR_TOOBIG;
137
138         /* check for no such proc */
139         procp = smb_ioctlProcsp[opcode];
140         if (procp == NULL) 
141             return CM_ERROR_BADOP;
142
143         /* otherwise, make the call */
144         ioctlp->outDatap += sizeof(long);       /* reserve room for return code */
145         code = (*procp)(ioctlp, userp);
146
147         osi_Log1(afsd_logp, "Ioctl return code 0x%x", code);
148
149         /* copy in return code */
150         memcpy(ioctlp->outAllocp, &code, sizeof(long));
151     }
152     return 0;
153 }
154
155 /* called when we receive a write call.  If this is the first write call after
156  * a series of reads (or the very first call), then we start a new call.
157  * We also ensure that things are properly initialized for the start of a call.
158  */
159 void smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
160 {
161         /* make sure the buffer(s) are allocated */
162         if (!ioctlp->inAllocp) ioctlp->inAllocp = malloc(SMB_IOCTL_MAXDATA);
163         if (!ioctlp->outAllocp) ioctlp->outAllocp = malloc(SMB_IOCTL_MAXDATA);
164
165         /* Fixes fs la problem.  We do a StrToOEM later and if this data isn't initialized we get memory issues. */
166        (void) memset(ioctlp->inAllocp, 0, SMB_IOCTL_MAXDATA);
167        (void) memset(ioctlp->outAllocp, 0, SMB_IOCTL_MAXDATA);
168
169         /* and make sure that we've reset our state for the new incoming request */
170         if (!(ioctlp->flags & SMB_IOCTLFLAG_DATAIN)) {
171                 ioctlp->inCopied = 0;
172                 ioctlp->outCopied = 0;
173                 ioctlp->inDatap = ioctlp->inAllocp;
174                 ioctlp->outDatap = ioctlp->outAllocp;
175                 ioctlp->flags |= SMB_IOCTLFLAG_DATAIN;
176         }
177 }
178
179 /* called from smb_ReceiveCoreRead when we receive a read on the ioctl fid */
180 long smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
181         smb_packet_t *outp)
182 {
183         smb_ioctl_t *iop;
184         long count;
185         long leftToCopy;
186         char *op;
187         long code;
188         cm_user_t *userp;
189
190         iop = fidp->ioctlp;
191         count = smb_GetSMBParm(inp, 1);
192         userp = smb_GetUserFromVCP(vcp, inp);
193
194         /* Identify tree */
195     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
196     if(code) {
197         cm_ReleaseUser(userp);
198         return CM_ERROR_NOSUCHPATH;
199     }
200
201         /* turn the connection around, if required */
202         code = smb_IoctlPrepareRead(fidp, iop, userp);
203
204         if (code) {
205                 cm_ReleaseUser(userp);
206                 return code;
207         }
208
209         leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
210         if (count > leftToCopy) count = leftToCopy;
211         
212         /* now set the parms for a read of count bytes */
213         smb_SetSMBParm(outp, 0, count);
214         smb_SetSMBParm(outp, 1, 0);
215         smb_SetSMBParm(outp, 2, 0);
216         smb_SetSMBParm(outp, 3, 0);
217         smb_SetSMBParm(outp, 4, 0);
218
219         smb_SetSMBDataLength(outp, count+3);
220
221         op = smb_GetSMBData(outp, NULL);
222         *op++ = 1;
223         *op++ = (char)(count & 0xff);
224         *op++ = (char)((count >> 8) & 0xff);
225         
226         /* now copy the data into the response packet */
227         memcpy(op, iop->outCopied + iop->outAllocp, count);
228
229         /* and adjust the counters */
230         iop->outCopied += count;
231         
232         cm_ReleaseUser(userp);
233
234         return 0;
235 }
236
237 /* called from smb_ReceiveCoreWrite when we receive a write call on the IOCTL
238  * file descriptor.
239  */
240 long smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
241 {
242         smb_ioctl_t *iop;
243         long count;
244         long code;
245         char *op;
246         int inDataBlockCount;
247
248         code = 0;
249         count = smb_GetSMBParm(inp, 1);
250         iop = fidp->ioctlp;
251         
252         smb_IoctlPrepareWrite(fidp, iop);
253
254         op = smb_GetSMBData(inp, NULL);
255         op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
256         
257         if (count + iop->inCopied > SMB_IOCTL_MAXDATA) {
258                 code = CM_ERROR_TOOBIG;
259                 goto done;
260         }
261         
262         /* copy data */
263         memcpy(iop->inDatap + iop->inCopied, op, count);
264         
265         /* adjust counts */
266         iop->inCopied += count;
267
268 done:
269         /* return # of bytes written */
270         if (code == 0) {
271                 smb_SetSMBParm(outp, 0, count);
272                 smb_SetSMBDataLength(outp, 0);
273         }
274
275         return code;
276 }
277
278 /* called from smb_ReceiveV3WriteX when we receive a write call on the IOCTL
279  * file descriptor.
280  */
281 long smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
282 {
283         smb_ioctl_t *iop;
284         long count;
285         long code;
286         char *op;
287         int inDataBlockCount;
288
289         code = 0;
290         count = smb_GetSMBParm(inp, 10);
291         iop = fidp->ioctlp;
292         
293         smb_IoctlPrepareWrite(fidp, iop);
294
295         op = inp->data + smb_GetSMBParm(inp, 11);
296         inDataBlockCount = count;
297         
298         if (count + iop->inCopied > SMB_IOCTL_MAXDATA) {
299                 code = CM_ERROR_TOOBIG;
300                 goto done;
301         }
302         
303         /* copy data */
304         memcpy(iop->inDatap + iop->inCopied, op, count);
305         
306         /* adjust counts */
307         iop->inCopied += count;
308
309 done:
310         /* return # of bytes written */
311         if (code == 0) {
312                 smb_SetSMBParm(outp, 2, count);
313                 smb_SetSMBParm(outp, 3, 0); /* reserved */
314                 smb_SetSMBParm(outp, 4, 0); /* reserved */
315                 smb_SetSMBParm(outp, 5, 0); /* reserved */
316                 smb_SetSMBDataLength(outp, 0);
317         }
318
319         return code;
320 }
321
322
323 /* called from V3 read to handle IOCTL descriptor reads */
324 long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
325 {
326     smb_ioctl_t *iop;
327     long count;
328     long code;
329     long leftToCopy;
330     char *op;
331     cm_user_t *userp;
332     smb_user_t *uidp;
333
334     iop = fidp->ioctlp;
335     count = smb_GetSMBParm(inp, 5);
336         
337     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
338     userp = smb_GetUserFromUID(uidp);
339     osi_assertx(userp != NULL, "null cm_user_t");
340     iop->uidp = uidp;
341     if (uidp && uidp->unp) {
342         osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
343                   uidp->userID, userp,
344                   osi_LogSaveString(afsd_logp, uidp->unp->name));
345     } else {
346         if (uidp)
347             osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
348                      uidp->userID, userp);
349         else
350             osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
351                      userp);
352     }
353
354     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
355     if (code) {
356         if (uidp)
357             smb_ReleaseUID(uidp);
358         cm_ReleaseUser(userp);
359         return CM_ERROR_NOSUCHPATH;
360     }
361
362     code = smb_IoctlPrepareRead(fidp, iop, userp);
363     if (uidp) {
364         iop->uidp = 0;
365         smb_ReleaseUID(uidp);
366     }
367     if (code) {
368         cm_ReleaseUser(userp);
369         return code;
370     }
371
372     leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
373     if (count > leftToCopy) count = leftToCopy;
374         
375     /* 0 and 1 are reserved for request chaining, were setup by our caller,
376      * and will be further filled in after we return.
377      */
378     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
379     smb_SetSMBParm(outp, 3, 0); /* resvd */
380     smb_SetSMBParm(outp, 4, 0); /* resvd */
381     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
382     /* fill in #6 when we have all the parameters' space reserved */
383     smb_SetSMBParm(outp, 7, 0); /* resv'd */
384     smb_SetSMBParm(outp, 8, 0); /* resv'd */
385     smb_SetSMBParm(outp, 9, 0); /* resv'd */
386     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
387     smb_SetSMBParm(outp, 11, 0);        /* reserved */
388
389     /* get op ptr after putting in the last parm, since otherwise we don't
390      * know where the data really is.
391      */
392     op = smb_GetSMBData(outp, NULL);
393         
394     /* now fill in offset from start of SMB header to first data byte (to op) */
395     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
396
397     /* set the packet data length the count of the # of bytes */
398     smb_SetSMBDataLength(outp, count);
399         
400     /* now copy the data into the response packet */
401     memcpy(op, iop->outCopied + iop->outAllocp, count);
402
403     /* and adjust the counters */
404     iop->outCopied += count;
405
406     /* and cleanup things */
407     cm_ReleaseUser(userp);
408
409     return 0;
410 }       
411
412 /* called from Read Raw to handle IOCTL descriptor reads */
413 long smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
414                       smb_packet_t *outp
415                       )
416 {
417     smb_ioctl_t *iop;
418     long leftToCopy;
419     NCB *ncbp;
420     long code;
421     cm_user_t *userp;
422
423     iop = fidp->ioctlp;
424
425     userp = smb_GetUserFromVCP(vcp, inp);
426
427     /* Log the user */
428     {
429         smb_user_t *uidp;
430
431         uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
432         if (uidp && uidp->unp) {
433             osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
434                      uidp->userID, userp,
435                      osi_LogSaveString(afsd_logp, uidp->unp->name));
436         } else if (uidp) {
437             osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
438                      uidp->userID, userp);
439         } else {
440             osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
441                      userp);
442         }
443         if (uidp) 
444             smb_ReleaseUID(uidp);
445     }   
446
447     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
448     if (code) {
449         cm_ReleaseUser(userp);
450         return CM_ERROR_NOSUCHPATH;
451     }
452
453     code = smb_IoctlPrepareRead(fidp, iop, userp);
454     if (code) {
455         cm_ReleaseUser(userp);
456         return code;
457     }
458
459     leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
460
461     ncbp = outp->ncbp;
462     memset((char *)ncbp, 0, sizeof(NCB));
463
464     ncbp->ncb_length = (unsigned short) leftToCopy;
465     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
466     ncbp->ncb_command = NCBSEND;
467     /*ncbp->ncb_lana_num = smb_LANadapter;*/
468     ncbp->ncb_lana_num = vcp->lana;
469
470     ncbp->ncb_buffer = iop->outCopied + iop->outAllocp;
471     code = Netbios(ncbp);
472
473     if (code != 0)
474         osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
475
476     cm_ReleaseUser(userp);
477
478     return 0;
479 }