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