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
12 #include <afs/param.h>
30 extern smb_vc_t *dead_vcp;
32 extern osi_hyper_t hzero;
34 smb_packet_t *smb_Directory_Watches = NULL;
35 osi_mutex_t smb_Dir_Watch_Lock;
37 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
39 /* protected by the smb_globalLock */
40 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
42 /* retrieve a held reference to a user structure corresponding to an incoming
44 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
49 uidp = smb_FindUID(vcp, inp->uid, 0);
50 if (!uidp) return NULL;
52 lock_ObtainMutex(&uidp->mx);
54 up = uidp->unp->userp;
57 lock_ReleaseMutex(&uidp->mx);
65 * Return extended attributes.
66 * Right now, we aren't using any of the "new" bits, so this looks exactly
67 * like smb_Attributes() (see smb.c).
69 unsigned long smb_ExtAttributes(cm_scache_t *scp)
73 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
74 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
79 * We used to mark a file RO if it was in an RO volume, but that
80 * turns out to be impolitic in NT. See defect 10007.
83 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
85 if ((scp->unixModeBits & 0222) == 0)
86 attrs |= 1; /* Read-only */
89 attrs = 0x80; /* FILE_ATTRIBUTE_NORMAL */
94 int smb_V3IsStarMask(char *maskp)
99 if (tc == '?' || tc == '*') return 1;
103 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
106 /* skip over null-terminated string */
107 *chainpp = inp + strlen(inp) + 1;
112 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
115 char *usern, *pwd, *pwdx;
116 smb_user_t *uidp, *dead_uidp;
117 unsigned short newUid;
123 /* Check for bad conns */
124 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
125 return CM_ERROR_REMOTECONN;
127 /* For NT LM 0.12 and up, get capabilities */
128 if (vcp->flags & SMB_VCFLAG_USENT) {
129 caps = smb_GetSMBParm(inp, 11);
131 vcp->flags |= SMB_VCFLAG_STATUS32;
132 /* for now, ignore other capability bits */
136 tp = smb_GetSMBData(inp, NULL);
137 if (vcp->flags & SMB_VCFLAG_USENT)
138 pwdx = smb_ParseString(tp, &tp);
139 pwd = smb_ParseString(tp, &tp);
140 usern = smb_ParseString(tp, &tp);
142 /* On Windows 2000, this function appears to be called more often than
143 it is expected to be called. This resulted in multiple smb_user_t
144 records existing all for the same user session which results in all
145 of the users tokens disappearing.
147 To avoid this problem, we look for an existing smb_user_t record
148 based on the users name, and use that one if we find it.
151 uidp = smb_FindUserByNameThisSession(vcp, usern);
152 if (uidp) { /* already there, so don't create a new one */
155 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
156 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
157 osi_Log3(afsd_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
158 smb_ReleaseUID(uidp);
161 /* do a global search for the username/machine name pair */
162 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
164 /* Create a new UID and cm_user_t structure */
167 userp = cm_NewUser();
168 lock_ObtainMutex(&vcp->mx);
169 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
170 lock_ReleaseMutex(&vcp->mx);
172 /* Create a new smb_user_t structure and connect them up */
173 lock_ObtainMutex(&unp->mx);
175 lock_ReleaseMutex(&unp->mx);
177 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
178 lock_ObtainMutex(&uidp->mx);
180 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",vcp,vcp->lana,vcp->lsn,newUid,usern);
181 osi_Log4(afsd_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
182 lock_ReleaseMutex(&uidp->mx);
183 smb_ReleaseUID(uidp);
186 /* Return UID to the client */
187 ((smb_t *)outp)->uid = newUid;
188 /* Also to the next chained message */
189 ((smb_t *)inp)->uid = newUid;
191 osi_Log3(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
192 osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_logp, s1));
193 smb_SetSMBParm(outp, 2, 0);
194 smb_SetSMBDataLength(outp, 0);
198 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
202 /* don't get tokens from this VC */
203 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
205 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
207 /* find the tree and free it */
208 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
210 char *s1 = NULL, *s2 = NULL;
212 if (s2 == NULL) s2 = " ";
213 if (s1 == NULL) {s1 = s2; s2 = " ";}
215 osi_Log4(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
217 osi_LogSaveString(afsd_logp,
218 (uidp->unp) ? uidp->unp->name: " "), s1, s2);
220 lock_ObtainMutex(&uidp->mx);
221 uidp->flags |= SMB_USERFLAG_DELETE;
223 * it doesn't get deleted right away
224 * because the vcp points to it
226 lock_ReleaseMutex(&uidp->mx);
229 osi_Log0(afsd_logp, "SMB3 user logoffX");
231 smb_SetSMBDataLength(outp, 0);
235 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
238 unsigned short newTid;
248 osi_Log0(afsd_logp, "SMB3 receive tree connect");
250 /* parse input parameters */
251 tp = smb_GetSMBData(inp, NULL);
252 passwordp = smb_ParseString(tp, &tp);
253 pathp = smb_ParseString(tp, &tp);
254 servicep = smb_ParseString(tp, &tp);
256 tp = strrchr(pathp, '\\');
258 return CM_ERROR_BADSMB;
260 strcpy(shareName, tp+1);
262 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
263 return CM_ERROR_NOIPC;
265 userp = smb_GetUser(vcp, inp);
267 lock_ObtainMutex(&vcp->mx);
268 newTid = vcp->tidCounter++;
269 lock_ReleaseMutex(&vcp->mx);
271 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
272 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
274 smb_ReleaseTID(tidp);
275 return CM_ERROR_BADSHARENAME;
277 lock_ObtainMutex(&tidp->mx);
279 tidp->pathname = sharePath;
280 lock_ReleaseMutex(&tidp->mx);
281 smb_ReleaseTID(tidp);
283 if (vcp->flags & SMB_VCFLAG_USENT)
284 smb_SetSMBParm(outp, 2, 0); /* OptionalSupport bits */
286 ((smb_t *)outp)->tid = newTid;
287 ((smb_t *)inp)->tid = newTid;
288 tp = smb_GetSMBData(outp, NULL);
292 smb_SetSMBDataLength(outp, 3);
294 osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
298 /* must be called with global tran lock held */
299 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
301 smb_tran2Packet_t *tp;
304 smbp = (smb_t *) inp->data;
305 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
306 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
312 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
313 int totalParms, int totalData)
315 smb_tran2Packet_t *tp;
318 smbp = (smb_t *) inp->data;
319 tp = malloc(sizeof(*tp));
320 memset(tp, 0, sizeof(*tp));
323 tp->curData = tp->curParms = 0;
324 tp->totalData = totalData;
325 tp->totalParms = totalParms;
330 tp->res[0] = smbp->res[0];
331 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
332 tp->opcode = smb_GetSMBParm(inp, 14);
334 tp->parmsp = malloc(totalParms);
336 tp->datap = malloc(totalData);
337 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
341 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
342 smb_tran2Packet_t *inp, smb_packet_t *outp,
343 int totalParms, int totalData)
345 smb_tran2Packet_t *tp;
346 unsigned short parmOffset;
347 unsigned short dataOffset;
348 unsigned short dataAlign;
350 tp = malloc(sizeof(*tp));
351 memset(tp, 0, sizeof(*tp));
353 tp->curData = tp->curParms = 0;
354 tp->totalData = totalData;
355 tp->totalParms = totalParms;
356 tp->oldTotalParms = totalParms;
361 tp->res[0] = inp->res[0];
362 tp->opcode = inp->opcode;
365 * We calculate where the parameters and data will start.
366 * This calculation must parallel the calculation in
367 * smb_SendTran2Packet.
370 parmOffset = 10*2 + 35;
371 parmOffset++; /* round to even */
372 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
374 dataOffset = parmOffset + totalParms;
375 dataAlign = dataOffset & 2; /* quad-align */
376 dataOffset += dataAlign;
377 tp->datap = outp->data + dataOffset;
382 /* free a tran2 packet; must be called with smb_globalLock held */
383 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
385 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
386 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
395 /* called with a VC, an input packet to respond to, and an error code.
396 * sends an error response.
398 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
399 smb_packet_t *tp, long code)
402 unsigned short errCode;
403 unsigned char errClass;
404 unsigned long NTStatus;
406 if (vcp->flags & SMB_VCFLAG_STATUS32)
407 smb_MapNTError(code, &NTStatus);
409 smb_MapCoreError(code, vcp, &errCode, &errClass);
411 smb_FormatResponsePacket(vcp, NULL, tp);
414 /* We can handle long names */
415 if (vcp->flags & SMB_VCFLAG_USENT)
416 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
418 /* now copy important fields from the tran 2 packet */
419 smbp->com = 0x32; /* tran 2 response */
420 smbp->tid = t2p->tid;
421 smbp->mid = t2p->mid;
422 smbp->pid = t2p->pid;
423 smbp->uid = t2p->uid;
424 smbp->res[0] = t2p->res[0];
425 if (vcp->flags & SMB_VCFLAG_STATUS32) {
426 smbp->rcls = (unsigned char) (NTStatus & 0xff);
427 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
428 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
429 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
430 smbp->flg2 |= 0x4000;
433 smbp->rcls = errClass;
434 smbp->errLow = (unsigned char) (errCode & 0xff);
435 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
439 smb_SendPacket(vcp, tp);
442 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
445 unsigned short parmOffset;
446 unsigned short dataOffset;
447 unsigned short totalLength;
448 unsigned short dataAlign;
451 smb_FormatResponsePacket(vcp, NULL, tp);
454 /* We can handle long names */
455 if (vcp->flags & SMB_VCFLAG_USENT)
456 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
458 /* now copy important fields from the tran 2 packet */
459 smbp->com = 0x32; /* tran 2 response */
460 smbp->tid = t2p->tid;
461 smbp->mid = t2p->mid;
462 smbp->pid = t2p->pid;
463 smbp->uid = t2p->uid;
464 smbp->res[0] = t2p->res[0];
466 totalLength = 1 + t2p->totalData + t2p->totalParms;
468 /* now add the core parameters (tran2 info) to the packet */
469 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
470 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
471 smb_SetSMBParm(tp, 2, 0); /* reserved */
472 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
473 parmOffset = 10*2 + 35; /* parm offset in packet */
474 parmOffset++; /* round to even */
475 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
476 * hdr, bcc and wct */
477 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
478 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
479 dataOffset = parmOffset + t2p->oldTotalParms;
480 dataAlign = dataOffset & 2; /* quad-align */
481 dataOffset += dataAlign;
482 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
483 smb_SetSMBParm(tp, 8, 0); /* data displacement */
484 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
487 datap = smb_GetSMBData(tp, NULL);
488 *datap++ = 0; /* we rounded to even */
490 totalLength += dataAlign;
491 smb_SetSMBDataLength(tp, totalLength);
493 /* next, send the datagram */
494 smb_SendPacket(vcp, tp);
497 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
499 smb_tran2Packet_t *asp;
511 /* We sometimes see 0 word count. What to do? */
512 if (*inp->wctp == 0) {
517 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
519 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
520 ptbuf[0] = "Transaction2 word count = 0";
521 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
522 1, inp->ncb_length, ptbuf, inp);
523 DeregisterEventSource(h);
525 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
528 smb_SetSMBDataLength(outp, 0);
529 smb_SendPacket(vcp, outp);
533 totalParms = smb_GetSMBParm(inp, 0);
534 totalData = smb_GetSMBParm(inp, 1);
536 firstPacket = (inp->inCom == 0x32);
538 /* find the packet we're reassembling */
539 lock_ObtainWrite(&smb_globalLock);
540 asp = smb_FindTran2Packet(vcp, inp);
542 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
544 lock_ReleaseWrite(&smb_globalLock);
546 /* now merge in this latest packet; start by looking up offsets */
548 parmDisp = dataDisp = 0;
549 parmOffset = smb_GetSMBParm(inp, 10);
550 dataOffset = smb_GetSMBParm(inp, 12);
551 parmCount = smb_GetSMBParm(inp, 9);
552 dataCount = smb_GetSMBParm(inp, 11);
553 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
554 asp->maxReturnData = smb_GetSMBParm(inp, 3);
556 osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
557 totalData, dataCount, asp->maxReturnData);
560 parmDisp = smb_GetSMBParm(inp, 4);
561 parmOffset = smb_GetSMBParm(inp, 3);
562 dataDisp = smb_GetSMBParm(inp, 7);
563 dataOffset = smb_GetSMBParm(inp, 6);
564 parmCount = smb_GetSMBParm(inp, 2);
565 dataCount = smb_GetSMBParm(inp, 5);
567 osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
568 parmCount, dataCount);
571 /* now copy the parms and data */
572 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
573 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
575 /* account for new bytes */
576 asp->curData += dataCount;
577 asp->curParms += parmCount;
579 /* finally, if we're done, remove the packet from the queue and dispatch it */
580 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
581 /* we've received it all */
582 lock_ObtainWrite(&smb_globalLock);
583 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
584 lock_ReleaseWrite(&smb_globalLock);
586 /* now dispatch it */
587 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",vcp,vcp->lana,vcp->lsn);
588 osi_Log4(afsd_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
589 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
591 /* if an error is returned, we're supposed to send an error packet,
592 * otherwise the dispatched function already did the data sending.
593 * We give dispatched proc the responsibility since it knows how much
597 smb_SendTran2Error(vcp, asp, outp, code);
600 /* free the input tran 2 packet */
601 lock_ObtainWrite(&smb_globalLock);
602 smb_FreeTran2Packet(asp);
603 lock_ReleaseWrite(&smb_globalLock);
605 else if (firstPacket) {
606 /* the first packet in a multi-packet request, we need to send an
607 * ack to get more data.
609 smb_SetSMBDataLength(outp, 0);
610 smb_SendPacket(vcp, outp);
616 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
619 smb_tran2Packet_t *outp;
624 cm_scache_t *dscp; /* dir we're dealing with */
625 cm_scache_t *scp; /* file we're creating */
637 int parmSlot; /* which parm we're dealing with */
646 extraInfo = (p->parmsp[0] & 1); /* return extra info */
647 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
649 openFun = p->parmsp[6]; /* open function */
650 excl = ((openFun & 3) == 0);
651 trunc = ((openFun & 3) == 2); /* truncate it */
652 openMode = (p->parmsp[1] & 0x7);
653 openAction = 0; /* tracks what we did */
655 attributes = p->parmsp[3];
656 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
658 /* compute initial mode bits based on read-only flag in attributes */
659 initialModeBits = 0666;
660 if (attributes & 1) initialModeBits &= ~0222;
662 pathp = (char *) (&p->parmsp[14]);
664 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
666 spacep = cm_GetSpace();
667 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
669 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
670 /* special case magic file name for receiving IOCTL requests
671 * (since IOCTL calls themselves aren't getting through).
673 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
674 smb_SetupIoctlFid(fidp, spacep);
676 /* copy out remainder of the parms */
678 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
680 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
681 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
682 outp->parmsp[parmSlot] = 0; parmSlot++;
683 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
684 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
685 outp->parmsp[parmSlot] = openMode; parmSlot++;
686 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
687 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
689 /* and the final "always present" stuff */
690 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
691 /* next write out the "unique" ID */
692 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
693 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
694 outp->parmsp[parmSlot] = 0; parmSlot++;
695 if (returnEALength) {
696 outp->parmsp[parmSlot] = 0; parmSlot++;
697 outp->parmsp[parmSlot] = 0; parmSlot++;
701 outp->totalParms = parmSlot * 2;
703 smb_SendTran2Packet(vcp, outp, op);
705 smb_FreeTran2Packet(outp);
707 /* and clean up fid reference */
708 smb_ReleaseFID(fidp);
712 userp = smb_GetTran2User(vcp, p);
713 tidPathp = smb_GetTIDPath(vcp, p->tid);
716 code = cm_NameI(cm_rootSCachep, pathp,
717 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
718 userp, tidPathp, &req, &scp);
720 code = cm_NameI(cm_rootSCachep, spacep->data,
721 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
722 userp, tidPathp, &req, &dscp);
723 cm_FreeSpace(spacep);
726 cm_ReleaseUser(userp);
727 smb_FreeTran2Packet(outp);
731 /* otherwise, scp points to the parent directory. Do a lookup,
732 * and truncate the file if we find it, otherwise we create the
735 if (!lastNamep) lastNamep = pathp;
737 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
739 if (code && code != CM_ERROR_NOSUCHFILE) {
740 cm_ReleaseSCache(dscp);
741 cm_ReleaseUser(userp);
742 smb_FreeTran2Packet(outp);
747 cm_FreeSpace(spacep);
750 /* if we get here, if code is 0, the file exists and is represented by
751 * scp. Otherwise, we have to create it.
754 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
756 if (dscp) cm_ReleaseSCache(dscp);
757 cm_ReleaseSCache(scp);
758 cm_ReleaseUser(userp);
759 smb_FreeTran2Packet(outp);
764 /* oops, file shouldn't be there */
765 if (dscp) cm_ReleaseSCache(dscp);
766 cm_ReleaseSCache(scp);
767 cm_ReleaseUser(userp);
768 smb_FreeTran2Packet(outp);
769 return CM_ERROR_EXISTS;
773 setAttr.mask = CM_ATTRMASK_LENGTH;
774 setAttr.length.LowPart = 0;
775 setAttr.length.HighPart = 0;
776 code = cm_SetAttr(scp, &setAttr, userp, &req);
777 openAction = 3; /* truncated existing file */
779 else openAction = 1; /* found existing file */
781 else if (!(openFun & 0x10)) {
782 /* don't create if not found */
783 if (dscp) cm_ReleaseSCache(dscp);
784 osi_assert(scp == NULL);
785 cm_ReleaseUser(userp);
786 smb_FreeTran2Packet(outp);
787 return CM_ERROR_NOSUCHFILE;
790 osi_assert(dscp != NULL && scp == NULL);
791 openAction = 2; /* created file */
792 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
793 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
794 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
796 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
797 smb_NotifyChange(FILE_ACTION_ADDED,
798 FILE_NOTIFY_CHANGE_FILE_NAME,
799 dscp, lastNamep, NULL, TRUE);
800 if (!excl && code == CM_ERROR_EXISTS) {
801 /* not an exclusive create, and someone else tried
802 * creating it already, then we open it anyway. We
803 * don't bother retrying after this, since if this next
804 * fails, that means that the file was deleted after we
807 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
811 setAttr.mask = CM_ATTRMASK_LENGTH;
812 setAttr.length.LowPart = 0;
813 setAttr.length.HighPart = 0;
814 code = cm_SetAttr(scp, &setAttr, userp,
817 } /* lookup succeeded */
821 /* we don't need this any longer */
822 if (dscp) cm_ReleaseSCache(dscp);
825 /* something went wrong creating or truncating the file */
826 if (scp) cm_ReleaseSCache(scp);
827 cm_ReleaseUser(userp);
828 smb_FreeTran2Packet(outp);
832 /* make sure we're about to open a file */
833 if (scp->fileType != CM_SCACHETYPE_FILE) {
834 cm_ReleaseSCache(scp);
835 cm_ReleaseUser(userp);
836 smb_FreeTran2Packet(outp);
837 return CM_ERROR_ISDIR;
840 /* now all we have to do is open the file itself */
841 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
844 /* save a pointer to the vnode */
847 /* compute open mode */
848 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
849 if (openMode == 1 || openMode == 2)
850 fidp->flags |= SMB_FID_OPENWRITE;
852 smb_ReleaseFID(fidp);
854 cm_Open(scp, 0, userp);
856 /* copy out remainder of the parms */
858 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
859 lock_ObtainMutex(&scp->mx);
861 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
862 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
863 outp->parmsp[parmSlot] = dosTime & 0xffff; parmSlot++;
864 outp->parmsp[parmSlot] = (dosTime>>16) & 0xffff; parmSlot++;
865 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
867 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
869 outp->parmsp[parmSlot] = openMode; parmSlot++;
870 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
871 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
873 /* and the final "always present" stuff */
874 outp->parmsp[parmSlot] = openAction; parmSlot++;
875 /* next write out the "unique" ID */
876 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
877 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
878 outp->parmsp[parmSlot] = 0; parmSlot++;
879 if (returnEALength) {
880 outp->parmsp[parmSlot] = 0; parmSlot++;
881 outp->parmsp[parmSlot] = 0; parmSlot++;
883 lock_ReleaseMutex(&scp->mx);
884 outp->totalData = 0; /* total # of data bytes */
885 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
887 smb_SendTran2Packet(vcp, outp, op);
889 smb_FreeTran2Packet(outp);
891 cm_ReleaseUser(userp);
892 /* leave scp held since we put it in fidp->scp */
896 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
898 return CM_ERROR_BADOP;
901 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
903 return CM_ERROR_BADOP;
906 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
908 smb_tran2Packet_t *outp;
909 smb_tran2QFSInfo_t qi;
912 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
914 osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
916 switch (p->parmsp[0]) {
917 case 1: responseSize = sizeof(qi.u.allocInfo); break;
918 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
919 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
920 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
921 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
922 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
923 default: return CM_ERROR_INVAL;
926 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
927 switch (p->parmsp[0]) {
930 qi.u.allocInfo.FSID = 0;
931 qi.u.allocInfo.sectorsPerAllocUnit = 1;
932 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
933 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
934 qi.u.allocInfo.bytesPerSector = 1024;
939 qi.u.volumeInfo.vsn = 1234;
940 qi.u.volumeInfo.vnCount = 4;
941 /* we're supposed to pad it out with zeroes to the end */
942 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
943 strcpy(qi.u.volumeInfo.label, "AFS");
948 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
949 qi.u.FSvolumeInfo.vsn = 1234;
950 qi.u.FSvolumeInfo.vnCount = 4;
951 strcpy(qi.u.FSvolumeInfo.label, "AFS");
957 temp.LowPart = 0x7fffffff;
958 qi.u.FSsizeInfo.totalAllocUnits = temp;
959 temp.LowPart = 0x3fffffff;
960 qi.u.FSsizeInfo.availAllocUnits = temp;
961 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
962 qi.u.FSsizeInfo.bytesPerSector = 1024;
967 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
968 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
972 /* FS attribute info */
973 /* attributes, defined in WINNT.H:
974 * FILE_CASE_SENSITIVE_SEARCH 0x1
975 * FILE_CASE_PRESERVED_NAMES 0x2
976 * <no name defined> 0x4000
977 * If bit 0x4000 is not set, Windows 95 thinks
978 * we can't handle long (non-8.3) names,
979 * despite our protestations to the contrary.
981 qi.u.FSattributeInfo.attributes = 0x4003;
982 qi.u.FSattributeInfo.maxCompLength = 255;
983 qi.u.FSattributeInfo.FSnameLength = 6;
984 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
988 /* copy out return data, and set corresponding sizes */
989 outp->totalParms = 0;
990 outp->totalData = responseSize;
991 memcpy(outp->datap, &qi, responseSize);
993 /* send and free the packets */
994 smb_SendTran2Packet(vcp, outp, op);
995 smb_FreeTran2Packet(outp);
1000 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1002 return CM_ERROR_BADOP;
1005 struct smb_ShortNameRock {
1009 size_t shortNameLen;
1012 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1015 struct smb_ShortNameRock *rockp;
1019 /* compare both names and vnodes, though probably just comparing vnodes
1020 * would be safe enough.
1022 if (stricmp(dep->name, rockp->maskp) != 0)
1024 if (ntohl(dep->fid.vnode) != rockp->vnode)
1026 /* This is the entry */
1027 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1028 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1029 return CM_ERROR_STOPNOW;
1032 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1033 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1035 struct smb_ShortNameRock rock;
1039 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1043 spacep = cm_GetSpace();
1044 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1046 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1048 cm_FreeSpace(spacep);
1049 if (code) return code;
1051 if (!lastNamep) lastNamep = pathp;
1054 thyper.HighPart = 0;
1055 rock.shortName = shortName;
1057 rock.maskp = lastNamep;
1058 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1061 cm_ReleaseSCache(dscp);
1064 return CM_ERROR_NOSUCHFILE;
1065 if (code == CM_ERROR_STOPNOW) {
1066 *shortNameLenp = rock.shortNameLen;
1072 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1074 smb_tran2Packet_t *outp;
1075 unsigned long dosTime;
1077 unsigned short infoLevel;
1079 unsigned short attributes;
1080 unsigned long extAttributes;
1085 cm_scache_t *scp, *dscp;
1094 infoLevel = p->parmsp[0];
1095 if (infoLevel == 6) nbytesRequired = 0;
1096 else if (infoLevel == 1) nbytesRequired = 22;
1097 else if (infoLevel == 2) nbytesRequired = 26;
1098 else if (infoLevel == 0x101) nbytesRequired = 40;
1099 else if (infoLevel == 0x102) nbytesRequired = 24;
1100 else if (infoLevel == 0x103) nbytesRequired = 4;
1101 else if (infoLevel == 0x108) nbytesRequired = 30;
1103 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1104 p->opcode, infoLevel);
1105 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1108 osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1109 osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
1111 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1113 if (infoLevel > 0x100)
1114 outp->totalParms = 2;
1116 outp->totalParms = 0;
1117 outp->totalData = nbytesRequired;
1119 /* now, if we're at infoLevel 6, we're only being asked to check
1120 * the syntax, so we just OK things now. In particular, we're *not*
1121 * being asked to verify anything about the state of any parent dirs.
1123 if (infoLevel == 6) {
1124 smb_SendTran2Packet(vcp, outp, opx);
1125 smb_FreeTran2Packet(outp);
1129 userp = smb_GetTran2User(vcp, p);
1131 tidPathp = smb_GetTIDPath(vcp, p->tid);
1134 * XXX Strange hack XXX
1136 * As of Patch 7 (13 January 98), we are having the following problem:
1137 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1138 * requests to look up "desktop.ini" in all the subdirectories.
1139 * This can cause zillions of timeouts looking up non-existent cells
1140 * and volumes, especially in the top-level directory.
1142 * We have not found any way to avoid this or work around it except
1143 * to explicitly ignore the requests for mount points that haven't
1144 * yet been evaluated and for directories that haven't yet been
1147 if (infoLevel == 0x101) {
1148 spacep = cm_GetSpace();
1149 smb_StripLastComponent(spacep->data, &lastComp,
1150 (char *)(&p->parmsp[3]));
1151 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1152 code = cm_NameI(cm_rootSCachep, spacep->data,
1156 userp, tidPathp, &req, &dscp);
1158 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1159 && !dscp->mountRootFidp)
1160 code = CM_ERROR_NOSUCHFILE;
1161 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1162 cm_buf_t *bp = buf_Find(dscp, &hzero);
1166 code = CM_ERROR_NOSUCHFILE;
1168 cm_ReleaseSCache(dscp);
1170 cm_FreeSpace(spacep);
1171 cm_ReleaseUser(userp);
1172 smb_SendTran2Error(vcp, p, opx, code);
1173 smb_FreeTran2Packet(outp);
1178 cm_FreeSpace(spacep);
1181 /* now do namei and stat, and copy out the info */
1182 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1183 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1186 cm_ReleaseUser(userp);
1187 smb_SendTran2Error(vcp, p, opx, code);
1188 smb_FreeTran2Packet(outp);
1192 lock_ObtainMutex(&scp->mx);
1193 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1194 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1195 if (code) goto done;
1197 /* now we have the status in the cache entry, and everything is locked.
1198 * Marshall the output data.
1201 /* for info level 108, figure out short name */
1202 if (infoLevel == 0x108) {
1203 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1204 tidPathp, scp->fid.vnode, shortName,
1211 *((u_long *)op) = len * 2; op += 4;
1212 mbstowcs((unsigned short *)op, shortName, len);
1217 if (infoLevel == 1 || infoLevel == 2) {
1218 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1219 *((u_long *)op) = dosTime; op += 4; /* creation time */
1220 *((u_long *)op) = dosTime; op += 4; /* access time */
1221 *((u_long *)op) = dosTime; op += 4; /* write time */
1222 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1223 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1224 attributes = smb_Attributes(scp);
1225 *((u_short *)op) = attributes; op += 2; /* attributes */
1227 else if (infoLevel == 0x101) {
1228 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1229 *((FILETIME *)op) = ft; op += 8; /* creation time */
1230 *((FILETIME *)op) = ft; op += 8; /* last access time */
1231 *((FILETIME *)op) = ft; op += 8; /* last write time */
1232 *((FILETIME *)op) = ft; op += 8; /* last change time */
1233 extAttributes = smb_ExtAttributes(scp);
1234 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1235 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1237 else if (infoLevel == 0x102) {
1238 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1239 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1240 *((u_long *)op) = scp->linkCount; op += 4;
1243 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1246 else if (infoLevel == 0x103) {
1247 memset(op, 0, 4); op += 4; /* EA size */
1250 /* now, if we are being asked about extended attrs, return a 0 size */
1251 if (infoLevel == 2) {
1252 *((u_long *)op) = 0; op += 4;
1256 /* send and free the packets */
1258 lock_ReleaseMutex(&scp->mx);
1259 cm_ReleaseSCache(scp);
1260 cm_ReleaseUser(userp);
1261 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1262 else smb_SendTran2Error(vcp, p, opx, code);
1263 smb_FreeTran2Packet(outp);
1268 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1270 return CM_ERROR_BADOP;
1273 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1275 smb_tran2Packet_t *outp;
1277 unsigned long attributes;
1278 unsigned short infoLevel;
1291 fidp = smb_FindFID(vcp, fid, 0);
1294 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1298 infoLevel = p->parmsp[1];
1299 if (infoLevel == 0x101) nbytesRequired = 40;
1300 else if (infoLevel == 0x102) nbytesRequired = 24;
1301 else if (infoLevel == 0x103) nbytesRequired = 4;
1302 else if (infoLevel == 0x104) nbytesRequired = 6;
1304 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1305 p->opcode, infoLevel);
1306 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1309 osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1311 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1313 if (infoLevel > 0x100)
1314 outp->totalParms = 2;
1316 outp->totalParms = 0;
1317 outp->totalData = nbytesRequired;
1319 userp = smb_GetTran2User(vcp, p);
1322 lock_ObtainMutex(&scp->mx);
1323 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1324 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1325 if (code) goto done;
1327 /* now we have the status in the cache entry, and everything is locked.
1328 * Marshall the output data.
1331 if (infoLevel == 0x101) {
1332 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1333 *((FILETIME *)op) = ft; op += 8; /* creation time */
1334 *((FILETIME *)op) = ft; op += 8; /* last access time */
1335 *((FILETIME *)op) = ft; op += 8; /* last write time */
1336 *((FILETIME *)op) = ft; op += 8; /* last change time */
1337 attributes = smb_ExtAttributes(scp);
1338 *((u_long *)op) = attributes; op += 4;
1339 *((u_long *)op) = 0; op += 4;
1341 else if (infoLevel == 0x102) {
1342 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1343 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1344 *((u_long *)op) = scp->linkCount; op += 4;
1345 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1347 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1350 else if (infoLevel == 0x103) {
1351 *((u_long *)op) = 0; op += 4;
1353 else if (infoLevel == 0x104) {
1357 if (fidp->NTopen_wholepathp)
1358 name = fidp->NTopen_wholepathp;
1360 name = "\\"; /* probably can't happen */
1362 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1363 *((u_long *)op) = len * 2; op += 4;
1364 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1367 /* send and free the packets */
1369 lock_ReleaseMutex(&scp->mx);
1370 cm_ReleaseUser(userp);
1371 smb_ReleaseFID(fidp);
1372 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1373 else smb_SendTran2Error(vcp, p, opx, code);
1374 smb_FreeTran2Packet(outp);
1379 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1384 unsigned short infoLevel;
1385 smb_tran2Packet_t *outp;
1393 fidp = smb_FindFID(vcp, fid, 0);
1396 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1400 infoLevel = p->parmsp[1];
1401 if (infoLevel > 0x104 || infoLevel < 0x101) {
1402 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1403 p->opcode, infoLevel);
1404 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1408 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1409 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1412 if ((infoLevel == 0x103 || infoLevel == 0x104)
1413 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1414 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1418 osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1420 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1422 outp->totalParms = 2;
1423 outp->totalData = 0;
1425 userp = smb_GetTran2User(vcp, p);
1429 if (infoLevel == 0x101) {
1431 unsigned int attribute;
1434 /* lock the vnode with a callback; we need the current status
1435 * to determine what the new status is, in some cases.
1437 lock_ObtainMutex(&scp->mx);
1438 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1439 CM_SCACHESYNC_GETSTATUS
1440 | CM_SCACHESYNC_NEEDCALLBACK);
1442 lock_ReleaseMutex(&scp->mx);
1446 /* prepare for setattr call */
1448 lastMod = *((FILETIME *)(p->datap + 16));
1449 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod))) {
1450 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1451 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1453 fidp->flags |= SMB_FID_MTIMESETDONE;
1455 attribute = *((u_long *)(p->datap + 32));
1456 if (attribute != 0) {
1457 if ((scp->unixModeBits & 0222)
1458 && (attribute & 1) != 0) {
1459 /* make a writable file read-only */
1460 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1461 attr.unixModeBits = scp->unixModeBits & ~0222;
1463 else if ((scp->unixModeBits & 0222) == 0
1464 && (attribute & 1) == 0) {
1465 /* make a read-only file writable */
1466 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1467 attr.unixModeBits = scp->unixModeBits | 0222;
1470 lock_ReleaseMutex(&scp->mx);
1474 code = cm_SetAttr(scp, &attr, userp, &req);
1478 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1479 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1482 attr.mask = CM_ATTRMASK_LENGTH;
1483 attr.length.LowPart = size.LowPart;
1484 attr.length.HighPart = size.HighPart;
1485 code = cm_SetAttr(scp, &attr, userp, &req);
1487 else if (infoLevel == 0x102) {
1488 if (*((char *)(p->datap))) {
1489 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1492 fidp->flags |= SMB_FID_DELONCLOSE;
1496 fidp->flags &= ~SMB_FID_DELONCLOSE;
1500 cm_ReleaseUser(userp);
1501 smb_ReleaseFID(fidp);
1502 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1503 else smb_SendTran2Error(vcp, p, op, code);
1504 smb_FreeTran2Packet(outp);
1509 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1511 return CM_ERROR_BADOP;
1514 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1516 return CM_ERROR_BADOP;
1519 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1521 return CM_ERROR_BADOP;
1524 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1526 return CM_ERROR_BADOP;
1529 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1531 return CM_ERROR_BADOP;
1534 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1535 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1540 cm_scache_t *targetScp; /* target if scp is a symlink */
1545 unsigned short attr;
1546 unsigned long lattr;
1547 smb_dirListPatch_t *patchp;
1548 smb_dirListPatch_t *npatchp;
1550 for(patchp = *dirPatchespp; patchp; patchp =
1551 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1552 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1554 lock_ObtainMutex(&scp->mx);
1555 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1556 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1558 lock_ReleaseMutex(&scp->mx);
1559 cm_ReleaseSCache(scp);
1563 /* now watch for a symlink */
1564 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1565 lock_ReleaseMutex(&scp->mx);
1566 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1569 /* we have a more accurate file to use (the
1570 * target of the symbolic link). Otherwise,
1571 * we'll just use the symlink anyway.
1573 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1575 cm_ReleaseSCache(scp);
1578 lock_ObtainMutex(&scp->mx);
1581 dptr = patchp->dptr;
1583 if (infoLevel >= 0x101) {
1585 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1587 /* copy to Creation Time */
1588 *((FILETIME *)dptr) = ft;
1591 /* copy to Last Access Time */
1592 *((FILETIME *)dptr) = ft;
1595 /* copy to Last Write Time */
1596 *((FILETIME *)dptr) = ft;
1599 /* copy to Change Time */
1600 *((FILETIME *)dptr) = ft;
1603 /* Use length for both file length and alloc length */
1604 *((LARGE_INTEGER *)dptr) = scp->length;
1606 *((LARGE_INTEGER *)dptr) = scp->length;
1609 /* Copy attributes */
1610 lattr = smb_ExtAttributes(scp);
1611 *((u_long *)dptr) = lattr;
1616 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1618 /* and copy out date */
1619 shortTemp = (dosTime>>16) & 0xffff;
1620 *((u_short *)dptr) = shortTemp;
1623 /* copy out creation time */
1624 shortTemp = dosTime & 0xffff;
1625 *((u_short *)dptr) = shortTemp;
1628 /* and copy out date */
1629 shortTemp = (dosTime>>16) & 0xffff;
1630 *((u_short *)dptr) = shortTemp;
1633 /* copy out access time */
1634 shortTemp = dosTime & 0xffff;
1635 *((u_short *)dptr) = shortTemp;
1638 /* and copy out date */
1639 shortTemp = (dosTime>>16) & 0xffff;
1640 *((u_short *)dptr) = shortTemp;
1643 /* copy out mod time */
1644 shortTemp = dosTime & 0xffff;
1645 *((u_short *)dptr) = shortTemp;
1648 /* copy out file length and alloc length,
1649 * using the same for both
1651 *((u_long *)dptr) = scp->length.LowPart;
1653 *((u_long *)dptr) = scp->length.LowPart;
1656 /* finally copy out attributes as short */
1657 attr = smb_Attributes(scp);
1658 *dptr++ = attr & 0xff;
1659 *dptr++ = (attr >> 8) & 0xff;
1662 lock_ReleaseMutex(&scp->mx);
1663 cm_ReleaseSCache(scp);
1666 /* now free the patches */
1667 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1668 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1672 /* and mark the list as empty */
1673 *dirPatchespp = NULL;
1678 /* do a case-folding search of the star name mask with the name in namep.
1679 * Return 1 if we match, otherwise 0.
1681 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1683 unsigned char tcp1, tcp2; /* Pattern characters */
1684 unsigned char tcn1; /* Name characters */
1685 int sawDot = 0, sawStar = 0;
1686 char *starNamep, *starMaskp;
1687 static char nullCharp[] = {0};
1689 /* make sure we only match 8.3 names, if requested */
1690 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1694 /* Next pattern character */
1697 /* Next name character */
1701 /* 0 - end of pattern */
1707 else if (tcp1 == '.' || tcp1 == '"') {
1717 * first dot in pattern;
1718 * must match dot or end of name
1723 else if (tcn1 == '.') {
1732 else if (tcp1 == '?') {
1733 if (tcn1 == 0 || tcn1 == '.')
1738 else if (tcp1 == '>') {
1739 if (tcn1 != 0 && tcn1 != '.')
1743 else if (tcp1 == '*' || tcp1 == '<') {
1747 else if (tcp2 == '.' || tcp2 == '"') {
1748 while (tcn1 != '.' && tcn1 != 0)
1763 * pattern character after '*' is not null or
1764 * period. If it is '?' or '>', we are not
1765 * going to understand it. If it is '*' or
1766 * '<', we are going to skip over it. None of
1767 * these are likely, I hope.
1769 /* skip over '*' and '<' */
1770 while (tcp2 == '*' || tcp2 == '<')
1773 /* skip over characters that don't match tcp2 */
1774 while (tcn1 != '.' && tcn1 != 0
1775 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1779 if (tcn1 == '.' || tcn1 == 0)
1782 /* Remember where we are */
1792 /* tcp1 is not a wildcard */
1793 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1798 /* if trying to match a star pattern, go back */
1800 maskp = starMaskp - 2;
1801 namep = starNamep + 1;
1811 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1820 smb_dirListPatch_t *dirListPatchesp;
1821 smb_dirListPatch_t *curPatchp;
1824 long orbytes; /* # of bytes in this output record */
1825 long ohbytes; /* # of bytes, except file name */
1826 long onbytes; /* # of bytes in name, incl. term. null */
1827 osi_hyper_t dirLength;
1828 osi_hyper_t bufferOffset;
1829 osi_hyper_t curOffset;
1831 smb_dirSearch_t *dsp;
1835 cm_pageHeader_t *pageHeaderp;
1836 cm_user_t *userp = NULL;
1839 long nextEntryCookie;
1840 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1841 char *op; /* output data ptr */
1842 char *origOp; /* original value of op */
1843 cm_space_t *spacep; /* for pathname buffer */
1844 long maxReturnData; /* max # of return data */
1845 long maxReturnParms; /* max # of return parms */
1846 long bytesInBuffer; /* # data bytes in the output buffer */
1848 char *maskp; /* mask part of path */
1852 smb_tran2Packet_t *outp; /* response packet */
1855 char shortName[13]; /* 8.3 name if needed */
1866 if (p->opcode == 1) {
1867 /* find first; obtain basic parameters from request */
1868 attribute = p->parmsp[0];
1869 maxCount = p->parmsp[1];
1870 infoLevel = p->parmsp[3];
1871 searchFlags = p->parmsp[2];
1872 dsp = smb_NewDirSearch(1);
1873 dsp->attribute = attribute;
1874 pathp = ((char *) p->parmsp) + 12; /* points to path */
1876 maskp = strrchr(pathp, '\\');
1877 if (maskp == NULL) maskp = pathp;
1878 else maskp++; /* skip over backslash */
1879 strcpy(dsp->mask, maskp); /* and save mask */
1880 /* track if this is likely to match a lot of entries */
1881 starPattern = smb_V3IsStarMask(maskp);
1884 osi_assert(p->opcode == 2);
1885 /* find next; obtain basic parameters from request or open dir file */
1886 dsp = smb_FindDirSearch(p->parmsp[0]);
1887 if (!dsp) return CM_ERROR_BADFD;
1888 attribute = dsp->attribute;
1889 maxCount = p->parmsp[1];
1890 infoLevel = p->parmsp[2];
1891 searchFlags = p->parmsp[5];
1893 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1895 starPattern = 1; /* assume, since required a Find Next */
1899 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1900 attribute, infoLevel, maxCount, searchFlags);
1902 osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1903 p->opcode, nextCookie);
1905 if (infoLevel >= 0x101)
1906 searchFlags &= ~4; /* no resume keys */
1908 dirListPatchesp = NULL;
1910 maxReturnData = p->maxReturnData;
1911 if (p->opcode == 1) /* find first */
1912 maxReturnParms = 10; /* bytes */
1914 maxReturnParms = 8; /* bytes */
1916 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1917 if (maxReturnData > 6000) maxReturnData = 6000;
1918 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1920 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1923 osi_Log1(afsd_logp, "T2 receive search dir %s",
1924 osi_LogSaveString(afsd_logp, pathp));
1926 /* bail out if request looks bad */
1927 if (p->opcode == 1 && !pathp) {
1928 return CM_ERROR_BADSMB;
1931 osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1932 nextCookie, dsp->cookie);
1934 userp = smb_GetTran2User(vcp, p);
1936 /* try to get the vnode for the path name next */
1937 lock_ObtainMutex(&dsp->mx);
1944 spacep = cm_GetSpace();
1945 smb_StripLastComponent(spacep->data, NULL, pathp);
1946 lock_ReleaseMutex(&dsp->mx);
1948 tidPathp = smb_GetTIDPath(vcp, p->tid);
1949 code = cm_NameI(cm_rootSCachep, spacep->data,
1950 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1951 userp, tidPathp, &req, &scp);
1952 cm_FreeSpace(spacep);
1954 lock_ObtainMutex(&dsp->mx);
1956 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
1958 /* we need one hold for the entry we just stored into,
1959 * and one for our own processing. When we're done
1960 * with this function, we'll drop the one for our own
1961 * processing. We held it once from the namei call,
1962 * and so we do another hold now.
1965 lock_ObtainMutex(&scp->mx);
1966 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
1967 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
1968 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
1969 dsp->flags |= SMB_DIRSEARCH_BULKST;
1971 lock_ReleaseMutex(&scp->mx);
1974 lock_ReleaseMutex(&dsp->mx);
1976 cm_ReleaseUser(userp);
1977 smb_FreeTran2Packet(outp);
1978 smb_DeleteDirSearch(dsp);
1979 smb_ReleaseDirSearch(dsp);
1983 /* get the directory size */
1984 lock_ObtainMutex(&scp->mx);
1985 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1986 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1988 lock_ReleaseMutex(&scp->mx);
1989 cm_ReleaseSCache(scp);
1990 cm_ReleaseUser(userp);
1991 smb_FreeTran2Packet(outp);
1992 smb_DeleteDirSearch(dsp);
1993 smb_ReleaseDirSearch(dsp);
1997 dirLength = scp->length;
1999 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2000 curOffset.HighPart = 0;
2001 curOffset.LowPart = nextCookie;
2002 origOp = outp->datap;
2009 if (searchFlags & 4)
2010 /* skip over resume key */
2013 /* make sure that curOffset.LowPart doesn't point to the first
2014 * 32 bytes in the 2nd through last dir page, and that it doesn't
2015 * point at the first 13 32-byte chunks in the first dir page,
2016 * since those are dir and page headers, and don't contain useful
2019 temp = curOffset.LowPart & (2048-1);
2020 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2021 /* we're in the first page */
2022 if (temp < 13*32) temp = 13*32;
2025 /* we're in a later dir page */
2026 if (temp < 32) temp = 32;
2029 /* make sure the low order 5 bits are zero */
2032 /* now put temp bits back ito curOffset.LowPart */
2033 curOffset.LowPart &= ~(2048-1);
2034 curOffset.LowPart |= temp;
2036 /* check if we've returned all the names that will fit in the
2037 * response packet; we check return count as well as the number
2038 * of bytes requested. We check the # of bytes after we find
2039 * the dir entry, since we'll need to check its size.
2041 if (returnedNames >= maxCount) break;
2043 /* check if we've passed the dir's EOF */
2044 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2049 /* see if we can use the bufferp we have now; compute in which
2050 * page the current offset would be, and check whether that's
2051 * the offset of the buffer we have. If not, get the buffer.
2053 thyper.HighPart = curOffset.HighPart;
2054 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2055 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2058 buf_Release(bufferp);
2061 lock_ReleaseMutex(&scp->mx);
2062 lock_ObtainRead(&scp->bufCreateLock);
2063 code = buf_Get(scp, &thyper, &bufferp);
2064 lock_ReleaseRead(&scp->bufCreateLock);
2066 /* now, if we're doing a star match, do bulk fetching
2067 * of all of the status info for files in the dir.
2070 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2073 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2074 && LargeIntegerGreaterThanOrEqualTo(
2075 thyper, scp->bulkStatProgress)) {
2076 /* Don't bulk stat if risking timeout */
2077 int now = GetCurrentTime();
2078 if (now - req.startTime > 5000) {
2079 scp->bulkStatProgress = thyper;
2080 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2081 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2083 cm_TryBulkStat(scp, &thyper,
2088 lock_ObtainMutex(&scp->mx);
2090 bufferOffset = thyper;
2092 /* now get the data in the cache */
2094 code = cm_SyncOp(scp, bufferp, userp, &req,
2096 CM_SCACHESYNC_NEEDCALLBACK
2097 | CM_SCACHESYNC_READ);
2100 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2102 /* otherwise, load the buffer and try again */
2103 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2108 buf_Release(bufferp);
2112 } /* if (wrong buffer) ... */
2114 /* now we have the buffer containing the entry we're interested
2115 * in; copy it out if it represents a non-deleted entry.
2117 entryInDir = curOffset.LowPart & (2048-1);
2118 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2120 /* page header will help tell us which entries are free. Page
2121 * header can change more often than once per buffer, since
2122 * AFS 3 dir page size may be less than (but not more than)
2123 * a buffer package buffer.
2125 /* only look intra-buffer */
2126 temp = curOffset.LowPart & (buf_bufferSize - 1);
2127 temp &= ~(2048 - 1); /* turn off intra-page bits */
2128 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2130 /* now determine which entry we're looking at in the page.
2131 * If it is free (there's a free bitmap at the start of the
2132 * dir), we should skip these 32 bytes.
2134 slotInPage = (entryInDir & 0x7e0) >> 5;
2135 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2136 & (1 << (slotInPage & 0x7)))) {
2137 /* this entry is free */
2138 numDirChunks = 1; /* only skip this guy */
2142 tp = bufferp->datap + entryInBuffer;
2143 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2145 /* while we're here, compute the next entry's location, too,
2146 * since we'll need it when writing out the cookie into the dir
2149 * XXXX Probably should do more sanity checking.
2151 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2153 /* compute offset of cookie representing next entry */
2154 nextEntryCookie = curOffset.LowPart
2155 + (CM_DIR_CHUNKSIZE * numDirChunks);
2157 /* Need 8.3 name? */
2159 if (infoLevel == 0x104
2160 && dep->fid.vnode != 0
2161 && !cm_Is8Dot3(dep->name)) {
2162 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2166 if (dep->fid.vnode != 0
2167 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2169 && smb_V3MatchMask(shortName, maskp,
2170 CM_FLAG_CASEFOLD)))) {
2172 /* Eliminate entries that don't match requested
2174 if (!(dsp->attribute & 0x10)) /* no directories */
2176 /* We have already done the cm_TryBulkStat above */
2177 fid.cell = scp->fid.cell;
2178 fid.volume = scp->fid.volume;
2179 fid.vnode = ntohl(dep->fid.vnode);
2180 fid.unique = ntohl(dep->fid.unique);
2181 fileType = cm_FindFileType(&fid);
2182 /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2183 "has filetype %d", dep->name,
2185 if (fileType == CM_SCACHETYPE_DIRECTORY)
2189 /* finally check if this name will fit */
2191 /* standard dir entry stuff */
2192 if (infoLevel < 0x101)
2193 ohbytes = 23; /* pre-NT */
2194 else if (infoLevel == 0x103)
2195 ohbytes = 12; /* NT names only */
2197 ohbytes = 64; /* NT */
2199 if (infoLevel == 0x104)
2200 ohbytes += 26; /* Short name & length */
2202 if (searchFlags & 4) {
2203 ohbytes += 4; /* if resume key required */
2207 && infoLevel != 0x101
2208 && infoLevel != 0x103)
2209 ohbytes += 4; /* EASIZE */
2211 /* add header to name & term. null */
2212 orbytes = onbytes + ohbytes + 1;
2214 /* now, we round up the record to a 4 byte alignment,
2215 * and we make sure that we have enough room here for
2216 * even the aligned version (so we don't have to worry
2217 * about an * overflow when we pad things out below).
2218 * That's the reason for the alignment arithmetic below.
2220 if (infoLevel >= 0x101)
2221 align = (4 - (orbytes & 3)) & 3;
2224 if (orbytes + bytesInBuffer + align > maxReturnData)
2227 /* this is one of the entries to use: it is not deleted
2228 * and it matches the star pattern we're looking for.
2229 * Put out the name, preceded by its length.
2231 /* First zero everything else */
2232 memset(origOp, 0, ohbytes);
2234 if (infoLevel <= 0x101)
2235 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2236 else if (infoLevel == 0x103)
2237 *((u_long *)(op + 8)) = onbytes;
2239 *((u_long *)(op + 60)) = onbytes;
2240 strcpy(origOp+ohbytes, dep->name);
2242 /* Short name if requested and needed */
2243 if (infoLevel == 0x104) {
2244 if (NeedShortName) {
2245 strcpy(op + 70, shortName);
2246 *(op + 68) = shortNameEnd - shortName;
2250 /* now, adjust the # of entries copied */
2253 /* NextEntryOffset and FileIndex */
2254 if (infoLevel >= 101) {
2255 int entryOffset = orbytes + align;
2256 *((u_long *)op) = entryOffset;
2257 *((u_long *)(op+4)) = nextEntryCookie;
2260 /* now we emit the attribute. This is tricky, since
2261 * we need to really stat the file to find out what
2262 * type of entry we've got. Right now, we're copying
2263 * out data from * a buffer, while holding the scp
2264 * locked, so it isn't really convenient to stat
2265 * something now. We'll put in a place holder
2266 * now, and make a second pass before returning this
2267 * to get the real attributes. So, we just skip the
2268 * data for now, and adjust it later. We allocate a
2269 * patch record to make it easy to find this point
2270 * later. The replay will happen at a time when it is
2271 * safe to unlock the directory.
2273 if (infoLevel != 0x103) {
2274 curPatchp = malloc(sizeof(*curPatchp));
2275 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2277 curPatchp->dptr = op;
2278 if (infoLevel >= 0x101)
2279 curPatchp->dptr += 8;
2280 curPatchp->fid.cell = scp->fid.cell;
2281 curPatchp->fid.volume = scp->fid.volume;
2282 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2283 curPatchp->fid.unique = ntohl(dep->fid.unique);
2286 curPatchp->dep = dep;
2289 if (searchFlags & 4)
2290 /* put out resume key */
2291 *((u_long *)origOp) = nextEntryCookie;
2293 /* Adjust byte ptr and count */
2294 origOp += orbytes; /* skip entire record */
2295 bytesInBuffer += orbytes;
2297 /* and pad the record out */
2298 while (--align >= 0) {
2303 } /* if we're including this name */
2306 /* and adjust curOffset to be where the new cookie is */
2307 thyper.HighPart = 0;
2308 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2309 curOffset = LargeIntegerAdd(thyper, curOffset);
2310 } /* while copying data for dir listing */
2312 /* release the mutex */
2313 lock_ReleaseMutex(&scp->mx);
2314 if (bufferp) buf_Release(bufferp);
2316 /* apply and free last set of patches; if not doing a star match, this
2317 * will be empty, but better safe (and freeing everything) than sorry.
2319 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2322 /* now put out the final parameters */
2323 if (returnedNames == 0) eos = 1;
2324 if (p->opcode == 1) {
2326 outp->parmsp[0] = (unsigned short) dsp->cookie;
2327 outp->parmsp[1] = returnedNames;
2328 outp->parmsp[2] = eos;
2329 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2330 outp->parmsp[4] = 0; /* don't need last name to continue
2331 * search, cookie is enough. Normally,
2332 * this is the offset of the file name
2333 * of the last entry returned.
2335 outp->totalParms = 10; /* in bytes */
2339 outp->parmsp[0] = returnedNames;
2340 outp->parmsp[1] = eos;
2341 outp->parmsp[2] = 0; /* EAS error */
2342 outp->parmsp[3] = 0; /* last name, as above */
2343 outp->totalParms = 8; /* in bytes */
2346 /* return # of bytes in the buffer */
2347 outp->totalData = bytesInBuffer;
2349 osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2350 returnedNames, code);
2352 /* Return error code if unsuccessful on first request */
2353 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2354 code = CM_ERROR_NOSUCHFILE;
2356 /* if we're supposed to close the search after this request, or if
2357 * we're supposed to close the search if we're done, and we're done,
2358 * or if something went wrong, close the search.
2360 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2361 if ((searchFlags & 1) || (returnedNames == 0)
2362 || code != 0) smb_DeleteDirSearch(dsp);
2364 smb_SendTran2Error(vcp, p, opx, code);
2366 smb_SendTran2Packet(vcp, outp, opx);
2368 smb_FreeTran2Packet(outp);
2369 smb_ReleaseDirSearch(dsp);
2370 cm_ReleaseSCache(scp);
2371 cm_ReleaseUser(userp);
2375 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2378 smb_dirSearch_t *dsp;
2380 dirHandle = smb_GetSMBParm(inp, 0);
2382 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2384 dsp = smb_FindDirSearch(dirHandle);
2387 return CM_ERROR_BADFD;
2389 /* otherwise, we have an FD to destroy */
2390 smb_DeleteDirSearch(dsp);
2391 smb_ReleaseDirSearch(dsp);
2393 /* and return results */
2394 smb_SetSMBDataLength(outp, 0);
2399 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2401 smb_SetSMBDataLength(outp, 0);
2405 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2412 cm_scache_t *dscp; /* dir we're dealing with */
2413 cm_scache_t *scp; /* file we're creating */
2415 int initialModeBits;
2425 int parmSlot; /* which parm we're dealing with */
2433 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2434 openFun = smb_GetSMBParm(inp, 8); /* open function */
2435 excl = ((openFun & 3) == 0);
2436 trunc = ((openFun & 3) == 2); /* truncate it */
2437 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2438 openAction = 0; /* tracks what we did */
2440 attributes = smb_GetSMBParm(inp, 5);
2441 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2443 /* compute initial mode bits based on read-only flag in attributes */
2444 initialModeBits = 0666;
2445 if (attributes & 1) initialModeBits &= ~0222;
2447 pathp = smb_GetSMBData(inp, NULL);
2449 spacep = inp->spacep;
2450 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2452 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2453 /* special case magic file name for receiving IOCTL requests
2454 * (since IOCTL calls themselves aren't getting through).
2456 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2457 smb_SetupIoctlFid(fidp, spacep);
2459 /* set inp->fid so that later read calls in same msg can find fid */
2460 inp->fid = fidp->fid;
2462 /* copy out remainder of the parms */
2464 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2466 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2467 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2468 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2469 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2470 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2471 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2472 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2473 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2475 /* and the final "always present" stuff */
2476 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2477 /* next write out the "unique" ID */
2478 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2479 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2480 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2481 smb_SetSMBDataLength(outp, 0);
2483 /* and clean up fid reference */
2484 smb_ReleaseFID(fidp);
2488 userp = smb_GetUser(vcp, inp);
2491 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2492 code = cm_NameI(cm_rootSCachep, pathp,
2493 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2494 userp, tidPathp, &req, &scp);
2496 code = cm_NameI(cm_rootSCachep, spacep->data,
2497 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2498 userp, tidPathp, &req, &dscp);
2501 cm_ReleaseUser(userp);
2505 /* otherwise, scp points to the parent directory. Do a lookup,
2506 * and truncate the file if we find it, otherwise we create the
2509 if (!lastNamep) lastNamep = pathp;
2511 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2513 if (code && code != CM_ERROR_NOSUCHFILE) {
2514 cm_ReleaseSCache(dscp);
2515 cm_ReleaseUser(userp);
2520 /* if we get here, if code is 0, the file exists and is represented by
2521 * scp. Otherwise, we have to create it. The dir may be represented
2522 * by dscp, or we may have found the file directly. If code is non-zero,
2526 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2528 if (dscp) cm_ReleaseSCache(dscp);
2529 cm_ReleaseSCache(scp);
2530 cm_ReleaseUser(userp);
2535 /* oops, file shouldn't be there */
2536 if (dscp) cm_ReleaseSCache(dscp);
2537 cm_ReleaseSCache(scp);
2538 cm_ReleaseUser(userp);
2539 return CM_ERROR_EXISTS;
2543 setAttr.mask = CM_ATTRMASK_LENGTH;
2544 setAttr.length.LowPart = 0;
2545 setAttr.length.HighPart = 0;
2546 code = cm_SetAttr(scp, &setAttr, userp, &req);
2547 openAction = 3; /* truncated existing file */
2549 else openAction = 1; /* found existing file */
2551 else if (!(openFun & 0x10)) {
2552 /* don't create if not found */
2553 if (dscp) cm_ReleaseSCache(dscp);
2554 cm_ReleaseUser(userp);
2555 return CM_ERROR_NOSUCHFILE;
2558 osi_assert(dscp != NULL);
2559 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2560 osi_LogSaveString(afsd_logp, lastNamep));
2561 openAction = 2; /* created file */
2562 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2563 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2564 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2566 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2567 smb_NotifyChange(FILE_ACTION_ADDED,
2568 FILE_NOTIFY_CHANGE_FILE_NAME,
2569 dscp, lastNamep, NULL, TRUE);
2570 if (!excl && code == CM_ERROR_EXISTS) {
2571 /* not an exclusive create, and someone else tried
2572 * creating it already, then we open it anyway. We
2573 * don't bother retrying after this, since if this next
2574 * fails, that means that the file was deleted after we
2575 * started this call.
2577 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2581 setAttr.mask = CM_ATTRMASK_LENGTH;
2582 setAttr.length.LowPart = 0;
2583 setAttr.length.HighPart = 0;
2584 code = cm_SetAttr(scp, &setAttr, userp,
2587 } /* lookup succeeded */
2591 /* we don't need this any longer */
2592 if (dscp) cm_ReleaseSCache(dscp);
2595 /* something went wrong creating or truncating the file */
2596 if (scp) cm_ReleaseSCache(scp);
2597 cm_ReleaseUser(userp);
2601 /* make sure we're about to open a file */
2602 if (scp->fileType != CM_SCACHETYPE_FILE) {
2603 cm_ReleaseSCache(scp);
2604 cm_ReleaseUser(userp);
2605 return CM_ERROR_ISDIR;
2608 /* now all we have to do is open the file itself */
2609 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2612 /* save a pointer to the vnode */
2615 /* compute open mode */
2616 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2617 if (openMode == 1 || openMode == 2)
2618 fidp->flags |= SMB_FID_OPENWRITE;
2620 smb_ReleaseFID(fidp);
2622 cm_Open(scp, 0, userp);
2624 /* set inp->fid so that later read calls in same msg can find fid */
2625 inp->fid = fidp->fid;
2627 /* copy out remainder of the parms */
2629 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2630 lock_ObtainMutex(&scp->mx);
2632 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2633 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2634 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2635 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2636 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2637 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2638 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2639 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2640 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2642 /* and the final "always present" stuff */
2643 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2644 /* next write out the "unique" ID */
2645 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2646 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2647 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2648 lock_ReleaseMutex(&scp->mx);
2649 smb_SetSMBDataLength(outp, 0);
2651 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2653 cm_ReleaseUser(userp);
2654 /* leave scp held since we put it in fidp->scp */
2658 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2665 unsigned char LockType;
2666 unsigned short NumberOfUnlocks, NumberOfLocks;
2667 unsigned long Timeout;
2669 LARGE_INTEGER LOffset, LLength;
2670 smb_waitingLock_t *waitingLock;
2677 fid = smb_GetSMBParm(inp, 2);
2678 fid = smb_ChainFID(fid, inp);
2680 fidp = smb_FindFID(vcp, fid, 0);
2681 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2682 return CM_ERROR_BADFD;
2684 /* set inp->fid so that later read calls in same msg can find fid */
2687 userp = smb_GetUser(vcp, inp);
2691 lock_ObtainMutex(&scp->mx);
2692 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2693 CM_SCACHESYNC_NEEDCALLBACK
2694 | CM_SCACHESYNC_GETSTATUS
2695 | CM_SCACHESYNC_LOCK);
2696 if (code) goto doneSync;
2698 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2699 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2700 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2701 NumberOfLocks = smb_GetSMBParm(inp, 7);
2703 op = smb_GetSMBData(inp, NULL);
2705 for (i=0; i<NumberOfUnlocks; i++) {
2706 if (LockType & 0x10) {
2708 LOffset.HighPart = *((LONG *)(op + 4));
2709 LOffset.LowPart = *((DWORD *)(op + 8));
2710 LLength.HighPart = *((LONG *)(op + 12));
2711 LLength.LowPart = *((DWORD *)(op + 16));
2715 /* Not Large Files */
2716 LOffset.HighPart = 0;
2717 LOffset.LowPart = *((DWORD *)(op + 2));
2718 LLength.HighPart = 0;
2719 LLength.LowPart = *((DWORD *)(op + 6));
2722 if (LargeIntegerNotEqualToZero(LOffset))
2724 /* Do not check length -- length check done in cm_Unlock */
2726 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2727 if (code) goto done;
2730 for (i=0; i<NumberOfLocks; i++) {
2731 if (LockType & 0x10) {
2733 LOffset.HighPart = *((LONG *)(op + 4));
2734 LOffset.LowPart = *((DWORD *)(op + 8));
2735 LLength.HighPart = *((LONG *)(op + 12));
2736 LLength.LowPart = *((DWORD *)(op + 16));
2740 /* Not Large Files */
2741 LOffset.HighPart = 0;
2742 LOffset.LowPart = *((DWORD *)(op + 2));
2743 LLength.HighPart = 0;
2744 LLength.LowPart = *((DWORD *)(op + 6));
2747 if (LargeIntegerNotEqualToZero(LOffset))
2749 if (LargeIntegerLessThan(LOffset, scp->length))
2752 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2753 userp, &req, &lockp);
2754 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2755 /* Put on waiting list */
2756 waitingLock = malloc(sizeof(smb_waitingLock_t));
2757 waitingLock->vcp = vcp;
2758 waitingLock->inp = smb_CopyPacket(inp);
2759 waitingLock->outp = smb_CopyPacket(outp);
2760 waitingLock->timeRemaining = Timeout;
2761 waitingLock->lockp = lockp;
2762 lock_ObtainWrite(&smb_globalLock);
2763 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2765 osi_Wakeup((long) &smb_allWaitingLocks);
2766 lock_ReleaseWrite(&smb_globalLock);
2767 /* don't send reply immediately */
2768 outp->flags |= SMB_PACKETFLAG_NOSEND;
2774 /* release any locks acquired before the failure */
2777 smb_SetSMBDataLength(outp, 0);
2779 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2781 lock_ReleaseMutex(&scp->mx);
2782 cm_ReleaseUser(userp);
2783 smb_ReleaseFID(fidp);
2788 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2800 fid = smb_GetSMBParm(inp, 0);
2801 fid = smb_ChainFID(fid, inp);
2803 fidp = smb_FindFID(vcp, fid, 0);
2804 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2805 return CM_ERROR_BADFD;
2808 userp = smb_GetUser(vcp, inp);
2812 /* otherwise, stat the file */
2813 lock_ObtainMutex(&scp->mx);
2814 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2815 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2816 if (code) goto done;
2818 /* decode times. We need a search time, but the response to this
2819 * call provides the date first, not the time, as returned in the
2820 * searchTime variable. So we take the high-order bits first.
2822 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2823 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2824 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2825 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2826 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2827 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2828 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2830 /* now handle file size and allocation size */
2831 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2832 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2833 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2834 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2836 /* file attribute */
2837 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2839 /* and finalize stuff */
2840 smb_SetSMBDataLength(outp, 0);
2844 lock_ReleaseMutex(&scp->mx);
2845 cm_ReleaseUser(userp);
2846 smb_ReleaseFID(fidp);
2850 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2864 fid = smb_GetSMBParm(inp, 0);
2865 fid = smb_ChainFID(fid, inp);
2867 fidp = smb_FindFID(vcp, fid, 0);
2868 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2869 return CM_ERROR_BADFD;
2872 userp = smb_GetUser(vcp, inp);
2876 /* now prepare to call cm_setattr. This message only sets various times,
2877 * and AFS only implements mtime, and we'll set the mtime if that's
2878 * requested. The others we'll ignore.
2880 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2882 if (searchTime != 0) {
2883 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2884 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2885 attrs.clientModTime = unixTime;
2886 code = cm_SetAttr(scp, &attrs, userp, &req);
2890 cm_ReleaseUser(userp);
2891 smb_ReleaseFID(fidp);
2896 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2899 long count, finalCount;
2906 fd = smb_GetSMBParm(inp, 2);
2907 count = smb_GetSMBParm(inp, 5);
2908 offset.HighPart = 0; /* too bad */
2909 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
2911 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
2912 fd, offset.LowPart, count);
2914 fd = smb_ChainFID(fd, inp);
2915 fidp = smb_FindFID(vcp, fd, 0);
2917 return CM_ERROR_BADFD;
2919 /* set inp->fid so that later read calls in same msg can find fid */
2922 if (fidp->flags & SMB_FID_IOCTL) {
2923 return smb_IoctlV3Read(fidp, vcp, inp, outp);
2926 userp = smb_GetUser(vcp, inp);
2928 /* 0 and 1 are reserved for request chaining, were setup by our caller,
2929 * and will be further filled in after we return.
2931 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
2932 smb_SetSMBParm(outp, 3, 0); /* resvd */
2933 smb_SetSMBParm(outp, 4, 0); /* resvd */
2934 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
2935 /* fill in #6 when we have all the parameters' space reserved */
2936 smb_SetSMBParm(outp, 7, 0); /* resv'd */
2937 smb_SetSMBParm(outp, 8, 0); /* resv'd */
2938 smb_SetSMBParm(outp, 9, 0); /* resv'd */
2939 smb_SetSMBParm(outp, 10, 0); /* resv'd */
2940 smb_SetSMBParm(outp, 11, 0); /* reserved */
2942 /* get op ptr after putting in the parms, since otherwise we don't
2943 * know where the data really is.
2945 op = smb_GetSMBData(outp, NULL);
2947 /* now fill in offset from start of SMB header to first data byte (to op) */
2948 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
2950 /* set the packet data length the count of the # of bytes */
2951 smb_SetSMBDataLength(outp, count);
2954 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
2956 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
2959 /* fix some things up */
2960 smb_SetSMBParm(outp, 5, finalCount);
2961 smb_SetSMBDataLength(outp, finalCount);
2963 smb_ReleaseFID(fidp);
2965 cm_ReleaseUser(userp);
2970 * Values for createDisp, copied from NTDDK.H
2972 * FILE_SUPERSEDE 0 (???)
2973 * FILE_OPEN 1 (open)
2974 * FILE_CREATE 2 (exclusive)
2975 * FILE_OPEN_IF 3 (non-exclusive)
2976 * FILE_OVERWRITE 4 (open & truncate, but do not create)
2977 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
2980 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2982 char *pathp, *realPathp;
2986 cm_scache_t *dscp; /* parent dir */
2987 cm_scache_t *scp; /* file to create or open */
2990 unsigned short nameLength;
2992 unsigned int requestOpLock;
2993 unsigned int requestBatchOpLock;
2994 unsigned int mustBeDir;
2996 unsigned int desiredAccess;
2997 unsigned int extAttributes;
2998 unsigned int createDisp;
2999 unsigned int createOptions;
3000 int initialModeBits;
3001 unsigned short baseFid;
3002 smb_fid_t *baseFidp;
3004 cm_scache_t *baseDirp;
3005 unsigned short openAction;
3019 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3020 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3021 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3022 requestOpLock = flags & 0x02;
3023 requestBatchOpLock = flags & 0x04;
3024 mustBeDir = flags & 0x08;
3027 * Why all of a sudden 32-bit FID?
3028 * We will reject all bits higher than 16.
3030 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3031 return CM_ERROR_INVAL;
3032 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3033 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3034 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3035 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3036 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3037 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3038 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3039 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3040 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3042 /* mustBeDir is never set; createOptions directory bit seems to be
3045 if (createOptions & 1)
3047 else if (createOptions & 0x40)
3053 * compute initial mode bits based on read-only flag in
3054 * extended attributes
3056 initialModeBits = 0666;
3057 if (extAttributes & 1) initialModeBits &= ~0222;
3059 pathp = smb_GetSMBData(inp, NULL);
3060 /* Sometimes path is not null-terminated, so we make a copy. */
3061 realPathp = malloc(nameLength+1);
3062 memcpy(realPathp, pathp, nameLength);
3063 realPathp[nameLength] = 0;
3065 spacep = inp->spacep;
3066 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3068 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3069 /* special case magic file name for receiving IOCTL requests
3070 * (since IOCTL calls themselves aren't getting through).
3072 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3073 smb_SetupIoctlFid(fidp, spacep);
3075 /* set inp->fid so that later read calls in same msg can find fid */
3076 inp->fid = fidp->fid;
3080 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3081 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3082 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3084 memset(&ft, 0, sizeof(ft));
3085 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3086 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3087 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3088 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3089 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3090 sz.HighPart = 0x7fff; sz.LowPart = 0;
3091 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3092 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3093 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3094 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3095 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3096 smb_SetSMBDataLength(outp, 0);
3098 /* clean up fid reference */
3099 smb_ReleaseFID(fidp);
3104 userp = smb_GetUser(vcp, inp);
3107 baseDirp = cm_rootSCachep;
3108 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3111 baseFidp = smb_FindFID(vcp, baseFid, 0);
3112 baseDirp = baseFidp->scp;
3116 /* compute open mode */
3118 if (desiredAccess & DELETE)
3119 fidflags |= SMB_FID_OPENDELETE;
3120 if (desiredAccess & AFS_ACCESS_READ)
3121 fidflags |= SMB_FID_OPENREAD;
3122 if (desiredAccess & AFS_ACCESS_WRITE)
3123 fidflags |= SMB_FID_OPENWRITE;
3127 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3128 userp, tidPathp, &req, &scp);
3129 if (code == 0) foundscp = TRUE;
3131 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3132 /* look up parent directory */
3133 code = cm_NameI(baseDirp, spacep->data,
3134 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3135 userp, tidPathp, &req, &dscp);
3137 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3140 cm_ReleaseUser(userp);
3145 if (!lastNamep) lastNamep = realPathp;
3148 if (!smb_IsLegalFilename(lastNamep))
3149 return CM_ERROR_BADNTFILENAME;
3152 code = cm_Lookup(dscp, lastNamep,
3153 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3155 if (code && code != CM_ERROR_NOSUCHFILE) {
3156 cm_ReleaseSCache(dscp);
3157 cm_ReleaseUser(userp);
3164 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3167 /* if we get here, if code is 0, the file exists and is represented by
3168 * scp. Otherwise, we have to create it. The dir may be represented
3169 * by dscp, or we may have found the file directly. If code is non-zero,
3173 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3176 if (dscp) cm_ReleaseSCache(dscp);
3177 cm_ReleaseSCache(scp);
3178 cm_ReleaseUser(userp);
3183 if (createDisp == 2) {
3184 /* oops, file shouldn't be there */
3185 if (dscp) cm_ReleaseSCache(dscp);
3186 cm_ReleaseSCache(scp);
3187 cm_ReleaseUser(userp);
3189 return CM_ERROR_EXISTS;
3193 || createDisp == 5) {
3194 setAttr.mask = CM_ATTRMASK_LENGTH;
3195 setAttr.length.LowPart = 0;
3196 setAttr.length.HighPart = 0;
3197 code = cm_SetAttr(scp, &setAttr, userp, &req);
3198 openAction = 3; /* truncated existing file */
3200 else openAction = 1; /* found existing file */
3202 else if (createDisp == 1 || createDisp == 4) {
3203 /* don't create if not found */
3204 if (dscp) cm_ReleaseSCache(dscp);
3205 cm_ReleaseUser(userp);
3207 return CM_ERROR_NOSUCHFILE;
3209 else if (realDirFlag == 0 || realDirFlag == -1) {
3210 osi_assert(dscp != NULL);
3211 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3212 osi_LogSaveString(afsd_logp, lastNamep));
3213 openAction = 2; /* created file */
3214 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3215 setAttr.clientModTime = time(NULL);
3216 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3218 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3219 smb_NotifyChange(FILE_ACTION_ADDED,
3220 FILE_NOTIFY_CHANGE_FILE_NAME,
3221 dscp, lastNamep, NULL, TRUE);
3222 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3223 /* Not an exclusive create, and someone else tried
3224 * creating it already, then we open it anyway. We
3225 * don't bother retrying after this, since if this next
3226 * fails, that means that the file was deleted after we
3227 * started this call.
3229 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3232 if (createDisp == 5) {
3233 setAttr.mask = CM_ATTRMASK_LENGTH;
3234 setAttr.length.LowPart = 0;
3235 setAttr.length.HighPart = 0;
3236 code = cm_SetAttr(scp, &setAttr, userp,
3239 } /* lookup succeeded */
3243 /* create directory */
3244 osi_assert(dscp != NULL);
3245 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory %s",
3246 osi_LogSaveString(afsd_logp, lastNamep));
3247 openAction = 2; /* created directory */
3248 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3249 setAttr.clientModTime = time(NULL);
3250 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3251 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3252 smb_NotifyChange(FILE_ACTION_ADDED,
3253 FILE_NOTIFY_CHANGE_DIR_NAME,
3254 dscp, lastNamep, NULL, TRUE);
3256 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3257 /* Not an exclusive create, and someone else tried
3258 * creating it already, then we open it anyway. We
3259 * don't bother retrying after this, since if this next
3260 * fails, that means that the file was deleted after we
3261 * started this call.
3263 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3269 /* something went wrong creating or truncating the file */
3270 if (scp) cm_ReleaseSCache(scp);
3271 cm_ReleaseUser(userp);
3276 /* make sure we have file vs. dir right */
3277 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3278 cm_ReleaseSCache(scp);
3279 cm_ReleaseUser(userp);
3281 return CM_ERROR_ISDIR;
3283 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3284 cm_ReleaseSCache(scp);
3285 cm_ReleaseUser(userp);
3287 return CM_ERROR_NOTDIR;
3290 /* open the file itself */
3291 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3293 /* save a pointer to the vnode */
3296 fidp->flags = fidflags;
3298 /* save parent dir and pathname for delete or change notification */
3299 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3300 fidp->flags |= SMB_FID_NTOPEN;
3301 fidp->NTopen_dscp = dscp;
3302 cm_HoldSCache(dscp);
3303 fidp->NTopen_pathp = strdup(lastNamep);
3305 fidp->NTopen_wholepathp = realPathp;
3307 /* we don't need this any longer */
3308 if (dscp) cm_ReleaseSCache(dscp);
3309 cm_Open(scp, 0, userp);
3311 /* set inp->fid so that later read calls in same msg can find fid */
3312 inp->fid = fidp->fid;
3316 lock_ObtainMutex(&scp->mx);
3317 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3318 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3319 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3320 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3321 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3322 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3323 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3324 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3325 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3327 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3328 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3329 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3330 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3331 smb_SetSMBParmByte(outp, parmSlot,
3332 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3333 lock_ReleaseMutex(&scp->mx);
3334 smb_SetSMBDataLength(outp, 0);
3336 osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3337 osi_LogSaveString(afsd_logp, realPathp));
3339 smb_ReleaseFID(fidp);
3341 cm_ReleaseUser(userp);
3343 /* leave scp held since we put it in fidp->scp */
3348 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3349 * Instead, ultimately, would like to use a subroutine for common code.
3351 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3353 char *pathp, *realPathp;
3357 cm_scache_t *dscp; /* parent dir */
3358 cm_scache_t *scp; /* file to create or open */
3361 unsigned long nameLength;
3363 unsigned int requestOpLock;
3364 unsigned int requestBatchOpLock;
3365 unsigned int mustBeDir;
3367 unsigned int desiredAccess;
3368 unsigned int extAttributes;
3369 unsigned int createDisp;
3370 unsigned int createOptions;
3371 int initialModeBits;
3372 unsigned short baseFid;
3373 smb_fid_t *baseFidp;
3375 cm_scache_t *baseDirp;
3376 unsigned short openAction;
3382 int parmOffset, dataOffset;
3393 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3394 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3395 parmp = inp->data + parmOffset;
3396 lparmp = (ULONG *) parmp;
3399 requestOpLock = flags & 0x02;
3400 requestBatchOpLock = flags & 0x04;
3401 mustBeDir = flags & 0x08;
3403 * Why all of a sudden 32-bit FID?
3404 * We will reject all bits higher than 16.
3406 if (lparmp[1] & 0xFFFF0000)
3407 return CM_ERROR_INVAL;
3408 baseFid = (unsigned short)lparmp[1];
3409 desiredAccess = lparmp[2];
3410 extAttributes = lparmp[5];
3411 createDisp = lparmp[7];
3412 createOptions = lparmp[8];
3413 nameLength = lparmp[11];
3415 /* mustBeDir is never set; createOptions directory bit seems to be
3418 if (createOptions & 1)
3420 else if (createOptions & 0x40)
3426 * compute initial mode bits based on read-only flag in
3427 * extended attributes
3429 initialModeBits = 0666;
3430 if (extAttributes & 1) initialModeBits &= ~0222;
3432 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3433 /* Sometimes path is not null-terminated, so we make a copy. */
3434 realPathp = malloc(nameLength+1);
3435 memcpy(realPathp, pathp, nameLength);
3436 realPathp[nameLength] = 0;
3438 spacep = cm_GetSpace();
3439 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3442 * Nothing here to handle SMB_IOCTL_FILENAME.
3443 * Will add it if necessary.
3446 userp = smb_GetUser(vcp, inp);
3449 baseDirp = cm_rootSCachep;
3450 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3453 baseFidp = smb_FindFID(vcp, baseFid, 0);
3454 baseDirp = baseFidp->scp;
3458 /* compute open mode */
3460 if (desiredAccess & DELETE)
3461 fidflags |= SMB_FID_OPENDELETE;
3462 if (desiredAccess & AFS_ACCESS_READ)
3463 fidflags |= SMB_FID_OPENREAD;
3464 if (desiredAccess & AFS_ACCESS_WRITE)
3465 fidflags |= SMB_FID_OPENWRITE;
3469 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3470 userp, tidPathp, &req, &scp);
3471 if (code == 0) foundscp = TRUE;
3473 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3474 /* look up parent directory */
3475 code = cm_NameI(baseDirp, spacep->data,
3476 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3477 userp, tidPathp, &req, &dscp);
3478 cm_FreeSpace(spacep);
3480 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3483 cm_ReleaseUser(userp);
3488 if (!lastNamep) lastNamep = realPathp;
3491 if (!smb_IsLegalFilename(lastNamep))
3492 return CM_ERROR_BADNTFILENAME;
3495 code = cm_Lookup(dscp, lastNamep,
3496 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3498 if (code && code != CM_ERROR_NOSUCHFILE) {
3499 cm_ReleaseSCache(dscp);
3500 cm_ReleaseUser(userp);
3507 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3508 cm_FreeSpace(spacep);
3511 /* if we get here, if code is 0, the file exists and is represented by
3512 * scp. Otherwise, we have to create it. The dir may be represented
3513 * by dscp, or we may have found the file directly. If code is non-zero,
3517 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3520 if (dscp) cm_ReleaseSCache(dscp);
3521 cm_ReleaseSCache(scp);
3522 cm_ReleaseUser(userp);
3527 if (createDisp == 2) {
3528 /* oops, file shouldn't be there */
3529 if (dscp) cm_ReleaseSCache(dscp);
3530 cm_ReleaseSCache(scp);
3531 cm_ReleaseUser(userp);
3533 return CM_ERROR_EXISTS;
3537 || createDisp == 5) {
3538 setAttr.mask = CM_ATTRMASK_LENGTH;
3539 setAttr.length.LowPart = 0;
3540 setAttr.length.HighPart = 0;
3541 code = cm_SetAttr(scp, &setAttr, userp, &req);
3542 openAction = 3; /* truncated existing file */
3544 else openAction = 1; /* found existing file */
3546 else if (createDisp == 1 || createDisp == 4) {
3547 /* don't create if not found */
3548 if (dscp) cm_ReleaseSCache(dscp);
3549 cm_ReleaseUser(userp);
3551 return CM_ERROR_NOSUCHFILE;
3553 else if (realDirFlag == 0 || realDirFlag == -1) {
3554 osi_assert(dscp != NULL);
3555 osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
3556 osi_LogSaveString(afsd_logp, lastNamep));
3557 openAction = 2; /* created file */
3558 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3559 setAttr.clientModTime = time(NULL);
3560 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3562 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3563 smb_NotifyChange(FILE_ACTION_ADDED,
3564 FILE_NOTIFY_CHANGE_FILE_NAME,
3565 dscp, lastNamep, NULL, TRUE);
3566 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3567 /* Not an exclusive create, and someone else tried
3568 * creating it already, then we open it anyway. We
3569 * don't bother retrying after this, since if this next
3570 * fails, that means that the file was deleted after we
3571 * started this call.
3573 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3576 if (createDisp == 5) {
3577 setAttr.mask = CM_ATTRMASK_LENGTH;
3578 setAttr.length.LowPart = 0;
3579 setAttr.length.HighPart = 0;
3580 code = cm_SetAttr(scp, &setAttr, userp,
3583 } /* lookup succeeded */
3587 /* create directory */
3588 osi_assert(dscp != NULL);
3590 "smb_ReceiveNTTranCreate creating directory %s",
3591 osi_LogSaveString(afsd_logp, lastNamep));
3592 openAction = 2; /* created directory */
3593 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3594 setAttr.clientModTime = time(NULL);
3595 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3596 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3597 smb_NotifyChange(FILE_ACTION_ADDED,
3598 FILE_NOTIFY_CHANGE_DIR_NAME,
3599 dscp, lastNamep, NULL, TRUE);
3601 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3602 /* Not an exclusive create, and someone else tried
3603 * creating it already, then we open it anyway. We
3604 * don't bother retrying after this, since if this next
3605 * fails, that means that the file was deleted after we
3606 * started this call.
3608 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3614 /* something went wrong creating or truncating the file */
3615 if (scp) cm_ReleaseSCache(scp);
3616 cm_ReleaseUser(userp);
3621 /* make sure we have file vs. dir right */
3622 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3623 cm_ReleaseSCache(scp);
3624 cm_ReleaseUser(userp);
3626 return CM_ERROR_ISDIR;
3628 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3629 cm_ReleaseSCache(scp);
3630 cm_ReleaseUser(userp);
3632 return CM_ERROR_NOTDIR;
3635 /* open the file itself */
3636 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3639 /* save a pointer to the vnode */
3642 fidp->flags = fidflags;
3644 /* save parent dir and pathname for deletion or change notification */
3645 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3646 fidp->flags |= SMB_FID_NTOPEN;
3647 fidp->NTopen_dscp = dscp;
3648 cm_HoldSCache(dscp);
3649 fidp->NTopen_pathp = strdup(lastNamep);
3651 fidp->NTopen_wholepathp = realPathp;
3653 /* we don't need this any longer */
3654 if (dscp) cm_ReleaseSCache(dscp);
3656 cm_Open(scp, 0, userp);
3658 /* set inp->fid so that later read calls in same msg can find fid */
3659 inp->fid = fidp->fid;
3662 parmOffset = 8*4 + 39;
3663 parmOffset += 1; /* pad to 4 */
3664 dataOffset = parmOffset + 70;
3668 /* Total Parameter Count */
3669 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3670 /* Total Data Count */
3671 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3672 /* Parameter Count */
3673 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3674 /* Parameter Offset */
3675 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3676 /* Parameter Displacement */
3677 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3679 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3681 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3682 /* Data Displacement */
3683 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3684 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3685 smb_SetSMBDataLength(outp, 70);
3687 lock_ObtainMutex(&scp->mx);
3688 outData = smb_GetSMBData(outp, NULL);
3689 outData++; /* round to get to parmOffset */
3690 *outData = 0; outData++; /* oplock */
3691 *outData = 0; outData++; /* reserved */
3692 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
3693 *((ULONG *)outData) = openAction; outData += 4;
3694 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
3695 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3696 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
3697 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
3698 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
3699 *((FILETIME *)outData) = ft; outData += 8; /* change time */
3700 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
3701 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
3702 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
3703 *((USHORT *)outData) = 0; outData += 2; /* filetype */
3704 *((USHORT *)outData) = 0; outData += 2; /* dev state */
3705 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
3706 outData += 2; /* is a dir? */
3707 lock_ReleaseMutex(&scp->mx);
3709 osi_Log1(afsd_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
3711 smb_ReleaseFID(fidp);
3713 cm_ReleaseUser(userp);
3715 /* leave scp held since we put it in fidp->scp */
3719 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
3722 smb_packet_t *savedPacketp;
3723 ULONG filter; USHORT fid, watchtree;
3727 filter = smb_GetSMBParm(inp, 19)
3728 | (smb_GetSMBParm(inp, 20) << 16);
3729 fid = smb_GetSMBParm(inp, 21);
3730 watchtree = smb_GetSMBParm(inp, 22) && 0xffff;
3732 savedPacketp = smb_CopyPacket(inp);
3733 savedPacketp->vcp = vcp;
3734 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3735 savedPacketp->nextp = smb_Directory_Watches;
3736 smb_Directory_Watches = savedPacketp;
3737 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
3739 fidp = smb_FindFID(vcp, fid, 0);
3741 osi_Log4(afsd_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
3742 filter, fid, watchtree, osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
3745 lock_ObtainMutex(&scp->mx);
3747 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
3749 scp->flags |= CM_SCACHEFLAG_WATCHED;
3750 lock_ReleaseMutex(&scp->mx);
3751 smb_ReleaseFID(fidp);
3753 outp->flags |= SMB_PACKETFLAG_NOSEND;
3758 unsigned char nullSecurityDesc[36] = {
3759 0x01, /* security descriptor revision */
3760 0x00, /* reserved, should be zero */
3761 0x00, 0x80, /* security descriptor control;
3762 * 0x8000 : self-relative format */
3763 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
3764 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
3765 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
3766 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
3767 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3768 /* "null SID" owner SID */
3769 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3770 /* "null SID" group SID */
3773 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3775 int parmOffset, parmCount, dataOffset, dataCount;
3783 ULONG securityInformation;
3785 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3786 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3787 parmp = inp->data + parmOffset;
3788 sparmp = (USHORT *) parmp;
3789 lparmp = (ULONG *) parmp;
3792 securityInformation = lparmp[1];
3794 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
3795 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3803 parmOffset = 8*4 + 39;
3804 parmOffset += 1; /* pad to 4 */
3806 dataOffset = parmOffset + parmCount;
3810 /* Total Parameter Count */
3811 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3812 /* Total Data Count */
3813 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3814 /* Parameter Count */
3815 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3816 /* Parameter Offset */
3817 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3818 /* Parameter Displacement */
3819 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3821 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3823 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3824 /* Data Displacement */
3825 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3826 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3827 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
3829 outData = smb_GetSMBData(outp, NULL);
3830 outData++; /* round to get to parmOffset */
3831 *((ULONG *)outData) = 36; outData += 4; /* length */
3833 if (maxData >= 36) {
3834 memcpy(outData, nullSecurityDesc, 36);
3838 return CM_ERROR_BUFFERTOOSMALL;
3841 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3843 unsigned short function;
3845 function = smb_GetSMBParm(inp, 18);
3847 osi_Log1(afsd_logp, "SMB NT Transact function %d", function);
3849 /* We can handle long names */
3850 if (vcp->flags & SMB_VCFLAG_USENT)
3851 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3855 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
3857 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
3859 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
3861 default: return CM_ERROR_INVAL;
3866 * smb_NotifyChange -- find relevant change notification messages and
3869 * If we don't know the file name (i.e. a callback break), filename is
3870 * NULL, and we return a zero-length list.
3872 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
3873 cm_scache_t *dscp, char *filename, char *otherFilename,
3874 BOOL isDirectParent)
3876 smb_packet_t *watch, *lastWatch, *nextWatch;
3877 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
3878 char *outData, *oldOutData;
3882 BOOL twoEntries = FALSE;
3883 ULONG otherNameLen, oldParmCount = 0;
3888 /* Get ready for rename within directory */
3889 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
3891 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
3894 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3895 watch = smb_Directory_Watches;
3897 filter = smb_GetSMBParm(watch, 19)
3898 | (smb_GetSMBParm(watch, 20) << 16);
3899 fid = smb_GetSMBParm(watch, 21);
3900 wtree = smb_GetSMBParm(watch, 22) & 0xffff;
3901 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
3902 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
3906 * Strange hack - bug in NT Client and NT Server that we
3909 if (filter == 3 && wtree)
3912 fidp = smb_FindFID(vcp, fid, 0);
3913 if (fidp->scp != dscp
3914 || (filter & notifyFilter) == 0
3915 || (!isDirectParent && !wtree)) {
3916 smb_ReleaseFID(fidp);
3918 watch = watch->nextp;
3921 smb_ReleaseFID(fidp);
3924 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
3925 fid, filter, wtree, osi_LogSaveString(afsd_logp, filename));
3927 nextWatch = watch->nextp;
3928 if (watch == smb_Directory_Watches)
3929 smb_Directory_Watches = nextWatch;
3931 lastWatch->nextp = nextWatch;
3933 /* Turn off WATCHED flag in dscp */
3934 lock_ObtainMutex(&dscp->mx);
3936 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
3938 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
3939 lock_ReleaseMutex(&dscp->mx);
3941 /* Convert to response packet */
3942 ((smb_t *) watch)->reb = 0x80;
3943 ((smb_t *) watch)->wct = 0;
3946 if (filename == NULL)
3949 nameLen = strlen(filename);
3950 parmCount = 3*4 + nameLen*2;
3951 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3953 otherNameLen = strlen(otherFilename);
3954 oldParmCount = parmCount;
3955 parmCount += 3*4 + otherNameLen*2;
3956 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3958 if (maxLen < parmCount)
3959 parmCount = 0; /* not enough room */
3961 parmOffset = 8*4 + 39;
3962 parmOffset += 1; /* pad to 4 */
3963 dataOffset = parmOffset + parmCount;
3967 /* Total Parameter Count */
3968 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
3969 /* Total Data Count */
3970 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3971 /* Parameter Count */
3972 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
3973 /* Parameter Offset */
3974 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
3975 /* Parameter Displacement */
3976 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3978 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3980 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
3981 /* Data Displacement */
3982 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3983 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
3984 smb_SetSMBDataLength(watch, parmCount + 1);
3986 if (parmCount != 0) {
3987 outData = smb_GetSMBData(watch, NULL);
3988 outData++; /* round to get to parmOffset */
3989 oldOutData = outData;
3990 *((DWORD *)outData) = oldParmCount; outData += 4;
3991 /* Next Entry Offset */
3992 *((DWORD *)outData) = action; outData += 4;
3994 *((DWORD *)outData) = nameLen*2; outData += 4;
3995 /* File Name Length */
3996 mbstowcs((WCHAR *)outData, filename, nameLen);
3999 outData = oldOutData + oldParmCount;
4000 *((DWORD *)outData) = 0; outData += 4;
4001 /* Next Entry Offset */
4002 *((DWORD *)outData) = otherAction; outData += 4;
4004 *((DWORD *)outData) = otherNameLen*2;
4005 outData += 4; /* File Name Length */
4006 mbstowcs((WCHAR *)outData, otherFilename,
4007 otherNameLen); /* File Name */
4012 * If filename is null, we don't know the cause of the
4013 * change notification. We return zero data (see above),
4014 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4015 * (= 0x010C). We set the error code here by hand, without
4016 * modifying wct and bcc.
4018 if (filename == NULL) {
4019 ((smb_t *) watch)->rcls = 0x0C;
4020 ((smb_t *) watch)->reh = 0x01;
4021 ((smb_t *) watch)->errLow = 0;
4022 ((smb_t *) watch)->errHigh = 0;
4023 /* Set NT Status codes flag */
4024 ((smb_t *) watch)->flg2 |= 0x4000;
4027 smb_SendPacket(vcp, watch);
4028 smb_FreePacket(watch);
4031 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4034 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4036 unsigned char *replyWctp;
4037 smb_packet_t *watch, *lastWatch;
4038 USHORT fid, watchtree;
4042 osi_Log0(afsd_logp, "SMB3 receive NT cancel");
4044 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4045 watch = smb_Directory_Watches;
4047 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4048 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4049 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4050 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4051 if (watch == smb_Directory_Watches)
4052 smb_Directory_Watches = watch->nextp;
4054 lastWatch->nextp = watch->nextp;
4055 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4057 /* Turn off WATCHED flag in scp */
4058 fid = smb_GetSMBParm(watch, 21);
4059 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4061 fidp = smb_FindFID(vcp, fid, 0);
4063 osi_Log3(afsd_logp, "Cancelling change notification for fid %d wtree %d file %s",
4065 osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
4068 lock_ObtainMutex(&scp->mx);
4070 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4072 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4073 lock_ReleaseMutex(&scp->mx);
4074 smb_ReleaseFID(fidp);
4076 /* assume STATUS32; return 0xC0000120 (CANCELED) */
4077 replyWctp = watch->wctp;
4081 ((smb_t *)watch)->rcls = 0x20;
4082 ((smb_t *)watch)->reh = 0x1;
4083 ((smb_t *)watch)->errLow = 0;
4084 ((smb_t *)watch)->errHigh = 0xC0;
4085 ((smb_t *)watch)->flg2 |= 0x4000;
4086 smb_SendPacket(vcp, watch);
4087 smb_FreePacket(watch);
4091 watch = watch->nextp;
4093 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4100 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4103 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4107 smb_username_t *unp;
4109 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4111 lock_ObtainMutex(&unp->mx);
4112 unp->userp = cm_NewUser();
4113 lock_ReleaseMutex(&unp->mx);
4114 osi_LogEvent("AFS smb_FindCMUserByName New User",NULL,"name[%s] machine[%s]",usern,machine);
4116 osi_LogEvent("AFS smb_FindCMUserByName Found",NULL,"name[%s] machine[%s]",usern,machine);