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 /* Make sure that lastComp is not NULL */
1153 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1154 code = cm_NameI(cm_rootSCachep, spacep->data,
1158 userp, tidPathp, &req, &dscp);
1160 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1161 && !dscp->mountRootFidp)
1162 code = CM_ERROR_NOSUCHFILE;
1163 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1164 cm_buf_t *bp = buf_Find(dscp, &hzero);
1168 code = CM_ERROR_NOSUCHFILE;
1170 cm_ReleaseSCache(dscp);
1172 cm_FreeSpace(spacep);
1173 cm_ReleaseUser(userp);
1174 smb_SendTran2Error(vcp, p, opx, code);
1175 smb_FreeTran2Packet(outp);
1180 cm_FreeSpace(spacep);
1183 /* now do namei and stat, and copy out the info */
1184 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1185 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1188 cm_ReleaseUser(userp);
1189 smb_SendTran2Error(vcp, p, opx, code);
1190 smb_FreeTran2Packet(outp);
1194 lock_ObtainMutex(&scp->mx);
1195 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1196 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1197 if (code) goto done;
1199 /* now we have the status in the cache entry, and everything is locked.
1200 * Marshall the output data.
1203 /* for info level 108, figure out short name */
1204 if (infoLevel == 0x108) {
1205 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1206 tidPathp, scp->fid.vnode, shortName,
1213 *((u_long *)op) = len * 2; op += 4;
1214 mbstowcs((unsigned short *)op, shortName, len);
1219 if (infoLevel == 1 || infoLevel == 2) {
1220 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1221 *((u_long *)op) = dosTime; op += 4; /* creation time */
1222 *((u_long *)op) = dosTime; op += 4; /* access time */
1223 *((u_long *)op) = dosTime; op += 4; /* write time */
1224 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1225 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1226 attributes = smb_Attributes(scp);
1227 *((u_short *)op) = attributes; op += 2; /* attributes */
1229 else if (infoLevel == 0x101) {
1230 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1231 *((FILETIME *)op) = ft; op += 8; /* creation time */
1232 *((FILETIME *)op) = ft; op += 8; /* last access time */
1233 *((FILETIME *)op) = ft; op += 8; /* last write time */
1234 *((FILETIME *)op) = ft; op += 8; /* last change time */
1235 extAttributes = smb_ExtAttributes(scp);
1236 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1237 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1239 else if (infoLevel == 0x102) {
1240 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1241 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1242 *((u_long *)op) = scp->linkCount; op += 4;
1245 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1248 else if (infoLevel == 0x103) {
1249 memset(op, 0, 4); op += 4; /* EA size */
1252 /* now, if we are being asked about extended attrs, return a 0 size */
1253 if (infoLevel == 2) {
1254 *((u_long *)op) = 0; op += 4;
1258 /* send and free the packets */
1260 lock_ReleaseMutex(&scp->mx);
1261 cm_ReleaseSCache(scp);
1262 cm_ReleaseUser(userp);
1263 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1264 else smb_SendTran2Error(vcp, p, opx, code);
1265 smb_FreeTran2Packet(outp);
1270 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1272 return CM_ERROR_BADOP;
1275 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1277 smb_tran2Packet_t *outp;
1279 unsigned long attributes;
1280 unsigned short infoLevel;
1293 fidp = smb_FindFID(vcp, fid, 0);
1296 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1300 infoLevel = p->parmsp[1];
1301 if (infoLevel == 0x101) nbytesRequired = 40;
1302 else if (infoLevel == 0x102) nbytesRequired = 24;
1303 else if (infoLevel == 0x103) nbytesRequired = 4;
1304 else if (infoLevel == 0x104) nbytesRequired = 6;
1306 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1307 p->opcode, infoLevel);
1308 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1311 osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1313 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1315 if (infoLevel > 0x100)
1316 outp->totalParms = 2;
1318 outp->totalParms = 0;
1319 outp->totalData = nbytesRequired;
1321 userp = smb_GetTran2User(vcp, p);
1324 lock_ObtainMutex(&scp->mx);
1325 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1326 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1327 if (code) goto done;
1329 /* now we have the status in the cache entry, and everything is locked.
1330 * Marshall the output data.
1333 if (infoLevel == 0x101) {
1334 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1335 *((FILETIME *)op) = ft; op += 8; /* creation time */
1336 *((FILETIME *)op) = ft; op += 8; /* last access time */
1337 *((FILETIME *)op) = ft; op += 8; /* last write time */
1338 *((FILETIME *)op) = ft; op += 8; /* last change time */
1339 attributes = smb_ExtAttributes(scp);
1340 *((u_long *)op) = attributes; op += 4;
1341 *((u_long *)op) = 0; op += 4;
1343 else if (infoLevel == 0x102) {
1344 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1345 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1346 *((u_long *)op) = scp->linkCount; op += 4;
1347 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1349 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1352 else if (infoLevel == 0x103) {
1353 *((u_long *)op) = 0; op += 4;
1355 else if (infoLevel == 0x104) {
1359 if (fidp->NTopen_wholepathp)
1360 name = fidp->NTopen_wholepathp;
1362 name = "\\"; /* probably can't happen */
1364 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1365 *((u_long *)op) = len * 2; op += 4;
1366 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1369 /* send and free the packets */
1371 lock_ReleaseMutex(&scp->mx);
1372 cm_ReleaseUser(userp);
1373 smb_ReleaseFID(fidp);
1374 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1375 else smb_SendTran2Error(vcp, p, opx, code);
1376 smb_FreeTran2Packet(outp);
1381 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1386 unsigned short infoLevel;
1387 smb_tran2Packet_t *outp;
1395 fidp = smb_FindFID(vcp, fid, 0);
1398 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1402 infoLevel = p->parmsp[1];
1403 if (infoLevel > 0x104 || infoLevel < 0x101) {
1404 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1405 p->opcode, infoLevel);
1406 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1410 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1411 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1414 if ((infoLevel == 0x103 || infoLevel == 0x104)
1415 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1416 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1420 osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1422 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1424 outp->totalParms = 2;
1425 outp->totalData = 0;
1427 userp = smb_GetTran2User(vcp, p);
1431 if (infoLevel == 0x101) {
1433 unsigned int attribute;
1436 /* lock the vnode with a callback; we need the current status
1437 * to determine what the new status is, in some cases.
1439 lock_ObtainMutex(&scp->mx);
1440 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1441 CM_SCACHESYNC_GETSTATUS
1442 | CM_SCACHESYNC_NEEDCALLBACK);
1444 lock_ReleaseMutex(&scp->mx);
1448 /* prepare for setattr call */
1450 lastMod = *((FILETIME *)(p->datap + 16));
1451 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod))) {
1452 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1453 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1455 fidp->flags |= SMB_FID_MTIMESETDONE;
1457 attribute = *((u_long *)(p->datap + 32));
1458 if (attribute != 0) {
1459 if ((scp->unixModeBits & 0222)
1460 && (attribute & 1) != 0) {
1461 /* make a writable file read-only */
1462 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1463 attr.unixModeBits = scp->unixModeBits & ~0222;
1465 else if ((scp->unixModeBits & 0222) == 0
1466 && (attribute & 1) == 0) {
1467 /* make a read-only file writable */
1468 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1469 attr.unixModeBits = scp->unixModeBits | 0222;
1472 lock_ReleaseMutex(&scp->mx);
1476 code = cm_SetAttr(scp, &attr, userp, &req);
1480 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1481 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1484 attr.mask = CM_ATTRMASK_LENGTH;
1485 attr.length.LowPart = size.LowPart;
1486 attr.length.HighPart = size.HighPart;
1487 code = cm_SetAttr(scp, &attr, userp, &req);
1489 else if (infoLevel == 0x102) {
1490 if (*((char *)(p->datap))) {
1491 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1494 fidp->flags |= SMB_FID_DELONCLOSE;
1498 fidp->flags &= ~SMB_FID_DELONCLOSE;
1502 cm_ReleaseUser(userp);
1503 smb_ReleaseFID(fidp);
1504 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1505 else smb_SendTran2Error(vcp, p, op, code);
1506 smb_FreeTran2Packet(outp);
1511 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1513 return CM_ERROR_BADOP;
1516 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1518 return CM_ERROR_BADOP;
1521 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1523 return CM_ERROR_BADOP;
1526 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1528 return CM_ERROR_BADOP;
1531 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1533 return CM_ERROR_BADOP;
1536 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1537 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1542 cm_scache_t *targetScp; /* target if scp is a symlink */
1547 unsigned short attr;
1548 unsigned long lattr;
1549 smb_dirListPatch_t *patchp;
1550 smb_dirListPatch_t *npatchp;
1552 for(patchp = *dirPatchespp; patchp; patchp =
1553 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1554 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1556 lock_ObtainMutex(&scp->mx);
1557 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1558 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1560 lock_ReleaseMutex(&scp->mx);
1561 cm_ReleaseSCache(scp);
1565 /* now watch for a symlink */
1566 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1567 lock_ReleaseMutex(&scp->mx);
1568 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1571 /* we have a more accurate file to use (the
1572 * target of the symbolic link). Otherwise,
1573 * we'll just use the symlink anyway.
1575 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1577 cm_ReleaseSCache(scp);
1580 lock_ObtainMutex(&scp->mx);
1583 dptr = patchp->dptr;
1585 if (infoLevel >= 0x101) {
1587 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1589 /* copy to Creation Time */
1590 *((FILETIME *)dptr) = ft;
1593 /* copy to Last Access Time */
1594 *((FILETIME *)dptr) = ft;
1597 /* copy to Last Write Time */
1598 *((FILETIME *)dptr) = ft;
1601 /* copy to Change Time */
1602 *((FILETIME *)dptr) = ft;
1605 /* Use length for both file length and alloc length */
1606 *((LARGE_INTEGER *)dptr) = scp->length;
1608 *((LARGE_INTEGER *)dptr) = scp->length;
1611 /* Copy attributes */
1612 lattr = smb_ExtAttributes(scp);
1613 *((u_long *)dptr) = lattr;
1618 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1620 /* and copy out date */
1621 shortTemp = (dosTime>>16) & 0xffff;
1622 *((u_short *)dptr) = shortTemp;
1625 /* copy out creation time */
1626 shortTemp = dosTime & 0xffff;
1627 *((u_short *)dptr) = shortTemp;
1630 /* and copy out date */
1631 shortTemp = (dosTime>>16) & 0xffff;
1632 *((u_short *)dptr) = shortTemp;
1635 /* copy out access time */
1636 shortTemp = dosTime & 0xffff;
1637 *((u_short *)dptr) = shortTemp;
1640 /* and copy out date */
1641 shortTemp = (dosTime>>16) & 0xffff;
1642 *((u_short *)dptr) = shortTemp;
1645 /* copy out mod time */
1646 shortTemp = dosTime & 0xffff;
1647 *((u_short *)dptr) = shortTemp;
1650 /* copy out file length and alloc length,
1651 * using the same for both
1653 *((u_long *)dptr) = scp->length.LowPart;
1655 *((u_long *)dptr) = scp->length.LowPart;
1658 /* finally copy out attributes as short */
1659 attr = smb_Attributes(scp);
1660 *dptr++ = attr & 0xff;
1661 *dptr++ = (attr >> 8) & 0xff;
1664 lock_ReleaseMutex(&scp->mx);
1665 cm_ReleaseSCache(scp);
1668 /* now free the patches */
1669 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1670 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1674 /* and mark the list as empty */
1675 *dirPatchespp = NULL;
1680 /* do a case-folding search of the star name mask with the name in namep.
1681 * Return 1 if we match, otherwise 0.
1683 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1685 unsigned char tcp1, tcp2; /* Pattern characters */
1686 unsigned char tcn1; /* Name characters */
1687 int sawDot = 0, sawStar = 0;
1688 char *starNamep, *starMaskp;
1689 static char nullCharp[] = {0};
1691 /* make sure we only match 8.3 names, if requested */
1692 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1696 /* Next pattern character */
1699 /* Next name character */
1703 /* 0 - end of pattern */
1709 else if (tcp1 == '.' || tcp1 == '"') {
1719 * first dot in pattern;
1720 * must match dot or end of name
1725 else if (tcn1 == '.') {
1734 else if (tcp1 == '?') {
1735 if (tcn1 == 0 || tcn1 == '.')
1740 else if (tcp1 == '>') {
1741 if (tcn1 != 0 && tcn1 != '.')
1745 else if (tcp1 == '*' || tcp1 == '<') {
1749 else if (tcp2 == '.' || tcp2 == '"') {
1750 while (tcn1 != '.' && tcn1 != 0)
1765 * pattern character after '*' is not null or
1766 * period. If it is '?' or '>', we are not
1767 * going to understand it. If it is '*' or
1768 * '<', we are going to skip over it. None of
1769 * these are likely, I hope.
1771 /* skip over '*' and '<' */
1772 while (tcp2 == '*' || tcp2 == '<')
1775 /* skip over characters that don't match tcp2 */
1776 while (tcn1 != '.' && tcn1 != 0
1777 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1781 if (tcn1 == '.' || tcn1 == 0)
1784 /* Remember where we are */
1794 /* tcp1 is not a wildcard */
1795 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1800 /* if trying to match a star pattern, go back */
1802 maskp = starMaskp - 2;
1803 namep = starNamep + 1;
1813 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1822 smb_dirListPatch_t *dirListPatchesp;
1823 smb_dirListPatch_t *curPatchp;
1826 long orbytes; /* # of bytes in this output record */
1827 long ohbytes; /* # of bytes, except file name */
1828 long onbytes; /* # of bytes in name, incl. term. null */
1829 osi_hyper_t dirLength;
1830 osi_hyper_t bufferOffset;
1831 osi_hyper_t curOffset;
1833 smb_dirSearch_t *dsp;
1837 cm_pageHeader_t *pageHeaderp;
1838 cm_user_t *userp = NULL;
1841 long nextEntryCookie;
1842 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1843 char *op; /* output data ptr */
1844 char *origOp; /* original value of op */
1845 cm_space_t *spacep; /* for pathname buffer */
1846 long maxReturnData; /* max # of return data */
1847 long maxReturnParms; /* max # of return parms */
1848 long bytesInBuffer; /* # data bytes in the output buffer */
1850 char *maskp; /* mask part of path */
1854 smb_tran2Packet_t *outp; /* response packet */
1857 char shortName[13]; /* 8.3 name if needed */
1868 if (p->opcode == 1) {
1869 /* find first; obtain basic parameters from request */
1870 attribute = p->parmsp[0];
1871 maxCount = p->parmsp[1];
1872 infoLevel = p->parmsp[3];
1873 searchFlags = p->parmsp[2];
1874 dsp = smb_NewDirSearch(1);
1875 dsp->attribute = attribute;
1876 pathp = ((char *) p->parmsp) + 12; /* points to path */
1878 maskp = strrchr(pathp, '\\');
1879 if (maskp == NULL) maskp = pathp;
1880 else maskp++; /* skip over backslash */
1881 strcpy(dsp->mask, maskp); /* and save mask */
1882 /* track if this is likely to match a lot of entries */
1883 starPattern = smb_V3IsStarMask(maskp);
1886 osi_assert(p->opcode == 2);
1887 /* find next; obtain basic parameters from request or open dir file */
1888 dsp = smb_FindDirSearch(p->parmsp[0]);
1889 if (!dsp) return CM_ERROR_BADFD;
1890 attribute = dsp->attribute;
1891 maxCount = p->parmsp[1];
1892 infoLevel = p->parmsp[2];
1893 searchFlags = p->parmsp[5];
1895 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1897 starPattern = 1; /* assume, since required a Find Next */
1901 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1902 attribute, infoLevel, maxCount, searchFlags);
1904 osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1905 p->opcode, nextCookie);
1907 if (infoLevel >= 0x101)
1908 searchFlags &= ~4; /* no resume keys */
1910 dirListPatchesp = NULL;
1912 maxReturnData = p->maxReturnData;
1913 if (p->opcode == 1) /* find first */
1914 maxReturnParms = 10; /* bytes */
1916 maxReturnParms = 8; /* bytes */
1918 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1919 if (maxReturnData > 6000) maxReturnData = 6000;
1920 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1922 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1925 osi_Log1(afsd_logp, "T2 receive search dir %s",
1926 osi_LogSaveString(afsd_logp, pathp));
1928 /* bail out if request looks bad */
1929 if (p->opcode == 1 && !pathp) {
1930 return CM_ERROR_BADSMB;
1933 osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1934 nextCookie, dsp->cookie);
1936 userp = smb_GetTran2User(vcp, p);
1938 /* try to get the vnode for the path name next */
1939 lock_ObtainMutex(&dsp->mx);
1946 spacep = cm_GetSpace();
1947 smb_StripLastComponent(spacep->data, NULL, pathp);
1948 lock_ReleaseMutex(&dsp->mx);
1950 tidPathp = smb_GetTIDPath(vcp, p->tid);
1951 code = cm_NameI(cm_rootSCachep, spacep->data,
1952 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1953 userp, tidPathp, &req, &scp);
1954 cm_FreeSpace(spacep);
1956 lock_ObtainMutex(&dsp->mx);
1958 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
1960 /* we need one hold for the entry we just stored into,
1961 * and one for our own processing. When we're done
1962 * with this function, we'll drop the one for our own
1963 * processing. We held it once from the namei call,
1964 * and so we do another hold now.
1967 lock_ObtainMutex(&scp->mx);
1968 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
1969 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
1970 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
1971 dsp->flags |= SMB_DIRSEARCH_BULKST;
1973 lock_ReleaseMutex(&scp->mx);
1976 lock_ReleaseMutex(&dsp->mx);
1978 cm_ReleaseUser(userp);
1979 smb_FreeTran2Packet(outp);
1980 smb_DeleteDirSearch(dsp);
1981 smb_ReleaseDirSearch(dsp);
1985 /* get the directory size */
1986 lock_ObtainMutex(&scp->mx);
1987 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1988 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1990 lock_ReleaseMutex(&scp->mx);
1991 cm_ReleaseSCache(scp);
1992 cm_ReleaseUser(userp);
1993 smb_FreeTran2Packet(outp);
1994 smb_DeleteDirSearch(dsp);
1995 smb_ReleaseDirSearch(dsp);
1999 dirLength = scp->length;
2001 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2002 curOffset.HighPart = 0;
2003 curOffset.LowPart = nextCookie;
2004 origOp = outp->datap;
2011 if (searchFlags & 4)
2012 /* skip over resume key */
2015 /* make sure that curOffset.LowPart doesn't point to the first
2016 * 32 bytes in the 2nd through last dir page, and that it doesn't
2017 * point at the first 13 32-byte chunks in the first dir page,
2018 * since those are dir and page headers, and don't contain useful
2021 temp = curOffset.LowPart & (2048-1);
2022 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2023 /* we're in the first page */
2024 if (temp < 13*32) temp = 13*32;
2027 /* we're in a later dir page */
2028 if (temp < 32) temp = 32;
2031 /* make sure the low order 5 bits are zero */
2034 /* now put temp bits back ito curOffset.LowPart */
2035 curOffset.LowPart &= ~(2048-1);
2036 curOffset.LowPart |= temp;
2038 /* check if we've returned all the names that will fit in the
2039 * response packet; we check return count as well as the number
2040 * of bytes requested. We check the # of bytes after we find
2041 * the dir entry, since we'll need to check its size.
2043 if (returnedNames >= maxCount) break;
2045 /* check if we've passed the dir's EOF */
2046 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2051 /* see if we can use the bufferp we have now; compute in which
2052 * page the current offset would be, and check whether that's
2053 * the offset of the buffer we have. If not, get the buffer.
2055 thyper.HighPart = curOffset.HighPart;
2056 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2057 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2060 buf_Release(bufferp);
2063 lock_ReleaseMutex(&scp->mx);
2064 lock_ObtainRead(&scp->bufCreateLock);
2065 code = buf_Get(scp, &thyper, &bufferp);
2066 lock_ReleaseRead(&scp->bufCreateLock);
2068 /* now, if we're doing a star match, do bulk fetching
2069 * of all of the status info for files in the dir.
2072 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2075 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2076 && LargeIntegerGreaterThanOrEqualTo(
2077 thyper, scp->bulkStatProgress)) {
2078 /* Don't bulk stat if risking timeout */
2079 int now = GetCurrentTime();
2080 if (now - req.startTime > 5000) {
2081 scp->bulkStatProgress = thyper;
2082 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2083 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2085 cm_TryBulkStat(scp, &thyper,
2090 lock_ObtainMutex(&scp->mx);
2092 bufferOffset = thyper;
2094 /* now get the data in the cache */
2096 code = cm_SyncOp(scp, bufferp, userp, &req,
2098 CM_SCACHESYNC_NEEDCALLBACK
2099 | CM_SCACHESYNC_READ);
2102 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2104 /* otherwise, load the buffer and try again */
2105 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2110 buf_Release(bufferp);
2114 } /* if (wrong buffer) ... */
2116 /* now we have the buffer containing the entry we're interested
2117 * in; copy it out if it represents a non-deleted entry.
2119 entryInDir = curOffset.LowPart & (2048-1);
2120 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2122 /* page header will help tell us which entries are free. Page
2123 * header can change more often than once per buffer, since
2124 * AFS 3 dir page size may be less than (but not more than)
2125 * a buffer package buffer.
2127 /* only look intra-buffer */
2128 temp = curOffset.LowPart & (buf_bufferSize - 1);
2129 temp &= ~(2048 - 1); /* turn off intra-page bits */
2130 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2132 /* now determine which entry we're looking at in the page.
2133 * If it is free (there's a free bitmap at the start of the
2134 * dir), we should skip these 32 bytes.
2136 slotInPage = (entryInDir & 0x7e0) >> 5;
2137 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2138 & (1 << (slotInPage & 0x7)))) {
2139 /* this entry is free */
2140 numDirChunks = 1; /* only skip this guy */
2144 tp = bufferp->datap + entryInBuffer;
2145 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2147 /* while we're here, compute the next entry's location, too,
2148 * since we'll need it when writing out the cookie into the dir
2151 * XXXX Probably should do more sanity checking.
2153 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2155 /* compute offset of cookie representing next entry */
2156 nextEntryCookie = curOffset.LowPart
2157 + (CM_DIR_CHUNKSIZE * numDirChunks);
2159 /* Need 8.3 name? */
2161 if (infoLevel == 0x104
2162 && dep->fid.vnode != 0
2163 && !cm_Is8Dot3(dep->name)) {
2164 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2168 if (dep->fid.vnode != 0
2169 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2171 && smb_V3MatchMask(shortName, maskp,
2172 CM_FLAG_CASEFOLD)))) {
2174 /* Eliminate entries that don't match requested
2176 if (!(dsp->attribute & 0x10)) /* no directories */
2178 /* We have already done the cm_TryBulkStat above */
2179 fid.cell = scp->fid.cell;
2180 fid.volume = scp->fid.volume;
2181 fid.vnode = ntohl(dep->fid.vnode);
2182 fid.unique = ntohl(dep->fid.unique);
2183 fileType = cm_FindFileType(&fid);
2184 /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2185 "has filetype %d", dep->name,
2187 if (fileType == CM_SCACHETYPE_DIRECTORY)
2191 /* finally check if this name will fit */
2193 /* standard dir entry stuff */
2194 if (infoLevel < 0x101)
2195 ohbytes = 23; /* pre-NT */
2196 else if (infoLevel == 0x103)
2197 ohbytes = 12; /* NT names only */
2199 ohbytes = 64; /* NT */
2201 if (infoLevel == 0x104)
2202 ohbytes += 26; /* Short name & length */
2204 if (searchFlags & 4) {
2205 ohbytes += 4; /* if resume key required */
2209 && infoLevel != 0x101
2210 && infoLevel != 0x103)
2211 ohbytes += 4; /* EASIZE */
2213 /* add header to name & term. null */
2214 orbytes = onbytes + ohbytes + 1;
2216 /* now, we round up the record to a 4 byte alignment,
2217 * and we make sure that we have enough room here for
2218 * even the aligned version (so we don't have to worry
2219 * about an * overflow when we pad things out below).
2220 * That's the reason for the alignment arithmetic below.
2222 if (infoLevel >= 0x101)
2223 align = (4 - (orbytes & 3)) & 3;
2226 if (orbytes + bytesInBuffer + align > maxReturnData)
2229 /* this is one of the entries to use: it is not deleted
2230 * and it matches the star pattern we're looking for.
2231 * Put out the name, preceded by its length.
2233 /* First zero everything else */
2234 memset(origOp, 0, ohbytes);
2236 if (infoLevel <= 0x101)
2237 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2238 else if (infoLevel == 0x103)
2239 *((u_long *)(op + 8)) = onbytes;
2241 *((u_long *)(op + 60)) = onbytes;
2242 strcpy(origOp+ohbytes, dep->name);
2244 /* Short name if requested and needed */
2245 if (infoLevel == 0x104) {
2246 if (NeedShortName) {
2247 strcpy(op + 70, shortName);
2248 *(op + 68) = shortNameEnd - shortName;
2252 /* now, adjust the # of entries copied */
2255 /* NextEntryOffset and FileIndex */
2256 if (infoLevel >= 101) {
2257 int entryOffset = orbytes + align;
2258 *((u_long *)op) = entryOffset;
2259 *((u_long *)(op+4)) = nextEntryCookie;
2262 /* now we emit the attribute. This is tricky, since
2263 * we need to really stat the file to find out what
2264 * type of entry we've got. Right now, we're copying
2265 * out data from * a buffer, while holding the scp
2266 * locked, so it isn't really convenient to stat
2267 * something now. We'll put in a place holder
2268 * now, and make a second pass before returning this
2269 * to get the real attributes. So, we just skip the
2270 * data for now, and adjust it later. We allocate a
2271 * patch record to make it easy to find this point
2272 * later. The replay will happen at a time when it is
2273 * safe to unlock the directory.
2275 if (infoLevel != 0x103) {
2276 curPatchp = malloc(sizeof(*curPatchp));
2277 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2279 curPatchp->dptr = op;
2280 if (infoLevel >= 0x101)
2281 curPatchp->dptr += 8;
2282 curPatchp->fid.cell = scp->fid.cell;
2283 curPatchp->fid.volume = scp->fid.volume;
2284 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2285 curPatchp->fid.unique = ntohl(dep->fid.unique);
2288 curPatchp->dep = dep;
2291 if (searchFlags & 4)
2292 /* put out resume key */
2293 *((u_long *)origOp) = nextEntryCookie;
2295 /* Adjust byte ptr and count */
2296 origOp += orbytes; /* skip entire record */
2297 bytesInBuffer += orbytes;
2299 /* and pad the record out */
2300 while (--align >= 0) {
2305 } /* if we're including this name */
2308 /* and adjust curOffset to be where the new cookie is */
2309 thyper.HighPart = 0;
2310 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2311 curOffset = LargeIntegerAdd(thyper, curOffset);
2312 } /* while copying data for dir listing */
2314 /* release the mutex */
2315 lock_ReleaseMutex(&scp->mx);
2316 if (bufferp) buf_Release(bufferp);
2318 /* apply and free last set of patches; if not doing a star match, this
2319 * will be empty, but better safe (and freeing everything) than sorry.
2321 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2324 /* now put out the final parameters */
2325 if (returnedNames == 0) eos = 1;
2326 if (p->opcode == 1) {
2328 outp->parmsp[0] = (unsigned short) dsp->cookie;
2329 outp->parmsp[1] = returnedNames;
2330 outp->parmsp[2] = eos;
2331 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2332 outp->parmsp[4] = 0; /* don't need last name to continue
2333 * search, cookie is enough. Normally,
2334 * this is the offset of the file name
2335 * of the last entry returned.
2337 outp->totalParms = 10; /* in bytes */
2341 outp->parmsp[0] = returnedNames;
2342 outp->parmsp[1] = eos;
2343 outp->parmsp[2] = 0; /* EAS error */
2344 outp->parmsp[3] = 0; /* last name, as above */
2345 outp->totalParms = 8; /* in bytes */
2348 /* return # of bytes in the buffer */
2349 outp->totalData = bytesInBuffer;
2351 osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2352 returnedNames, code);
2354 /* Return error code if unsuccessful on first request */
2355 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2356 code = CM_ERROR_NOSUCHFILE;
2358 /* if we're supposed to close the search after this request, or if
2359 * we're supposed to close the search if we're done, and we're done,
2360 * or if something went wrong, close the search.
2362 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2363 if ((searchFlags & 1) || (returnedNames == 0)
2364 || code != 0) smb_DeleteDirSearch(dsp);
2366 smb_SendTran2Error(vcp, p, opx, code);
2368 smb_SendTran2Packet(vcp, outp, opx);
2370 smb_FreeTran2Packet(outp);
2371 smb_ReleaseDirSearch(dsp);
2372 cm_ReleaseSCache(scp);
2373 cm_ReleaseUser(userp);
2377 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2380 smb_dirSearch_t *dsp;
2382 dirHandle = smb_GetSMBParm(inp, 0);
2384 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2386 dsp = smb_FindDirSearch(dirHandle);
2389 return CM_ERROR_BADFD;
2391 /* otherwise, we have an FD to destroy */
2392 smb_DeleteDirSearch(dsp);
2393 smb_ReleaseDirSearch(dsp);
2395 /* and return results */
2396 smb_SetSMBDataLength(outp, 0);
2401 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2403 smb_SetSMBDataLength(outp, 0);
2407 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2414 cm_scache_t *dscp; /* dir we're dealing with */
2415 cm_scache_t *scp; /* file we're creating */
2417 int initialModeBits;
2427 int parmSlot; /* which parm we're dealing with */
2435 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2436 openFun = smb_GetSMBParm(inp, 8); /* open function */
2437 excl = ((openFun & 3) == 0);
2438 trunc = ((openFun & 3) == 2); /* truncate it */
2439 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2440 openAction = 0; /* tracks what we did */
2442 attributes = smb_GetSMBParm(inp, 5);
2443 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2445 /* compute initial mode bits based on read-only flag in attributes */
2446 initialModeBits = 0666;
2447 if (attributes & 1) initialModeBits &= ~0222;
2449 pathp = smb_GetSMBData(inp, NULL);
2451 spacep = inp->spacep;
2452 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2454 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2455 /* special case magic file name for receiving IOCTL requests
2456 * (since IOCTL calls themselves aren't getting through).
2458 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2459 smb_SetupIoctlFid(fidp, spacep);
2461 /* set inp->fid so that later read calls in same msg can find fid */
2462 inp->fid = fidp->fid;
2464 /* copy out remainder of the parms */
2466 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2468 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2469 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2470 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2471 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2472 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2473 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2474 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2475 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2477 /* and the final "always present" stuff */
2478 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2479 /* next write out the "unique" ID */
2480 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2481 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2482 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2483 smb_SetSMBDataLength(outp, 0);
2485 /* and clean up fid reference */
2486 smb_ReleaseFID(fidp);
2490 userp = smb_GetUser(vcp, inp);
2493 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2494 code = cm_NameI(cm_rootSCachep, pathp,
2495 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2496 userp, tidPathp, &req, &scp);
2498 code = cm_NameI(cm_rootSCachep, spacep->data,
2499 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2500 userp, tidPathp, &req, &dscp);
2503 cm_ReleaseUser(userp);
2507 /* otherwise, scp points to the parent directory. Do a lookup,
2508 * and truncate the file if we find it, otherwise we create the
2511 if (!lastNamep) lastNamep = pathp;
2513 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2515 if (code && code != CM_ERROR_NOSUCHFILE) {
2516 cm_ReleaseSCache(dscp);
2517 cm_ReleaseUser(userp);
2522 /* if we get here, if code is 0, the file exists and is represented by
2523 * scp. Otherwise, we have to create it. The dir may be represented
2524 * by dscp, or we may have found the file directly. If code is non-zero,
2528 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2530 if (dscp) cm_ReleaseSCache(dscp);
2531 cm_ReleaseSCache(scp);
2532 cm_ReleaseUser(userp);
2537 /* oops, file shouldn't be there */
2538 if (dscp) cm_ReleaseSCache(dscp);
2539 cm_ReleaseSCache(scp);
2540 cm_ReleaseUser(userp);
2541 return CM_ERROR_EXISTS;
2545 setAttr.mask = CM_ATTRMASK_LENGTH;
2546 setAttr.length.LowPart = 0;
2547 setAttr.length.HighPart = 0;
2548 code = cm_SetAttr(scp, &setAttr, userp, &req);
2549 openAction = 3; /* truncated existing file */
2551 else openAction = 1; /* found existing file */
2553 else if (!(openFun & 0x10)) {
2554 /* don't create if not found */
2555 if (dscp) cm_ReleaseSCache(dscp);
2556 cm_ReleaseUser(userp);
2557 return CM_ERROR_NOSUCHFILE;
2560 osi_assert(dscp != NULL);
2561 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2562 osi_LogSaveString(afsd_logp, lastNamep));
2563 openAction = 2; /* created file */
2564 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2565 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2566 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2568 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2569 smb_NotifyChange(FILE_ACTION_ADDED,
2570 FILE_NOTIFY_CHANGE_FILE_NAME,
2571 dscp, lastNamep, NULL, TRUE);
2572 if (!excl && code == CM_ERROR_EXISTS) {
2573 /* not an exclusive create, and someone else tried
2574 * creating it already, then we open it anyway. We
2575 * don't bother retrying after this, since if this next
2576 * fails, that means that the file was deleted after we
2577 * started this call.
2579 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2583 setAttr.mask = CM_ATTRMASK_LENGTH;
2584 setAttr.length.LowPart = 0;
2585 setAttr.length.HighPart = 0;
2586 code = cm_SetAttr(scp, &setAttr, userp,
2589 } /* lookup succeeded */
2593 /* we don't need this any longer */
2594 if (dscp) cm_ReleaseSCache(dscp);
2597 /* something went wrong creating or truncating the file */
2598 if (scp) cm_ReleaseSCache(scp);
2599 cm_ReleaseUser(userp);
2603 /* make sure we're about to open a file */
2604 if (scp->fileType != CM_SCACHETYPE_FILE) {
2605 cm_ReleaseSCache(scp);
2606 cm_ReleaseUser(userp);
2607 return CM_ERROR_ISDIR;
2610 /* now all we have to do is open the file itself */
2611 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2614 /* save a pointer to the vnode */
2617 /* compute open mode */
2618 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2619 if (openMode == 1 || openMode == 2)
2620 fidp->flags |= SMB_FID_OPENWRITE;
2622 smb_ReleaseFID(fidp);
2624 cm_Open(scp, 0, userp);
2626 /* set inp->fid so that later read calls in same msg can find fid */
2627 inp->fid = fidp->fid;
2629 /* copy out remainder of the parms */
2631 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2632 lock_ObtainMutex(&scp->mx);
2634 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2635 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2636 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2637 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2638 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2639 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2640 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2641 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2642 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2644 /* and the final "always present" stuff */
2645 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2646 /* next write out the "unique" ID */
2647 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2648 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2649 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2650 lock_ReleaseMutex(&scp->mx);
2651 smb_SetSMBDataLength(outp, 0);
2653 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2655 cm_ReleaseUser(userp);
2656 /* leave scp held since we put it in fidp->scp */
2660 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2667 unsigned char LockType;
2668 unsigned short NumberOfUnlocks, NumberOfLocks;
2669 unsigned long Timeout;
2671 LARGE_INTEGER LOffset, LLength;
2672 smb_waitingLock_t *waitingLock;
2679 fid = smb_GetSMBParm(inp, 2);
2680 fid = smb_ChainFID(fid, inp);
2682 fidp = smb_FindFID(vcp, fid, 0);
2683 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2684 return CM_ERROR_BADFD;
2686 /* set inp->fid so that later read calls in same msg can find fid */
2689 userp = smb_GetUser(vcp, inp);
2693 lock_ObtainMutex(&scp->mx);
2694 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2695 CM_SCACHESYNC_NEEDCALLBACK
2696 | CM_SCACHESYNC_GETSTATUS
2697 | CM_SCACHESYNC_LOCK);
2698 if (code) goto doneSync;
2700 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2701 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2702 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2703 NumberOfLocks = smb_GetSMBParm(inp, 7);
2705 op = smb_GetSMBData(inp, NULL);
2707 for (i=0; i<NumberOfUnlocks; i++) {
2708 if (LockType & 0x10) {
2710 LOffset.HighPart = *((LONG *)(op + 4));
2711 LOffset.LowPart = *((DWORD *)(op + 8));
2712 LLength.HighPart = *((LONG *)(op + 12));
2713 LLength.LowPart = *((DWORD *)(op + 16));
2717 /* Not Large Files */
2718 LOffset.HighPart = 0;
2719 LOffset.LowPart = *((DWORD *)(op + 2));
2720 LLength.HighPart = 0;
2721 LLength.LowPart = *((DWORD *)(op + 6));
2724 if (LargeIntegerNotEqualToZero(LOffset))
2726 /* Do not check length -- length check done in cm_Unlock */
2728 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2729 if (code) goto done;
2732 for (i=0; i<NumberOfLocks; i++) {
2733 if (LockType & 0x10) {
2735 LOffset.HighPart = *((LONG *)(op + 4));
2736 LOffset.LowPart = *((DWORD *)(op + 8));
2737 LLength.HighPart = *((LONG *)(op + 12));
2738 LLength.LowPart = *((DWORD *)(op + 16));
2742 /* Not Large Files */
2743 LOffset.HighPart = 0;
2744 LOffset.LowPart = *((DWORD *)(op + 2));
2745 LLength.HighPart = 0;
2746 LLength.LowPart = *((DWORD *)(op + 6));
2749 if (LargeIntegerNotEqualToZero(LOffset))
2751 if (LargeIntegerLessThan(LOffset, scp->length))
2754 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2755 userp, &req, &lockp);
2756 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2757 /* Put on waiting list */
2758 waitingLock = malloc(sizeof(smb_waitingLock_t));
2759 waitingLock->vcp = vcp;
2760 waitingLock->inp = smb_CopyPacket(inp);
2761 waitingLock->outp = smb_CopyPacket(outp);
2762 waitingLock->timeRemaining = Timeout;
2763 waitingLock->lockp = lockp;
2764 lock_ObtainWrite(&smb_globalLock);
2765 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2767 osi_Wakeup((long) &smb_allWaitingLocks);
2768 lock_ReleaseWrite(&smb_globalLock);
2769 /* don't send reply immediately */
2770 outp->flags |= SMB_PACKETFLAG_NOSEND;
2776 /* release any locks acquired before the failure */
2779 smb_SetSMBDataLength(outp, 0);
2781 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2783 lock_ReleaseMutex(&scp->mx);
2784 cm_ReleaseUser(userp);
2785 smb_ReleaseFID(fidp);
2790 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2802 fid = smb_GetSMBParm(inp, 0);
2803 fid = smb_ChainFID(fid, inp);
2805 fidp = smb_FindFID(vcp, fid, 0);
2806 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2807 return CM_ERROR_BADFD;
2810 userp = smb_GetUser(vcp, inp);
2814 /* otherwise, stat the file */
2815 lock_ObtainMutex(&scp->mx);
2816 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2817 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2818 if (code) goto done;
2820 /* decode times. We need a search time, but the response to this
2821 * call provides the date first, not the time, as returned in the
2822 * searchTime variable. So we take the high-order bits first.
2824 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2825 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2826 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2827 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2828 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2829 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2830 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2832 /* now handle file size and allocation size */
2833 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2834 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2835 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2836 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2838 /* file attribute */
2839 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2841 /* and finalize stuff */
2842 smb_SetSMBDataLength(outp, 0);
2846 lock_ReleaseMutex(&scp->mx);
2847 cm_ReleaseUser(userp);
2848 smb_ReleaseFID(fidp);
2852 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2866 fid = smb_GetSMBParm(inp, 0);
2867 fid = smb_ChainFID(fid, inp);
2869 fidp = smb_FindFID(vcp, fid, 0);
2870 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2871 return CM_ERROR_BADFD;
2874 userp = smb_GetUser(vcp, inp);
2878 /* now prepare to call cm_setattr. This message only sets various times,
2879 * and AFS only implements mtime, and we'll set the mtime if that's
2880 * requested. The others we'll ignore.
2882 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2884 if (searchTime != 0) {
2885 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2886 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2887 attrs.clientModTime = unixTime;
2888 code = cm_SetAttr(scp, &attrs, userp, &req);
2892 cm_ReleaseUser(userp);
2893 smb_ReleaseFID(fidp);
2898 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2901 long count, finalCount;
2908 fd = smb_GetSMBParm(inp, 2);
2909 count = smb_GetSMBParm(inp, 5);
2910 offset.HighPart = 0; /* too bad */
2911 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
2913 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
2914 fd, offset.LowPart, count);
2916 fd = smb_ChainFID(fd, inp);
2917 fidp = smb_FindFID(vcp, fd, 0);
2919 return CM_ERROR_BADFD;
2921 /* set inp->fid so that later read calls in same msg can find fid */
2924 if (fidp->flags & SMB_FID_IOCTL) {
2925 return smb_IoctlV3Read(fidp, vcp, inp, outp);
2928 userp = smb_GetUser(vcp, inp);
2930 /* 0 and 1 are reserved for request chaining, were setup by our caller,
2931 * and will be further filled in after we return.
2933 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
2934 smb_SetSMBParm(outp, 3, 0); /* resvd */
2935 smb_SetSMBParm(outp, 4, 0); /* resvd */
2936 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
2937 /* fill in #6 when we have all the parameters' space reserved */
2938 smb_SetSMBParm(outp, 7, 0); /* resv'd */
2939 smb_SetSMBParm(outp, 8, 0); /* resv'd */
2940 smb_SetSMBParm(outp, 9, 0); /* resv'd */
2941 smb_SetSMBParm(outp, 10, 0); /* resv'd */
2942 smb_SetSMBParm(outp, 11, 0); /* reserved */
2944 /* get op ptr after putting in the parms, since otherwise we don't
2945 * know where the data really is.
2947 op = smb_GetSMBData(outp, NULL);
2949 /* now fill in offset from start of SMB header to first data byte (to op) */
2950 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
2952 /* set the packet data length the count of the # of bytes */
2953 smb_SetSMBDataLength(outp, count);
2956 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
2958 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
2961 /* fix some things up */
2962 smb_SetSMBParm(outp, 5, finalCount);
2963 smb_SetSMBDataLength(outp, finalCount);
2965 smb_ReleaseFID(fidp);
2967 cm_ReleaseUser(userp);
2972 * Values for createDisp, copied from NTDDK.H
2974 * FILE_SUPERSEDE 0 (???)
2975 * FILE_OPEN 1 (open)
2976 * FILE_CREATE 2 (exclusive)
2977 * FILE_OPEN_IF 3 (non-exclusive)
2978 * FILE_OVERWRITE 4 (open & truncate, but do not create)
2979 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
2982 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2984 char *pathp, *realPathp;
2988 cm_scache_t *dscp; /* parent dir */
2989 cm_scache_t *scp; /* file to create or open */
2992 unsigned short nameLength;
2994 unsigned int requestOpLock;
2995 unsigned int requestBatchOpLock;
2996 unsigned int mustBeDir;
2998 unsigned int desiredAccess;
2999 unsigned int extAttributes;
3000 unsigned int createDisp;
3001 unsigned int createOptions;
3002 int initialModeBits;
3003 unsigned short baseFid;
3004 smb_fid_t *baseFidp;
3006 cm_scache_t *baseDirp;
3007 unsigned short openAction;
3021 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3022 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3023 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3024 requestOpLock = flags & 0x02;
3025 requestBatchOpLock = flags & 0x04;
3026 mustBeDir = flags & 0x08;
3029 * Why all of a sudden 32-bit FID?
3030 * We will reject all bits higher than 16.
3032 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3033 return CM_ERROR_INVAL;
3034 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3035 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3036 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3037 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3038 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3039 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3040 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3041 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3042 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3044 /* mustBeDir is never set; createOptions directory bit seems to be
3047 if (createOptions & 1)
3049 else if (createOptions & 0x40)
3055 * compute initial mode bits based on read-only flag in
3056 * extended attributes
3058 initialModeBits = 0666;
3059 if (extAttributes & 1) initialModeBits &= ~0222;
3061 pathp = smb_GetSMBData(inp, NULL);
3062 /* Sometimes path is not null-terminated, so we make a copy. */
3063 realPathp = malloc(nameLength+1);
3064 memcpy(realPathp, pathp, nameLength);
3065 realPathp[nameLength] = 0;
3067 spacep = inp->spacep;
3068 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3070 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3071 /* special case magic file name for receiving IOCTL requests
3072 * (since IOCTL calls themselves aren't getting through).
3074 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3075 smb_SetupIoctlFid(fidp, spacep);
3077 /* set inp->fid so that later read calls in same msg can find fid */
3078 inp->fid = fidp->fid;
3082 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3083 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3084 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3086 memset(&ft, 0, sizeof(ft));
3087 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3088 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3089 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3090 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3091 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3092 sz.HighPart = 0x7fff; sz.LowPart = 0;
3093 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3094 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3095 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3096 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3097 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3098 smb_SetSMBDataLength(outp, 0);
3100 /* clean up fid reference */
3101 smb_ReleaseFID(fidp);
3106 userp = smb_GetUser(vcp, inp);
3109 baseDirp = cm_rootSCachep;
3110 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3113 baseFidp = smb_FindFID(vcp, baseFid, 0);
3114 baseDirp = baseFidp->scp;
3118 /* compute open mode */
3120 if (desiredAccess & DELETE)
3121 fidflags |= SMB_FID_OPENDELETE;
3122 if (desiredAccess & AFS_ACCESS_READ)
3123 fidflags |= SMB_FID_OPENREAD;
3124 if (desiredAccess & AFS_ACCESS_WRITE)
3125 fidflags |= SMB_FID_OPENWRITE;
3129 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3130 userp, tidPathp, &req, &scp);
3131 if (code == 0) foundscp = TRUE;
3133 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3134 /* look up parent directory */
3135 code = cm_NameI(baseDirp, spacep->data,
3136 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3137 userp, tidPathp, &req, &dscp);
3139 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3142 cm_ReleaseUser(userp);
3147 if (!lastNamep) lastNamep = realPathp;
3150 if (!smb_IsLegalFilename(lastNamep))
3151 return CM_ERROR_BADNTFILENAME;
3154 code = cm_Lookup(dscp, lastNamep,
3155 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3157 if (code && code != CM_ERROR_NOSUCHFILE) {
3158 cm_ReleaseSCache(dscp);
3159 cm_ReleaseUser(userp);
3166 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3169 /* if we get here, if code is 0, the file exists and is represented by
3170 * scp. Otherwise, we have to create it. The dir may be represented
3171 * by dscp, or we may have found the file directly. If code is non-zero,
3175 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3178 if (dscp) cm_ReleaseSCache(dscp);
3179 cm_ReleaseSCache(scp);
3180 cm_ReleaseUser(userp);
3185 if (createDisp == 2) {
3186 /* oops, file shouldn't be there */
3187 if (dscp) cm_ReleaseSCache(dscp);
3188 cm_ReleaseSCache(scp);
3189 cm_ReleaseUser(userp);
3191 return CM_ERROR_EXISTS;
3195 || createDisp == 5) {
3196 setAttr.mask = CM_ATTRMASK_LENGTH;
3197 setAttr.length.LowPart = 0;
3198 setAttr.length.HighPart = 0;
3199 code = cm_SetAttr(scp, &setAttr, userp, &req);
3200 openAction = 3; /* truncated existing file */
3202 else openAction = 1; /* found existing file */
3204 else if (createDisp == 1 || createDisp == 4) {
3205 /* don't create if not found */
3206 if (dscp) cm_ReleaseSCache(dscp);
3207 cm_ReleaseUser(userp);
3209 return CM_ERROR_NOSUCHFILE;
3211 else if (realDirFlag == 0 || realDirFlag == -1) {
3212 osi_assert(dscp != NULL);
3213 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3214 osi_LogSaveString(afsd_logp, lastNamep));
3215 openAction = 2; /* created file */
3216 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3217 setAttr.clientModTime = time(NULL);
3218 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3220 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3221 smb_NotifyChange(FILE_ACTION_ADDED,
3222 FILE_NOTIFY_CHANGE_FILE_NAME,
3223 dscp, lastNamep, NULL, TRUE);
3224 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3225 /* Not an exclusive create, and someone else tried
3226 * creating it already, then we open it anyway. We
3227 * don't bother retrying after this, since if this next
3228 * fails, that means that the file was deleted after we
3229 * started this call.
3231 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3234 if (createDisp == 5) {
3235 setAttr.mask = CM_ATTRMASK_LENGTH;
3236 setAttr.length.LowPart = 0;
3237 setAttr.length.HighPart = 0;
3238 code = cm_SetAttr(scp, &setAttr, userp,
3241 } /* lookup succeeded */
3245 /* create directory */
3246 osi_assert(dscp != NULL);
3247 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory %s",
3248 osi_LogSaveString(afsd_logp, lastNamep));
3249 openAction = 2; /* created directory */
3250 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3251 setAttr.clientModTime = time(NULL);
3252 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3253 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3254 smb_NotifyChange(FILE_ACTION_ADDED,
3255 FILE_NOTIFY_CHANGE_DIR_NAME,
3256 dscp, lastNamep, NULL, TRUE);
3258 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3259 /* Not an exclusive create, and someone else tried
3260 * creating it already, then we open it anyway. We
3261 * don't bother retrying after this, since if this next
3262 * fails, that means that the file was deleted after we
3263 * started this call.
3265 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3271 /* something went wrong creating or truncating the file */
3272 if (scp) cm_ReleaseSCache(scp);
3273 cm_ReleaseUser(userp);
3278 /* make sure we have file vs. dir right */
3279 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3280 cm_ReleaseSCache(scp);
3281 cm_ReleaseUser(userp);
3283 return CM_ERROR_ISDIR;
3285 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3286 cm_ReleaseSCache(scp);
3287 cm_ReleaseUser(userp);
3289 return CM_ERROR_NOTDIR;
3292 /* open the file itself */
3293 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3295 /* save a pointer to the vnode */
3298 fidp->flags = fidflags;
3300 /* save parent dir and pathname for delete or change notification */
3301 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3302 fidp->flags |= SMB_FID_NTOPEN;
3303 fidp->NTopen_dscp = dscp;
3304 cm_HoldSCache(dscp);
3305 fidp->NTopen_pathp = strdup(lastNamep);
3307 fidp->NTopen_wholepathp = realPathp;
3309 /* we don't need this any longer */
3310 if (dscp) cm_ReleaseSCache(dscp);
3311 cm_Open(scp, 0, userp);
3313 /* set inp->fid so that later read calls in same msg can find fid */
3314 inp->fid = fidp->fid;
3318 lock_ObtainMutex(&scp->mx);
3319 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3320 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3321 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3322 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3323 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3324 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3325 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3326 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3327 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3329 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3330 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3331 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3332 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3333 smb_SetSMBParmByte(outp, parmSlot,
3334 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3335 lock_ReleaseMutex(&scp->mx);
3336 smb_SetSMBDataLength(outp, 0);
3338 osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3339 osi_LogSaveString(afsd_logp, realPathp));
3341 smb_ReleaseFID(fidp);
3343 cm_ReleaseUser(userp);
3345 /* leave scp held since we put it in fidp->scp */
3350 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3351 * Instead, ultimately, would like to use a subroutine for common code.
3353 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3355 char *pathp, *realPathp;
3359 cm_scache_t *dscp; /* parent dir */
3360 cm_scache_t *scp; /* file to create or open */
3363 unsigned long nameLength;
3365 unsigned int requestOpLock;
3366 unsigned int requestBatchOpLock;
3367 unsigned int mustBeDir;
3369 unsigned int desiredAccess;
3370 unsigned int extAttributes;
3371 unsigned int createDisp;
3372 unsigned int createOptions;
3373 int initialModeBits;
3374 unsigned short baseFid;
3375 smb_fid_t *baseFidp;
3377 cm_scache_t *baseDirp;
3378 unsigned short openAction;
3384 int parmOffset, dataOffset;
3395 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3396 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3397 parmp = inp->data + parmOffset;
3398 lparmp = (ULONG *) parmp;
3401 requestOpLock = flags & 0x02;
3402 requestBatchOpLock = flags & 0x04;
3403 mustBeDir = flags & 0x08;
3405 * Why all of a sudden 32-bit FID?
3406 * We will reject all bits higher than 16.
3408 if (lparmp[1] & 0xFFFF0000)
3409 return CM_ERROR_INVAL;
3410 baseFid = (unsigned short)lparmp[1];
3411 desiredAccess = lparmp[2];
3412 extAttributes = lparmp[5];
3413 createDisp = lparmp[7];
3414 createOptions = lparmp[8];
3415 nameLength = lparmp[11];
3417 /* mustBeDir is never set; createOptions directory bit seems to be
3420 if (createOptions & 1)
3422 else if (createOptions & 0x40)
3428 * compute initial mode bits based on read-only flag in
3429 * extended attributes
3431 initialModeBits = 0666;
3432 if (extAttributes & 1) initialModeBits &= ~0222;
3434 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3435 /* Sometimes path is not null-terminated, so we make a copy. */
3436 realPathp = malloc(nameLength+1);
3437 memcpy(realPathp, pathp, nameLength);
3438 realPathp[nameLength] = 0;
3440 spacep = cm_GetSpace();
3441 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3444 * Nothing here to handle SMB_IOCTL_FILENAME.
3445 * Will add it if necessary.
3448 userp = smb_GetUser(vcp, inp);
3451 baseDirp = cm_rootSCachep;
3452 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3455 baseFidp = smb_FindFID(vcp, baseFid, 0);
3456 baseDirp = baseFidp->scp;
3460 /* compute open mode */
3462 if (desiredAccess & DELETE)
3463 fidflags |= SMB_FID_OPENDELETE;
3464 if (desiredAccess & AFS_ACCESS_READ)
3465 fidflags |= SMB_FID_OPENREAD;
3466 if (desiredAccess & AFS_ACCESS_WRITE)
3467 fidflags |= SMB_FID_OPENWRITE;
3471 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3472 userp, tidPathp, &req, &scp);
3473 if (code == 0) foundscp = TRUE;
3475 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3476 /* look up parent directory */
3477 code = cm_NameI(baseDirp, spacep->data,
3478 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3479 userp, tidPathp, &req, &dscp);
3480 cm_FreeSpace(spacep);
3482 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3485 cm_ReleaseUser(userp);
3490 if (!lastNamep) lastNamep = realPathp;
3493 if (!smb_IsLegalFilename(lastNamep))
3494 return CM_ERROR_BADNTFILENAME;
3497 code = cm_Lookup(dscp, lastNamep,
3498 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3500 if (code && code != CM_ERROR_NOSUCHFILE) {
3501 cm_ReleaseSCache(dscp);
3502 cm_ReleaseUser(userp);
3509 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3510 cm_FreeSpace(spacep);
3513 /* if we get here, if code is 0, the file exists and is represented by
3514 * scp. Otherwise, we have to create it. The dir may be represented
3515 * by dscp, or we may have found the file directly. If code is non-zero,
3519 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3522 if (dscp) cm_ReleaseSCache(dscp);
3523 cm_ReleaseSCache(scp);
3524 cm_ReleaseUser(userp);
3529 if (createDisp == 2) {
3530 /* oops, file shouldn't be there */
3531 if (dscp) cm_ReleaseSCache(dscp);
3532 cm_ReleaseSCache(scp);
3533 cm_ReleaseUser(userp);
3535 return CM_ERROR_EXISTS;
3539 || createDisp == 5) {
3540 setAttr.mask = CM_ATTRMASK_LENGTH;
3541 setAttr.length.LowPart = 0;
3542 setAttr.length.HighPart = 0;
3543 code = cm_SetAttr(scp, &setAttr, userp, &req);
3544 openAction = 3; /* truncated existing file */
3546 else openAction = 1; /* found existing file */
3548 else if (createDisp == 1 || createDisp == 4) {
3549 /* don't create if not found */
3550 if (dscp) cm_ReleaseSCache(dscp);
3551 cm_ReleaseUser(userp);
3553 return CM_ERROR_NOSUCHFILE;
3555 else if (realDirFlag == 0 || realDirFlag == -1) {
3556 osi_assert(dscp != NULL);
3557 osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
3558 osi_LogSaveString(afsd_logp, lastNamep));
3559 openAction = 2; /* created file */
3560 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3561 setAttr.clientModTime = time(NULL);
3562 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3564 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3565 smb_NotifyChange(FILE_ACTION_ADDED,
3566 FILE_NOTIFY_CHANGE_FILE_NAME,
3567 dscp, lastNamep, NULL, TRUE);
3568 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3569 /* Not an exclusive create, and someone else tried
3570 * creating it already, then we open it anyway. We
3571 * don't bother retrying after this, since if this next
3572 * fails, that means that the file was deleted after we
3573 * started this call.
3575 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3578 if (createDisp == 5) {
3579 setAttr.mask = CM_ATTRMASK_LENGTH;
3580 setAttr.length.LowPart = 0;
3581 setAttr.length.HighPart = 0;
3582 code = cm_SetAttr(scp, &setAttr, userp,
3585 } /* lookup succeeded */
3589 /* create directory */
3590 osi_assert(dscp != NULL);
3592 "smb_ReceiveNTTranCreate creating directory %s",
3593 osi_LogSaveString(afsd_logp, lastNamep));
3594 openAction = 2; /* created directory */
3595 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3596 setAttr.clientModTime = time(NULL);
3597 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3598 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3599 smb_NotifyChange(FILE_ACTION_ADDED,
3600 FILE_NOTIFY_CHANGE_DIR_NAME,
3601 dscp, lastNamep, NULL, TRUE);
3603 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3604 /* Not an exclusive create, and someone else tried
3605 * creating it already, then we open it anyway. We
3606 * don't bother retrying after this, since if this next
3607 * fails, that means that the file was deleted after we
3608 * started this call.
3610 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3616 /* something went wrong creating or truncating the file */
3617 if (scp) cm_ReleaseSCache(scp);
3618 cm_ReleaseUser(userp);
3623 /* make sure we have file vs. dir right */
3624 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3625 cm_ReleaseSCache(scp);
3626 cm_ReleaseUser(userp);
3628 return CM_ERROR_ISDIR;
3630 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3631 cm_ReleaseSCache(scp);
3632 cm_ReleaseUser(userp);
3634 return CM_ERROR_NOTDIR;
3637 /* open the file itself */
3638 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3641 /* save a pointer to the vnode */
3644 fidp->flags = fidflags;
3646 /* save parent dir and pathname for deletion or change notification */
3647 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3648 fidp->flags |= SMB_FID_NTOPEN;
3649 fidp->NTopen_dscp = dscp;
3650 cm_HoldSCache(dscp);
3651 fidp->NTopen_pathp = strdup(lastNamep);
3653 fidp->NTopen_wholepathp = realPathp;
3655 /* we don't need this any longer */
3656 if (dscp) cm_ReleaseSCache(dscp);
3658 cm_Open(scp, 0, userp);
3660 /* set inp->fid so that later read calls in same msg can find fid */
3661 inp->fid = fidp->fid;
3664 parmOffset = 8*4 + 39;
3665 parmOffset += 1; /* pad to 4 */
3666 dataOffset = parmOffset + 70;
3670 /* Total Parameter Count */
3671 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3672 /* Total Data Count */
3673 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3674 /* Parameter Count */
3675 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3676 /* Parameter Offset */
3677 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3678 /* Parameter Displacement */
3679 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3681 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3683 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3684 /* Data Displacement */
3685 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3686 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3687 smb_SetSMBDataLength(outp, 70);
3689 lock_ObtainMutex(&scp->mx);
3690 outData = smb_GetSMBData(outp, NULL);
3691 outData++; /* round to get to parmOffset */
3692 *outData = 0; outData++; /* oplock */
3693 *outData = 0; outData++; /* reserved */
3694 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
3695 *((ULONG *)outData) = openAction; outData += 4;
3696 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
3697 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3698 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
3699 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
3700 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
3701 *((FILETIME *)outData) = ft; outData += 8; /* change time */
3702 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
3703 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
3704 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
3705 *((USHORT *)outData) = 0; outData += 2; /* filetype */
3706 *((USHORT *)outData) = 0; outData += 2; /* dev state */
3707 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
3708 outData += 2; /* is a dir? */
3709 lock_ReleaseMutex(&scp->mx);
3711 osi_Log1(afsd_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
3713 smb_ReleaseFID(fidp);
3715 cm_ReleaseUser(userp);
3717 /* leave scp held since we put it in fidp->scp */
3721 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
3724 smb_packet_t *savedPacketp;
3725 ULONG filter; USHORT fid, watchtree;
3729 filter = smb_GetSMBParm(inp, 19)
3730 | (smb_GetSMBParm(inp, 20) << 16);
3731 fid = smb_GetSMBParm(inp, 21);
3732 watchtree = smb_GetSMBParm(inp, 22) && 0xffff;
3734 savedPacketp = smb_CopyPacket(inp);
3735 savedPacketp->vcp = vcp;
3736 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3737 savedPacketp->nextp = smb_Directory_Watches;
3738 smb_Directory_Watches = savedPacketp;
3739 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
3741 fidp = smb_FindFID(vcp, fid, 0);
3743 osi_Log4(afsd_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
3744 filter, fid, watchtree, osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
3747 lock_ObtainMutex(&scp->mx);
3749 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
3751 scp->flags |= CM_SCACHEFLAG_WATCHED;
3752 lock_ReleaseMutex(&scp->mx);
3753 smb_ReleaseFID(fidp);
3755 outp->flags |= SMB_PACKETFLAG_NOSEND;
3760 unsigned char nullSecurityDesc[36] = {
3761 0x01, /* security descriptor revision */
3762 0x00, /* reserved, should be zero */
3763 0x00, 0x80, /* security descriptor control;
3764 * 0x8000 : self-relative format */
3765 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
3766 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
3767 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
3768 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
3769 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3770 /* "null SID" owner SID */
3771 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3772 /* "null SID" group SID */
3775 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3777 int parmOffset, parmCount, dataOffset, dataCount;
3785 ULONG securityInformation;
3787 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3788 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3789 parmp = inp->data + parmOffset;
3790 sparmp = (USHORT *) parmp;
3791 lparmp = (ULONG *) parmp;
3794 securityInformation = lparmp[1];
3796 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
3797 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3805 parmOffset = 8*4 + 39;
3806 parmOffset += 1; /* pad to 4 */
3808 dataOffset = parmOffset + parmCount;
3812 /* Total Parameter Count */
3813 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3814 /* Total Data Count */
3815 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3816 /* Parameter Count */
3817 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
3818 /* Parameter Offset */
3819 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3820 /* Parameter Displacement */
3821 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3823 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
3825 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3826 /* Data Displacement */
3827 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3828 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3829 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
3831 outData = smb_GetSMBData(outp, NULL);
3832 outData++; /* round to get to parmOffset */
3833 *((ULONG *)outData) = 36; outData += 4; /* length */
3835 if (maxData >= 36) {
3836 memcpy(outData, nullSecurityDesc, 36);
3840 return CM_ERROR_BUFFERTOOSMALL;
3843 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3845 unsigned short function;
3847 function = smb_GetSMBParm(inp, 18);
3849 osi_Log1(afsd_logp, "SMB NT Transact function %d", function);
3851 /* We can handle long names */
3852 if (vcp->flags & SMB_VCFLAG_USENT)
3853 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3857 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
3859 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
3861 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
3863 default: return CM_ERROR_INVAL;
3868 * smb_NotifyChange -- find relevant change notification messages and
3871 * If we don't know the file name (i.e. a callback break), filename is
3872 * NULL, and we return a zero-length list.
3874 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
3875 cm_scache_t *dscp, char *filename, char *otherFilename,
3876 BOOL isDirectParent)
3878 smb_packet_t *watch, *lastWatch, *nextWatch;
3879 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
3880 char *outData, *oldOutData;
3884 BOOL twoEntries = FALSE;
3885 ULONG otherNameLen, oldParmCount = 0;
3890 /* Get ready for rename within directory */
3891 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
3893 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
3896 lock_ObtainMutex(&smb_Dir_Watch_Lock);
3897 watch = smb_Directory_Watches;
3899 filter = smb_GetSMBParm(watch, 19)
3900 | (smb_GetSMBParm(watch, 20) << 16);
3901 fid = smb_GetSMBParm(watch, 21);
3902 wtree = smb_GetSMBParm(watch, 22) & 0xffff;
3903 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
3904 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
3908 * Strange hack - bug in NT Client and NT Server that we
3911 if (filter == 3 && wtree)
3914 fidp = smb_FindFID(vcp, fid, 0);
3915 if (fidp->scp != dscp
3916 || (filter & notifyFilter) == 0
3917 || (!isDirectParent && !wtree)) {
3918 smb_ReleaseFID(fidp);
3920 watch = watch->nextp;
3923 smb_ReleaseFID(fidp);
3926 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
3927 fid, filter, wtree, osi_LogSaveString(afsd_logp, filename));
3929 nextWatch = watch->nextp;
3930 if (watch == smb_Directory_Watches)
3931 smb_Directory_Watches = nextWatch;
3933 lastWatch->nextp = nextWatch;
3935 /* Turn off WATCHED flag in dscp */
3936 lock_ObtainMutex(&dscp->mx);
3938 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
3940 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
3941 lock_ReleaseMutex(&dscp->mx);
3943 /* Convert to response packet */
3944 ((smb_t *) watch)->reb = 0x80;
3945 ((smb_t *) watch)->wct = 0;
3948 if (filename == NULL)
3951 nameLen = strlen(filename);
3952 parmCount = 3*4 + nameLen*2;
3953 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3955 otherNameLen = strlen(otherFilename);
3956 oldParmCount = parmCount;
3957 parmCount += 3*4 + otherNameLen*2;
3958 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
3960 if (maxLen < parmCount)
3961 parmCount = 0; /* not enough room */
3963 parmOffset = 8*4 + 39;
3964 parmOffset += 1; /* pad to 4 */
3965 dataOffset = parmOffset + parmCount;
3969 /* Total Parameter Count */
3970 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
3971 /* Total Data Count */
3972 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3973 /* Parameter Count */
3974 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
3975 /* Parameter Offset */
3976 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
3977 /* Parameter Displacement */
3978 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3980 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3982 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
3983 /* Data Displacement */
3984 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
3985 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
3986 smb_SetSMBDataLength(watch, parmCount + 1);
3988 if (parmCount != 0) {
3989 outData = smb_GetSMBData(watch, NULL);
3990 outData++; /* round to get to parmOffset */
3991 oldOutData = outData;
3992 *((DWORD *)outData) = oldParmCount; outData += 4;
3993 /* Next Entry Offset */
3994 *((DWORD *)outData) = action; outData += 4;
3996 *((DWORD *)outData) = nameLen*2; outData += 4;
3997 /* File Name Length */
3998 mbstowcs((WCHAR *)outData, filename, nameLen);
4001 outData = oldOutData + oldParmCount;
4002 *((DWORD *)outData) = 0; outData += 4;
4003 /* Next Entry Offset */
4004 *((DWORD *)outData) = otherAction; outData += 4;
4006 *((DWORD *)outData) = otherNameLen*2;
4007 outData += 4; /* File Name Length */
4008 mbstowcs((WCHAR *)outData, otherFilename,
4009 otherNameLen); /* File Name */
4014 * If filename is null, we don't know the cause of the
4015 * change notification. We return zero data (see above),
4016 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4017 * (= 0x010C). We set the error code here by hand, without
4018 * modifying wct and bcc.
4020 if (filename == NULL) {
4021 ((smb_t *) watch)->rcls = 0x0C;
4022 ((smb_t *) watch)->reh = 0x01;
4023 ((smb_t *) watch)->errLow = 0;
4024 ((smb_t *) watch)->errHigh = 0;
4025 /* Set NT Status codes flag */
4026 ((smb_t *) watch)->flg2 |= 0x4000;
4029 smb_SendPacket(vcp, watch);
4030 smb_FreePacket(watch);
4033 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4036 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4038 unsigned char *replyWctp;
4039 smb_packet_t *watch, *lastWatch;
4040 USHORT fid, watchtree;
4044 osi_Log0(afsd_logp, "SMB3 receive NT cancel");
4046 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4047 watch = smb_Directory_Watches;
4049 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4050 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4051 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4052 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4053 if (watch == smb_Directory_Watches)
4054 smb_Directory_Watches = watch->nextp;
4056 lastWatch->nextp = watch->nextp;
4057 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4059 /* Turn off WATCHED flag in scp */
4060 fid = smb_GetSMBParm(watch, 21);
4061 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4063 fidp = smb_FindFID(vcp, fid, 0);
4065 osi_Log3(afsd_logp, "Cancelling change notification for fid %d wtree %d file %s",
4067 osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
4070 lock_ObtainMutex(&scp->mx);
4072 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4074 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4075 lock_ReleaseMutex(&scp->mx);
4076 smb_ReleaseFID(fidp);
4078 /* assume STATUS32; return 0xC0000120 (CANCELED) */
4079 replyWctp = watch->wctp;
4083 ((smb_t *)watch)->rcls = 0x20;
4084 ((smb_t *)watch)->reh = 0x1;
4085 ((smb_t *)watch)->errLow = 0;
4086 ((smb_t *)watch)->errHigh = 0xC0;
4087 ((smb_t *)watch)->flg2 |= 0x4000;
4088 smb_SendPacket(vcp, watch);
4089 smb_FreePacket(watch);
4093 watch = watch->nextp;
4095 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4102 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4105 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4109 smb_username_t *unp;
4111 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4113 lock_ObtainMutex(&unp->mx);
4114 unp->userp = cm_NewUser();
4115 lock_ReleaseMutex(&unp->mx);
4116 osi_LogEvent("AFS smb_FindCMUserByName New User",NULL,"name[%s] machine[%s]",usern,machine);
4118 osi_LogEvent("AFS smb_FindCMUserByName Found",NULL,"name[%s] machine[%s]",usern,machine);