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 #ifndef USE_OLD_MATCHING
1749 // char table for case insensitive comparison
1750 char mapCaseTable[256];
1752 VOID initUpperCaseTable(VOID)
1755 for (i = 0; i < 256; ++i)
1756 mapCaseTable[i] = toupper(i);
1757 // make '"' match '.'
1758 mapCaseTable[(int)'"'] = toupper('.');
1761 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
1763 // Note : this procedure works recursively calling itself.
1765 // PSZ pattern : string containing metacharacters.
1766 // PSZ name : file name to be compared with 'pattern'.
1768 // BOOL : TRUE/FALSE (match/mistmatch)
1770 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
1771 PSZ pename; // points to the last 'name' character
1773 pename = name + strlen(name) - 1;
1777 if (*(++pattern) != '<' || *(++pattern) != '*') {
1778 if (*name == '.') return FALSE;
1784 while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?')) ++pattern;
1785 if (!*pattern) return TRUE;
1786 for (p = pename; p >= name; --p) {
1787 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
1788 szWildCardMatchFileName(pattern + 1, p + 1))
1793 if (mapCaseTable[*name] != mapCaseTable[*pattern]) return FALSE;
1797 } /* endwhile */ return !*pattern;
1800 /* do a case-folding search of the star name mask with the name in namep.
1801 * Return 1 if we match, otherwise 0.
1803 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1805 /* make sure we only match 8.3 names, if requested */
1806 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
1809 return szWildCardMatchFileName(maskp, namep) ? 1:0;
1812 #else /* USE_OLD_MATCHING */
1813 /* do a case-folding search of the star name mask with the name in namep.
1814 * Return 1 if we match, otherwise 0.
1816 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1818 unsigned char tcp1, tcp2; /* Pattern characters */
1819 unsigned char tcn1; /* Name characters */
1820 int sawDot = 0, sawStar = 0, req8dot3 = 0;
1821 char *starNamep, *starMaskp;
1822 static char nullCharp[] = {0};
1823 int casefold = flags & CM_FLAG_CASEFOLD;
1825 /* make sure we only match 8.3 names, if requested */
1826 req8dot3 = (flags & CM_FLAG_8DOT3);
1827 if (req8dot3 && !cm_Is8Dot3(namep))
1832 /* Next pattern character */
1835 /* Next name character */
1839 /* 0 - end of pattern */
1845 else if (tcp1 == '.' || tcp1 == '"') {
1855 * first dot in pattern;
1856 * must match dot or end of name
1861 else if (tcn1 == '.') {
1870 else if (tcp1 == '?') {
1871 if (tcn1 == 0 || tcn1 == '.')
1876 else if (tcp1 == '>') {
1877 if (tcn1 != 0 && tcn1 != '.')
1881 else if (tcp1 == '*' || tcp1 == '<') {
1885 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
1886 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
1901 * pattern character after '*' is not null or
1902 * period. If it is '?' or '>', we are not
1903 * going to understand it. If it is '*' or
1904 * '<', we are going to skip over it. None of
1905 * these are likely, I hope.
1907 /* skip over '*' and '<' */
1908 while (tcp2 == '*' || tcp2 == '<')
1911 /* skip over characters that don't match tcp2 */
1912 while (req8dot3 && tcn1 != '.' && tcn1 != 0 &&
1913 ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) ||
1914 (!casefold && tcn1 != tcp2)))
1918 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
1921 /* Remember where we are */
1931 /* tcp1 is not a wildcard */
1932 if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) ||
1933 (!casefold && tcn1 == tcp1)) {
1938 /* if trying to match a star pattern, go back */
1940 maskp = starMaskp - 2;
1941 namep = starNamep + 1;
1950 #endif /* USE_OLD_MATCHING */
1952 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1961 smb_dirListPatch_t *dirListPatchesp;
1962 smb_dirListPatch_t *curPatchp;
1965 long orbytes; /* # of bytes in this output record */
1966 long ohbytes; /* # of bytes, except file name */
1967 long onbytes; /* # of bytes in name, incl. term. null */
1968 osi_hyper_t dirLength;
1969 osi_hyper_t bufferOffset;
1970 osi_hyper_t curOffset;
1972 smb_dirSearch_t *dsp;
1976 cm_pageHeader_t *pageHeaderp;
1977 cm_user_t *userp = NULL;
1980 long nextEntryCookie;
1981 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1982 char *op; /* output data ptr */
1983 char *origOp; /* original value of op */
1984 cm_space_t *spacep; /* for pathname buffer */
1985 long maxReturnData; /* max # of return data */
1986 long maxReturnParms; /* max # of return parms */
1987 long bytesInBuffer; /* # data bytes in the output buffer */
1989 char *maskp; /* mask part of path */
1993 smb_tran2Packet_t *outp; /* response packet */
1996 char shortName[13]; /* 8.3 name if needed */
2008 if (p->opcode == 1) {
2009 /* find first; obtain basic parameters from request */
2010 attribute = p->parmsp[0];
2011 maxCount = p->parmsp[1];
2012 infoLevel = p->parmsp[3];
2013 searchFlags = p->parmsp[2];
2014 dsp = smb_NewDirSearch(1);
2015 dsp->attribute = attribute;
2016 pathp = ((char *) p->parmsp) + 12; /* points to path */
2018 maskp = strrchr(pathp, '\\');
2019 if (maskp == NULL) maskp = pathp;
2020 else maskp++; /* skip over backslash */
2021 strcpy(dsp->mask, maskp); /* and save mask */
2022 /* track if this is likely to match a lot of entries */
2023 starPattern = smb_V3IsStarMask(maskp);
2026 osi_assert(p->opcode == 2);
2027 /* find next; obtain basic parameters from request or open dir file */
2028 dsp = smb_FindDirSearch(p->parmsp[0]);
2029 if (!dsp) return CM_ERROR_BADFD;
2030 attribute = dsp->attribute;
2031 maxCount = p->parmsp[1];
2032 infoLevel = p->parmsp[2];
2033 searchFlags = p->parmsp[5];
2035 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
2037 starPattern = 1; /* assume, since required a Find Next */
2041 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
2042 attribute, infoLevel, maxCount, searchFlags);
2044 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
2045 p->opcode, nextCookie);
2047 if (infoLevel >= 0x101)
2048 searchFlags &= ~4; /* no resume keys */
2050 dirListPatchesp = NULL;
2052 maxReturnData = p->maxReturnData;
2053 if (p->opcode == 1) /* find first */
2054 maxReturnParms = 10; /* bytes */
2056 maxReturnParms = 8; /* bytes */
2058 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
2059 if (maxReturnData > 6000)
2060 maxReturnData = 6000;
2061 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
2063 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
2066 osi_Log1(smb_logp, "T2 receive search dir %s",
2067 osi_LogSaveString(smb_logp, pathp));
2069 /* bail out if request looks bad */
2070 if (p->opcode == 1 && !pathp) {
2071 smb_ReleaseDirSearch(dsp);
2072 smb_FreeTran2Packet(outp);
2073 return CM_ERROR_BADSMB;
2076 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
2077 nextCookie, dsp->cookie);
2079 userp = smb_GetTran2User(vcp, p);
2081 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2082 smb_ReleaseDirSearch(dsp);
2083 smb_FreeTran2Packet(outp);
2084 return CM_ERROR_BADSMB;
2087 /* try to get the vnode for the path name next */
2088 lock_ObtainMutex(&dsp->mx);
2095 spacep = cm_GetSpace();
2096 smb_StripLastComponent(spacep->data, NULL, pathp);
2097 lock_ReleaseMutex(&dsp->mx);
2099 tidPathp = smb_GetTIDPath(vcp, p->tid);
2100 code = cm_NameI(cm_rootSCachep, spacep->data,
2101 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2102 userp, tidPathp, &req, &scp);
2103 cm_FreeSpace(spacep);
2105 lock_ObtainMutex(&dsp->mx);
2107 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2109 /* we need one hold for the entry we just stored into,
2110 * and one for our own processing. When we're done
2111 * with this function, we'll drop the one for our own
2112 * processing. We held it once from the namei call,
2113 * and so we do another hold now.
2116 lock_ObtainMutex(&scp->mx);
2117 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2118 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2119 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2120 dsp->flags |= SMB_DIRSEARCH_BULKST;
2122 lock_ReleaseMutex(&scp->mx);
2125 lock_ReleaseMutex(&dsp->mx);
2127 cm_ReleaseUser(userp);
2128 smb_FreeTran2Packet(outp);
2129 smb_DeleteDirSearch(dsp);
2130 smb_ReleaseDirSearch(dsp);
2134 /* get the directory size */
2135 lock_ObtainMutex(&scp->mx);
2136 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2137 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2139 lock_ReleaseMutex(&scp->mx);
2140 cm_ReleaseSCache(scp);
2141 cm_ReleaseUser(userp);
2142 smb_FreeTran2Packet(outp);
2143 smb_DeleteDirSearch(dsp);
2144 smb_ReleaseDirSearch(dsp);
2149 dirLength = scp->length;
2151 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2152 curOffset.HighPart = 0;
2153 curOffset.LowPart = nextCookie;
2154 origOp = outp->datap;
2162 if (searchFlags & 4)
2163 /* skip over resume key */
2166 /* make sure that curOffset.LowPart doesn't point to the first
2167 * 32 bytes in the 2nd through last dir page, and that it doesn't
2168 * point at the first 13 32-byte chunks in the first dir page,
2169 * since those are dir and page headers, and don't contain useful
2172 temp = curOffset.LowPart & (2048-1);
2173 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2174 /* we're in the first page */
2175 if (temp < 13*32) temp = 13*32;
2178 /* we're in a later dir page */
2179 if (temp < 32) temp = 32;
2182 /* make sure the low order 5 bits are zero */
2185 /* now put temp bits back ito curOffset.LowPart */
2186 curOffset.LowPart &= ~(2048-1);
2187 curOffset.LowPart |= temp;
2189 /* check if we've passed the dir's EOF */
2190 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2195 /* check if we've returned all the names that will fit in the
2196 * response packet; we check return count as well as the number
2197 * of bytes requested. We check the # of bytes after we find
2198 * the dir entry, since we'll need to check its size.
2200 if (returnedNames >= maxCount) {
2204 /* see if we can use the bufferp we have now; compute in which
2205 * page the current offset would be, and check whether that's
2206 * the offset of the buffer we have. If not, get the buffer.
2208 thyper.HighPart = curOffset.HighPart;
2209 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2210 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2213 buf_Release(bufferp);
2216 lock_ReleaseMutex(&scp->mx);
2217 lock_ObtainRead(&scp->bufCreateLock);
2218 code = buf_Get(scp, &thyper, &bufferp);
2219 lock_ReleaseRead(&scp->bufCreateLock);
2221 /* now, if we're doing a star match, do bulk fetching
2222 * of all of the status info for files in the dir.
2225 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2228 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2229 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
2230 /* Don't bulk stat if risking timeout */
2231 int now = GetCurrentTime();
2232 if (now - req.startTime > 5000) {
2233 scp->bulkStatProgress = thyper;
2234 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2235 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2237 cm_TryBulkStat(scp, &thyper, userp, &req);
2241 lock_ObtainMutex(&scp->mx);
2243 bufferOffset = thyper;
2245 /* now get the data in the cache */
2247 code = cm_SyncOp(scp, bufferp, userp, &req,
2249 CM_SCACHESYNC_NEEDCALLBACK
2250 | CM_SCACHESYNC_READ);
2253 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2255 /* otherwise, load the buffer and try again */
2256 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2261 buf_Release(bufferp);
2265 } /* if (wrong buffer) ... */
2267 /* now we have the buffer containing the entry we're interested
2268 * in; copy it out if it represents a non-deleted entry.
2270 entryInDir = curOffset.LowPart & (2048-1);
2271 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2273 /* page header will help tell us which entries are free. Page
2274 * header can change more often than once per buffer, since
2275 * AFS 3 dir page size may be less than (but not more than)
2276 * a buffer package buffer.
2278 /* only look intra-buffer */
2279 temp = curOffset.LowPart & (buf_bufferSize - 1);
2280 temp &= ~(2048 - 1); /* turn off intra-page bits */
2281 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2283 /* now determine which entry we're looking at in the page.
2284 * If it is free (there's a free bitmap at the start of the
2285 * dir), we should skip these 32 bytes.
2287 slotInPage = (entryInDir & 0x7e0) >> 5;
2288 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2289 & (1 << (slotInPage & 0x7)))) {
2290 /* this entry is free */
2291 numDirChunks = 1; /* only skip this guy */
2295 tp = bufferp->datap + entryInBuffer;
2296 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2298 /* while we're here, compute the next entry's location, too,
2299 * since we'll need it when writing out the cookie into the dir
2302 * XXXX Probably should do more sanity checking.
2304 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2306 /* compute offset of cookie representing next entry */
2307 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
2309 /* Need 8.3 name? */
2311 if (infoLevel == 0x104
2312 && dep->fid.vnode != 0
2313 && !cm_Is8Dot3(dep->name)) {
2314 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2318 /* When matching, we are using doing a case fold if we have a wildcard mask.
2319 * If we get a non-wildcard match, it's a lookup for a specific file.
2321 if (dep->fid.vnode != 0 &&
2322 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
2324 && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
2326 /* Eliminate entries that don't match requested attributes */
2327 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
2328 smb_IsDotFile(dep->name))
2329 goto nextEntry; /* no hidden files */
2331 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
2333 /* We have already done the cm_TryBulkStat above */
2334 fid.cell = scp->fid.cell;
2335 fid.volume = scp->fid.volume;
2336 fid.vnode = ntohl(dep->fid.vnode);
2337 fid.unique = ntohl(dep->fid.unique);
2338 fileType = cm_FindFileType(&fid);
2339 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
2340 "has filetype %d", dep->name,
2342 if (fileType == CM_SCACHETYPE_DIRECTORY)
2346 /* finally check if this name will fit */
2348 /* standard dir entry stuff */
2349 if (infoLevel < 0x101)
2350 ohbytes = 23; /* pre-NT */
2351 else if (infoLevel == 0x103)
2352 ohbytes = 12; /* NT names only */
2354 ohbytes = 64; /* NT */
2356 if (infoLevel == 0x104)
2357 ohbytes += 26; /* Short name & length */
2359 if (searchFlags & 4) {
2360 ohbytes += 4; /* if resume key required */
2364 && infoLevel != 0x101
2365 && infoLevel != 0x103)
2366 ohbytes += 4; /* EASIZE */
2368 /* add header to name & term. null */
2369 orbytes = onbytes + ohbytes + 1;
2371 /* now, we round up the record to a 4 byte alignment,
2372 * and we make sure that we have enough room here for
2373 * even the aligned version (so we don't have to worry
2374 * about an * overflow when we pad things out below).
2375 * That's the reason for the alignment arithmetic below.
2377 if (infoLevel >= 0x101)
2378 align = (4 - (orbytes & 3)) & 3;
2381 if (orbytes + bytesInBuffer + align > maxReturnData)
2384 /* this is one of the entries to use: it is not deleted
2385 * and it matches the star pattern we're looking for.
2386 * Put out the name, preceded by its length.
2388 /* First zero everything else */
2389 memset(origOp, 0, ohbytes);
2391 if (infoLevel <= 0x101)
2392 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2393 else if (infoLevel == 0x103)
2394 *((u_long *)(op + 8)) = onbytes;
2396 *((u_long *)(op + 60)) = onbytes;
2397 strcpy(origOp+ohbytes, dep->name);
2399 /* Short name if requested and needed */
2400 if (infoLevel == 0x104) {
2401 if (NeedShortName) {
2402 strcpy(op + 70, shortName);
2403 *(op + 68) = shortNameEnd - shortName;
2407 /* now, adjust the # of entries copied */
2410 /* NextEntryOffset and FileIndex */
2411 if (infoLevel >= 101) {
2412 int entryOffset = orbytes + align;
2413 *((u_long *)op) = entryOffset;
2414 *((u_long *)(op+4)) = nextEntryCookie;
2417 /* now we emit the attribute. This is tricky, since
2418 * we need to really stat the file to find out what
2419 * type of entry we've got. Right now, we're copying
2420 * out data from * a buffer, while holding the scp
2421 * locked, so it isn't really convenient to stat
2422 * something now. We'll put in a place holder
2423 * now, and make a second pass before returning this
2424 * to get the real attributes. So, we just skip the
2425 * data for now, and adjust it later. We allocate a
2426 * patch record to make it easy to find this point
2427 * later. The replay will happen at a time when it is
2428 * safe to unlock the directory.
2430 if (infoLevel != 0x103) {
2431 curPatchp = malloc(sizeof(*curPatchp));
2432 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2434 curPatchp->dptr = op;
2435 if (infoLevel >= 0x101)
2436 curPatchp->dptr += 8;
2438 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2439 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2442 curPatchp->flags = 0;
2444 curPatchp->fid.cell = scp->fid.cell;
2445 curPatchp->fid.volume = scp->fid.volume;
2446 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2447 curPatchp->fid.unique = ntohl(dep->fid.unique);
2450 curPatchp->dep = dep;
2453 if (searchFlags & 4)
2454 /* put out resume key */
2455 *((u_long *)origOp) = nextEntryCookie;
2457 /* Adjust byte ptr and count */
2458 origOp += orbytes; /* skip entire record */
2459 bytesInBuffer += orbytes;
2461 /* and pad the record out */
2462 while (--align >= 0) {
2467 } /* if we're including this name */
2468 else if(!NeedShortName &&
2471 dep->fid.vnode != 0 &&
2472 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
2473 /* We were looking for exact matches, but here's an inexact one*/
2478 /* and adjust curOffset to be where the new cookie is */
2479 thyper.HighPart = 0;
2480 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2481 curOffset = LargeIntegerAdd(thyper, curOffset);
2482 } /* while copying data for dir listing */
2484 /* If we didn't get a star pattern, we did an exact match during the first pass.
2485 * If there were no exact matches found, we fail over to inexact matches by
2486 * marking the query as a star pattern (matches all case permutations), and
2487 * re-running the query.
2489 if (returnedNames == 0 && !starPattern && foundInexact) {
2490 osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
2495 /* release the mutex */
2496 lock_ReleaseMutex(&scp->mx);
2497 if (bufferp) buf_Release(bufferp);
2499 /* apply and free last set of patches; if not doing a star match, this
2500 * will be empty, but better safe (and freeing everything) than sorry.
2502 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2505 /* now put out the final parameters */
2506 if (returnedNames == 0) eos = 1;
2507 if (p->opcode == 1) {
2509 outp->parmsp[0] = (unsigned short) dsp->cookie;
2510 outp->parmsp[1] = returnedNames;
2511 outp->parmsp[2] = eos;
2512 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2513 outp->parmsp[4] = 0;
2514 /* don't need last name to continue
2515 * search, cookie is enough. Normally,
2516 * this is the offset of the file name
2517 * of the last entry returned.
2519 outp->totalParms = 10; /* in bytes */
2523 outp->parmsp[0] = returnedNames;
2524 outp->parmsp[1] = eos;
2525 outp->parmsp[2] = 0; /* EAS error */
2526 outp->parmsp[3] = 0; /* last name, as above */
2527 outp->totalParms = 8; /* in bytes */
2530 /* return # of bytes in the buffer */
2531 outp->totalData = bytesInBuffer;
2533 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
2534 returnedNames, code);
2536 /* Return error code if unsuccessful on first request */
2537 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2538 code = CM_ERROR_NOSUCHFILE;
2540 /* if we're supposed to close the search after this request, or if
2541 * we're supposed to close the search if we're done, and we're done,
2542 * or if something went wrong, close the search.
2544 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2545 if ((searchFlags & 1) || (returnedNames == 0) ||
2546 ((searchFlags & 2) && eos) || code != 0)
2547 smb_DeleteDirSearch(dsp);
2549 smb_SendTran2Error(vcp, p, opx, code);
2551 smb_SendTran2Packet(vcp, outp, opx);
2553 smb_FreeTran2Packet(outp);
2554 smb_ReleaseDirSearch(dsp);
2555 cm_ReleaseSCache(scp);
2556 cm_ReleaseUser(userp);
2560 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2563 smb_dirSearch_t *dsp;
2565 dirHandle = smb_GetSMBParm(inp, 0);
2567 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
2569 dsp = smb_FindDirSearch(dirHandle);
2572 return CM_ERROR_BADFD;
2574 /* otherwise, we have an FD to destroy */
2575 smb_DeleteDirSearch(dsp);
2576 smb_ReleaseDirSearch(dsp);
2578 /* and return results */
2579 smb_SetSMBDataLength(outp, 0);
2584 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2586 smb_SetSMBDataLength(outp, 0);
2590 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2597 cm_scache_t *dscp; /* dir we're dealing with */
2598 cm_scache_t *scp; /* file we're creating */
2600 int initialModeBits;
2610 int parmSlot; /* which parm we're dealing with */
2618 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2619 openFun = smb_GetSMBParm(inp, 8); /* open function */
2620 excl = ((openFun & 3) == 0);
2621 trunc = ((openFun & 3) == 2); /* truncate it */
2622 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2623 openAction = 0; /* tracks what we did */
2625 attributes = smb_GetSMBParm(inp, 5);
2626 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2628 /* compute initial mode bits based on read-only flag in attributes */
2629 initialModeBits = 0666;
2630 if (attributes & 1) initialModeBits &= ~0222;
2632 pathp = smb_GetSMBData(inp, NULL);
2634 spacep = inp->spacep;
2635 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2637 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2638 /* special case magic file name for receiving IOCTL requests
2639 * (since IOCTL calls themselves aren't getting through).
2642 osi_Log0(smb_logp, "IOCTL Open");
2645 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2646 smb_SetupIoctlFid(fidp, spacep);
2648 /* set inp->fid so that later read calls in same msg can find fid */
2649 inp->fid = fidp->fid;
2651 /* copy out remainder of the parms */
2653 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2655 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2656 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2657 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2658 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2659 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2660 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2661 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2662 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2664 /* and the final "always present" stuff */
2665 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2666 /* next write out the "unique" ID */
2667 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2668 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2669 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2670 smb_SetSMBDataLength(outp, 0);
2672 /* and clean up fid reference */
2673 smb_ReleaseFID(fidp);
2677 #ifdef DEBUG_VERBOSE
2679 char *hexp, *asciip;
2680 asciip = (lastNamep ? lastNamep : pathp );
2681 hexp = osi_HexifyString(asciip);
2682 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2686 userp = smb_GetUser(vcp, inp);
2689 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2690 code = cm_NameI(cm_rootSCachep, pathp,
2691 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2692 userp, tidPathp, &req, &scp);
2694 code = cm_NameI(cm_rootSCachep, spacep->data,
2695 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2696 userp, tidPathp, &req, &dscp);
2699 cm_ReleaseUser(userp);
2703 /* otherwise, scp points to the parent directory. Do a lookup,
2704 * and truncate the file if we find it, otherwise we create the
2707 if (!lastNamep) lastNamep = pathp;
2709 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2711 if (code && code != CM_ERROR_NOSUCHFILE) {
2712 cm_ReleaseSCache(dscp);
2713 cm_ReleaseUser(userp);
2718 /* if we get here, if code is 0, the file exists and is represented by
2719 * scp. Otherwise, we have to create it. The dir may be represented
2720 * by dscp, or we may have found the file directly. If code is non-zero,
2724 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2726 if (dscp) cm_ReleaseSCache(dscp);
2727 cm_ReleaseSCache(scp);
2728 cm_ReleaseUser(userp);
2733 /* oops, file shouldn't be there */
2734 if (dscp) cm_ReleaseSCache(dscp);
2735 cm_ReleaseSCache(scp);
2736 cm_ReleaseUser(userp);
2737 return CM_ERROR_EXISTS;
2741 setAttr.mask = CM_ATTRMASK_LENGTH;
2742 setAttr.length.LowPart = 0;
2743 setAttr.length.HighPart = 0;
2744 code = cm_SetAttr(scp, &setAttr, userp, &req);
2745 openAction = 3; /* truncated existing file */
2747 else openAction = 1; /* found existing file */
2749 else if (!(openFun & 0x10)) {
2750 /* don't create if not found */
2751 if (dscp) cm_ReleaseSCache(dscp);
2752 cm_ReleaseUser(userp);
2753 return CM_ERROR_NOSUCHFILE;
2756 osi_assert(dscp != NULL);
2757 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
2758 osi_LogSaveString(smb_logp, lastNamep));
2759 openAction = 2; /* created file */
2760 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2761 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2762 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2764 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2765 smb_NotifyChange(FILE_ACTION_ADDED,
2766 FILE_NOTIFY_CHANGE_FILE_NAME,
2767 dscp, lastNamep, NULL, TRUE);
2768 if (!excl && code == CM_ERROR_EXISTS) {
2769 /* not an exclusive create, and someone else tried
2770 * creating it already, then we open it anyway. We
2771 * don't bother retrying after this, since if this next
2772 * fails, that means that the file was deleted after we
2773 * started this call.
2775 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2779 setAttr.mask = CM_ATTRMASK_LENGTH;
2780 setAttr.length.LowPart = 0;
2781 setAttr.length.HighPart = 0;
2782 code = cm_SetAttr(scp, &setAttr, userp, &req);
2784 } /* lookup succeeded */
2788 /* we don't need this any longer */
2789 if (dscp) cm_ReleaseSCache(dscp);
2792 /* something went wrong creating or truncating the file */
2793 if (scp) cm_ReleaseSCache(scp);
2794 cm_ReleaseUser(userp);
2798 /* make sure we're about to open a file */
2799 if (scp->fileType != CM_SCACHETYPE_FILE) {
2800 cm_ReleaseSCache(scp);
2801 cm_ReleaseUser(userp);
2802 return CM_ERROR_ISDIR;
2805 /* now all we have to do is open the file itself */
2806 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2809 /* save a pointer to the vnode */
2812 /* compute open mode */
2813 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2814 if (openMode == 1 || openMode == 2)
2815 fidp->flags |= SMB_FID_OPENWRITE;
2817 smb_ReleaseFID(fidp);
2819 cm_Open(scp, 0, userp);
2821 /* set inp->fid so that later read calls in same msg can find fid */
2822 inp->fid = fidp->fid;
2824 /* copy out remainder of the parms */
2826 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2827 lock_ObtainMutex(&scp->mx);
2829 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2830 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2831 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2832 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2833 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2834 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2835 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2836 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2837 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2839 /* and the final "always present" stuff */
2840 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2841 /* next write out the "unique" ID */
2842 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2843 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2844 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2845 lock_ReleaseMutex(&scp->mx);
2846 smb_SetSMBDataLength(outp, 0);
2848 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
2850 cm_ReleaseUser(userp);
2851 /* leave scp held since we put it in fidp->scp */
2855 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2862 unsigned char LockType;
2863 unsigned short NumberOfUnlocks, NumberOfLocks;
2864 unsigned long Timeout;
2866 LARGE_INTEGER LOffset, LLength;
2867 smb_waitingLock_t *waitingLock;
2874 fid = smb_GetSMBParm(inp, 2);
2875 fid = smb_ChainFID(fid, inp);
2877 fidp = smb_FindFID(vcp, fid, 0);
2878 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2879 return CM_ERROR_BADFD;
2881 /* set inp->fid so that later read calls in same msg can find fid */
2884 userp = smb_GetUser(vcp, inp);
2888 lock_ObtainMutex(&scp->mx);
2889 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2890 CM_SCACHESYNC_NEEDCALLBACK
2891 | CM_SCACHESYNC_GETSTATUS
2892 | CM_SCACHESYNC_LOCK);
2893 if (code) goto doneSync;
2895 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2896 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2897 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2898 NumberOfLocks = smb_GetSMBParm(inp, 7);
2900 op = smb_GetSMBData(inp, NULL);
2902 for (i=0; i<NumberOfUnlocks; i++) {
2903 if (LockType & 0x10) {
2905 LOffset.HighPart = *((LONG *)(op + 4));
2906 LOffset.LowPart = *((DWORD *)(op + 8));
2907 LLength.HighPart = *((LONG *)(op + 12));
2908 LLength.LowPart = *((DWORD *)(op + 16));
2912 /* Not Large Files */
2913 LOffset.HighPart = 0;
2914 LOffset.LowPart = *((DWORD *)(op + 2));
2915 LLength.HighPart = 0;
2916 LLength.LowPart = *((DWORD *)(op + 6));
2919 if (LargeIntegerNotEqualToZero(LOffset))
2921 /* Do not check length -- length check done in cm_Unlock */
2923 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2924 if (code) goto done;
2927 for (i=0; i<NumberOfLocks; i++) {
2928 if (LockType & 0x10) {
2930 LOffset.HighPart = *((LONG *)(op + 4));
2931 LOffset.LowPart = *((DWORD *)(op + 8));
2932 LLength.HighPart = *((LONG *)(op + 12));
2933 LLength.LowPart = *((DWORD *)(op + 16));
2937 /* Not Large Files */
2938 LOffset.HighPart = 0;
2939 LOffset.LowPart = *((DWORD *)(op + 2));
2940 LLength.HighPart = 0;
2941 LLength.LowPart = *((DWORD *)(op + 6));
2944 if (LargeIntegerNotEqualToZero(LOffset))
2946 if (LargeIntegerLessThan(LOffset, scp->length))
2949 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2950 userp, &req, &lockp);
2951 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2952 /* Put on waiting list */
2953 waitingLock = malloc(sizeof(smb_waitingLock_t));
2954 waitingLock->vcp = vcp;
2955 waitingLock->inp = smb_CopyPacket(inp);
2956 waitingLock->outp = smb_CopyPacket(outp);
2957 waitingLock->timeRemaining = Timeout;
2958 waitingLock->lockp = lockp;
2959 lock_ObtainWrite(&smb_globalLock);
2960 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2962 osi_Wakeup((long) &smb_allWaitingLocks);
2963 lock_ReleaseWrite(&smb_globalLock);
2964 /* don't send reply immediately */
2965 outp->flags |= SMB_PACKETFLAG_NOSEND;
2971 /* release any locks acquired before the failure */
2974 smb_SetSMBDataLength(outp, 0);
2976 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2978 lock_ReleaseMutex(&scp->mx);
2979 cm_ReleaseUser(userp);
2980 smb_ReleaseFID(fidp);
2985 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2997 fid = smb_GetSMBParm(inp, 0);
2998 fid = smb_ChainFID(fid, inp);
3000 fidp = smb_FindFID(vcp, fid, 0);
3001 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3002 return CM_ERROR_BADFD;
3005 userp = smb_GetUser(vcp, inp);
3009 /* otherwise, stat the file */
3010 lock_ObtainMutex(&scp->mx);
3011 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3012 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3013 if (code) goto done;
3015 /* decode times. We need a search time, but the response to this
3016 * call provides the date first, not the time, as returned in the
3017 * searchTime variable. So we take the high-order bits first.
3019 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
3020 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
3021 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
3022 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
3023 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
3024 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
3025 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
3027 /* now handle file size and allocation size */
3028 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
3029 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
3030 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
3031 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
3033 /* file attribute */
3034 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
3036 /* and finalize stuff */
3037 smb_SetSMBDataLength(outp, 0);
3041 lock_ReleaseMutex(&scp->mx);
3042 cm_ReleaseUser(userp);
3043 smb_ReleaseFID(fidp);
3047 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3061 fid = smb_GetSMBParm(inp, 0);
3062 fid = smb_ChainFID(fid, inp);
3064 fidp = smb_FindFID(vcp, fid, 0);
3065 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3066 return CM_ERROR_BADFD;
3069 userp = smb_GetUser(vcp, inp);
3073 /* now prepare to call cm_setattr. This message only sets various times,
3074 * and AFS only implements mtime, and we'll set the mtime if that's
3075 * requested. The others we'll ignore.
3077 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
3079 if (searchTime != 0) {
3080 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
3082 if ( unixTime != -1 ) {
3083 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
3084 attrs.clientModTime = unixTime;
3085 code = cm_SetAttr(scp, &attrs, userp, &req);
3087 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
3089 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
3094 cm_ReleaseUser(userp);
3095 smb_ReleaseFID(fidp);
3100 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3103 long count, finalCount;
3110 fd = smb_GetSMBParm(inp, 2);
3111 count = smb_GetSMBParm(inp, 5);
3112 offset.HighPart = 0; /* too bad */
3113 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3115 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3116 fd, offset.LowPart, count);
3118 fd = smb_ChainFID(fd, inp);
3119 fidp = smb_FindFID(vcp, fd, 0);
3121 return CM_ERROR_BADFD;
3123 /* set inp->fid so that later read calls in same msg can find fid */
3126 if (fidp->flags & SMB_FID_IOCTL) {
3127 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3130 userp = smb_GetUser(vcp, inp);
3132 /* 0 and 1 are reserved for request chaining, were setup by our caller,
3133 * and will be further filled in after we return.
3135 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3136 smb_SetSMBParm(outp, 3, 0); /* resvd */
3137 smb_SetSMBParm(outp, 4, 0); /* resvd */
3138 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3139 /* fill in #6 when we have all the parameters' space reserved */
3140 smb_SetSMBParm(outp, 7, 0); /* resv'd */
3141 smb_SetSMBParm(outp, 8, 0); /* resv'd */
3142 smb_SetSMBParm(outp, 9, 0); /* resv'd */
3143 smb_SetSMBParm(outp, 10, 0); /* resv'd */
3144 smb_SetSMBParm(outp, 11, 0); /* reserved */
3146 /* get op ptr after putting in the parms, since otherwise we don't
3147 * know where the data really is.
3149 op = smb_GetSMBData(outp, NULL);
3151 /* now fill in offset from start of SMB header to first data byte (to op) */
3152 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3154 /* set the packet data length the count of the # of bytes */
3155 smb_SetSMBDataLength(outp, count);
3158 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3160 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3163 /* fix some things up */
3164 smb_SetSMBParm(outp, 5, finalCount);
3165 smb_SetSMBDataLength(outp, finalCount);
3167 smb_ReleaseFID(fidp);
3169 cm_ReleaseUser(userp);
3174 * Values for createDisp, copied from NTDDK.H
3176 * FILE_SUPERSEDE 0 (???)
3177 * FILE_OPEN 1 (open)
3178 * FILE_CREATE 2 (exclusive)
3179 * FILE_OPEN_IF 3 (non-exclusive)
3180 * FILE_OVERWRITE 4 (open & truncate, but do not create)
3181 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
3184 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3186 char *pathp, *realPathp;
3190 cm_scache_t *dscp; /* parent dir */
3191 cm_scache_t *scp; /* file to create or open */
3195 unsigned short nameLength;
3197 unsigned int requestOpLock;
3198 unsigned int requestBatchOpLock;
3199 unsigned int mustBeDir;
3200 unsigned int treeCreate;
3202 unsigned int desiredAccess;
3203 unsigned int extAttributes;
3204 unsigned int createDisp;
3205 unsigned int createOptions;
3206 int initialModeBits;
3207 unsigned short baseFid;
3208 smb_fid_t *baseFidp;
3210 cm_scache_t *baseDirp;
3211 unsigned short openAction;
3226 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3227 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3228 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3229 requestOpLock = flags & 0x02;
3230 requestBatchOpLock = flags & 0x04;
3231 mustBeDir = flags & 0x08;
3234 * Why all of a sudden 32-bit FID?
3235 * We will reject all bits higher than 16.
3237 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3238 return CM_ERROR_INVAL;
3239 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3240 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3241 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3242 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3243 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3244 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3245 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3246 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3247 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3249 /* mustBeDir is never set; createOptions directory bit seems to be
3252 if (createOptions & 1)
3254 else if (createOptions & 0x40)
3260 * compute initial mode bits based on read-only flag in
3261 * extended attributes
3263 initialModeBits = 0666;
3264 if (extAttributes & 1) initialModeBits &= ~0222;
3266 pathp = smb_GetSMBData(inp, NULL);
3267 /* Sometimes path is not null-terminated, so we make a copy. */
3268 realPathp = malloc(nameLength+1);
3269 memcpy(realPathp, pathp, nameLength);
3270 realPathp[nameLength] = 0;
3272 spacep = inp->spacep;
3273 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3275 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
3276 osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3278 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3279 /* special case magic file name for receiving IOCTL requests
3280 * (since IOCTL calls themselves aren't getting through).
3282 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3283 smb_SetupIoctlFid(fidp, spacep);
3285 /* set inp->fid so that later read calls in same msg can find fid */
3286 inp->fid = fidp->fid;
3290 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3291 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3292 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3294 memset(&ft, 0, sizeof(ft));
3295 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3296 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3297 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3298 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3299 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3300 sz.HighPart = 0x7fff; sz.LowPart = 0;
3301 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3302 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3303 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3304 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3305 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3306 smb_SetSMBDataLength(outp, 0);
3308 /* clean up fid reference */
3309 smb_ReleaseFID(fidp);
3314 #ifdef DEBUG_VERBOSE
3316 char *hexp, *asciip;
3317 asciip = (lastNamep? lastNamep : realPathp);
3318 hexp = osi_HexifyString( asciip );
3319 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3323 userp = smb_GetUser(vcp, inp);
3325 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3327 return CM_ERROR_INVAL;
3331 baseDirp = cm_rootSCachep;
3332 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3335 baseFidp = smb_FindFID(vcp, baseFid, 0);
3337 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3339 cm_ReleaseUser(userp);
3340 return CM_ERROR_INVAL;
3342 baseDirp = baseFidp->scp;
3346 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
3348 /* compute open mode */
3350 if (desiredAccess & DELETE)
3351 fidflags |= SMB_FID_OPENDELETE;
3352 if (desiredAccess & AFS_ACCESS_READ)
3353 fidflags |= SMB_FID_OPENREAD;
3354 if (desiredAccess & AFS_ACCESS_WRITE)
3355 fidflags |= SMB_FID_OPENWRITE;
3359 /* For an exclusive create, we want to do a case sensitive match for the last component. */
3360 if (createDisp == 2 || createDisp == 4) {
3361 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3362 userp, tidPathp, &req, &dscp);
3364 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
3365 userp, tidPathp, &req, &scp);
3369 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3370 userp, tidPathp, &req, &scp);
3373 if (code == 0) foundscp = TRUE;
3375 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3376 /* look up parent directory */
3377 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3378 * the immediate parent. We have to work our way up realPathp until we hit something that we
3386 code = cm_NameI(baseDirp, spacep->data,
3387 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3388 userp, tidPathp, &req, &dscp);
3391 (tp = strrchr(spacep->data,'\\')) &&
3392 (createDisp == 2) &&
3393 (realDirFlag == 1)) {
3396 treeStartp = realPathp + (tp - spacep->data);
3398 if (*tp && !smb_IsLegalFilename(tp)) {
3399 if(baseFid != 0) smb_ReleaseFID(baseFidp);
3400 cm_ReleaseUser(userp);
3402 return CM_ERROR_BADNTFILENAME;
3411 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3414 osi_Log0(smb_logp,"NTCreateX parent not found");
3415 cm_ReleaseUser(userp);
3420 if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3421 /* A file exists where we want a directory. */
3422 cm_ReleaseSCache(dscp);
3423 cm_ReleaseUser(userp);
3425 return CM_ERROR_EXISTS;
3428 if (!lastNamep) lastNamep = realPathp;
3431 if (!smb_IsLegalFilename(lastNamep)) {
3432 cm_ReleaseSCache(dscp);
3433 cm_ReleaseUser(userp);
3435 return CM_ERROR_BADNTFILENAME;
3438 if (!foundscp && !treeCreate) {
3439 if(createDisp == 2 || createDisp == 4)
3440 code = cm_Lookup(dscp, lastNamep,
3441 CM_FLAG_FOLLOW, userp, &req, &scp);
3443 code = cm_Lookup(dscp, lastNamep,
3444 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3446 if (code && code != CM_ERROR_NOSUCHFILE) {
3447 cm_ReleaseSCache(dscp);
3448 cm_ReleaseUser(userp);
3455 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3458 /* if we get here, if code is 0, the file exists and is represented by
3459 * scp. Otherwise, we have to create it. The dir may be represented
3460 * by dscp, or we may have found the file directly. If code is non-zero,
3463 if (code == 0 && !treeCreate) {
3464 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3467 if (dscp) cm_ReleaseSCache(dscp);
3468 cm_ReleaseSCache(scp);
3469 cm_ReleaseUser(userp);
3474 if (createDisp == 2) {
3475 /* oops, file shouldn't be there */
3476 if (dscp) cm_ReleaseSCache(dscp);
3477 cm_ReleaseSCache(scp);
3478 cm_ReleaseUser(userp);
3480 return CM_ERROR_EXISTS;
3484 || createDisp == 5) {
3485 setAttr.mask = CM_ATTRMASK_LENGTH;
3486 setAttr.length.LowPart = 0;
3487 setAttr.length.HighPart = 0;
3488 code = cm_SetAttr(scp, &setAttr, userp, &req);
3489 openAction = 3; /* truncated existing file */
3491 else openAction = 1; /* found existing file */
3493 else if (createDisp == 1 || createDisp == 4) {
3494 /* don't create if not found */
3495 if (dscp) cm_ReleaseSCache(dscp);
3496 cm_ReleaseUser(userp);
3498 return CM_ERROR_NOSUCHFILE;
3500 else if (realDirFlag == 0 || realDirFlag == -1) {
3501 osi_assert(dscp != NULL);
3502 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
3503 osi_LogSaveString(smb_logp, lastNamep));
3504 openAction = 2; /* created file */
3505 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3506 setAttr.clientModTime = time(NULL);
3507 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3509 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3510 smb_NotifyChange(FILE_ACTION_ADDED,
3511 FILE_NOTIFY_CHANGE_FILE_NAME,
3512 dscp, lastNamep, NULL, TRUE);
3513 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3514 /* Not an exclusive create, and someone else tried
3515 * creating it already, then we open it anyway. We
3516 * don't bother retrying after this, since if this next
3517 * fails, that means that the file was deleted after we
3518 * started this call.
3520 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3523 if (createDisp == 5) {
3524 setAttr.mask = CM_ATTRMASK_LENGTH;
3525 setAttr.length.LowPart = 0;
3526 setAttr.length.HighPart = 0;
3527 code = cm_SetAttr(scp, &setAttr, userp,
3530 } /* lookup succeeded */
3535 char *cp; /* This component */
3536 int clen = 0; /* length of component */
3540 /* create directory */
3541 if ( !treeCreate ) treeStartp = lastNamep;
3542 osi_assert(dscp != NULL);
3543 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3544 osi_LogSaveString(smb_logp, treeStartp));
3545 openAction = 2; /* created directory */
3547 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3548 setAttr.clientModTime = time(NULL);
3555 tp = strchr(pp, '\\');
3559 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
3563 strncpy(cp,pp,clen);
3569 if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3571 /* cp is the next component to be created. */
3572 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3573 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3574 smb_NotifyChange(FILE_ACTION_ADDED,
3575 FILE_NOTIFY_CHANGE_DIR_NAME,
3576 tscp, cp, NULL, TRUE);
3578 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3579 /* Not an exclusive create, and someone else tried
3580 * creating it already, then we open it anyway. We
3581 * don't bother retrying after this, since if this next
3582 * fails, that means that the file was deleted after we
3583 * started this call.
3585 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3590 if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3591 cm_ReleaseSCache(tscp);
3592 tscp = scp; /* Newly created directory will be next parent */
3597 if we get here and code == 0, then scp is the last directory created, and tscp is the
3598 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
3604 /* something went wrong creating or truncating the file */
3605 if (scp) cm_ReleaseSCache(scp);
3606 if (dscp) cm_ReleaseSCache(dscp);
3607 cm_ReleaseUser(userp);
3612 /* make sure we have file vs. dir right (only applies for single component case) */
3613 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3614 cm_ReleaseSCache(scp);
3615 if (dscp) cm_ReleaseSCache(dscp);
3616 cm_ReleaseUser(userp);
3618 return CM_ERROR_ISDIR;
3620 /* (only applies to single component case) */
3621 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3622 cm_ReleaseSCache(scp);
3623 if (dscp) cm_ReleaseSCache(dscp);
3624 cm_ReleaseUser(userp);
3626 return CM_ERROR_NOTDIR;
3629 /* open the file itself */
3630 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3632 /* save a pointer to the vnode */
3635 fidp->flags = fidflags;
3637 /* save parent dir and pathname for delete or change notification */
3638 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3639 fidp->flags |= SMB_FID_NTOPEN;
3640 fidp->NTopen_dscp = dscp;
3641 cm_HoldSCache(dscp);
3642 fidp->NTopen_pathp = strdup(lastNamep);
3644 fidp->NTopen_wholepathp = realPathp;
3646 /* we don't need this any longer */
3647 if (dscp) cm_ReleaseSCache(dscp);
3648 cm_Open(scp, 0, userp);
3650 /* set inp->fid so that later read calls in same msg can find fid */
3651 inp->fid = fidp->fid;
3655 lock_ObtainMutex(&scp->mx);
3656 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3657 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3658 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3659 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3660 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3661 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3662 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3663 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3664 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3666 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3667 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3668 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3669 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3670 smb_SetSMBParmByte(outp, parmSlot,
3671 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3672 lock_ReleaseMutex(&scp->mx);
3673 smb_SetSMBDataLength(outp, 0);
3675 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3676 osi_LogSaveString(smb_logp, realPathp));
3678 smb_ReleaseFID(fidp);
3680 cm_ReleaseUser(userp);
3682 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3684 /* leave scp held since we put it in fidp->scp */
3689 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3690 * Instead, ultimately, would like to use a subroutine for common code.
3692 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3694 char *pathp, *realPathp;
3698 cm_scache_t *dscp; /* parent dir */
3699 cm_scache_t *scp; /* file to create or open */
3702 unsigned long nameLength;
3704 unsigned int requestOpLock;
3705 unsigned int requestBatchOpLock;
3706 unsigned int mustBeDir;
3707 unsigned int extendedRespRequired;
3709 unsigned int desiredAccess;
3710 #ifdef DEBUG_VERBOSE
3711 unsigned int allocSize;
3712 unsigned int shareAccess;
3714 unsigned int extAttributes;
3715 unsigned int createDisp;
3716 #ifdef DEBUG_VERBOSE
3719 unsigned int createOptions;
3720 int initialModeBits;
3721 unsigned short baseFid;
3722 smb_fid_t *baseFidp;
3724 cm_scache_t *baseDirp;
3725 unsigned short openAction;
3731 int parmOffset, dataOffset;
3742 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3743 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3744 parmp = inp->data + parmOffset;
3745 lparmp = (ULONG *) parmp;
3748 requestOpLock = flags & 0x02;
3749 requestBatchOpLock = flags & 0x04;
3750 mustBeDir = flags & 0x08;
3751 extendedRespRequired = flags & 0x10;
3754 * Why all of a sudden 32-bit FID?
3755 * We will reject all bits higher than 16.
3757 if (lparmp[1] & 0xFFFF0000)
3758 return CM_ERROR_INVAL;
3759 baseFid = (unsigned short)lparmp[1];
3760 desiredAccess = lparmp[2];
3761 #ifdef DEBUG_VERBOSE
3762 allocSize = lparmp[3];
3763 #endif /* DEBUG_VERSOSE */
3764 extAttributes = lparmp[5];
3766 shareAccess = lparmp[6];
3768 createDisp = lparmp[7];
3769 createOptions = lparmp[8];
3770 #ifdef DEBUG_VERBOSE
3773 nameLength = lparmp[11];
3775 #ifdef DEBUG_VERBOSE
3776 osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3777 osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3778 osi_Log1(smb_logp,"... flags[%x]",flags);
3781 /* mustBeDir is never set; createOptions directory bit seems to be
3784 if (createOptions & 1)
3786 else if (createOptions & 0x40)
3792 * compute initial mode bits based on read-only flag in
3793 * extended attributes
3795 initialModeBits = 0666;
3796 if (extAttributes & 1) initialModeBits &= ~0222;
3798 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3799 /* Sometimes path is not null-terminated, so we make a copy. */
3800 realPathp = malloc(nameLength+1);
3801 memcpy(realPathp, pathp, nameLength);
3802 realPathp[nameLength] = 0;
3804 spacep = cm_GetSpace();
3805 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3808 * Nothing here to handle SMB_IOCTL_FILENAME.
3809 * Will add it if necessary.
3812 #ifdef DEBUG_VERBOSE
3814 char *hexp, *asciip;
3815 asciip = (lastNamep? lastNamep : realPathp);
3816 hexp = osi_HexifyString( asciip );
3817 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3822 userp = smb_GetUser(vcp, inp);
3824 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3826 return CM_ERROR_INVAL;
3830 baseDirp = cm_rootSCachep;
3831 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3834 baseFidp = smb_FindFID(vcp, baseFid, 0);
3836 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3838 cm_ReleaseUser(userp);
3839 return CM_ERROR_INVAL;
3841 baseDirp = baseFidp->scp;
3845 /* compute open mode */
3847 if (desiredAccess & DELETE)
3848 fidflags |= SMB_FID_OPENDELETE;
3849 if (desiredAccess & AFS_ACCESS_READ)
3850 fidflags |= SMB_FID_OPENREAD;
3851 if (desiredAccess & AFS_ACCESS_WRITE)
3852 fidflags |= SMB_FID_OPENWRITE;
3856 if (createDisp == 2 || createDisp == 4) {
3857 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3858 userp, tidPathp, &req, &dscp);
3860 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
3861 userp, tidPathp, &req, &scp);
3865 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3866 userp, tidPathp, &req, &scp);
3869 if (code == 0) foundscp = TRUE;
3871 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3872 /* look up parent directory */
3874 code = cm_NameI(baseDirp, spacep->data,
3875 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3876 userp, tidPathp, &req, &dscp);
3880 cm_FreeSpace(spacep);
3883 smb_ReleaseFID(baseFidp);
3888 cm_ReleaseUser(userp);
3893 if (!lastNamep) lastNamep = realPathp;
3896 if (!smb_IsLegalFilename(lastNamep))
3897 return CM_ERROR_BADNTFILENAME;
3900 if (createDisp == 2 || createDisp == 4)
3901 code = cm_Lookup(dscp, lastNamep,
3902 CM_FLAG_FOLLOW, userp, &req, &scp);
3904 code = cm_Lookup(dscp, lastNamep,
3905 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3907 if (code && code != CM_ERROR_NOSUCHFILE) {
3908 cm_ReleaseSCache(dscp);
3909 cm_ReleaseUser(userp);
3917 smb_ReleaseFID(baseFidp);
3920 cm_FreeSpace(spacep);
3923 /* if we get here, if code is 0, the file exists and is represented by
3924 * scp. Otherwise, we have to create it. The dir may be represented
3925 * by dscp, or we may have found the file directly. If code is non-zero,
3929 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3932 if (dscp) cm_ReleaseSCache(dscp);
3933 cm_ReleaseSCache(scp);
3934 cm_ReleaseUser(userp);
3939 if (createDisp == 2) {
3940 /* oops, file shouldn't be there */
3941 if (dscp) cm_ReleaseSCache(dscp);
3942 cm_ReleaseSCache(scp);
3943 cm_ReleaseUser(userp);
3945 return CM_ERROR_EXISTS;
3949 || createDisp == 5) {
3950 setAttr.mask = CM_ATTRMASK_LENGTH;
3951 setAttr.length.LowPart = 0;
3952 setAttr.length.HighPart = 0;
3953 code = cm_SetAttr(scp, &setAttr, userp, &req);
3954 openAction = 3; /* truncated existing file */
3956 else openAction = 1; /* found existing file */
3958 else if (createDisp == 1 || createDisp == 4) {
3959 /* don't create if not found */
3960 if (dscp) cm_ReleaseSCache(dscp);
3961 cm_ReleaseUser(userp);
3963 return CM_ERROR_NOSUCHFILE;
3965 else if (realDirFlag == 0 || realDirFlag == -1) {
3966 osi_assert(dscp != NULL);
3967 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
3968 osi_LogSaveString(smb_logp, lastNamep));
3969 openAction = 2; /* created file */
3970 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3971 setAttr.clientModTime = time(NULL);
3972 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3974 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3975 smb_NotifyChange(FILE_ACTION_ADDED,
3976 FILE_NOTIFY_CHANGE_FILE_NAME,
3977 dscp, lastNamep, NULL, TRUE);
3978 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3979 /* Not an exclusive create, and someone else tried
3980 * creating it already, then we open it anyway. We
3981 * don't bother retrying after this, since if this next
3982 * fails, that means that the file was deleted after we
3983 * started this call.
3985 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3988 if (createDisp == 5) {
3989 setAttr.mask = CM_ATTRMASK_LENGTH;
3990 setAttr.length.LowPart = 0;
3991 setAttr.length.HighPart = 0;
3992 code = cm_SetAttr(scp, &setAttr, userp,
3995 } /* lookup succeeded */
3999 /* create directory */
4000 osi_assert(dscp != NULL);
4002 "smb_ReceiveNTTranCreate creating directory %s",
4003 osi_LogSaveString(smb_logp, lastNamep));
4004 openAction = 2; /* created directory */
4005 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4006 setAttr.clientModTime = time(NULL);
4007 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
4008 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4009 smb_NotifyChange(FILE_ACTION_ADDED,
4010 FILE_NOTIFY_CHANGE_DIR_NAME,
4011 dscp, lastNamep, NULL, TRUE);
4013 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
4014 /* Not an exclusive create, and someone else tried
4015 * creating it already, then we open it anyway. We
4016 * don't bother retrying after this, since if this next
4017 * fails, that means that the file was deleted after we
4018 * started this call.
4020 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4026 /* something went wrong creating or truncating the file */
4027 if (scp) cm_ReleaseSCache(scp);
4028 cm_ReleaseUser(userp);
4033 /* make sure we have file vs. dir right */
4034 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
4035 cm_ReleaseSCache(scp);
4036 cm_ReleaseUser(userp);
4038 return CM_ERROR_ISDIR;
4040 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
4041 cm_ReleaseSCache(scp);
4042 cm_ReleaseUser(userp);
4044 return CM_ERROR_NOTDIR;
4047 /* open the file itself */
4048 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4051 /* save a pointer to the vnode */
4054 fidp->flags = fidflags;
4056 /* save parent dir and pathname for deletion or change notification */
4057 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
4058 fidp->flags |= SMB_FID_NTOPEN;
4059 fidp->NTopen_dscp = dscp;
4060 cm_HoldSCache(dscp);
4061 fidp->NTopen_pathp = strdup(lastNamep);
4063 fidp->NTopen_wholepathp = realPathp;
4065 /* we don't need this any longer */
4066 if (dscp) cm_ReleaseSCache(dscp);
4068 cm_Open(scp, 0, userp);
4070 /* set inp->fid so that later read calls in same msg can find fid */
4071 inp->fid = fidp->fid;
4073 /* check whether we are required to send an extended response */
4074 if (!extendedRespRequired) {
4076 parmOffset = 8*4 + 39;
4077 parmOffset += 1; /* pad to 4 */
4078 dataOffset = parmOffset + 70;
4082 /* Total Parameter Count */
4083 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4084 /* Total Data Count */
4085 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4086 /* Parameter Count */
4087 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4088 /* Parameter Offset */
4089 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4090 /* Parameter Displacement */
4091 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4093 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4095 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4096 /* Data Displacement */
4097 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4098 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4099 smb_SetSMBDataLength(outp, 70);
4101 lock_ObtainMutex(&scp->mx);
4102 outData = smb_GetSMBData(outp, NULL);
4103 outData++; /* round to get to parmOffset */
4104 *outData = 0; outData++; /* oplock */
4105 *outData = 0; outData++; /* reserved */
4106 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4107 *((ULONG *)outData) = openAction; outData += 4;
4108 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
4109 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4110 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
4111 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
4112 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
4113 *((FILETIME *)outData) = ft; outData += 8; /* change time */
4114 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4115 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4116 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4117 *((USHORT *)outData) = 0; outData += 2; /* filetype */
4118 *((USHORT *)outData) = 0; outData += 2; /* dev state */
4119 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4120 outData += 2; /* is a dir? */
4121 lock_ReleaseMutex(&scp->mx);
4124 parmOffset = 8*4 + 39;
4125 parmOffset += 1; /* pad to 4 */
4126 dataOffset = parmOffset + 104;
4130 /* Total Parameter Count */
4131 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4132 /* Total Data Count */
4133 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4134 /* Parameter Count */
4135 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4136 /* Parameter Offset */
4137 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4138 /* Parameter Displacement */
4139 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4141 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4143 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4144 /* Data Displacement */
4145 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4146 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4147 smb_SetSMBDataLength(outp, 105);
4149 lock_ObtainMutex(&scp->mx);
4150 outData = smb_GetSMBData(outp, NULL);
4151 outData++; /* round to get to parmOffset */
4152 *outData = 0; outData++; /* oplock */
4153 *outData = 1; outData++; /* response type */
4154 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4155 *((ULONG *)outData) = openAction; outData += 4;
4156 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
4157 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4158 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
4159 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
4160 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
4161 *((FILETIME *)outData) = ft; outData += 8; /* change time */
4162 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4163 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4164 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4165 *((USHORT *)outData) = 0; outData += 2; /* filetype */
4166 *((USHORT *)outData) = 0; outData += 2; /* dev state */
4167 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4168 outData += 1; /* is a dir? */
4169 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
4170 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
4171 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
4172 lock_ReleaseMutex(&scp->mx);
4175 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
4177 smb_ReleaseFID(fidp);
4179 cm_ReleaseUser(userp);
4181 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
4182 /* leave scp held since we put it in fidp->scp */
4186 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
4189 smb_packet_t *savedPacketp;
4190 ULONG filter; USHORT fid, watchtree;
4194 filter = smb_GetSMBParm(inp, 19)
4195 | (smb_GetSMBParm(inp, 20) << 16);
4196 fid = smb_GetSMBParm(inp, 21);
4197 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
4199 fidp = smb_FindFID(vcp, fid, 0);
4201 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
4202 return CM_ERROR_BADFD;
4205 savedPacketp = smb_CopyPacket(inp);
4206 savedPacketp->vcp = vcp; /* TODO: refcount vcp? */
4207 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4208 savedPacketp->nextp = smb_Directory_Watches;
4209 smb_Directory_Watches = savedPacketp;
4210 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4212 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
4213 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
4216 lock_ObtainMutex(&scp->mx);
4218 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
4220 scp->flags |= CM_SCACHEFLAG_WATCHED;
4221 lock_ReleaseMutex(&scp->mx);
4222 smb_ReleaseFID(fidp);
4224 outp->flags |= SMB_PACKETFLAG_NOSEND;
4228 unsigned char nullSecurityDesc[36] = {
4229 0x01, /* security descriptor revision */
4230 0x00, /* reserved, should be zero */
4231 0x00, 0x80, /* security descriptor control;
4232 * 0x8000 : self-relative format */
4233 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
4234 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
4235 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
4236 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
4237 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4238 /* "null SID" owner SID */
4239 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4240 /* "null SID" group SID */
4243 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4245 int parmOffset, parmCount, dataOffset, dataCount;
4253 ULONG securityInformation;
4255 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4256 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4257 parmp = inp->data + parmOffset;
4258 sparmp = (USHORT *) parmp;
4259 lparmp = (ULONG *) parmp;
4262 securityInformation = lparmp[1];
4264 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
4265 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4273 parmOffset = 8*4 + 39;
4274 parmOffset += 1; /* pad to 4 */
4276 dataOffset = parmOffset + parmCount;
4280 /* Total Parameter Count */
4281 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4282 /* Total Data Count */
4283 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4284 /* Parameter Count */
4285 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4286 /* Parameter Offset */
4287 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4288 /* Parameter Displacement */
4289 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4291 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4293 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4294 /* Data Displacement */
4295 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4296 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4297 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
4299 outData = smb_GetSMBData(outp, NULL);
4300 outData++; /* round to get to parmOffset */
4301 *((ULONG *)outData) = 36; outData += 4; /* length */
4303 if (maxData >= 36) {
4304 memcpy(outData, nullSecurityDesc, 36);
4308 return CM_ERROR_BUFFERTOOSMALL;
4311 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4313 unsigned short function;
4315 function = smb_GetSMBParm(inp, 18);
4317 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
4319 /* We can handle long names */
4320 if (vcp->flags & SMB_VCFLAG_USENT)
4321 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
4325 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
4327 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
4329 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
4331 default: return CM_ERROR_INVAL;
4336 * smb_NotifyChange -- find relevant change notification messages and
4339 * If we don't know the file name (i.e. a callback break), filename is
4340 * NULL, and we return a zero-length list.
4342 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
4343 cm_scache_t *dscp, char *filename, char *otherFilename,
4344 BOOL isDirectParent)
4346 smb_packet_t *watch, *lastWatch, *nextWatch;
4347 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
4348 char *outData, *oldOutData;
4352 BOOL twoEntries = FALSE;
4353 ULONG otherNameLen, oldParmCount = 0;
4358 /* Get ready for rename within directory */
4359 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
4361 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
4364 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4365 watch = smb_Directory_Watches;
4367 filter = smb_GetSMBParm(watch, 19)
4368 | (smb_GetSMBParm(watch, 20) << 16);
4369 fid = smb_GetSMBParm(watch, 21);
4370 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
4371 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
4372 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
4376 * Strange hack - bug in NT Client and NT Server that we
4379 if (filter == 3 && wtree)
4382 fidp = smb_FindFID(vcp, fid, 0);
4385 watch = watch->nextp;
4388 if (fidp->scp != dscp
4389 || (filter & notifyFilter) == 0
4390 || (!isDirectParent && !wtree)) {
4391 smb_ReleaseFID(fidp);
4393 watch = watch->nextp;
4396 smb_ReleaseFID(fidp);
4399 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
4400 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
4402 nextWatch = watch->nextp;
4403 if (watch == smb_Directory_Watches)
4404 smb_Directory_Watches = nextWatch;
4406 lastWatch->nextp = nextWatch;
4408 /* Turn off WATCHED flag in dscp */
4409 lock_ObtainMutex(&dscp->mx);
4411 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4413 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
4414 lock_ReleaseMutex(&dscp->mx);
4416 /* Convert to response packet */
4417 ((smb_t *) watch)->reb = 0x80;
4418 ((smb_t *) watch)->wct = 0;
4421 if (filename == NULL)
4424 nameLen = strlen(filename);
4425 parmCount = 3*4 + nameLen*2;
4426 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4428 otherNameLen = strlen(otherFilename);
4429 oldParmCount = parmCount;
4430 parmCount += 3*4 + otherNameLen*2;
4431 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4433 if (maxLen < parmCount)
4434 parmCount = 0; /* not enough room */
4436 parmOffset = 8*4 + 39;
4437 parmOffset += 1; /* pad to 4 */
4438 dataOffset = parmOffset + parmCount;
4442 /* Total Parameter Count */
4443 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4444 /* Total Data Count */
4445 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4446 /* Parameter Count */
4447 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4448 /* Parameter Offset */
4449 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
4450 /* Parameter Displacement */
4451 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4453 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4455 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
4456 /* Data Displacement */
4457 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4458 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
4459 smb_SetSMBDataLength(watch, parmCount + 1);
4461 if (parmCount != 0) {
4462 outData = smb_GetSMBData(watch, NULL);
4463 outData++; /* round to get to parmOffset */
4464 oldOutData = outData;
4465 *((DWORD *)outData) = oldParmCount; outData += 4;
4466 /* Next Entry Offset */
4467 *((DWORD *)outData) = action; outData += 4;
4469 *((DWORD *)outData) = nameLen*2; outData += 4;
4470 /* File Name Length */
4471 mbstowcs((WCHAR *)outData, filename, nameLen);
4474 outData = oldOutData + oldParmCount;
4475 *((DWORD *)outData) = 0; outData += 4;
4476 /* Next Entry Offset */
4477 *((DWORD *)outData) = otherAction; outData += 4;
4479 *((DWORD *)outData) = otherNameLen*2;
4480 outData += 4; /* File Name Length */
4481 mbstowcs((WCHAR *)outData, otherFilename,
4482 otherNameLen); /* File Name */
4487 * If filename is null, we don't know the cause of the
4488 * change notification. We return zero data (see above),
4489 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4490 * (= 0x010C). We set the error code here by hand, without
4491 * modifying wct and bcc.
4493 if (filename == NULL) {
4494 ((smb_t *) watch)->rcls = 0x0C;
4495 ((smb_t *) watch)->reh = 0x01;
4496 ((smb_t *) watch)->errLow = 0;
4497 ((smb_t *) watch)->errHigh = 0;
4498 /* Set NT Status codes flag */
4499 ((smb_t *) watch)->flg2 |= 0x4000;
4502 smb_SendPacket(vcp, watch);
4503 smb_FreePacket(watch);
4506 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4509 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4511 unsigned char *replyWctp;
4512 smb_packet_t *watch, *lastWatch;
4513 USHORT fid, watchtree;
4517 osi_Log0(smb_logp, "SMB3 receive NT cancel");
4519 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4520 watch = smb_Directory_Watches;
4522 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4523 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4524 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4525 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4526 if (watch == smb_Directory_Watches)
4527 smb_Directory_Watches = watch->nextp;
4529 lastWatch->nextp = watch->nextp;
4530 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4532 /* Turn off WATCHED flag in scp */
4533 fid = smb_GetSMBParm(watch, 21);
4534 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4536 fidp = smb_FindFID(vcp, fid, 0);
4538 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
4540 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
4543 lock_ObtainMutex(&scp->mx);
4545 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4547 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4548 lock_ReleaseMutex(&scp->mx);
4549 smb_ReleaseFID(fidp);
4551 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
4554 /* assume STATUS32; return 0xC0000120 (CANCELED) */
4555 replyWctp = watch->wctp;
4559 ((smb_t *)watch)->rcls = 0x20;
4560 ((smb_t *)watch)->reh = 0x1;
4561 ((smb_t *)watch)->errLow = 0;
4562 ((smb_t *)watch)->errHigh = 0xC0;
4563 ((smb_t *)watch)->flg2 |= 0x4000;
4564 smb_SendPacket(vcp, watch);
4565 smb_FreePacket(watch);
4569 watch = watch->nextp;
4571 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4578 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4581 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4584 smb_username_t *unp;
4586 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4588 lock_ObtainMutex(&unp->mx);
4589 unp->userp = cm_NewUser();
4590 lock_ReleaseMutex(&unp->mx);
4591 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
4593 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);