2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afs/param.h>
26 smb_ioctlProc_t *smb_ioctlProcsp[SMB_IOCTL_MAXPROCS];
28 /*extern unsigned char smb_LANadapter;*/
30 void smb_InitIoctl(void)
33 for (i=0; i<SMB_IOCTL_MAXPROCS; i++)
34 smb_ioctlProcsp[i] = NULL;
36 smb_ioctlProcsp[VIOCGETAL] = cm_IoctlGetACL;
37 smb_ioctlProcsp[VIOC_FILE_CELL_NAME] = cm_IoctlGetFileCellName;
38 smb_ioctlProcsp[VIOCSETAL] = cm_IoctlSetACL;
39 smb_ioctlProcsp[VIOC_FLUSHVOLUME] = cm_IoctlFlushVolume;
40 smb_ioctlProcsp[VIOCFLUSH] = cm_IoctlFlushFile;
41 smb_ioctlProcsp[VIOCSETVOLSTAT] = cm_IoctlSetVolumeStatus;
42 smb_ioctlProcsp[VIOCGETVOLSTAT] = cm_IoctlGetVolumeStatus;
43 smb_ioctlProcsp[VIOCWHEREIS] = cm_IoctlWhereIs;
44 smb_ioctlProcsp[VIOC_AFS_STAT_MT_PT] = cm_IoctlStatMountPoint;
45 smb_ioctlProcsp[VIOC_AFS_DELETE_MT_PT] = cm_IoctlDeleteMountPoint;
46 smb_ioctlProcsp[VIOCCKSERV] = cm_IoctlCheckServers;
47 smb_ioctlProcsp[VIOC_GAG] = cm_IoctlGag;
48 smb_ioctlProcsp[VIOCCKBACK] = cm_IoctlCheckVolumes;
49 smb_ioctlProcsp[VIOCSETCACHESIZE] = cm_IoctlSetCacheSize;
50 smb_ioctlProcsp[VIOCGETCACHEPARMS] = cm_IoctlGetCacheParms;
51 smb_ioctlProcsp[VIOCGETCELL] = cm_IoctlGetCell;
52 smb_ioctlProcsp[VIOCNEWCELL] = cm_IoctlNewCell;
53 smb_ioctlProcsp[VIOC_GET_WS_CELL] = cm_IoctlGetWsCell;
54 smb_ioctlProcsp[VIOC_AFS_SYSNAME] = cm_IoctlSysName;
55 smb_ioctlProcsp[VIOC_GETCELLSTATUS] = cm_IoctlGetCellStatus;
56 smb_ioctlProcsp[VIOC_SETCELLSTATUS] = cm_IoctlSetCellStatus;
57 smb_ioctlProcsp[VIOC_SETSPREFS] = cm_IoctlSetSPrefs;
58 smb_ioctlProcsp[VIOC_GETSPREFS] = cm_IoctlGetSPrefs;
59 smb_ioctlProcsp[VIOC_STOREBEHIND] = cm_IoctlStoreBehind;
60 smb_ioctlProcsp[VIOC_AFS_CREATE_MT_PT] = cm_IoctlCreateMountPoint;
61 smb_ioctlProcsp[VIOC_TRACECTL] = cm_IoctlTraceControl;
62 smb_ioctlProcsp[VIOCSETTOK] = cm_IoctlSetToken;
63 smb_ioctlProcsp[VIOCGETTOK] = cm_IoctlGetTokenIter;
64 smb_ioctlProcsp[VIOCNEWGETTOK] = cm_IoctlGetToken;
65 smb_ioctlProcsp[VIOCDELTOK] = cm_IoctlDelToken;
66 smb_ioctlProcsp[VIOCDELALLTOK] = cm_IoctlDelAllToken;
67 smb_ioctlProcsp[VIOC_SYMLINK] = cm_IoctlSymlink;
68 smb_ioctlProcsp[VIOC_LISTSYMLINK] = cm_IoctlListlink;
69 smb_ioctlProcsp[VIOC_DELSYMLINK] = cm_IoctlDeletelink;
70 smb_ioctlProcsp[VIOC_MAKESUBMOUNT] = cm_IoctlMakeSubmount;
71 smb_ioctlProcsp[VIOC_GETRXKCRYPT] = cm_IoctlGetRxkcrypt;
72 smb_ioctlProcsp[VIOC_SETRXKCRYPT] = cm_IoctlSetRxkcrypt;
73 smb_ioctlProcsp[VIOC_ISSYMLINK] = cm_IoctlIslink;
74 smb_ioctlProcsp[VIOC_TRACEMEMDUMP] = cm_IoctlMemoryDump;
75 smb_ioctlProcsp[VIOC_ISSYMLINK] = cm_IoctlIslink;
76 smb_ioctlProcsp[VIOC_FLUSHALL] = cm_IoctlFlushAllVolumes;
77 smb_ioctlProcsp[VIOCGETFID] = cm_IoctlGetFid;
78 smb_ioctlProcsp[VIOCGETOWNER] = cm_IoctlGetOwner;
79 smb_ioctlProcsp[VIOC_RXSTAT_PROC] = cm_IoctlRxStatProcess;
80 smb_ioctlProcsp[VIOC_RXSTAT_PEER] = cm_IoctlRxStatPeer;
81 smb_ioctlProcsp[VIOC_UUIDCTL] = cm_IoctlUUIDControl;
82 smb_ioctlProcsp[VIOC_PATH_AVAILABILITY] = cm_IoctlPathAvailability;
83 smb_ioctlProcsp[VIOC_GETFILETYPE] = cm_IoctlGetFileType;
84 smb_ioctlProcsp[VIOC_VOLSTAT_TEST] = cm_IoctlVolStatTest;
87 /* called to make a fid structure into an IOCTL fid structure */
88 void smb_SetupIoctlFid(smb_fid_t *fidp, cm_space_t *prefix)
91 cm_space_t *copyPrefix;
93 lock_ObtainMutex(&fidp->mx);
94 fidp->flags |= SMB_FID_IOCTL;
95 fidp->scp = &cm_data.fakeSCache;
96 cm_HoldSCache(fidp->scp);
97 if (fidp->ioctlp == NULL) {
98 iop = malloc(sizeof(*iop));
99 memset(iop, 0, sizeof(*iop));
104 copyPrefix = cm_GetSpace();
105 strcpy(copyPrefix->data, prefix->data);
106 fidp->ioctlp->prefix = copyPrefix;
108 lock_ReleaseMutex(&fidp->mx);
111 /* called when we receive a read call, does the send of the received data if
112 * this is the first read call. This is the function that actually makes the
113 * call to the ioctl code.
115 long smb_IoctlPrepareRead(smb_fid_t *fidp, smb_ioctl_t *ioctlp, cm_user_t *userp)
118 smb_ioctlProc_t *procp = NULL;
121 if (ioctlp->flags & SMB_IOCTLFLAG_DATAIN) {
122 ioctlp->flags &= ~SMB_IOCTLFLAG_DATAIN;
124 /* do the call now, or fail if we didn't get an opcode, or
125 * enough of an opcode.
127 if (ioctlp->inCopied < sizeof(long))
128 return CM_ERROR_INVAL;
129 memcpy(&opcode, ioctlp->inDatap, sizeof(long));
130 ioctlp->inDatap += sizeof(long);
132 osi_Log1(afsd_logp, "Ioctl opcode 0x%x", opcode);
134 /* check for opcode out of bounds */
135 if (opcode < 0 || opcode >= SMB_IOCTL_MAXPROCS)
136 return CM_ERROR_TOOBIG;
138 /* check for no such proc */
139 procp = smb_ioctlProcsp[opcode];
141 return CM_ERROR_BADOP;
143 /* otherwise, make the call */
144 ioctlp->outDatap += sizeof(long); /* reserve room for return code */
145 code = (*procp)(ioctlp, userp);
147 osi_Log1(afsd_logp, "Ioctl return code 0x%x", code);
149 /* copy in return code */
150 memcpy(ioctlp->outAllocp, &code, sizeof(long));
155 /* called when we receive a write call. If this is the first write call after
156 * a series of reads (or the very first call), then we start a new call.
157 * We also ensure that things are properly initialized for the start of a call.
159 void smb_IoctlPrepareWrite(smb_fid_t *fidp, smb_ioctl_t *ioctlp)
161 /* make sure the buffer(s) are allocated */
162 if (!ioctlp->inAllocp) ioctlp->inAllocp = malloc(SMB_IOCTL_MAXDATA);
163 if (!ioctlp->outAllocp) ioctlp->outAllocp = malloc(SMB_IOCTL_MAXDATA);
165 /* Fixes fs la problem. We do a StrToOEM later and if this data isn't initialized we get memory issues. */
166 (void) memset(ioctlp->inAllocp, 0, SMB_IOCTL_MAXDATA);
167 (void) memset(ioctlp->outAllocp, 0, SMB_IOCTL_MAXDATA);
169 /* and make sure that we've reset our state for the new incoming request */
170 if (!(ioctlp->flags & SMB_IOCTLFLAG_DATAIN)) {
171 ioctlp->inCopied = 0;
172 ioctlp->outCopied = 0;
173 ioctlp->inDatap = ioctlp->inAllocp;
174 ioctlp->outDatap = ioctlp->outAllocp;
175 ioctlp->flags |= SMB_IOCTLFLAG_DATAIN;
179 /* called from smb_ReceiveCoreRead when we receive a read on the ioctl fid */
180 long smb_IoctlRead(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
191 count = smb_GetSMBParm(inp, 1);
192 userp = smb_GetUserFromVCP(vcp, inp);
195 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
197 cm_ReleaseUser(userp);
198 return CM_ERROR_NOSUCHPATH;
201 /* turn the connection around, if required */
202 code = smb_IoctlPrepareRead(fidp, iop, userp);
205 cm_ReleaseUser(userp);
209 leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
210 if (count > leftToCopy) count = leftToCopy;
212 /* now set the parms for a read of count bytes */
213 smb_SetSMBParm(outp, 0, count);
214 smb_SetSMBParm(outp, 1, 0);
215 smb_SetSMBParm(outp, 2, 0);
216 smb_SetSMBParm(outp, 3, 0);
217 smb_SetSMBParm(outp, 4, 0);
219 smb_SetSMBDataLength(outp, count+3);
221 op = smb_GetSMBData(outp, NULL);
223 *op++ = (char)(count & 0xff);
224 *op++ = (char)((count >> 8) & 0xff);
226 /* now copy the data into the response packet */
227 memcpy(op, iop->outCopied + iop->outAllocp, count);
229 /* and adjust the counters */
230 iop->outCopied += count;
232 cm_ReleaseUser(userp);
237 /* called from smb_ReceiveCoreWrite when we receive a write call on the IOCTL
240 long smb_IoctlWrite(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
246 int inDataBlockCount;
249 count = smb_GetSMBParm(inp, 1);
252 smb_IoctlPrepareWrite(fidp, iop);
254 op = smb_GetSMBData(inp, NULL);
255 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
257 if (count + iop->inCopied > SMB_IOCTL_MAXDATA) {
258 code = CM_ERROR_TOOBIG;
263 memcpy(iop->inDatap + iop->inCopied, op, count);
266 iop->inCopied += count;
269 /* return # of bytes written */
271 smb_SetSMBParm(outp, 0, count);
272 smb_SetSMBDataLength(outp, 0);
278 /* called from smb_ReceiveV3WriteX when we receive a write call on the IOCTL
281 long smb_IoctlV3Write(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
287 int inDataBlockCount;
290 count = smb_GetSMBParm(inp, 10);
293 smb_IoctlPrepareWrite(fidp, iop);
295 op = inp->data + smb_GetSMBParm(inp, 11);
296 inDataBlockCount = count;
298 if (count + iop->inCopied > SMB_IOCTL_MAXDATA) {
299 code = CM_ERROR_TOOBIG;
304 memcpy(iop->inDatap + iop->inCopied, op, count);
307 iop->inCopied += count;
310 /* return # of bytes written */
312 smb_SetSMBParm(outp, 2, count);
313 smb_SetSMBParm(outp, 3, 0); /* reserved */
314 smb_SetSMBParm(outp, 4, 0); /* reserved */
315 smb_SetSMBParm(outp, 5, 0); /* reserved */
316 smb_SetSMBDataLength(outp, 0);
323 /* called from V3 read to handle IOCTL descriptor reads */
324 long smb_IoctlV3Read(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
335 count = smb_GetSMBParm(inp, 5);
337 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
338 userp = smb_GetUserFromUID(uidp);
339 osi_assertx(userp != NULL, "null cm_user_t");
341 if (uidp && uidp->unp) {
342 osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
344 osi_LogSaveString(afsd_logp, uidp->unp->name));
347 osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
348 uidp->userID, userp);
350 osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
354 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
357 smb_ReleaseUID(uidp);
358 cm_ReleaseUser(userp);
359 return CM_ERROR_NOSUCHPATH;
362 code = smb_IoctlPrepareRead(fidp, iop, userp);
365 smb_ReleaseUID(uidp);
368 cm_ReleaseUser(userp);
372 leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
373 if (count > leftToCopy) count = leftToCopy;
375 /* 0 and 1 are reserved for request chaining, were setup by our caller,
376 * and will be further filled in after we return.
378 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
379 smb_SetSMBParm(outp, 3, 0); /* resvd */
380 smb_SetSMBParm(outp, 4, 0); /* resvd */
381 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
382 /* fill in #6 when we have all the parameters' space reserved */
383 smb_SetSMBParm(outp, 7, 0); /* resv'd */
384 smb_SetSMBParm(outp, 8, 0); /* resv'd */
385 smb_SetSMBParm(outp, 9, 0); /* resv'd */
386 smb_SetSMBParm(outp, 10, 0); /* resv'd */
387 smb_SetSMBParm(outp, 11, 0); /* reserved */
389 /* get op ptr after putting in the last parm, since otherwise we don't
390 * know where the data really is.
392 op = smb_GetSMBData(outp, NULL);
394 /* now fill in offset from start of SMB header to first data byte (to op) */
395 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
397 /* set the packet data length the count of the # of bytes */
398 smb_SetSMBDataLength(outp, count);
400 /* now copy the data into the response packet */
401 memcpy(op, iop->outCopied + iop->outAllocp, count);
403 /* and adjust the counters */
404 iop->outCopied += count;
406 /* and cleanup things */
407 cm_ReleaseUser(userp);
412 /* called from Read Raw to handle IOCTL descriptor reads */
413 long smb_IoctlReadRaw(smb_fid_t *fidp, smb_vc_t *vcp, smb_packet_t *inp,
425 userp = smb_GetUserFromVCP(vcp, inp);
431 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
432 if (uidp && uidp->unp) {
433 osi_Log3(afsd_logp, "Ioctl uid %d user %x name %s",
435 osi_LogSaveString(afsd_logp, uidp->unp->name));
437 osi_Log2(afsd_logp, "Ioctl uid %d user %x no name",
438 uidp->userID, userp);
440 osi_Log1(afsd_logp, "Ioctl no uid user %x no name",
444 smb_ReleaseUID(uidp);
447 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &iop->tidPathp);
449 cm_ReleaseUser(userp);
450 return CM_ERROR_NOSUCHPATH;
453 code = smb_IoctlPrepareRead(fidp, iop, userp);
455 cm_ReleaseUser(userp);
459 leftToCopy = (long)((iop->outDatap - iop->outAllocp) - iop->outCopied);
462 memset((char *)ncbp, 0, sizeof(NCB));
464 ncbp->ncb_length = (unsigned short) leftToCopy;
465 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
466 ncbp->ncb_command = NCBSEND;
467 /*ncbp->ncb_lana_num = smb_LANadapter;*/
468 ncbp->ncb_lana_num = vcp->lana;
470 ncbp->ncb_buffer = iop->outCopied + iop->outAllocp;
471 code = Netbios(ncbp);
474 osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
476 cm_ReleaseUser(userp);