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