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