windows-fs-exa-20051001
[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 }
85
86 /* called to make a fid structure into an IOCTL fid structure */
87 void smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
88 {
89     smb_ioctl_t *iop;
90     cm_space_t *copyPrefix;
91
92     lock_ObtainMutex(&fidp->mx);
93     fidp->flags |= SMB_FID_IOCTL;
94     fidp->scp = &cm_data.fakeSCache;
95     cm_HoldSCache(fidp->scp);
96     if (fidp->ioctlp == NULL) {
97         iop = malloc(sizeof(*iop));
98         memset(iop, 0, sizeof(*iop));
99         fidp->ioctlp = iop;
100         iop->fidp = fidp;
101     }
102     if (prefix) {
103         copyPrefix = cm_GetSpace();
104         strcpy(copyPrefix->data, prefix->data);
105         fidp->ioctlp->prefix = copyPrefix;
106     }
107     lock_ReleaseMutex(&fidp->mx);
108 }
109
110 /* called when we receive a read call, does the send of the received data if
111  * this is the first read call.  This is the function that actually makes the
112  * call to the ioctl code.
113  */
114 smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
115 {
116     long opcode;
117     smb_ioctlProc_t *procp;
118     long code;
119
120     if (ioctlp->flags & SMB_IOCTLFLAG_DATAIN) {
121         ioctlp->flags &= ~SMB_IOCTLFLAG_DATAIN;
122
123         /* do the call now, or fail if we didn't get an opcode, or
124          * enough of an opcode.
125          */
126         if (ioctlp->inCopied < sizeof(long)) 
127             return CM_ERROR_INVAL;
128         memcpy(&opcode, ioctlp->inDatap, sizeof(long));
129         ioctlp->inDatap += sizeof(long);
130
131         osi_Log1(afsd_logp, "Ioctl opcode 0x%x", opcode);
132
133         /* check for opcode out of bounds */
134         if (opcode < 0 || opcode >= SMB_IOCTL_MAXPROCS)
135             return CM_ERROR_TOOBIG;
136
137         /* check for no such proc */
138         procp = smb_ioctlProcsp[opcode];
139         if (procp == NULL) 
140             return CM_ERROR_BADOP;
141
142         /* otherwise, make the call */
143         ioctlp->outDatap += sizeof(long);       /* reserve room for return code */
144         code = (*procp)(ioctlp, userp);
145
146         osi_Log1(afsd_logp, "Ioctl return code 0x%x", code);
147
148         /* copy in return code */
149         memcpy(ioctlp->outAllocp, &code, sizeof(long));
150     }
151     return 0;
152 }
153
154 /* called when we receive a write call.  If this is the first write call after
155  * a series of reads (or the very first call), then we start a new call.
156  * We also ensure that things are properly initialized for the start of a call.
157  */
158 void smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
159 {
160         /* make sure the buffer(s) are allocated */
161         if (!ioctlp->inAllocp) ioctlp->inAllocp = malloc(SMB_IOCTL_MAXDATA);
162         if (!ioctlp->outAllocp) ioctlp->outAllocp = malloc(SMB_IOCTL_MAXDATA);
163
164         /* Fixes fs la problem.  We do a StrToOEM later and if this data isn't initialized we get memory issues. */
165        (void) memset(ioctlp->inAllocp, 0, SMB_IOCTL_MAXDATA);
166        (void) memset(ioctlp->outAllocp, 0, SMB_IOCTL_MAXDATA);
167
168         /* and make sure that we've reset our state for the new incoming request */
169         if (!(ioctlp->flags & SMB_IOCTLFLAG_DATAIN)) {
170                 ioctlp->inCopied = 0;
171                 ioctlp->outCopied = 0;
172                 ioctlp->inDatap = ioctlp->inAllocp;
173                 ioctlp->outDatap = ioctlp->outAllocp;
174                 ioctlp->flags |= SMB_IOCTLFLAG_DATAIN;
175         }
176 }
177
178 /* called from smb_ReceiveCoreRead when we receive a read on the ioctl fid */
179 long smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
180         smb_packet_t *outp)
181 {
182         smb_ioctl_t *iop;
183         long count;
184         long leftToCopy;
185         char *op;
186         long code;
187         cm_user_t *userp;
188
189         iop = fidp->ioctlp;
190         count = smb_GetSMBParm(inp, 1);
191         userp = smb_GetUser(vcp, inp);
192
193         /* Identify tree */
194     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
195     if(code) {
196         cm_ReleaseUser(userp);
197         return CM_ERROR_NOSUCHPATH;
198     }
199
200         /* turn the connection around, if required */
201         code = smb_IoctlPrepareRead(fidp, iop, userp);
202
203         if (code) {
204                 cm_ReleaseUser(userp);
205                 return code;
206         }
207
208         leftToCopy = (iop->outDatap - iop->outAllocp) - iop->outCopied;
209         if (count > leftToCopy) count = leftToCopy;
210         
211         /* now set the parms for a read of count bytes */
212         smb_SetSMBParm(outp, 0, count);
213         smb_SetSMBParm(outp, 1, 0);
214         smb_SetSMBParm(outp, 2, 0);
215         smb_SetSMBParm(outp, 3, 0);
216         smb_SetSMBParm(outp, 4, 0);
217
218         smb_SetSMBDataLength(outp, count+3);
219
220         op = smb_GetSMBData(outp, NULL);
221         *op++ = 1;
222         *op++ = (char)(count & 0xff);
223         *op++ = (char)((count >> 8) & 0xff);
224         
225         /* now copy the data into the response packet */
226         memcpy(op, iop->outCopied + iop->outAllocp, count);
227
228         /* and adjust the counters */
229         iop->outCopied += count;
230         
231         cm_ReleaseUser(userp);
232         smb_ReleaseFID(fidp);
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         smb_ReleaseFID(fidp);
276         return code;
277 }
278
279 /* called from V3 read to handle IOCTL descriptor reads */
280 long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
281 {
282         smb_ioctl_t *iop;
283     long count;
284     long code;
285     long leftToCopy;
286     char *op;
287     cm_user_t *userp;
288     smb_user_t *uidp;
289
290     iop = fidp->ioctlp;
291     count = smb_GetSMBParm(inp, 5);
292         
293         userp = smb_GetUser(vcp, inp);
294         osi_assert(userp != 0);
295
296     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
297     iop->uidp = uidp;
298     if (uidp && uidp->unp)
299         osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
300                   uidp->userID, userp,
301                   osi_LogSaveString(afsd_logp, uidp->unp->name));
302     else {
303         if (uidp)
304                     osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
305                       uidp->userID, userp);
306         else
307                     osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
308                      userp);
309     }
310
311         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
312     if(code) {
313         smb_ReleaseUID(uidp);
314         cm_ReleaseUser(userp);
315         smb_ReleaseFID(fidp);
316         return CM_ERROR_NOSUCHPATH;
317     }
318
319         code = smb_IoctlPrepareRead(fidp, iop, userp);
320     if (uidp) {
321         iop->uidp = 0;
322         smb_ReleaseUID(uidp);
323     }
324     if (code) {
325                 cm_ReleaseUser(userp);
326         smb_ReleaseFID(fidp);
327                 return code;
328     }
329
330         leftToCopy = (iop->outDatap - iop->outAllocp) - iop->outCopied;
331     if (count > leftToCopy) count = leftToCopy;
332         
333         /* 0 and 1 are reserved for request chaining, were setup by our caller,
334          * and will be further filled in after we return.
335          */
336         smb_SetSMBParm(outp, 2, 0);     /* remaining bytes, for pipes */
337         smb_SetSMBParm(outp, 3, 0);     /* resvd */
338         smb_SetSMBParm(outp, 4, 0);     /* resvd */
339         smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
340         /* fill in #6 when we have all the parameters' space reserved */
341         smb_SetSMBParm(outp, 7, 0);     /* resv'd */
342         smb_SetSMBParm(outp, 8, 0);     /* resv'd */
343         smb_SetSMBParm(outp, 9, 0);     /* resv'd */
344         smb_SetSMBParm(outp, 10, 0);    /* resv'd */
345         smb_SetSMBParm(outp, 11, 0);    /* reserved */
346
347         /* get op ptr after putting in the last parm, since otherwise we don't
348          * know where the data really is.
349          */
350         op = smb_GetSMBData(outp, NULL);
351         
352         /* now fill in offset from start of SMB header to first data byte (to op) */
353         smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
354
355         /* set the packet data length the count of the # of bytes */
356         smb_SetSMBDataLength(outp, count);
357         
358         /* now copy the data into the response packet */
359         memcpy(op, iop->outCopied + iop->outAllocp, count);
360
361         /* and adjust the counters */
362         iop->outCopied += count;
363         
364         /* and cleanup things */
365         cm_ReleaseUser(userp);
366         smb_ReleaseFID(fidp);
367
368         return 0;
369 }
370
371 /* called from Read Raw to handle IOCTL descriptor reads */
372 long smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
373         smb_packet_t *outp
374 #ifdef DJGPP
375 , dos_ptr rawBuf
376 #endif /* DJGPP */
377 )
378 {
379         smb_ioctl_t *iop;
380         long leftToCopy;
381         NCB *ncbp;
382         long code;
383         cm_user_t *userp;
384 #ifdef DJGPP
385         dos_ptr dos_ncb;
386
387         if (rawBuf == 0)
388         {
389                 osi_Log0(afsd_logp, "Failed to get raw buf for smb_IoctlReadRaw");
390                 return -1;
391         }
392 #endif /* DJGPP */
393
394         iop = fidp->ioctlp;
395
396         userp = smb_GetUser(vcp, inp);
397
398         {
399                 smb_user_t *uidp;
400
401                 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
402                 if (uidp && uidp->unp)
403                     osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
404                              uidp->userID, userp,
405                              osi_LogSaveString(afsd_logp, uidp->unp->name));
406                 else if (uidp)
407                     osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
408                              uidp->userID, userp);
409         else 
410                     osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
411                              userp);
412                 if (uidp) smb_ReleaseUID(uidp);
413         }
414
415     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
416     if(code) {
417         cm_ReleaseUser(userp);
418         smb_ReleaseFID(fidp);
419         return CM_ERROR_NOSUCHPATH;
420     }
421
422         code = smb_IoctlPrepareRead(fidp, iop, userp);
423         if (code) {
424                 cm_ReleaseUser(userp);
425                 smb_ReleaseFID(fidp);
426                 return code;
427         }
428
429         leftToCopy = (iop->outDatap - iop->outAllocp) - iop->outCopied;
430
431         ncbp = outp->ncbp;
432         memset((char *)ncbp, 0, sizeof(NCB));
433
434         ncbp->ncb_length = (unsigned short) leftToCopy;
435         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
436         ncbp->ncb_command = NCBSEND;
437     /*ncbp->ncb_lana_num = smb_LANadapter;*/
438         ncbp->ncb_lana_num = vcp->lana;
439
440 #ifndef DJGPP
441         ncbp->ncb_buffer = iop->outCopied + iop->outAllocp;
442         code = Netbios(ncbp);
443 #else /* DJGPP */
444         dosmemput(iop->outCopied + iop->outAllocp, ncbp->ncb_length, rawBuf);
445         ncbp->ncb_buffer = rawBuf;
446         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
447         code = Netbios(ncbp, dos_ncb);
448 #endif /* !DJGPP */
449
450         if (code != 0)
451                 osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
452
453         cm_ReleaseUser(userp);
454         smb_ReleaseFID(fidp);
455
456         return 0;
457 }