2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
28 extern osi_hyper_t hzero;
30 smb_packet_t *smb_Directory_Watches = NULL;
31 osi_mutex_t smb_Dir_Watch_Lock;
33 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
35 /* protected by the smb_globalLock */
36 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
38 /* retrieve a held reference to a user structure corresponding to an incoming
40 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
45 uidp = smb_FindUID(vcp, inp->uid, 0);
46 if (!uidp) return NULL;
48 lock_ObtainMutex(&uidp->mx);
50 up = uidp->unp->userp;
53 lock_ReleaseMutex(&uidp->mx);
61 * Return extended attributes.
62 * Right now, we aren't using any of the "new" bits, so this looks exactly
63 * like smb_Attributes() (see smb.c).
65 unsigned long smb_ExtAttributes(cm_scache_t *scp)
69 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
70 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
71 attrs = SMB_ATTR_DIRECTORY;
75 * We used to mark a file RO if it was in an RO volume, but that
76 * turns out to be impolitic in NT. See defect 10007.
79 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
81 if ((scp->unixModeBits & 0222) == 0)
82 attrs |= SMB_ATTR_READONLY; /* Read-only */
85 attrs = SMB_ATTR_NORMAL; /* FILE_ATTRIBUTE_NORMAL */
90 int smb_V3IsStarMask(char *maskp)
95 if (tc == '?' || tc == '*')
100 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
103 /* skip over null-terminated string */
104 *chainpp = inp + strlen(inp) + 1;
109 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
112 char *usern, *pwd, *pwdx;
114 unsigned short newUid;
120 /* Check for bad conns */
121 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
122 return CM_ERROR_REMOTECONN;
124 /* For NT LM 0.12 and up, get capabilities */
125 if (vcp->flags & SMB_VCFLAG_USENT) {
126 caps = smb_GetSMBParm(inp, 11);
128 vcp->flags |= SMB_VCFLAG_STATUS32;
129 /* for now, ignore other capability bits */
133 tp = smb_GetSMBData(inp, NULL);
134 if (vcp->flags & SMB_VCFLAG_USENT)
135 pwdx = smb_ParseString(tp, &tp);
136 pwd = smb_ParseString(tp, &tp);
137 usern = smb_ParseString(tp, &tp);
139 /* On Windows 2000, this function appears to be called more often than
140 it is expected to be called. This resulted in multiple smb_user_t
141 records existing all for the same user session which results in all
142 of the users tokens disappearing.
144 To avoid this problem, we look for an existing smb_user_t record
145 based on the users name, and use that one if we find it.
148 uidp = smb_FindUserByNameThisSession(vcp, usern);
149 if (uidp) { /* already there, so don't create a new one */
152 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
153 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
154 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
155 smb_ReleaseUID(uidp);
158 /* do a global search for the username/machine name pair */
159 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
161 /* Create a new UID and cm_user_t structure */
164 userp = cm_NewUser();
165 lock_ObtainMutex(&vcp->mx);
166 if (!vcp->uidCounter)
167 vcp->uidCounter++; /* handle unlikely wraparounds */
168 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
169 lock_ReleaseMutex(&vcp->mx);
171 /* Create a new smb_user_t structure and connect them up */
172 lock_ObtainMutex(&unp->mx);
174 lock_ReleaseMutex(&unp->mx);
176 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
177 lock_ObtainMutex(&uidp->mx);
179 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,usern);
180 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
181 lock_ReleaseMutex(&uidp->mx);
182 smb_ReleaseUID(uidp);
185 /* Return UID to the client */
186 ((smb_t *)outp)->uid = newUid;
187 /* Also to the next chained message */
188 ((smb_t *)inp)->uid = newUid;
190 osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
191 osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
192 smb_SetSMBParm(outp, 2, 0);
193 smb_SetSMBDataLength(outp, 0);
197 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
201 /* don't get tokens from this VC */
202 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
204 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
206 /* find the tree and free it */
207 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
208 /* TODO: smb_ReleaseUID() ? */
210 char *s1 = NULL, *s2 = NULL;
212 if (s2 == NULL) s2 = " ";
213 if (s1 == NULL) {s1 = s2; s2 = " ";}
215 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s",
217 osi_LogSaveString(smb_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(smb_logp, "SMB3 user logoffX");
231 smb_SetSMBDataLength(outp, 0);
235 #define SMB_SUPPORT_SEARCH_BITS 0x0001
237 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
240 unsigned short newTid;
250 osi_Log0(smb_logp, "SMB3 receive tree connect");
252 /* parse input parameters */
253 tp = smb_GetSMBData(inp, NULL);
254 passwordp = smb_ParseString(tp, &tp);
255 pathp = smb_ParseString(tp, &tp);
256 servicep = smb_ParseString(tp, &tp);
258 tp = strrchr(pathp, '\\');
260 return CM_ERROR_BADSMB;
262 strcpy(shareName, tp+1);
264 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
265 return CM_ERROR_NOIPC;
267 userp = smb_GetUser(vcp, inp);
269 lock_ObtainMutex(&vcp->mx);
270 newTid = vcp->tidCounter++;
271 lock_ReleaseMutex(&vcp->mx);
273 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
274 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
276 smb_ReleaseTID(tidp);
277 return CM_ERROR_BADSHARENAME;
279 lock_ObtainMutex(&tidp->mx);
281 tidp->pathname = sharePath;
282 lock_ReleaseMutex(&tidp->mx);
283 smb_ReleaseTID(tidp);
285 if (vcp->flags & SMB_VCFLAG_USENT)
287 int policy = smb_FindShareCSCPolicy(shareName);
288 smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
291 ((smb_t *)outp)->tid = newTid;
292 ((smb_t *)inp)->tid = newTid;
293 tp = smb_GetSMBData(outp, NULL);
297 smb_SetSMBDataLength(outp, 3);
299 osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
303 /* must be called with global tran lock held */
304 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
306 smb_tran2Packet_t *tp;
309 smbp = (smb_t *) inp->data;
310 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
311 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
317 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
318 int totalParms, int totalData)
320 smb_tran2Packet_t *tp;
323 smbp = (smb_t *) inp->data;
324 tp = malloc(sizeof(*tp));
325 memset(tp, 0, sizeof(*tp));
328 tp->curData = tp->curParms = 0;
329 tp->totalData = totalData;
330 tp->totalParms = totalParms;
335 tp->res[0] = smbp->res[0];
336 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
337 tp->opcode = smb_GetSMBParm(inp, 14);
339 tp->parmsp = malloc(totalParms);
341 tp->datap = malloc(totalData);
342 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
346 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
347 smb_tran2Packet_t *inp, smb_packet_t *outp,
348 int totalParms, int totalData)
350 smb_tran2Packet_t *tp;
351 unsigned short parmOffset;
352 unsigned short dataOffset;
353 unsigned short dataAlign;
355 tp = malloc(sizeof(*tp));
356 memset(tp, 0, sizeof(*tp));
358 tp->curData = tp->curParms = 0;
359 tp->totalData = totalData;
360 tp->totalParms = totalParms;
361 tp->oldTotalParms = totalParms;
366 tp->res[0] = inp->res[0];
367 tp->opcode = inp->opcode;
370 * We calculate where the parameters and data will start.
371 * This calculation must parallel the calculation in
372 * smb_SendTran2Packet.
375 parmOffset = 10*2 + 35;
376 parmOffset++; /* round to even */
377 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
379 dataOffset = parmOffset + totalParms;
380 dataAlign = dataOffset & 2; /* quad-align */
381 dataOffset += dataAlign;
382 tp->datap = outp->data + dataOffset;
387 /* free a tran2 packet; must be called with smb_globalLock held */
388 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
390 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
391 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
400 /* called with a VC, an input packet to respond to, and an error code.
401 * sends an error response.
403 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
404 smb_packet_t *tp, long code)
407 unsigned short errCode;
408 unsigned char errClass;
409 unsigned long NTStatus;
411 if (vcp->flags & SMB_VCFLAG_STATUS32)
412 smb_MapNTError(code, &NTStatus);
414 smb_MapCoreError(code, vcp, &errCode, &errClass);
416 smb_FormatResponsePacket(vcp, NULL, tp);
419 /* We can handle long names */
420 if (vcp->flags & SMB_VCFLAG_USENT)
421 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
423 /* now copy important fields from the tran 2 packet */
424 smbp->com = 0x32; /* tran 2 response */
425 smbp->tid = t2p->tid;
426 smbp->mid = t2p->mid;
427 smbp->pid = t2p->pid;
428 smbp->uid = t2p->uid;
429 smbp->res[0] = t2p->res[0];
430 if (vcp->flags & SMB_VCFLAG_STATUS32) {
431 smbp->rcls = (unsigned char) (NTStatus & 0xff);
432 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
433 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
434 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
435 smbp->flg2 |= 0x4000;
438 smbp->rcls = errClass;
439 smbp->errLow = (unsigned char) (errCode & 0xff);
440 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
444 smb_SendPacket(vcp, tp);
447 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
450 unsigned short parmOffset;
451 unsigned short dataOffset;
452 unsigned short totalLength;
453 unsigned short dataAlign;
456 smb_FormatResponsePacket(vcp, NULL, tp);
459 /* We can handle long names */
460 if (vcp->flags & SMB_VCFLAG_USENT)
461 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
463 /* now copy important fields from the tran 2 packet */
464 smbp->com = 0x32; /* tran 2 response */
465 smbp->tid = t2p->tid;
466 smbp->mid = t2p->mid;
467 smbp->pid = t2p->pid;
468 smbp->uid = t2p->uid;
469 smbp->res[0] = t2p->res[0];
471 totalLength = 1 + t2p->totalData + t2p->totalParms;
473 /* now add the core parameters (tran2 info) to the packet */
474 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
475 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
476 smb_SetSMBParm(tp, 2, 0); /* reserved */
477 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
478 parmOffset = 10*2 + 35; /* parm offset in packet */
479 parmOffset++; /* round to even */
480 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
481 * hdr, bcc and wct */
482 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
483 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
484 dataOffset = parmOffset + t2p->oldTotalParms;
485 dataAlign = dataOffset & 2; /* quad-align */
486 dataOffset += dataAlign;
487 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
488 smb_SetSMBParm(tp, 8, 0); /* data displacement */
489 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
492 datap = smb_GetSMBData(tp, NULL);
493 *datap++ = 0; /* we rounded to even */
495 totalLength += dataAlign;
496 smb_SetSMBDataLength(tp, totalLength);
498 /* next, send the datagram */
499 smb_SendPacket(vcp, tp);
502 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
504 smb_tran2Packet_t *asp;
516 /* We sometimes see 0 word count. What to do? */
517 if (*inp->wctp == 0) {
522 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
524 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
525 ptbuf[0] = "Transaction2 word count = 0";
526 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
527 1, inp->ncb_length, ptbuf, inp);
528 DeregisterEventSource(h);
530 osi_Log0(smb_logp, "TRANSACTION2 word count = 0");
533 smb_SetSMBDataLength(outp, 0);
534 smb_SendPacket(vcp, outp);
538 totalParms = smb_GetSMBParm(inp, 0);
539 totalData = smb_GetSMBParm(inp, 1);
541 firstPacket = (inp->inCom == 0x32);
543 /* find the packet we're reassembling */
544 lock_ObtainWrite(&smb_globalLock);
545 asp = smb_FindTran2Packet(vcp, inp);
547 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
549 lock_ReleaseWrite(&smb_globalLock);
551 /* now merge in this latest packet; start by looking up offsets */
553 parmDisp = dataDisp = 0;
554 parmOffset = smb_GetSMBParm(inp, 10);
555 dataOffset = smb_GetSMBParm(inp, 12);
556 parmCount = smb_GetSMBParm(inp, 9);
557 dataCount = smb_GetSMBParm(inp, 11);
558 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
559 asp->maxReturnData = smb_GetSMBParm(inp, 3);
561 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
562 totalData, dataCount, asp->maxReturnData);
565 parmDisp = smb_GetSMBParm(inp, 4);
566 parmOffset = smb_GetSMBParm(inp, 3);
567 dataDisp = smb_GetSMBParm(inp, 7);
568 dataOffset = smb_GetSMBParm(inp, 6);
569 parmCount = smb_GetSMBParm(inp, 2);
570 dataCount = smb_GetSMBParm(inp, 5);
572 osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
573 parmCount, dataCount);
576 /* now copy the parms and data */
577 if ( parmCount != 0 )
579 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
581 if ( dataCount != 0 ) {
582 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
585 /* account for new bytes */
586 asp->curData += dataCount;
587 asp->curParms += parmCount;
589 /* finally, if we're done, remove the packet from the queue and dispatch it */
590 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
591 /* we've received it all */
592 lock_ObtainWrite(&smb_globalLock);
593 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
594 lock_ReleaseWrite(&smb_globalLock);
596 /* now dispatch it */
597 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
598 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
599 osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
600 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
603 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
604 osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
605 code = CM_ERROR_BADOP;
608 /* if an error is returned, we're supposed to send an error packet,
609 * otherwise the dispatched function already did the data sending.
610 * We give dispatched proc the responsibility since it knows how much
614 smb_SendTran2Error(vcp, asp, outp, code);
617 /* free the input tran 2 packet */
618 lock_ObtainWrite(&smb_globalLock);
619 smb_FreeTran2Packet(asp);
620 lock_ReleaseWrite(&smb_globalLock);
622 else if (firstPacket) {
623 /* the first packet in a multi-packet request, we need to send an
624 * ack to get more data.
626 smb_SetSMBDataLength(outp, 0);
627 smb_SendPacket(vcp, outp);
633 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
636 smb_tran2Packet_t *outp;
641 cm_scache_t *dscp; /* dir we're dealing with */
642 cm_scache_t *scp; /* file we're creating */
654 int parmSlot; /* which parm we're dealing with */
663 extraInfo = (p->parmsp[0] & 1); /* return extra info */
664 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
666 openFun = p->parmsp[6]; /* open function */
667 excl = ((openFun & 3) == 0);
668 trunc = ((openFun & 3) == 2); /* truncate it */
669 openMode = (p->parmsp[1] & 0x7);
670 openAction = 0; /* tracks what we did */
672 attributes = p->parmsp[3];
673 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
675 /* compute initial mode bits based on read-only flag in attributes */
676 initialModeBits = 0666;
677 if (attributes & 1) initialModeBits &= ~0222;
679 pathp = (char *) (&p->parmsp[14]);
681 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
683 spacep = cm_GetSpace();
684 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
686 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
687 /* special case magic file name for receiving IOCTL requests
688 * (since IOCTL calls themselves aren't getting through).
690 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
691 smb_SetupIoctlFid(fidp, spacep);
693 /* copy out remainder of the parms */
695 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
697 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
698 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
699 outp->parmsp[parmSlot] = 0; parmSlot++;
700 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
701 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
702 outp->parmsp[parmSlot] = openMode; parmSlot++;
703 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
704 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
706 /* and the final "always present" stuff */
707 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
708 /* next write out the "unique" ID */
709 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
710 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
711 outp->parmsp[parmSlot] = 0; parmSlot++;
712 if (returnEALength) {
713 outp->parmsp[parmSlot] = 0; parmSlot++;
714 outp->parmsp[parmSlot] = 0; parmSlot++;
718 outp->totalParms = parmSlot * 2;
720 smb_SendTran2Packet(vcp, outp, op);
722 smb_FreeTran2Packet(outp);
724 /* and clean up fid reference */
725 smb_ReleaseFID(fidp);
732 asciip = (lastNamep ? lastNamep : pathp);
733 hexp = osi_HexifyString( asciip );
734 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
739 userp = smb_GetTran2User(vcp, p);
740 /* In the off chance that userp is NULL, we log and abandon */
742 osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
743 smb_FreeTran2Packet(outp);
744 return CM_ERROR_BADSMB;
747 tidPathp = smb_GetTIDPath(vcp, p->tid);
750 code = cm_NameI(cm_rootSCachep, pathp,
751 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
752 userp, tidPathp, &req, &scp);
754 code = cm_NameI(cm_rootSCachep, spacep->data,
755 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
756 userp, tidPathp, &req, &dscp);
757 cm_FreeSpace(spacep);
760 cm_ReleaseUser(userp);
761 smb_FreeTran2Packet(outp);
765 /* otherwise, scp points to the parent directory. Do a lookup,
766 * and truncate the file if we find it, otherwise we create the
769 if (!lastNamep) lastNamep = pathp;
771 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
773 if (code && code != CM_ERROR_NOSUCHFILE) {
774 cm_ReleaseSCache(dscp);
775 cm_ReleaseUser(userp);
776 smb_FreeTran2Packet(outp);
781 cm_FreeSpace(spacep);
784 /* if we get here, if code is 0, the file exists and is represented by
785 * scp. Otherwise, we have to create it.
788 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
790 if (dscp) cm_ReleaseSCache(dscp);
791 cm_ReleaseSCache(scp);
792 cm_ReleaseUser(userp);
793 smb_FreeTran2Packet(outp);
798 /* oops, file shouldn't be there */
799 if (dscp) cm_ReleaseSCache(dscp);
800 cm_ReleaseSCache(scp);
801 cm_ReleaseUser(userp);
802 smb_FreeTran2Packet(outp);
803 return CM_ERROR_EXISTS;
807 setAttr.mask = CM_ATTRMASK_LENGTH;
808 setAttr.length.LowPart = 0;
809 setAttr.length.HighPart = 0;
810 code = cm_SetAttr(scp, &setAttr, userp, &req);
811 openAction = 3; /* truncated existing file */
813 else openAction = 1; /* found existing file */
815 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
816 /* don't create if not found */
817 if (dscp) cm_ReleaseSCache(dscp);
818 osi_assert(scp == NULL);
819 cm_ReleaseUser(userp);
820 smb_FreeTran2Packet(outp);
821 return CM_ERROR_NOSUCHFILE;
824 osi_assert(dscp != NULL && scp == NULL);
825 openAction = 2; /* created file */
826 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
827 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
828 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
830 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
831 smb_NotifyChange(FILE_ACTION_ADDED,
832 FILE_NOTIFY_CHANGE_FILE_NAME,
833 dscp, lastNamep, NULL, TRUE);
834 if (!excl && code == CM_ERROR_EXISTS) {
835 /* not an exclusive create, and someone else tried
836 * creating it already, then we open it anyway. We
837 * don't bother retrying after this, since if this next
838 * fails, that means that the file was deleted after we
841 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
845 setAttr.mask = CM_ATTRMASK_LENGTH;
846 setAttr.length.LowPart = 0;
847 setAttr.length.HighPart = 0;
848 code = cm_SetAttr(scp, &setAttr, userp,
851 } /* lookup succeeded */
855 /* we don't need this any longer */
856 if (dscp) cm_ReleaseSCache(dscp);
859 /* something went wrong creating or truncating the file */
860 if (scp) cm_ReleaseSCache(scp);
861 cm_ReleaseUser(userp);
862 smb_FreeTran2Packet(outp);
866 /* make sure we're about to open a file */
867 if (scp->fileType != CM_SCACHETYPE_FILE) {
868 cm_ReleaseSCache(scp);
869 cm_ReleaseUser(userp);
870 smb_FreeTran2Packet(outp);
871 return CM_ERROR_ISDIR;
874 /* now all we have to do is open the file itself */
875 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
878 /* save a pointer to the vnode */
881 /* compute open mode */
882 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
883 if (openMode == 1 || openMode == 2)
884 fidp->flags |= SMB_FID_OPENWRITE;
886 smb_ReleaseFID(fidp);
888 cm_Open(scp, 0, userp);
890 /* copy out remainder of the parms */
892 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
893 lock_ObtainMutex(&scp->mx);
895 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
896 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
897 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
898 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
899 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
901 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
903 outp->parmsp[parmSlot] = openMode; parmSlot++;
904 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
905 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
907 /* and the final "always present" stuff */
908 outp->parmsp[parmSlot] = openAction; parmSlot++;
909 /* next write out the "unique" ID */
910 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
911 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
912 outp->parmsp[parmSlot] = 0; parmSlot++;
913 if (returnEALength) {
914 outp->parmsp[parmSlot] = 0; parmSlot++;
915 outp->parmsp[parmSlot] = 0; parmSlot++;
917 lock_ReleaseMutex(&scp->mx);
918 outp->totalData = 0; /* total # of data bytes */
919 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
921 smb_SendTran2Packet(vcp, outp, op);
923 smb_FreeTran2Packet(outp);
925 cm_ReleaseUser(userp);
926 /* leave scp held since we put it in fidp->scp */
930 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
932 return CM_ERROR_BADOP;
935 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
937 return CM_ERROR_BADOP;
940 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
942 smb_tran2Packet_t *outp;
943 smb_tran2QFSInfo_t qi;
946 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
948 osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
950 switch (p->parmsp[0]) {
951 case 1: responseSize = sizeof(qi.u.allocInfo); break;
952 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
953 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
954 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
955 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
956 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
957 default: return CM_ERROR_INVAL;
960 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
961 switch (p->parmsp[0]) {
964 qi.u.allocInfo.FSID = 0;
965 qi.u.allocInfo.sectorsPerAllocUnit = 1;
966 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
967 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
968 qi.u.allocInfo.bytesPerSector = 1024;
973 qi.u.volumeInfo.vsn = 1234;
974 qi.u.volumeInfo.vnCount = 4;
975 /* we're supposed to pad it out with zeroes to the end */
976 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
977 memcpy(qi.u.volumeInfo.label, "AFS", 4);
982 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
983 qi.u.FSvolumeInfo.vsn = 1234;
984 qi.u.FSvolumeInfo.vnCount = 8;
985 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
991 temp.LowPart = 0x7fffffff;
992 qi.u.FSsizeInfo.totalAllocUnits = temp;
993 temp.LowPart = 0x3fffffff;
994 qi.u.FSsizeInfo.availAllocUnits = temp;
995 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
996 qi.u.FSsizeInfo.bytesPerSector = 1024;
1000 /* FS device info */
1001 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
1002 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1006 /* FS attribute info */
1007 /* attributes, defined in WINNT.H:
1008 * FILE_CASE_SENSITIVE_SEARCH 0x1
1009 * FILE_CASE_PRESERVED_NAMES 0x2
1010 * <no name defined> 0x4000
1011 * If bit 0x4000 is not set, Windows 95 thinks
1012 * we can't handle long (non-8.3) names,
1013 * despite our protestations to the contrary.
1015 qi.u.FSattributeInfo.attributes = 0x4003;
1016 qi.u.FSattributeInfo.maxCompLength = 255;
1017 qi.u.FSattributeInfo.FSnameLength = 6;
1018 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1022 /* copy out return data, and set corresponding sizes */
1023 outp->totalParms = 0;
1024 outp->totalData = responseSize;
1025 memcpy(outp->datap, &qi, responseSize);
1027 /* send and free the packets */
1028 smb_SendTran2Packet(vcp, outp, op);
1029 smb_FreeTran2Packet(outp);
1034 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1036 return CM_ERROR_BADOP;
1039 struct smb_ShortNameRock {
1043 size_t shortNameLen;
1046 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1049 struct smb_ShortNameRock *rockp;
1053 /* compare both names and vnodes, though probably just comparing vnodes
1054 * would be safe enough.
1056 if (cm_stricmp(dep->name, rockp->maskp) != 0)
1058 if (ntohl(dep->fid.vnode) != rockp->vnode)
1060 /* This is the entry */
1061 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1062 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1063 return CM_ERROR_STOPNOW;
1066 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1067 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1069 struct smb_ShortNameRock rock;
1073 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1077 spacep = cm_GetSpace();
1078 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1080 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1082 cm_FreeSpace(spacep);
1083 if (code) return code;
1085 if (!lastNamep) lastNamep = pathp;
1088 thyper.HighPart = 0;
1089 rock.shortName = shortName;
1091 rock.maskp = lastNamep;
1092 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1095 cm_ReleaseSCache(dscp);
1098 return CM_ERROR_NOSUCHFILE;
1099 if (code == CM_ERROR_STOPNOW) {
1100 *shortNameLenp = rock.shortNameLen;
1106 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1108 smb_tran2Packet_t *outp;
1109 unsigned long dosTime;
1111 unsigned short infoLevel;
1113 unsigned short attributes;
1114 unsigned long extAttributes;
1119 cm_scache_t *scp, *dscp;
1128 infoLevel = p->parmsp[0];
1129 if (infoLevel == 6) nbytesRequired = 0;
1130 else if (infoLevel == 1) nbytesRequired = 22;
1131 else if (infoLevel == 2) nbytesRequired = 26;
1132 else if (infoLevel == 0x101) nbytesRequired = 40;
1133 else if (infoLevel == 0x102) nbytesRequired = 24;
1134 else if (infoLevel == 0x103) nbytesRequired = 4;
1135 else if (infoLevel == 0x108) nbytesRequired = 30;
1137 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1138 p->opcode, infoLevel);
1139 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1142 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1143 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
1145 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1147 if (infoLevel > 0x100)
1148 outp->totalParms = 2;
1150 outp->totalParms = 0;
1151 outp->totalData = nbytesRequired;
1153 /* now, if we're at infoLevel 6, we're only being asked to check
1154 * the syntax, so we just OK things now. In particular, we're *not*
1155 * being asked to verify anything about the state of any parent dirs.
1157 if (infoLevel == 6) {
1158 smb_SendTran2Packet(vcp, outp, opx);
1159 smb_FreeTran2Packet(outp);
1163 userp = smb_GetTran2User(vcp, p);
1165 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1166 smb_FreeTran2Packet(outp);
1167 return CM_ERROR_BADSMB;
1170 tidPathp = smb_GetTIDPath(vcp, p->tid);
1173 * XXX Strange hack XXX
1175 * As of Patch 7 (13 January 98), we are having the following problem:
1176 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1177 * requests to look up "desktop.ini" in all the subdirectories.
1178 * This can cause zillions of timeouts looking up non-existent cells
1179 * and volumes, especially in the top-level directory.
1181 * We have not found any way to avoid this or work around it except
1182 * to explicitly ignore the requests for mount points that haven't
1183 * yet been evaluated and for directories that haven't yet been
1186 if (infoLevel == 0x101) {
1187 spacep = cm_GetSpace();
1188 smb_StripLastComponent(spacep->data, &lastComp,
1189 (char *)(&p->parmsp[3]));
1190 /* Make sure that lastComp is not NULL */
1192 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1193 code = cm_NameI(cm_rootSCachep, spacep->data,
1197 userp, tidPathp, &req, &dscp);
1199 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1200 && !dscp->mountRootFidp)
1201 code = CM_ERROR_NOSUCHFILE;
1202 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1203 cm_buf_t *bp = buf_Find(dscp, &hzero);
1207 code = CM_ERROR_NOSUCHFILE;
1209 cm_ReleaseSCache(dscp);
1211 cm_FreeSpace(spacep);
1212 cm_ReleaseUser(userp);
1213 smb_SendTran2Error(vcp, p, opx, code);
1214 smb_FreeTran2Packet(outp);
1220 cm_FreeSpace(spacep);
1223 /* now do namei and stat, and copy out the info */
1224 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1225 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1228 cm_ReleaseUser(userp);
1229 smb_SendTran2Error(vcp, p, opx, code);
1230 smb_FreeTran2Packet(outp);
1234 lock_ObtainMutex(&scp->mx);
1235 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1236 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1237 if (code) goto done;
1239 /* now we have the status in the cache entry, and everything is locked.
1240 * Marshall the output data.
1243 /* for info level 108, figure out short name */
1244 if (infoLevel == 0x108) {
1245 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1246 tidPathp, scp->fid.vnode, shortName,
1253 *((u_long *)op) = len * 2; op += 4;
1254 mbstowcs((unsigned short *)op, shortName, len);
1259 if (infoLevel == 1 || infoLevel == 2) {
1260 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1261 *((u_long *)op) = dosTime; op += 4; /* creation time */
1262 *((u_long *)op) = dosTime; op += 4; /* access time */
1263 *((u_long *)op) = dosTime; op += 4; /* write time */
1264 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1265 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1266 attributes = smb_Attributes(scp);
1267 *((u_short *)op) = attributes; op += 2; /* attributes */
1269 else if (infoLevel == 0x101) {
1270 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1271 *((FILETIME *)op) = ft; op += 8; /* creation time */
1272 *((FILETIME *)op) = ft; op += 8; /* last access time */
1273 *((FILETIME *)op) = ft; op += 8; /* last write time */
1274 *((FILETIME *)op) = ft; op += 8; /* last change time */
1275 extAttributes = smb_ExtAttributes(scp);
1276 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1277 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1279 else if (infoLevel == 0x102) {
1280 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1281 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1282 *((u_long *)op) = scp->linkCount; op += 4;
1285 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1288 else if (infoLevel == 0x103) {
1289 memset(op, 0, 4); op += 4; /* EA size */
1292 /* now, if we are being asked about extended attrs, return a 0 size */
1293 if (infoLevel == 2) {
1294 *((u_long *)op) = 0; op += 4;
1298 /* send and free the packets */
1300 lock_ReleaseMutex(&scp->mx);
1301 cm_ReleaseSCache(scp);
1302 cm_ReleaseUser(userp);
1304 smb_SendTran2Packet(vcp, outp, opx);
1306 smb_SendTran2Error(vcp, p, opx, code);
1307 smb_FreeTran2Packet(outp);
1312 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1314 return CM_ERROR_BADOP;
1317 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1319 smb_tran2Packet_t *outp;
1321 unsigned long attributes;
1322 unsigned short infoLevel;
1335 fidp = smb_FindFID(vcp, fid, 0);
1338 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1342 infoLevel = p->parmsp[1];
1343 if (infoLevel == 0x101) nbytesRequired = 40;
1344 else if (infoLevel == 0x102) nbytesRequired = 24;
1345 else if (infoLevel == 0x103) nbytesRequired = 4;
1346 else if (infoLevel == 0x104) nbytesRequired = 6;
1348 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1349 p->opcode, infoLevel);
1350 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1351 smb_ReleaseFID(fidp);
1354 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1356 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1358 if (infoLevel > 0x100)
1359 outp->totalParms = 2;
1361 outp->totalParms = 0;
1362 outp->totalData = nbytesRequired;
1364 userp = smb_GetTran2User(vcp, p);
1366 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
1367 code = CM_ERROR_BADSMB;
1372 lock_ObtainMutex(&scp->mx);
1373 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1374 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1375 if (code) goto done;
1377 /* now we have the status in the cache entry, and everything is locked.
1378 * Marshall the output data.
1381 if (infoLevel == 0x101) {
1382 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1383 *((FILETIME *)op) = ft; op += 8; /* creation time */
1384 *((FILETIME *)op) = ft; op += 8; /* last access time */
1385 *((FILETIME *)op) = ft; op += 8; /* last write time */
1386 *((FILETIME *)op) = ft; op += 8; /* last change time */
1387 attributes = smb_ExtAttributes(scp);
1388 *((u_long *)op) = attributes; op += 4;
1389 *((u_long *)op) = 0; op += 4;
1391 else if (infoLevel == 0x102) {
1392 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1393 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1394 *((u_long *)op) = scp->linkCount; op += 4;
1395 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1396 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1400 else if (infoLevel == 0x103) {
1401 *((u_long *)op) = 0; op += 4;
1403 else if (infoLevel == 0x104) {
1407 if (fidp->NTopen_wholepathp)
1408 name = fidp->NTopen_wholepathp;
1410 name = "\\"; /* probably can't happen */
1412 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1413 *((u_long *)op) = len * 2; op += 4;
1414 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1417 /* send and free the packets */
1419 lock_ReleaseMutex(&scp->mx);
1420 cm_ReleaseUser(userp);
1421 smb_ReleaseFID(fidp);
1422 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1423 else smb_SendTran2Error(vcp, p, opx, code);
1424 smb_FreeTran2Packet(outp);
1429 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1434 unsigned short infoLevel;
1435 smb_tran2Packet_t *outp;
1443 fidp = smb_FindFID(vcp, fid, 0);
1446 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1450 infoLevel = p->parmsp[1];
1451 if (infoLevel > 0x104 || infoLevel < 0x101) {
1452 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1453 p->opcode, infoLevel);
1454 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1455 smb_ReleaseFID(fidp);
1459 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1460 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1461 smb_ReleaseFID(fidp);
1464 if ((infoLevel == 0x103 || infoLevel == 0x104)
1465 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1466 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1467 smb_ReleaseFID(fidp);
1471 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
1473 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1475 outp->totalParms = 2;
1476 outp->totalData = 0;
1478 userp = smb_GetTran2User(vcp, p);
1480 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
1481 code = CM_ERROR_BADSMB;
1487 if (infoLevel == 0x101) {
1489 unsigned int attribute;
1492 /* lock the vnode with a callback; we need the current status
1493 * to determine what the new status is, in some cases.
1495 lock_ObtainMutex(&scp->mx);
1496 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1497 CM_SCACHESYNC_GETSTATUS
1498 | CM_SCACHESYNC_NEEDCALLBACK);
1500 lock_ReleaseMutex(&scp->mx);
1504 /* prepare for setattr call */
1507 lastMod = *((FILETIME *)(p->datap + 16));
1508 /* when called as result of move a b, lastMod is (-1, -1).
1509 * If the check for -1 is not present, timestamp
1510 * of the resulting file will be 1969 (-1)
1512 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
1513 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1514 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1515 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1517 fidp->flags |= SMB_FID_MTIMESETDONE;
1520 attribute = *((u_long *)(p->datap + 32));
1521 if (attribute != 0) {
1522 if ((scp->unixModeBits & 0222)
1523 && (attribute & 1) != 0) {
1524 /* make a writable file read-only */
1525 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1526 attr.unixModeBits = scp->unixModeBits & ~0222;
1528 else if ((scp->unixModeBits & 0222) == 0
1529 && (attribute & 1) == 0) {
1530 /* make a read-only file writable */
1531 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1532 attr.unixModeBits = scp->unixModeBits | 0222;
1535 lock_ReleaseMutex(&scp->mx);
1539 code = cm_SetAttr(scp, &attr, userp, &req);
1543 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1544 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1547 attr.mask = CM_ATTRMASK_LENGTH;
1548 attr.length.LowPart = size.LowPart;
1549 attr.length.HighPart = size.HighPart;
1550 code = cm_SetAttr(scp, &attr, userp, &req);
1552 else if (infoLevel == 0x102) {
1553 if (*((char *)(p->datap))) {
1554 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1557 fidp->flags |= SMB_FID_DELONCLOSE;
1561 fidp->flags &= ~SMB_FID_DELONCLOSE;
1565 cm_ReleaseUser(userp);
1566 smb_ReleaseFID(fidp);
1567 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1568 else smb_SendTran2Error(vcp, p, op, code);
1569 smb_FreeTran2Packet(outp);
1574 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1576 return CM_ERROR_BADOP;
1579 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1581 return CM_ERROR_BADOP;
1584 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1586 return CM_ERROR_BADOP;
1589 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1591 return CM_ERROR_BADOP;
1594 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1596 return CM_ERROR_BADOP;
1599 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1600 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1605 cm_scache_t *targetScp; /* target if scp is a symlink */
1610 unsigned short attr;
1611 unsigned long lattr;
1612 smb_dirListPatch_t *patchp;
1613 smb_dirListPatch_t *npatchp;
1615 for(patchp = *dirPatchespp; patchp; patchp =
1616 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1617 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1619 lock_ObtainMutex(&scp->mx);
1620 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1621 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1623 lock_ReleaseMutex(&scp->mx);
1624 cm_ReleaseSCache(scp);
1628 /* now watch for a symlink */
1629 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1630 lock_ReleaseMutex(&scp->mx);
1631 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
1633 /* we have a more accurate file to use (the
1634 * target of the symbolic link). Otherwise,
1635 * we'll just use the symlink anyway.
1637 osi_Log2(smb_logp, "symlink vp %x to vp %x",
1639 cm_ReleaseSCache(scp);
1642 lock_ObtainMutex(&scp->mx);
1645 dptr = patchp->dptr;
1647 if (infoLevel >= 0x101) {
1649 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1651 /* copy to Creation Time */
1652 *((FILETIME *)dptr) = ft;
1655 /* copy to Last Access Time */
1656 *((FILETIME *)dptr) = ft;
1659 /* copy to Last Write Time */
1660 *((FILETIME *)dptr) = ft;
1663 /* copy to Change Time */
1664 *((FILETIME *)dptr) = ft;
1667 /* Use length for both file length and alloc length */
1668 *((LARGE_INTEGER *)dptr) = scp->length;
1670 *((LARGE_INTEGER *)dptr) = scp->length;
1673 /* Copy attributes */
1674 lattr = smb_ExtAttributes(scp);
1675 /* merge in hidden (dot file) attribute */
1676 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1677 lattr |= SMB_ATTR_HIDDEN;
1678 *((u_long *)dptr) = lattr;
1683 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1685 /* and copy out date */
1686 shortTemp = (dosTime>>16) & 0xffff;
1687 *((u_short *)dptr) = shortTemp;
1690 /* copy out creation time */
1691 shortTemp = dosTime & 0xffff;
1692 *((u_short *)dptr) = shortTemp;
1695 /* and copy out date */
1696 shortTemp = (dosTime>>16) & 0xffff;
1697 *((u_short *)dptr) = shortTemp;
1700 /* copy out access time */
1701 shortTemp = dosTime & 0xffff;
1702 *((u_short *)dptr) = shortTemp;
1705 /* and copy out date */
1706 shortTemp = (dosTime>>16) & 0xffff;
1707 *((u_short *)dptr) = shortTemp;
1710 /* copy out mod time */
1711 shortTemp = dosTime & 0xffff;
1712 *((u_short *)dptr) = shortTemp;
1715 /* copy out file length and alloc length,
1716 * using the same for both
1718 *((u_long *)dptr) = scp->length.LowPart;
1720 *((u_long *)dptr) = scp->length.LowPart;
1723 /* finally copy out attributes as short */
1724 attr = smb_Attributes(scp);
1725 /* merge in hidden (dot file) attribute */
1726 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1727 attr |= SMB_ATTR_HIDDEN;
1728 *dptr++ = attr & 0xff;
1729 *dptr++ = (attr >> 8) & 0xff;
1732 lock_ReleaseMutex(&scp->mx);
1733 cm_ReleaseSCache(scp);
1736 /* now free the patches */
1737 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1738 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1742 /* and mark the list as empty */
1743 *dirPatchespp = NULL;
1748 /* do a case-folding search of the star name mask with the name in namep.
1749 * Return 1 if we match, otherwise 0.
1751 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1753 unsigned char tcp1, tcp2; /* Pattern characters */
1754 unsigned char tcn1; /* Name characters */
1755 int sawDot = 0, sawStar = 0, req8dot3 = 0;
1756 char *starNamep, *starMaskp;
1757 static char nullCharp[] = {0};
1758 int casefold = flags & CM_FLAG_CASEFOLD;
1760 /* make sure we only match 8.3 names, if requested */
1761 req8dot3 = (flags & CM_FLAG_8DOT3);
1762 if (req8dot3 && !cm_Is8Dot3(namep))
1767 /* Next pattern character */
1770 /* Next name character */
1774 /* 0 - end of pattern */
1780 else if (tcp1 == '.' || tcp1 == '"') {
1790 * first dot in pattern;
1791 * must match dot or end of name
1796 else if (tcn1 == '.') {
1805 else if (tcp1 == '?') {
1806 if (tcn1 == 0 || tcn1 == '.')
1811 else if (tcp1 == '>') {
1812 if (tcn1 != 0 && tcn1 != '.')
1816 else if (tcp1 == '*' || tcp1 == '<') {
1820 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
1821 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
1836 * pattern character after '*' is not null or
1837 * period. If it is '?' or '>', we are not
1838 * going to understand it. If it is '*' or
1839 * '<', we are going to skip over it. None of
1840 * these are likely, I hope.
1842 /* skip over '*' and '<' */
1843 while (tcp2 == '*' || tcp2 == '<')
1846 /* skip over characters that don't match tcp2 */
1847 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
1848 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
1849 (!casefold && tcn1 != tcp2)))
1853 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
1856 /* Remember where we are */
1866 /* tcp1 is not a wildcard */
1867 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
1868 (!casefold && tcn1 == tcp1)) {
1873 /* if trying to match a star pattern, go back */
1875 maskp = starMaskp - 2;
1876 namep = starNamep + 1;
1886 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1895 smb_dirListPatch_t *dirListPatchesp;
1896 smb_dirListPatch_t *curPatchp;
1899 long orbytes; /* # of bytes in this output record */
1900 long ohbytes; /* # of bytes, except file name */
1901 long onbytes; /* # of bytes in name, incl. term. null */
1902 osi_hyper_t dirLength;
1903 osi_hyper_t bufferOffset;
1904 osi_hyper_t curOffset;
1906 smb_dirSearch_t *dsp;
1910 cm_pageHeader_t *pageHeaderp;
1911 cm_user_t *userp = NULL;
1914 long nextEntryCookie;
1915 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1916 char *op; /* output data ptr */
1917 char *origOp; /* original value of op */
1918 cm_space_t *spacep; /* for pathname buffer */
1919 long maxReturnData; /* max # of return data */
1920 long maxReturnParms; /* max # of return parms */
1921 long bytesInBuffer; /* # data bytes in the output buffer */
1923 char *maskp; /* mask part of path */
1927 smb_tran2Packet_t *outp; /* response packet */
1930 char shortName[13]; /* 8.3 name if needed */
1942 if (p->opcode == 1) {
1943 /* find first; obtain basic parameters from request */
1944 attribute = p->parmsp[0];
1945 maxCount = p->parmsp[1];
1946 infoLevel = p->parmsp[3];
1947 searchFlags = p->parmsp[2];
1948 dsp = smb_NewDirSearch(1);
1949 dsp->attribute = attribute;
1950 pathp = ((char *) p->parmsp) + 12; /* points to path */
1952 maskp = strrchr(pathp, '\\');
1953 if (maskp == NULL) maskp = pathp;
1954 else maskp++; /* skip over backslash */
1955 strcpy(dsp->mask, maskp); /* and save mask */
1956 /* track if this is likely to match a lot of entries */
1957 starPattern = smb_V3IsStarMask(maskp);
1960 osi_assert(p->opcode == 2);
1961 /* find next; obtain basic parameters from request or open dir file */
1962 dsp = smb_FindDirSearch(p->parmsp[0]);
1963 if (!dsp) return CM_ERROR_BADFD;
1964 attribute = dsp->attribute;
1965 maxCount = p->parmsp[1];
1966 infoLevel = p->parmsp[2];
1967 searchFlags = p->parmsp[5];
1969 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1971 starPattern = 1; /* assume, since required a Find Next */
1975 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1976 attribute, infoLevel, maxCount, searchFlags);
1978 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
1979 p->opcode, nextCookie);
1981 if (infoLevel >= 0x101)
1982 searchFlags &= ~4; /* no resume keys */
1984 dirListPatchesp = NULL;
1986 maxReturnData = p->maxReturnData;
1987 if (p->opcode == 1) /* find first */
1988 maxReturnParms = 10; /* bytes */
1990 maxReturnParms = 8; /* bytes */
1992 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1993 if (maxReturnData > 6000)
1994 maxReturnData = 6000;
1995 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1997 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
2000 osi_Log1(smb_logp, "T2 receive search dir %s",
2001 osi_LogSaveString(smb_logp, pathp));
2003 /* bail out if request looks bad */
2004 if (p->opcode == 1 && !pathp) {
2005 smb_ReleaseDirSearch(dsp);
2006 smb_FreeTran2Packet(outp);
2007 return CM_ERROR_BADSMB;
2010 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
2011 nextCookie, dsp->cookie);
2013 userp = smb_GetTran2User(vcp, p);
2015 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2016 smb_ReleaseDirSearch(dsp);
2017 smb_FreeTran2Packet(outp);
2018 return CM_ERROR_BADSMB;
2021 /* try to get the vnode for the path name next */
2022 lock_ObtainMutex(&dsp->mx);
2029 spacep = cm_GetSpace();
2030 smb_StripLastComponent(spacep->data, NULL, pathp);
2031 lock_ReleaseMutex(&dsp->mx);
2033 tidPathp = smb_GetTIDPath(vcp, p->tid);
2034 code = cm_NameI(cm_rootSCachep, spacep->data,
2035 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2036 userp, tidPathp, &req, &scp);
2037 cm_FreeSpace(spacep);
2039 lock_ObtainMutex(&dsp->mx);
2041 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2043 /* we need one hold for the entry we just stored into,
2044 * and one for our own processing. When we're done
2045 * with this function, we'll drop the one for our own
2046 * processing. We held it once from the namei call,
2047 * and so we do another hold now.
2050 lock_ObtainMutex(&scp->mx);
2051 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2052 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2053 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2054 dsp->flags |= SMB_DIRSEARCH_BULKST;
2056 lock_ReleaseMutex(&scp->mx);
2059 lock_ReleaseMutex(&dsp->mx);
2061 cm_ReleaseUser(userp);
2062 smb_FreeTran2Packet(outp);
2063 smb_DeleteDirSearch(dsp);
2064 smb_ReleaseDirSearch(dsp);
2068 /* get the directory size */
2069 lock_ObtainMutex(&scp->mx);
2070 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2071 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2073 lock_ReleaseMutex(&scp->mx);
2074 cm_ReleaseSCache(scp);
2075 cm_ReleaseUser(userp);
2076 smb_FreeTran2Packet(outp);
2077 smb_DeleteDirSearch(dsp);
2078 smb_ReleaseDirSearch(dsp);
2083 dirLength = scp->length;
2085 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2086 curOffset.HighPart = 0;
2087 curOffset.LowPart = nextCookie;
2088 origOp = outp->datap;
2096 if (searchFlags & 4)
2097 /* skip over resume key */
2100 /* make sure that curOffset.LowPart doesn't point to the first
2101 * 32 bytes in the 2nd through last dir page, and that it doesn't
2102 * point at the first 13 32-byte chunks in the first dir page,
2103 * since those are dir and page headers, and don't contain useful
2106 temp = curOffset.LowPart & (2048-1);
2107 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2108 /* we're in the first page */
2109 if (temp < 13*32) temp = 13*32;
2112 /* we're in a later dir page */
2113 if (temp < 32) temp = 32;
2116 /* make sure the low order 5 bits are zero */
2119 /* now put temp bits back ito curOffset.LowPart */
2120 curOffset.LowPart &= ~(2048-1);
2121 curOffset.LowPart |= temp;
2123 /* check if we've passed the dir's EOF */
2124 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2129 /* check if we've returned all the names that will fit in the
2130 * response packet; we check return count as well as the number
2131 * of bytes requested. We check the # of bytes after we find
2132 * the dir entry, since we'll need to check its size.
2134 if (returnedNames >= maxCount) {
2138 /* see if we can use the bufferp we have now; compute in which
2139 * page the current offset would be, and check whether that's
2140 * the offset of the buffer we have. If not, get the buffer.
2142 thyper.HighPart = curOffset.HighPart;
2143 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2144 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2147 buf_Release(bufferp);
2150 lock_ReleaseMutex(&scp->mx);
2151 lock_ObtainRead(&scp->bufCreateLock);
2152 code = buf_Get(scp, &thyper, &bufferp);
2153 lock_ReleaseRead(&scp->bufCreateLock);
2155 /* now, if we're doing a star match, do bulk fetching
2156 * of all of the status info for files in the dir.
2159 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2162 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2163 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
2164 /* Don't bulk stat if risking timeout */
2165 int now = GetCurrentTime();
2166 if (now - req.startTime > 5000) {
2167 scp->bulkStatProgress = thyper;
2168 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2169 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2171 cm_TryBulkStat(scp, &thyper, userp, &req);
2175 lock_ObtainMutex(&scp->mx);
2177 bufferOffset = thyper;
2179 /* now get the data in the cache */
2181 code = cm_SyncOp(scp, bufferp, userp, &req,
2183 CM_SCACHESYNC_NEEDCALLBACK
2184 | CM_SCACHESYNC_READ);
2187 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2189 /* otherwise, load the buffer and try again */
2190 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2195 buf_Release(bufferp);
2199 } /* if (wrong buffer) ... */
2201 /* now we have the buffer containing the entry we're interested
2202 * in; copy it out if it represents a non-deleted entry.
2204 entryInDir = curOffset.LowPart & (2048-1);
2205 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2207 /* page header will help tell us which entries are free. Page
2208 * header can change more often than once per buffer, since
2209 * AFS 3 dir page size may be less than (but not more than)
2210 * a buffer package buffer.
2212 /* only look intra-buffer */
2213 temp = curOffset.LowPart & (buf_bufferSize - 1);
2214 temp &= ~(2048 - 1); /* turn off intra-page bits */
2215 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2217 /* now determine which entry we're looking at in the page.
2218 * If it is free (there's a free bitmap at the start of the
2219 * dir), we should skip these 32 bytes.
2221 slotInPage = (entryInDir & 0x7e0) >> 5;
2222 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2223 & (1 << (slotInPage & 0x7)))) {
2224 /* this entry is free */
2225 numDirChunks = 1; /* only skip this guy */
2229 tp = bufferp->datap + entryInBuffer;
2230 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2232 /* while we're here, compute the next entry's location, too,
2233 * since we'll need it when writing out the cookie into the dir
2236 * XXXX Probably should do more sanity checking.
2238 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2240 /* compute offset of cookie representing next entry */
2241 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
2243 /* Need 8.3 name? */
2245 if (infoLevel == 0x104
2246 && dep->fid.vnode != 0
2247 && !cm_Is8Dot3(dep->name)) {
2248 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2252 /* When matching, we are using doing a case fold if we have a wildcard mask.
2253 * If we get a non-wildcard match, it's a lookup for a specific file.
2255 if (dep->fid.vnode != 0 &&
2256 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
2258 && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
2260 /* Eliminate entries that don't match requested attributes */
2261 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
2262 smb_IsDotFile(dep->name))
2263 goto nextEntry; /* no hidden files */
2265 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
2267 /* We have already done the cm_TryBulkStat above */
2268 fid.cell = scp->fid.cell;
2269 fid.volume = scp->fid.volume;
2270 fid.vnode = ntohl(dep->fid.vnode);
2271 fid.unique = ntohl(dep->fid.unique);
2272 fileType = cm_FindFileType(&fid);
2273 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
2274 "has filetype %d", dep->name,
2276 if (fileType == CM_SCACHETYPE_DIRECTORY)
2280 /* finally check if this name will fit */
2282 /* standard dir entry stuff */
2283 if (infoLevel < 0x101)
2284 ohbytes = 23; /* pre-NT */
2285 else if (infoLevel == 0x103)
2286 ohbytes = 12; /* NT names only */
2288 ohbytes = 64; /* NT */
2290 if (infoLevel == 0x104)
2291 ohbytes += 26; /* Short name & length */
2293 if (searchFlags & 4) {
2294 ohbytes += 4; /* if resume key required */
2298 && infoLevel != 0x101
2299 && infoLevel != 0x103)
2300 ohbytes += 4; /* EASIZE */
2302 /* add header to name & term. null */
2303 orbytes = onbytes + ohbytes + 1;
2305 /* now, we round up the record to a 4 byte alignment,
2306 * and we make sure that we have enough room here for
2307 * even the aligned version (so we don't have to worry
2308 * about an * overflow when we pad things out below).
2309 * That's the reason for the alignment arithmetic below.
2311 if (infoLevel >= 0x101)
2312 align = (4 - (orbytes & 3)) & 3;
2315 if (orbytes + bytesInBuffer + align > maxReturnData)
2318 /* this is one of the entries to use: it is not deleted
2319 * and it matches the star pattern we're looking for.
2320 * Put out the name, preceded by its length.
2322 /* First zero everything else */
2323 memset(origOp, 0, ohbytes);
2325 if (infoLevel <= 0x101)
2326 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2327 else if (infoLevel == 0x103)
2328 *((u_long *)(op + 8)) = onbytes;
2330 *((u_long *)(op + 60)) = onbytes;
2331 strcpy(origOp+ohbytes, dep->name);
2333 /* Short name if requested and needed */
2334 if (infoLevel == 0x104) {
2335 if (NeedShortName) {
2336 strcpy(op + 70, shortName);
2337 *(op + 68) = shortNameEnd - shortName;
2341 /* now, adjust the # of entries copied */
2344 /* NextEntryOffset and FileIndex */
2345 if (infoLevel >= 101) {
2346 int entryOffset = orbytes + align;
2347 *((u_long *)op) = entryOffset;
2348 *((u_long *)(op+4)) = nextEntryCookie;
2351 /* now we emit the attribute. This is tricky, since
2352 * we need to really stat the file to find out what
2353 * type of entry we've got. Right now, we're copying
2354 * out data from * a buffer, while holding the scp
2355 * locked, so it isn't really convenient to stat
2356 * something now. We'll put in a place holder
2357 * now, and make a second pass before returning this
2358 * to get the real attributes. So, we just skip the
2359 * data for now, and adjust it later. We allocate a
2360 * patch record to make it easy to find this point
2361 * later. The replay will happen at a time when it is
2362 * safe to unlock the directory.
2364 if (infoLevel != 0x103) {
2365 curPatchp = malloc(sizeof(*curPatchp));
2366 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2368 curPatchp->dptr = op;
2369 if (infoLevel >= 0x101)
2370 curPatchp->dptr += 8;
2372 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2373 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2376 curPatchp->flags = 0;
2378 curPatchp->fid.cell = scp->fid.cell;
2379 curPatchp->fid.volume = scp->fid.volume;
2380 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2381 curPatchp->fid.unique = ntohl(dep->fid.unique);
2384 curPatchp->dep = dep;
2387 if (searchFlags & 4)
2388 /* put out resume key */
2389 *((u_long *)origOp) = nextEntryCookie;
2391 /* Adjust byte ptr and count */
2392 origOp += orbytes; /* skip entire record */
2393 bytesInBuffer += orbytes;
2395 /* and pad the record out */
2396 while (--align >= 0) {
2401 } /* if we're including this name */
2402 else if(!NeedShortName &&
2405 dep->fid.vnode != 0 &&
2406 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
2407 /* We were looking for exact matches, but here's an inexact one*/
2412 /* and adjust curOffset to be where the new cookie is */
2413 thyper.HighPart = 0;
2414 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2415 curOffset = LargeIntegerAdd(thyper, curOffset);
2416 } /* while copying data for dir listing */
2418 /* If we didn't get a star pattern, we did an exact match during the first pass.
2419 * If there were no exact matches found, we fail over to inexact matches by
2420 * marking the query as a star pattern (matches all case permutations), and
2421 * re-running the query.
2423 if (returnedNames == 0 && !starPattern && foundInexact) {
2424 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
2429 /* release the mutex */
2430 lock_ReleaseMutex(&scp->mx);
2431 if (bufferp) buf_Release(bufferp);
2433 /* apply and free last set of patches; if not doing a star match, this
2434 * will be empty, but better safe (and freeing everything) than sorry.
2436 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2439 /* now put out the final parameters */
2440 if (returnedNames == 0) eos = 1;
2441 if (p->opcode == 1) {
2443 outp->parmsp[0] = (unsigned short) dsp->cookie;
2444 outp->parmsp[1] = returnedNames;
2445 outp->parmsp[2] = eos;
2446 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2447 outp->parmsp[4] = 0;
2448 /* don't need last name to continue
2449 * search, cookie is enough. Normally,
2450 * this is the offset of the file name
2451 * of the last entry returned.
2453 outp->totalParms = 10; /* in bytes */
2457 outp->parmsp[0] = returnedNames;
2458 outp->parmsp[1] = eos;
2459 outp->parmsp[2] = 0; /* EAS error */
2460 outp->parmsp[3] = 0; /* last name, as above */
2461 outp->totalParms = 8; /* in bytes */
2464 /* return # of bytes in the buffer */
2465 outp->totalData = bytesInBuffer;
2467 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
2468 returnedNames, code);
2470 /* Return error code if unsuccessful on first request */
2471 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2472 code = CM_ERROR_NOSUCHFILE;
2474 /* if we're supposed to close the search after this request, or if
2475 * we're supposed to close the search if we're done, and we're done,
2476 * or if something went wrong, close the search.
2478 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2479 if ((searchFlags & 1) || (returnedNames == 0) ||
2480 ((searchFlags & 2) && eos) || code != 0)
2481 smb_DeleteDirSearch(dsp);
2483 smb_SendTran2Error(vcp, p, opx, code);
2485 smb_SendTran2Packet(vcp, outp, opx);
2487 smb_FreeTran2Packet(outp);
2488 smb_ReleaseDirSearch(dsp);
2489 cm_ReleaseSCache(scp);
2490 cm_ReleaseUser(userp);
2494 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2497 smb_dirSearch_t *dsp;
2499 dirHandle = smb_GetSMBParm(inp, 0);
2501 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
2503 dsp = smb_FindDirSearch(dirHandle);
2506 return CM_ERROR_BADFD;
2508 /* otherwise, we have an FD to destroy */
2509 smb_DeleteDirSearch(dsp);
2510 smb_ReleaseDirSearch(dsp);
2512 /* and return results */
2513 smb_SetSMBDataLength(outp, 0);
2518 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2520 smb_SetSMBDataLength(outp, 0);
2524 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2531 cm_scache_t *dscp; /* dir we're dealing with */
2532 cm_scache_t *scp; /* file we're creating */
2534 int initialModeBits;
2544 int parmSlot; /* which parm we're dealing with */
2552 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2553 openFun = smb_GetSMBParm(inp, 8); /* open function */
2554 excl = ((openFun & 3) == 0);
2555 trunc = ((openFun & 3) == 2); /* truncate it */
2556 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2557 openAction = 0; /* tracks what we did */
2559 attributes = smb_GetSMBParm(inp, 5);
2560 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2562 /* compute initial mode bits based on read-only flag in attributes */
2563 initialModeBits = 0666;
2564 if (attributes & 1) initialModeBits &= ~0222;
2566 pathp = smb_GetSMBData(inp, NULL);
2568 spacep = inp->spacep;
2569 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2571 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2572 /* special case magic file name for receiving IOCTL requests
2573 * (since IOCTL calls themselves aren't getting through).
2576 osi_Log0(smb_logp, "IOCTL Open");
2579 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2580 smb_SetupIoctlFid(fidp, spacep);
2582 /* set inp->fid so that later read calls in same msg can find fid */
2583 inp->fid = fidp->fid;
2585 /* copy out remainder of the parms */
2587 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2589 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2590 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2591 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2592 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2593 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2594 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2595 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2596 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2598 /* and the final "always present" stuff */
2599 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2600 /* next write out the "unique" ID */
2601 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2602 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2603 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2604 smb_SetSMBDataLength(outp, 0);
2606 /* and clean up fid reference */
2607 smb_ReleaseFID(fidp);
2611 #ifdef DEBUG_VERBOSE
2613 char *hexp, *asciip;
2614 asciip = (lastNamep ? lastNamep : pathp );
2615 hexp = osi_HexifyString(asciip);
2616 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2620 userp = smb_GetUser(vcp, inp);
2623 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2624 code = cm_NameI(cm_rootSCachep, pathp,
2625 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2626 userp, tidPathp, &req, &scp);
2628 code = cm_NameI(cm_rootSCachep, spacep->data,
2629 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2630 userp, tidPathp, &req, &dscp);
2633 cm_ReleaseUser(userp);
2637 /* otherwise, scp points to the parent directory. Do a lookup,
2638 * and truncate the file if we find it, otherwise we create the
2641 if (!lastNamep) lastNamep = pathp;
2643 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2645 if (code && code != CM_ERROR_NOSUCHFILE) {
2646 cm_ReleaseSCache(dscp);
2647 cm_ReleaseUser(userp);
2652 /* if we get here, if code is 0, the file exists and is represented by
2653 * scp. Otherwise, we have to create it. The dir may be represented
2654 * by dscp, or we may have found the file directly. If code is non-zero,
2658 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2660 if (dscp) cm_ReleaseSCache(dscp);
2661 cm_ReleaseSCache(scp);
2662 cm_ReleaseUser(userp);
2667 /* oops, file shouldn't be there */
2668 if (dscp) cm_ReleaseSCache(dscp);
2669 cm_ReleaseSCache(scp);
2670 cm_ReleaseUser(userp);
2671 return CM_ERROR_EXISTS;
2675 setAttr.mask = CM_ATTRMASK_LENGTH;
2676 setAttr.length.LowPart = 0;
2677 setAttr.length.HighPart = 0;
2678 code = cm_SetAttr(scp, &setAttr, userp, &req);
2679 openAction = 3; /* truncated existing file */
2681 else openAction = 1; /* found existing file */
2683 else if (!(openFun & 0x10)) {
2684 /* don't create if not found */
2685 if (dscp) cm_ReleaseSCache(dscp);
2686 cm_ReleaseUser(userp);
2687 return CM_ERROR_NOSUCHFILE;
2690 osi_assert(dscp != NULL);
2691 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
2692 osi_LogSaveString(smb_logp, lastNamep));
2693 openAction = 2; /* created file */
2694 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2695 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2696 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2698 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2699 smb_NotifyChange(FILE_ACTION_ADDED,
2700 FILE_NOTIFY_CHANGE_FILE_NAME,
2701 dscp, lastNamep, NULL, TRUE);
2702 if (!excl && code == CM_ERROR_EXISTS) {
2703 /* not an exclusive create, and someone else tried
2704 * creating it already, then we open it anyway. We
2705 * don't bother retrying after this, since if this next
2706 * fails, that means that the file was deleted after we
2707 * started this call.
2709 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2713 setAttr.mask = CM_ATTRMASK_LENGTH;
2714 setAttr.length.LowPart = 0;
2715 setAttr.length.HighPart = 0;
2716 code = cm_SetAttr(scp, &setAttr, userp, &req);
2718 } /* lookup succeeded */
2722 /* we don't need this any longer */
2723 if (dscp) cm_ReleaseSCache(dscp);
2726 /* something went wrong creating or truncating the file */
2727 if (scp) cm_ReleaseSCache(scp);
2728 cm_ReleaseUser(userp);
2732 /* make sure we're about to open a file */
2733 if (scp->fileType != CM_SCACHETYPE_FILE) {
2734 cm_ReleaseSCache(scp);
2735 cm_ReleaseUser(userp);
2736 return CM_ERROR_ISDIR;
2739 /* now all we have to do is open the file itself */
2740 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2743 /* save a pointer to the vnode */
2746 /* compute open mode */
2747 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2748 if (openMode == 1 || openMode == 2)
2749 fidp->flags |= SMB_FID_OPENWRITE;
2751 smb_ReleaseFID(fidp);
2753 cm_Open(scp, 0, userp);
2755 /* set inp->fid so that later read calls in same msg can find fid */
2756 inp->fid = fidp->fid;
2758 /* copy out remainder of the parms */
2760 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2761 lock_ObtainMutex(&scp->mx);
2763 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2764 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2765 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2766 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2767 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2768 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2769 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2770 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2771 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2773 /* and the final "always present" stuff */
2774 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2775 /* next write out the "unique" ID */
2776 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2777 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2778 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2779 lock_ReleaseMutex(&scp->mx);
2780 smb_SetSMBDataLength(outp, 0);
2782 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
2784 cm_ReleaseUser(userp);
2785 /* leave scp held since we put it in fidp->scp */
2789 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2796 unsigned char LockType;
2797 unsigned short NumberOfUnlocks, NumberOfLocks;
2798 unsigned long Timeout;
2800 LARGE_INTEGER LOffset, LLength;
2801 smb_waitingLock_t *waitingLock;
2808 fid = smb_GetSMBParm(inp, 2);
2809 fid = smb_ChainFID(fid, inp);
2811 fidp = smb_FindFID(vcp, fid, 0);
2812 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2813 return CM_ERROR_BADFD;
2815 /* set inp->fid so that later read calls in same msg can find fid */
2818 userp = smb_GetUser(vcp, inp);
2822 lock_ObtainMutex(&scp->mx);
2823 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2824 CM_SCACHESYNC_NEEDCALLBACK
2825 | CM_SCACHESYNC_GETSTATUS
2826 | CM_SCACHESYNC_LOCK);
2827 if (code) goto doneSync;
2829 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2830 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2831 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2832 NumberOfLocks = smb_GetSMBParm(inp, 7);
2834 op = smb_GetSMBData(inp, NULL);
2836 for (i=0; i<NumberOfUnlocks; i++) {
2837 if (LockType & 0x10) {
2839 LOffset.HighPart = *((LONG *)(op + 4));
2840 LOffset.LowPart = *((DWORD *)(op + 8));
2841 LLength.HighPart = *((LONG *)(op + 12));
2842 LLength.LowPart = *((DWORD *)(op + 16));
2846 /* Not Large Files */
2847 LOffset.HighPart = 0;
2848 LOffset.LowPart = *((DWORD *)(op + 2));
2849 LLength.HighPart = 0;
2850 LLength.LowPart = *((DWORD *)(op + 6));
2853 if (LargeIntegerNotEqualToZero(LOffset))
2855 /* Do not check length -- length check done in cm_Unlock */
2857 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2858 if (code) goto done;
2861 for (i=0; i<NumberOfLocks; i++) {
2862 if (LockType & 0x10) {
2864 LOffset.HighPart = *((LONG *)(op + 4));
2865 LOffset.LowPart = *((DWORD *)(op + 8));
2866 LLength.HighPart = *((LONG *)(op + 12));
2867 LLength.LowPart = *((DWORD *)(op + 16));
2871 /* Not Large Files */
2872 LOffset.HighPart = 0;
2873 LOffset.LowPart = *((DWORD *)(op + 2));
2874 LLength.HighPart = 0;
2875 LLength.LowPart = *((DWORD *)(op + 6));
2878 if (LargeIntegerNotEqualToZero(LOffset))
2880 if (LargeIntegerLessThan(LOffset, scp->length))
2883 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2884 userp, &req, &lockp);
2885 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2886 /* Put on waiting list */
2887 waitingLock = malloc(sizeof(smb_waitingLock_t));
2888 waitingLock->vcp = vcp;
2889 waitingLock->inp = smb_CopyPacket(inp);
2890 waitingLock->outp = smb_CopyPacket(outp);
2891 waitingLock->timeRemaining = Timeout;
2892 waitingLock->lockp = lockp;
2893 lock_ObtainWrite(&smb_globalLock);
2894 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2896 osi_Wakeup((long) &smb_allWaitingLocks);
2897 lock_ReleaseWrite(&smb_globalLock);
2898 /* don't send reply immediately */
2899 outp->flags |= SMB_PACKETFLAG_NOSEND;
2905 /* release any locks acquired before the failure */
2908 smb_SetSMBDataLength(outp, 0);
2910 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2912 lock_ReleaseMutex(&scp->mx);
2913 cm_ReleaseUser(userp);
2914 smb_ReleaseFID(fidp);
2919 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2931 fid = smb_GetSMBParm(inp, 0);
2932 fid = smb_ChainFID(fid, inp);
2934 fidp = smb_FindFID(vcp, fid, 0);
2935 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2936 return CM_ERROR_BADFD;
2939 userp = smb_GetUser(vcp, inp);
2943 /* otherwise, stat the file */
2944 lock_ObtainMutex(&scp->mx);
2945 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2946 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2947 if (code) goto done;
2949 /* decode times. We need a search time, but the response to this
2950 * call provides the date first, not the time, as returned in the
2951 * searchTime variable. So we take the high-order bits first.
2953 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2954 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2955 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2956 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2957 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2958 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2959 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2961 /* now handle file size and allocation size */
2962 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2963 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2964 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2965 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2967 /* file attribute */
2968 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2970 /* and finalize stuff */
2971 smb_SetSMBDataLength(outp, 0);
2975 lock_ReleaseMutex(&scp->mx);
2976 cm_ReleaseUser(userp);
2977 smb_ReleaseFID(fidp);
2981 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2995 fid = smb_GetSMBParm(inp, 0);
2996 fid = smb_ChainFID(fid, inp);
2998 fidp = smb_FindFID(vcp, fid, 0);
2999 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3000 return CM_ERROR_BADFD;
3003 userp = smb_GetUser(vcp, inp);
3007 /* now prepare to call cm_setattr. This message only sets various times,
3008 * and AFS only implements mtime, and we'll set the mtime if that's
3009 * requested. The others we'll ignore.
3011 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
3013 if (searchTime != 0) {
3014 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
3016 if ( unixTime != -1 ) {
3017 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
3018 attrs.clientModTime = unixTime;
3019 code = cm_SetAttr(scp, &attrs, userp, &req);
3021 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
3023 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
3028 cm_ReleaseUser(userp);
3029 smb_ReleaseFID(fidp);
3034 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3037 long count, finalCount;
3044 fd = smb_GetSMBParm(inp, 2);
3045 count = smb_GetSMBParm(inp, 5);
3046 offset.HighPart = 0; /* too bad */
3047 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3049 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3050 fd, offset.LowPart, count);
3052 fd = smb_ChainFID(fd, inp);
3053 fidp = smb_FindFID(vcp, fd, 0);
3055 return CM_ERROR_BADFD;
3057 /* set inp->fid so that later read calls in same msg can find fid */
3060 if (fidp->flags & SMB_FID_IOCTL) {
3061 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3064 userp = smb_GetUser(vcp, inp);
3066 /* 0 and 1 are reserved for request chaining, were setup by our caller,
3067 * and will be further filled in after we return.
3069 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3070 smb_SetSMBParm(outp, 3, 0); /* resvd */
3071 smb_SetSMBParm(outp, 4, 0); /* resvd */
3072 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3073 /* fill in #6 when we have all the parameters' space reserved */
3074 smb_SetSMBParm(outp, 7, 0); /* resv'd */
3075 smb_SetSMBParm(outp, 8, 0); /* resv'd */
3076 smb_SetSMBParm(outp, 9, 0); /* resv'd */
3077 smb_SetSMBParm(outp, 10, 0); /* resv'd */
3078 smb_SetSMBParm(outp, 11, 0); /* reserved */
3080 /* get op ptr after putting in the parms, since otherwise we don't
3081 * know where the data really is.
3083 op = smb_GetSMBData(outp, NULL);
3085 /* now fill in offset from start of SMB header to first data byte (to op) */
3086 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3088 /* set the packet data length the count of the # of bytes */
3089 smb_SetSMBDataLength(outp, count);
3092 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3094 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3097 /* fix some things up */
3098 smb_SetSMBParm(outp, 5, finalCount);
3099 smb_SetSMBDataLength(outp, finalCount);
3101 smb_ReleaseFID(fidp);
3103 cm_ReleaseUser(userp);
3108 * Values for createDisp, copied from NTDDK.H
3110 * FILE_SUPERSEDE 0 (???)
3111 * FILE_OPEN 1 (open)
3112 * FILE_CREATE 2 (exclusive)
3113 * FILE_OPEN_IF 3 (non-exclusive)
3114 * FILE_OVERWRITE 4 (open & truncate, but do not create)
3115 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
3118 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3120 char *pathp, *realPathp;
3124 cm_scache_t *dscp; /* parent dir */
3125 cm_scache_t *scp; /* file to create or open */
3129 unsigned short nameLength;
3131 unsigned int requestOpLock;
3132 unsigned int requestBatchOpLock;
3133 unsigned int mustBeDir;
3134 unsigned int treeCreate;
3136 unsigned int desiredAccess;
3137 unsigned int extAttributes;
3138 unsigned int createDisp;
3139 unsigned int createOptions;
3140 int initialModeBits;
3141 unsigned short baseFid;
3142 smb_fid_t *baseFidp;
3144 cm_scache_t *baseDirp;
3145 unsigned short openAction;
3160 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3161 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3162 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3163 requestOpLock = flags & 0x02;
3164 requestBatchOpLock = flags & 0x04;
3165 mustBeDir = flags & 0x08;
3168 * Why all of a sudden 32-bit FID?
3169 * We will reject all bits higher than 16.
3171 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3172 return CM_ERROR_INVAL;
3173 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3174 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3175 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3176 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3177 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3178 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3179 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3180 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3181 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3183 /* mustBeDir is never set; createOptions directory bit seems to be
3186 if (createOptions & 1)
3188 else if (createOptions & 0x40)
3194 * compute initial mode bits based on read-only flag in
3195 * extended attributes
3197 initialModeBits = 0666;
3198 if (extAttributes & 1) initialModeBits &= ~0222;
3200 pathp = smb_GetSMBData(inp, NULL);
3201 /* Sometimes path is not null-terminated, so we make a copy. */
3202 realPathp = malloc(nameLength+1);
3203 memcpy(realPathp, pathp, nameLength);
3204 realPathp[nameLength] = 0;
3206 spacep = inp->spacep;
3207 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3209 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
3210 osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3212 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3213 /* special case magic file name for receiving IOCTL requests
3214 * (since IOCTL calls themselves aren't getting through).
3216 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3217 smb_SetupIoctlFid(fidp, spacep);
3219 /* set inp->fid so that later read calls in same msg can find fid */
3220 inp->fid = fidp->fid;
3224 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3225 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3226 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3228 memset(&ft, 0, sizeof(ft));
3229 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3230 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3231 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3232 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3233 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3234 sz.HighPart = 0x7fff; sz.LowPart = 0;
3235 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3236 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3237 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3238 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3239 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3240 smb_SetSMBDataLength(outp, 0);
3242 /* clean up fid reference */
3243 smb_ReleaseFID(fidp);
3248 #ifdef DEBUG_VERBOSE
3250 char *hexp, *asciip;
3251 asciip = (lastNamep? lastNamep : realPathp);
3252 hexp = osi_HexifyString( asciip );
3253 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3257 userp = smb_GetUser(vcp, inp);
3259 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3261 return CM_ERROR_INVAL;
3265 baseDirp = cm_rootSCachep;
3266 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3269 baseFidp = smb_FindFID(vcp, baseFid, 0);
3271 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3273 cm_ReleaseUser(userp);
3274 return CM_ERROR_INVAL;
3276 baseDirp = baseFidp->scp;
3280 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
3282 /* compute open mode */
3284 if (desiredAccess & DELETE)
3285 fidflags |= SMB_FID_OPENDELETE;
3286 if (desiredAccess & AFS_ACCESS_READ)
3287 fidflags |= SMB_FID_OPENREAD;
3288 if (desiredAccess & AFS_ACCESS_WRITE)
3289 fidflags |= SMB_FID_OPENWRITE;
3293 /* For an exclusive create, we want to do a case sensitive match for the last component. */
3294 if (createDisp == 2 || createDisp == 4) {
3295 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3296 userp, tidPathp, &req, &dscp);
3298 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
3299 userp, tidPathp, &req, &scp);
3303 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3304 userp, tidPathp, &req, &scp);
3307 if (code == 0) foundscp = TRUE;
3309 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3310 /* look up parent directory */
3311 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3312 * the immediate parent. We have to work our way up realPathp until we hit something that we
3320 code = cm_NameI(baseDirp, spacep->data,
3321 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3322 userp, tidPathp, &req, &dscp);
3325 (tp = strrchr(spacep->data,'\\')) &&
3326 (createDisp == 2) &&
3327 (realDirFlag == 1)) {
3330 treeStartp = realPathp + (tp - spacep->data);
3332 if (*tp && !smb_IsLegalFilename(tp)) {
3333 if(baseFid != 0) smb_ReleaseFID(baseFidp);
3334 cm_ReleaseUser(userp);
3336 return CM_ERROR_BADNTFILENAME;
3345 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3348 osi_Log0(smb_logp,"NTCreateX parent not found");
3349 cm_ReleaseUser(userp);
3354 if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3355 /* A file exists where we want a directory. */
3356 cm_ReleaseSCache(dscp);
3357 cm_ReleaseUser(userp);
3359 return CM_ERROR_EXISTS;
3362 if (!lastNamep) lastNamep = realPathp;
3365 if (!smb_IsLegalFilename(lastNamep)) {
3366 cm_ReleaseSCache(dscp);
3367 cm_ReleaseUser(userp);
3369 return CM_ERROR_BADNTFILENAME;
3372 if (!foundscp && !treeCreate) {
3373 if(createDisp == 2 || createDisp == 4)
3374 code = cm_Lookup(dscp, lastNamep,
3375 CM_FLAG_FOLLOW, userp, &req, &scp);
3377 code = cm_Lookup(dscp, lastNamep,
3378 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3380 if (code && code != CM_ERROR_NOSUCHFILE) {
3381 cm_ReleaseSCache(dscp);
3382 cm_ReleaseUser(userp);
3389 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3392 /* if we get here, if code is 0, the file exists and is represented by
3393 * scp. Otherwise, we have to create it. The dir may be represented
3394 * by dscp, or we may have found the file directly. If code is non-zero,
3397 if (code == 0 && !treeCreate) {
3398 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3401 if (dscp) cm_ReleaseSCache(dscp);
3402 cm_ReleaseSCache(scp);
3403 cm_ReleaseUser(userp);
3408 if (createDisp == 2) {
3409 /* oops, file shouldn't be there */
3410 if (dscp) cm_ReleaseSCache(dscp);
3411 cm_ReleaseSCache(scp);
3412 cm_ReleaseUser(userp);
3414 return CM_ERROR_EXISTS;
3418 || createDisp == 5) {
3419 setAttr.mask = CM_ATTRMASK_LENGTH;
3420 setAttr.length.LowPart = 0;
3421 setAttr.length.HighPart = 0;
3422 code = cm_SetAttr(scp, &setAttr, userp, &req);
3423 openAction = 3; /* truncated existing file */
3425 else openAction = 1; /* found existing file */
3427 else if (createDisp == 1 || createDisp == 4) {
3428 /* don't create if not found */
3429 if (dscp) cm_ReleaseSCache(dscp);
3430 cm_ReleaseUser(userp);
3432 return CM_ERROR_NOSUCHFILE;
3434 else if (realDirFlag == 0 || realDirFlag == -1) {
3435 osi_assert(dscp != NULL);
3436 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
3437 osi_LogSaveString(smb_logp, lastNamep));
3438 openAction = 2; /* created file */
3439 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3440 setAttr.clientModTime = time(NULL);
3441 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3443 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3444 smb_NotifyChange(FILE_ACTION_ADDED,
3445 FILE_NOTIFY_CHANGE_FILE_NAME,
3446 dscp, lastNamep, NULL, TRUE);
3447 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3448 /* Not an exclusive create, and someone else tried
3449 * creating it already, then we open it anyway. We
3450 * don't bother retrying after this, since if this next
3451 * fails, that means that the file was deleted after we
3452 * started this call.
3454 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3457 if (createDisp == 5) {
3458 setAttr.mask = CM_ATTRMASK_LENGTH;
3459 setAttr.length.LowPart = 0;
3460 setAttr.length.HighPart = 0;
3461 code = cm_SetAttr(scp, &setAttr, userp,
3464 } /* lookup succeeded */
3469 char *cp; /* This component */
3470 int clen = 0; /* length of component */
3474 /* create directory */
3475 if ( !treeCreate ) treeStartp = lastNamep;
3476 osi_assert(dscp != NULL);
3477 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3478 osi_LogSaveString(smb_logp, treeStartp));
3479 openAction = 2; /* created directory */
3481 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3482 setAttr.clientModTime = time(NULL);
3489 tp = strchr(pp, '\\');
3493 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
3497 strncpy(cp,pp,clen);
3503 if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3505 /* cp is the next component to be created. */
3506 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3507 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3508 smb_NotifyChange(FILE_ACTION_ADDED,
3509 FILE_NOTIFY_CHANGE_DIR_NAME,
3510 tscp, cp, NULL, TRUE);
3512 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3513 /* Not an exclusive create, and someone else tried
3514 * creating it already, then we open it anyway. We
3515 * don't bother retrying after this, since if this next
3516 * fails, that means that the file was deleted after we
3517 * started this call.
3519 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3524 if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3525 cm_ReleaseSCache(tscp);
3526 tscp = scp; /* Newly created directory will be next parent */
3531 if we get here and code == 0, then scp is the last directory created, and tscp is the
3532 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
3538 /* something went wrong creating or truncating the file */
3539 if (scp) cm_ReleaseSCache(scp);
3540 if (dscp) cm_ReleaseSCache(dscp);
3541 cm_ReleaseUser(userp);
3546 /* make sure we have file vs. dir right (only applies for single component case) */
3547 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3548 cm_ReleaseSCache(scp);
3549 if (dscp) cm_ReleaseSCache(dscp);
3550 cm_ReleaseUser(userp);
3552 return CM_ERROR_ISDIR;
3554 /* (only applies to single component case) */
3555 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3556 cm_ReleaseSCache(scp);
3557 if (dscp) cm_ReleaseSCache(dscp);
3558 cm_ReleaseUser(userp);
3560 return CM_ERROR_NOTDIR;
3563 /* open the file itself */
3564 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3566 /* save a pointer to the vnode */
3569 fidp->flags = fidflags;
3571 /* save parent dir and pathname for delete or change notification */
3572 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3573 fidp->flags |= SMB_FID_NTOPEN;
3574 fidp->NTopen_dscp = dscp;
3575 cm_HoldSCache(dscp);
3576 fidp->NTopen_pathp = strdup(lastNamep);
3578 fidp->NTopen_wholepathp = realPathp;
3580 /* we don't need this any longer */
3581 if (dscp) cm_ReleaseSCache(dscp);
3582 cm_Open(scp, 0, userp);
3584 /* set inp->fid so that later read calls in same msg can find fid */
3585 inp->fid = fidp->fid;
3589 lock_ObtainMutex(&scp->mx);
3590 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3591 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3592 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3593 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3594 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3595 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3596 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3597 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3598 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3600 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3601 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3602 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3603 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3604 smb_SetSMBParmByte(outp, parmSlot,
3605 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3606 lock_ReleaseMutex(&scp->mx);
3607 smb_SetSMBDataLength(outp, 0);
3609 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3610 osi_LogSaveString(smb_logp, realPathp));
3612 smb_ReleaseFID(fidp);
3614 cm_ReleaseUser(userp);
3616 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3618 /* leave scp held since we put it in fidp->scp */
3623 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3624 * Instead, ultimately, would like to use a subroutine for common code.
3626 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3628 char *pathp, *realPathp;
3632 cm_scache_t *dscp; /* parent dir */
3633 cm_scache_t *scp; /* file to create or open */
3636 unsigned long nameLength;
3638 unsigned int requestOpLock;
3639 unsigned int requestBatchOpLock;
3640 unsigned int mustBeDir;
3641 unsigned int extendedRespRequired;
3643 unsigned int desiredAccess;
3644 #ifdef DEBUG_VERBOSE
3645 unsigned int allocSize;
3646 unsigned int shareAccess;
3648 unsigned int extAttributes;
3649 unsigned int createDisp;
3650 #ifdef DEBUG_VERBOSE
3653 unsigned int createOptions;
3654 int initialModeBits;
3655 unsigned short baseFid;
3656 smb_fid_t *baseFidp;
3658 cm_scache_t *baseDirp;
3659 unsigned short openAction;
3665 int parmOffset, dataOffset;
3676 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3677 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3678 parmp = inp->data + parmOffset;
3679 lparmp = (ULONG *) parmp;
3682 requestOpLock = flags & 0x02;
3683 requestBatchOpLock = flags & 0x04;
3684 mustBeDir = flags & 0x08;
3685 extendedRespRequired = flags & 0x10;
3688 * Why all of a sudden 32-bit FID?
3689 * We will reject all bits higher than 16.
3691 if (lparmp[1] & 0xFFFF0000)
3692 return CM_ERROR_INVAL;
3693 baseFid = (unsigned short)lparmp[1];
3694 desiredAccess = lparmp[2];
3695 #ifdef DEBUG_VERBOSE
3696 allocSize = lparmp[3];
3697 #endif /* DEBUG_VERSOSE */
3698 extAttributes = lparmp[5];
3700 shareAccess = lparmp[6];
3702 createDisp = lparmp[7];
3703 createOptions = lparmp[8];
3704 #ifdef DEBUG_VERBOSE
3707 nameLength = lparmp[11];
3709 #ifdef DEBUG_VERBOSE
3710 osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3711 osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3712 osi_Log1(smb_logp,"... flags[%x]",flags);
3715 /* mustBeDir is never set; createOptions directory bit seems to be
3718 if (createOptions & 1)
3720 else if (createOptions & 0x40)
3726 * compute initial mode bits based on read-only flag in
3727 * extended attributes
3729 initialModeBits = 0666;
3730 if (extAttributes & 1) initialModeBits &= ~0222;
3732 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3733 /* Sometimes path is not null-terminated, so we make a copy. */
3734 realPathp = malloc(nameLength+1);
3735 memcpy(realPathp, pathp, nameLength);
3736 realPathp[nameLength] = 0;
3738 spacep = cm_GetSpace();
3739 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3742 * Nothing here to handle SMB_IOCTL_FILENAME.
3743 * Will add it if necessary.
3746 #ifdef DEBUG_VERBOSE
3748 char *hexp, *asciip;
3749 asciip = (lastNamep? lastNamep : realPathp);
3750 hexp = osi_HexifyString( asciip );
3751 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3756 userp = smb_GetUser(vcp, inp);
3758 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3760 return CM_ERROR_INVAL;
3764 baseDirp = cm_rootSCachep;
3765 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3768 baseFidp = smb_FindFID(vcp, baseFid, 0);
3770 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3772 cm_ReleaseUser(userp);
3773 return CM_ERROR_INVAL;
3775 baseDirp = baseFidp->scp;
3779 /* compute open mode */
3781 if (desiredAccess & DELETE)
3782 fidflags |= SMB_FID_OPENDELETE;
3783 if (desiredAccess & AFS_ACCESS_READ)
3784 fidflags |= SMB_FID_OPENREAD;
3785 if (desiredAccess & AFS_ACCESS_WRITE)
3786 fidflags |= SMB_FID_OPENWRITE;
3790 if (createDisp == 2 || createDisp == 4) {
3791 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3792 userp, tidPathp, &req, &dscp);
3794 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
3795 userp, tidPathp, &req, &scp);
3799 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3800 userp, tidPathp, &req, &scp);
3803 if (code == 0) foundscp = TRUE;
3805 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3806 /* look up parent directory */
3808 code = cm_NameI(baseDirp, spacep->data,
3809 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3810 userp, tidPathp, &req, &dscp);
3814 cm_FreeSpace(spacep);
3817 smb_ReleaseFID(baseFidp);
3822 cm_ReleaseUser(userp);
3827 if (!lastNamep) lastNamep = realPathp;
3830 if (!smb_IsLegalFilename(lastNamep))
3831 return CM_ERROR_BADNTFILENAME;
3834 if (createDisp == 2 || createDisp == 4)
3835 code = cm_Lookup(dscp, lastNamep,
3836 CM_FLAG_FOLLOW, userp, &req, &scp);
3838 code = cm_Lookup(dscp, lastNamep,
3839 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3841 if (code && code != CM_ERROR_NOSUCHFILE) {
3842 cm_ReleaseSCache(dscp);
3843 cm_ReleaseUser(userp);
3851 smb_ReleaseFID(baseFidp);
3854 cm_FreeSpace(spacep);
3857 /* if we get here, if code is 0, the file exists and is represented by
3858 * scp. Otherwise, we have to create it. The dir may be represented
3859 * by dscp, or we may have found the file directly. If code is non-zero,
3863 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3866 if (dscp) cm_ReleaseSCache(dscp);
3867 cm_ReleaseSCache(scp);
3868 cm_ReleaseUser(userp);
3873 if (createDisp == 2) {
3874 /* oops, file shouldn't be there */
3875 if (dscp) cm_ReleaseSCache(dscp);
3876 cm_ReleaseSCache(scp);
3877 cm_ReleaseUser(userp);
3879 return CM_ERROR_EXISTS;
3883 || createDisp == 5) {
3884 setAttr.mask = CM_ATTRMASK_LENGTH;
3885 setAttr.length.LowPart = 0;
3886 setAttr.length.HighPart = 0;
3887 code = cm_SetAttr(scp, &setAttr, userp, &req);
3888 openAction = 3; /* truncated existing file */
3890 else openAction = 1; /* found existing file */
3892 else if (createDisp == 1 || createDisp == 4) {
3893 /* don't create if not found */
3894 if (dscp) cm_ReleaseSCache(dscp);
3895 cm_ReleaseUser(userp);
3897 return CM_ERROR_NOSUCHFILE;
3899 else if (realDirFlag == 0 || realDirFlag == -1) {
3900 osi_assert(dscp != NULL);
3901 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
3902 osi_LogSaveString(smb_logp, lastNamep));
3903 openAction = 2; /* created file */
3904 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3905 setAttr.clientModTime = time(NULL);
3906 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3908 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3909 smb_NotifyChange(FILE_ACTION_ADDED,
3910 FILE_NOTIFY_CHANGE_FILE_NAME,
3911 dscp, lastNamep, NULL, TRUE);
3912 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3913 /* Not an exclusive create, and someone else tried
3914 * creating it already, then we open it anyway. We
3915 * don't bother retrying after this, since if this next
3916 * fails, that means that the file was deleted after we
3917 * started this call.
3919 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3922 if (createDisp == 5) {
3923 setAttr.mask = CM_ATTRMASK_LENGTH;
3924 setAttr.length.LowPart = 0;
3925 setAttr.length.HighPart = 0;
3926 code = cm_SetAttr(scp, &setAttr, userp,
3929 } /* lookup succeeded */
3933 /* create directory */
3934 osi_assert(dscp != NULL);
3936 "smb_ReceiveNTTranCreate creating directory %s",
3937 osi_LogSaveString(smb_logp, lastNamep));
3938 openAction = 2; /* created directory */
3939 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3940 setAttr.clientModTime = time(NULL);
3941 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3942 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3943 smb_NotifyChange(FILE_ACTION_ADDED,
3944 FILE_NOTIFY_CHANGE_DIR_NAME,
3945 dscp, lastNamep, NULL, TRUE);
3947 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3948 /* Not an exclusive create, and someone else tried
3949 * creating it already, then we open it anyway. We
3950 * don't bother retrying after this, since if this next
3951 * fails, that means that the file was deleted after we
3952 * started this call.
3954 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3960 /* something went wrong creating or truncating the file */
3961 if (scp) cm_ReleaseSCache(scp);
3962 cm_ReleaseUser(userp);
3967 /* make sure we have file vs. dir right */
3968 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3969 cm_ReleaseSCache(scp);
3970 cm_ReleaseUser(userp);
3972 return CM_ERROR_ISDIR;
3974 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3975 cm_ReleaseSCache(scp);
3976 cm_ReleaseUser(userp);
3978 return CM_ERROR_NOTDIR;
3981 /* open the file itself */
3982 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3985 /* save a pointer to the vnode */
3988 fidp->flags = fidflags;
3990 /* save parent dir and pathname for deletion or change notification */
3991 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3992 fidp->flags |= SMB_FID_NTOPEN;
3993 fidp->NTopen_dscp = dscp;
3994 cm_HoldSCache(dscp);
3995 fidp->NTopen_pathp = strdup(lastNamep);
3997 fidp->NTopen_wholepathp = realPathp;
3999 /* we don't need this any longer */
4000 if (dscp) cm_ReleaseSCache(dscp);
4002 cm_Open(scp, 0, userp);
4004 /* set inp->fid so that later read calls in same msg can find fid */
4005 inp->fid = fidp->fid;
4007 /* check whether we are required to send an extended response */
4008 if (!extendedRespRequired) {
4010 parmOffset = 8*4 + 39;
4011 parmOffset += 1; /* pad to 4 */
4012 dataOffset = parmOffset + 70;
4016 /* Total Parameter Count */
4017 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4018 /* Total Data Count */
4019 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4020 /* Parameter Count */
4021 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4022 /* Parameter Offset */
4023 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4024 /* Parameter Displacement */
4025 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4027 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4029 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4030 /* Data Displacement */
4031 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4032 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4033 smb_SetSMBDataLength(outp, 70);
4035 lock_ObtainMutex(&scp->mx);
4036 outData = smb_GetSMBData(outp, NULL);
4037 outData++; /* round to get to parmOffset */
4038 *outData = 0; outData++; /* oplock */
4039 *outData = 0; outData++; /* reserved */
4040 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4041 *((ULONG *)outData) = openAction; outData += 4;
4042 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
4043 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4044 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
4045 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
4046 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
4047 *((FILETIME *)outData) = ft; outData += 8; /* change time */
4048 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4049 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4050 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4051 *((USHORT *)outData) = 0; outData += 2; /* filetype */
4052 *((USHORT *)outData) = 0; outData += 2; /* dev state */
4053 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4054 outData += 2; /* is a dir? */
4055 lock_ReleaseMutex(&scp->mx);
4058 parmOffset = 8*4 + 39;
4059 parmOffset += 1; /* pad to 4 */
4060 dataOffset = parmOffset + 104;
4064 /* Total Parameter Count */
4065 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4066 /* Total Data Count */
4067 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4068 /* Parameter Count */
4069 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4070 /* Parameter Offset */
4071 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4072 /* Parameter Displacement */
4073 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4075 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4077 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4078 /* Data Displacement */
4079 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4080 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4081 smb_SetSMBDataLength(outp, 105);
4083 lock_ObtainMutex(&scp->mx);
4084 outData = smb_GetSMBData(outp, NULL);
4085 outData++; /* round to get to parmOffset */
4086 *outData = 0; outData++; /* oplock */
4087 *outData = 1; outData++; /* response type */
4088 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4089 *((ULONG *)outData) = openAction; outData += 4;
4090 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
4091 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4092 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
4093 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
4094 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
4095 *((FILETIME *)outData) = ft; outData += 8; /* change time */
4096 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4097 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4098 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4099 *((USHORT *)outData) = 0; outData += 2; /* filetype */
4100 *((USHORT *)outData) = 0; outData += 2; /* dev state */
4101 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4102 outData += 1; /* is a dir? */
4103 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
4104 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
4105 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
4106 lock_ReleaseMutex(&scp->mx);
4109 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
4111 smb_ReleaseFID(fidp);
4113 cm_ReleaseUser(userp);
4115 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
4116 /* leave scp held since we put it in fidp->scp */
4120 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
4123 smb_packet_t *savedPacketp;
4124 ULONG filter; USHORT fid, watchtree;
4128 filter = smb_GetSMBParm(inp, 19)
4129 | (smb_GetSMBParm(inp, 20) << 16);
4130 fid = smb_GetSMBParm(inp, 21);
4131 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
4133 fidp = smb_FindFID(vcp, fid, 0);
4135 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
4136 return CM_ERROR_BADFD;
4139 savedPacketp = smb_CopyPacket(inp);
4140 savedPacketp->vcp = vcp; /* TODO: refcount vcp? */
4141 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4142 savedPacketp->nextp = smb_Directory_Watches;
4143 smb_Directory_Watches = savedPacketp;
4144 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4146 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
4147 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
4150 lock_ObtainMutex(&scp->mx);
4152 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
4154 scp->flags |= CM_SCACHEFLAG_WATCHED;
4155 lock_ReleaseMutex(&scp->mx);
4156 smb_ReleaseFID(fidp);
4158 outp->flags |= SMB_PACKETFLAG_NOSEND;
4162 unsigned char nullSecurityDesc[36] = {
4163 0x01, /* security descriptor revision */
4164 0x00, /* reserved, should be zero */
4165 0x00, 0x80, /* security descriptor control;
4166 * 0x8000 : self-relative format */
4167 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
4168 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
4169 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
4170 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
4171 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4172 /* "null SID" owner SID */
4173 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4174 /* "null SID" group SID */
4177 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4179 int parmOffset, parmCount, dataOffset, dataCount;
4187 ULONG securityInformation;
4189 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4190 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4191 parmp = inp->data + parmOffset;
4192 sparmp = (USHORT *) parmp;
4193 lparmp = (ULONG *) parmp;
4196 securityInformation = lparmp[1];
4198 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
4199 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4207 parmOffset = 8*4 + 39;
4208 parmOffset += 1; /* pad to 4 */
4210 dataOffset = parmOffset + parmCount;
4214 /* Total Parameter Count */
4215 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4216 /* Total Data Count */
4217 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4218 /* Parameter Count */
4219 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4220 /* Parameter Offset */
4221 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4222 /* Parameter Displacement */
4223 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4225 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4227 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4228 /* Data Displacement */
4229 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4230 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4231 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
4233 outData = smb_GetSMBData(outp, NULL);
4234 outData++; /* round to get to parmOffset */
4235 *((ULONG *)outData) = 36; outData += 4; /* length */
4237 if (maxData >= 36) {
4238 memcpy(outData, nullSecurityDesc, 36);
4242 return CM_ERROR_BUFFERTOOSMALL;
4245 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4247 unsigned short function;
4249 function = smb_GetSMBParm(inp, 18);
4251 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
4253 /* We can handle long names */
4254 if (vcp->flags & SMB_VCFLAG_USENT)
4255 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
4259 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
4261 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
4263 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
4265 default: return CM_ERROR_INVAL;
4270 * smb_NotifyChange -- find relevant change notification messages and
4273 * If we don't know the file name (i.e. a callback break), filename is
4274 * NULL, and we return a zero-length list.
4276 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
4277 cm_scache_t *dscp, char *filename, char *otherFilename,
4278 BOOL isDirectParent)
4280 smb_packet_t *watch, *lastWatch, *nextWatch;
4281 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
4282 char *outData, *oldOutData;
4286 BOOL twoEntries = FALSE;
4287 ULONG otherNameLen, oldParmCount = 0;
4292 /* Get ready for rename within directory */
4293 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
4295 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
4298 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4299 watch = smb_Directory_Watches;
4301 filter = smb_GetSMBParm(watch, 19)
4302 | (smb_GetSMBParm(watch, 20) << 16);
4303 fid = smb_GetSMBParm(watch, 21);
4304 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
4305 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
4306 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
4310 * Strange hack - bug in NT Client and NT Server that we
4313 if (filter == 3 && wtree)
4316 fidp = smb_FindFID(vcp, fid, 0);
4319 watch = watch->nextp;
4322 if (fidp->scp != dscp
4323 || (filter & notifyFilter) == 0
4324 || (!isDirectParent && !wtree)) {
4325 smb_ReleaseFID(fidp);
4327 watch = watch->nextp;
4330 smb_ReleaseFID(fidp);
4333 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
4334 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
4336 nextWatch = watch->nextp;
4337 if (watch == smb_Directory_Watches)
4338 smb_Directory_Watches = nextWatch;
4340 lastWatch->nextp = nextWatch;
4342 /* Turn off WATCHED flag in dscp */
4343 lock_ObtainMutex(&dscp->mx);
4345 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4347 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
4348 lock_ReleaseMutex(&dscp->mx);
4350 /* Convert to response packet */
4351 ((smb_t *) watch)->reb = 0x80;
4352 ((smb_t *) watch)->wct = 0;
4355 if (filename == NULL)
4358 nameLen = strlen(filename);
4359 parmCount = 3*4 + nameLen*2;
4360 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4362 otherNameLen = strlen(otherFilename);
4363 oldParmCount = parmCount;
4364 parmCount += 3*4 + otherNameLen*2;
4365 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4367 if (maxLen < parmCount)
4368 parmCount = 0; /* not enough room */
4370 parmOffset = 8*4 + 39;
4371 parmOffset += 1; /* pad to 4 */
4372 dataOffset = parmOffset + parmCount;
4376 /* Total Parameter Count */
4377 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4378 /* Total Data Count */
4379 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4380 /* Parameter Count */
4381 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4382 /* Parameter Offset */
4383 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
4384 /* Parameter Displacement */
4385 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4387 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4389 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
4390 /* Data Displacement */
4391 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4392 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
4393 smb_SetSMBDataLength(watch, parmCount + 1);
4395 if (parmCount != 0) {
4396 outData = smb_GetSMBData(watch, NULL);
4397 outData++; /* round to get to parmOffset */
4398 oldOutData = outData;
4399 *((DWORD *)outData) = oldParmCount; outData += 4;
4400 /* Next Entry Offset */
4401 *((DWORD *)outData) = action; outData += 4;
4403 *((DWORD *)outData) = nameLen*2; outData += 4;
4404 /* File Name Length */
4405 mbstowcs((WCHAR *)outData, filename, nameLen);
4408 outData = oldOutData + oldParmCount;
4409 *((DWORD *)outData) = 0; outData += 4;
4410 /* Next Entry Offset */
4411 *((DWORD *)outData) = otherAction; outData += 4;
4413 *((DWORD *)outData) = otherNameLen*2;
4414 outData += 4; /* File Name Length */
4415 mbstowcs((WCHAR *)outData, otherFilename,
4416 otherNameLen); /* File Name */
4421 * If filename is null, we don't know the cause of the
4422 * change notification. We return zero data (see above),
4423 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4424 * (= 0x010C). We set the error code here by hand, without
4425 * modifying wct and bcc.
4427 if (filename == NULL) {
4428 ((smb_t *) watch)->rcls = 0x0C;
4429 ((smb_t *) watch)->reh = 0x01;
4430 ((smb_t *) watch)->errLow = 0;
4431 ((smb_t *) watch)->errHigh = 0;
4432 /* Set NT Status codes flag */
4433 ((smb_t *) watch)->flg2 |= 0x4000;
4436 smb_SendPacket(vcp, watch);
4437 smb_FreePacket(watch);
4440 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4443 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4445 unsigned char *replyWctp;
4446 smb_packet_t *watch, *lastWatch;
4447 USHORT fid, watchtree;
4451 osi_Log0(smb_logp, "SMB3 receive NT cancel");
4453 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4454 watch = smb_Directory_Watches;
4456 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4457 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4458 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4459 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4460 if (watch == smb_Directory_Watches)
4461 smb_Directory_Watches = watch->nextp;
4463 lastWatch->nextp = watch->nextp;
4464 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4466 /* Turn off WATCHED flag in scp */
4467 fid = smb_GetSMBParm(watch, 21);
4468 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4470 fidp = smb_FindFID(vcp, fid, 0);
4472 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
4474 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
4477 lock_ObtainMutex(&scp->mx);
4479 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4481 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4482 lock_ReleaseMutex(&scp->mx);
4483 smb_ReleaseFID(fidp);
4485 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
4488 /* assume STATUS32; return 0xC0000120 (CANCELED) */
4489 replyWctp = watch->wctp;
4493 ((smb_t *)watch)->rcls = 0x20;
4494 ((smb_t *)watch)->reh = 0x1;
4495 ((smb_t *)watch)->errLow = 0;
4496 ((smb_t *)watch)->errHigh = 0xC0;
4497 ((smb_t *)watch)->flg2 |= 0x4000;
4498 smb_SendPacket(vcp, watch);
4499 smb_FreePacket(watch);
4503 watch = watch->nextp;
4505 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4512 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4515 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4518 smb_username_t *unp;
4520 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4522 lock_ObtainMutex(&unp->mx);
4523 unp->userp = cm_NewUser();
4524 lock_ReleaseMutex(&unp->mx);
4525 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
4527 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);