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