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 || createDisp == 5) {
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,
3366 if (code == CM_ERROR_NOSUCHFILE) {
3367 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
3368 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
3369 if (code == 0 && realDirFlag == 1) {
3370 cm_ReleaseSCache(scp);
3371 cm_ReleaseSCache(dscp);
3372 cm_ReleaseUser(userp);
3374 return CM_ERROR_EXISTS;
3380 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3381 userp, tidPathp, &req, &scp);
3386 if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3387 /* look up parent directory */
3388 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3389 * the immediate parent. We have to work our way up realPathp until we hit something that we
3397 code = cm_NameI(baseDirp, spacep->data,
3398 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3399 userp, tidPathp, &req, &dscp);
3402 (tp = strrchr(spacep->data,'\\')) &&
3403 (createDisp == 2) &&
3404 (realDirFlag == 1)) {
3407 treeStartp = realPathp + (tp - spacep->data);
3409 if (*tp && !smb_IsLegalFilename(tp)) {
3411 smb_ReleaseFID(baseFidp);
3412 cm_ReleaseUser(userp);
3414 return CM_ERROR_BADNTFILENAME;
3424 smb_ReleaseFID(baseFidp);
3427 osi_Log0(smb_logp,"NTCreateX parent not found");
3428 cm_ReleaseUser(userp);
3433 if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3434 /* A file exists where we want a directory. */
3435 cm_ReleaseSCache(dscp);
3436 cm_ReleaseUser(userp);
3438 return CM_ERROR_EXISTS;
3442 lastNamep = realPathp;
3446 if (!smb_IsLegalFilename(lastNamep)) {
3447 cm_ReleaseSCache(dscp);
3448 cm_ReleaseUser(userp);
3450 return CM_ERROR_BADNTFILENAME;
3453 if (!foundscp && !treeCreate) {
3454 if(createDisp == 2 || createDisp == 4)
3455 code = cm_Lookup(dscp, lastNamep,
3456 CM_FLAG_FOLLOW, userp, &req, &scp);
3458 code = cm_Lookup(dscp, lastNamep,
3459 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3461 if (code && code != CM_ERROR_NOSUCHFILE) {
3462 cm_ReleaseSCache(dscp);
3463 cm_ReleaseUser(userp);
3471 smb_ReleaseFID(baseFidp);
3474 /* if we get here, if code is 0, the file exists and is represented by
3475 * scp. Otherwise, we have to create it. The dir may be represented
3476 * by dscp, or we may have found the file directly. If code is non-zero,
3479 if (code == 0 && !treeCreate) {
3480 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3483 if (dscp) cm_ReleaseSCache(dscp);
3484 cm_ReleaseSCache(scp);
3485 cm_ReleaseUser(userp);
3490 if (createDisp == 2) {
3491 /* oops, file shouldn't be there */
3492 if (dscp) cm_ReleaseSCache(dscp);
3493 cm_ReleaseSCache(scp);
3494 cm_ReleaseUser(userp);
3496 return CM_ERROR_EXISTS;
3500 || createDisp == 5) {
3501 setAttr.mask = CM_ATTRMASK_LENGTH;
3502 setAttr.length.LowPart = 0;
3503 setAttr.length.HighPart = 0;
3504 code = cm_SetAttr(scp, &setAttr, userp, &req);
3505 openAction = 3; /* truncated existing file */
3507 else openAction = 1; /* found existing file */
3509 else if (createDisp == 1 || createDisp == 4) {
3510 /* don't create if not found */
3511 if (dscp) cm_ReleaseSCache(dscp);
3512 cm_ReleaseUser(userp);
3514 return CM_ERROR_NOSUCHFILE;
3516 else if (realDirFlag == 0 || realDirFlag == -1) {
3517 osi_assert(dscp != NULL);
3518 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
3519 osi_LogSaveString(smb_logp, lastNamep));
3520 openAction = 2; /* created file */
3521 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3522 setAttr.clientModTime = time(NULL);
3523 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3525 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3526 smb_NotifyChange(FILE_ACTION_ADDED,
3527 FILE_NOTIFY_CHANGE_FILE_NAME,
3528 dscp, lastNamep, NULL, TRUE);
3529 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3530 /* Not an exclusive create, and someone else tried
3531 * creating it already, then we open it anyway. We
3532 * don't bother retrying after this, since if this next
3533 * fails, that means that the file was deleted after we
3534 * started this call.
3536 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3539 if (createDisp == 5) {
3540 setAttr.mask = CM_ATTRMASK_LENGTH;
3541 setAttr.length.LowPart = 0;
3542 setAttr.length.HighPart = 0;
3543 code = cm_SetAttr(scp, &setAttr, userp,
3546 } /* lookup succeeded */
3551 char *cp; /* This component */
3552 int clen = 0; /* length of component */
3556 /* create directory */
3557 if ( !treeCreate ) treeStartp = lastNamep;
3558 osi_assert(dscp != NULL);
3559 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3560 osi_LogSaveString(smb_logp, treeStartp));
3561 openAction = 2; /* created directory */
3563 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3564 setAttr.clientModTime = time(NULL);
3571 tp = strchr(pp, '\\');
3575 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
3579 strncpy(cp,pp,clen);
3585 if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3587 /* cp is the next component to be created. */
3588 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3589 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3590 smb_NotifyChange(FILE_ACTION_ADDED,
3591 FILE_NOTIFY_CHANGE_DIR_NAME,
3592 tscp, cp, NULL, TRUE);
3594 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3595 /* Not an exclusive create, and someone else tried
3596 * creating it already, then we open it anyway. We
3597 * don't bother retrying after this, since if this next
3598 * fails, that means that the file was deleted after we
3599 * started this call.
3601 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3606 if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3607 cm_ReleaseSCache(tscp);
3608 tscp = scp; /* Newly created directory will be next parent */
3613 if we get here and code == 0, then scp is the last directory created, and tscp is the
3614 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
3620 /* something went wrong creating or truncating the file */
3621 if (scp) cm_ReleaseSCache(scp);
3622 if (dscp) cm_ReleaseSCache(dscp);
3623 cm_ReleaseUser(userp);
3628 /* make sure we have file vs. dir right (only applies for single component case) */
3629 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3630 cm_ReleaseSCache(scp);
3631 if (dscp) cm_ReleaseSCache(dscp);
3632 cm_ReleaseUser(userp);
3634 return CM_ERROR_ISDIR;
3636 /* (only applies to single component case) */
3637 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3638 cm_ReleaseSCache(scp);
3639 if (dscp) cm_ReleaseSCache(dscp);
3640 cm_ReleaseUser(userp);
3642 return CM_ERROR_NOTDIR;
3645 /* open the file itself */
3646 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3648 /* save a pointer to the vnode */
3651 fidp->flags = fidflags;
3653 /* save parent dir and pathname for delete or change notification */
3654 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3655 fidp->flags |= SMB_FID_NTOPEN;
3656 fidp->NTopen_dscp = dscp;
3657 cm_HoldSCache(dscp);
3658 fidp->NTopen_pathp = strdup(lastNamep);
3660 fidp->NTopen_wholepathp = realPathp;
3662 /* we don't need this any longer */
3663 if (dscp) cm_ReleaseSCache(dscp);
3664 cm_Open(scp, 0, userp);
3666 /* set inp->fid so that later read calls in same msg can find fid */
3667 inp->fid = fidp->fid;
3671 lock_ObtainMutex(&scp->mx);
3672 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3673 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3674 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3675 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3676 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3677 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3678 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3679 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3680 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3682 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3683 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3684 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3685 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3686 smb_SetSMBParmByte(outp, parmSlot,
3687 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3688 lock_ReleaseMutex(&scp->mx);
3689 smb_SetSMBDataLength(outp, 0);
3691 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3692 osi_LogSaveString(smb_logp, realPathp));
3694 smb_ReleaseFID(fidp);
3696 cm_ReleaseUser(userp);
3698 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3700 /* leave scp held since we put it in fidp->scp */
3705 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3706 * Instead, ultimately, would like to use a subroutine for common code.
3708 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3710 char *pathp, *realPathp;
3714 cm_scache_t *dscp; /* parent dir */
3715 cm_scache_t *scp; /* file to create or open */
3718 unsigned long nameLength;
3720 unsigned int requestOpLock;
3721 unsigned int requestBatchOpLock;
3722 unsigned int mustBeDir;
3723 unsigned int extendedRespRequired;
3725 unsigned int desiredAccess;
3726 #ifdef DEBUG_VERBOSE
3727 unsigned int allocSize;
3728 unsigned int shareAccess;
3730 unsigned int extAttributes;
3731 unsigned int createDisp;
3732 #ifdef DEBUG_VERBOSE
3735 unsigned int createOptions;
3736 int initialModeBits;
3737 unsigned short baseFid;
3738 smb_fid_t *baseFidp;
3740 cm_scache_t *baseDirp;
3741 unsigned short openAction;
3747 int parmOffset, dataOffset;
3758 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3759 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3760 parmp = inp->data + parmOffset;
3761 lparmp = (ULONG *) parmp;
3764 requestOpLock = flags & 0x02;
3765 requestBatchOpLock = flags & 0x04;
3766 mustBeDir = flags & 0x08;
3767 extendedRespRequired = flags & 0x10;
3770 * Why all of a sudden 32-bit FID?
3771 * We will reject all bits higher than 16.
3773 if (lparmp[1] & 0xFFFF0000)
3774 return CM_ERROR_INVAL;
3775 baseFid = (unsigned short)lparmp[1];
3776 desiredAccess = lparmp[2];
3777 #ifdef DEBUG_VERBOSE
3778 allocSize = lparmp[3];
3779 #endif /* DEBUG_VERSOSE */
3780 extAttributes = lparmp[5];
3782 shareAccess = lparmp[6];
3784 createDisp = lparmp[7];
3785 createOptions = lparmp[8];
3786 #ifdef DEBUG_VERBOSE
3789 nameLength = lparmp[11];
3791 #ifdef DEBUG_VERBOSE
3792 osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3793 osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3794 osi_Log1(smb_logp,"... flags[%x]",flags);
3797 /* mustBeDir is never set; createOptions directory bit seems to be
3800 if (createOptions & 1)
3802 else if (createOptions & 0x40)
3808 * compute initial mode bits based on read-only flag in
3809 * extended attributes
3811 initialModeBits = 0666;
3812 if (extAttributes & 1) initialModeBits &= ~0222;
3814 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3815 /* Sometimes path is not null-terminated, so we make a copy. */
3816 realPathp = malloc(nameLength+1);
3817 memcpy(realPathp, pathp, nameLength);
3818 realPathp[nameLength] = 0;
3820 spacep = cm_GetSpace();
3821 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3824 * Nothing here to handle SMB_IOCTL_FILENAME.
3825 * Will add it if necessary.
3828 #ifdef DEBUG_VERBOSE
3830 char *hexp, *asciip;
3831 asciip = (lastNamep? lastNamep : realPathp);
3832 hexp = osi_HexifyString( asciip );
3833 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3838 userp = smb_GetUser(vcp, inp);
3840 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3842 return CM_ERROR_INVAL;
3846 baseDirp = cm_rootSCachep;
3847 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3850 baseFidp = smb_FindFID(vcp, baseFid, 0);
3852 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3854 cm_ReleaseUser(userp);
3855 return CM_ERROR_INVAL;
3857 baseDirp = baseFidp->scp;
3861 /* compute open mode */
3863 if (desiredAccess & DELETE)
3864 fidflags |= SMB_FID_OPENDELETE;
3865 if (desiredAccess & AFS_ACCESS_READ)
3866 fidflags |= SMB_FID_OPENREAD;
3867 if (desiredAccess & AFS_ACCESS_WRITE)
3868 fidflags |= SMB_FID_OPENWRITE;
3872 if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
3873 code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3874 userp, tidPathp, &req, &dscp);
3876 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
3878 if (code == CM_ERROR_NOSUCHFILE) {
3879 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
3880 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
3881 if (code == 0 && realDirFlag == 1) {
3882 cm_ReleaseSCache(scp);
3883 cm_ReleaseSCache(dscp);
3884 cm_ReleaseUser(userp);
3886 return CM_ERROR_EXISTS;
3892 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3893 userp, tidPathp, &req, &scp);
3896 if (code == 0) foundscp = TRUE;
3898 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3899 /* look up parent directory */
3901 code = cm_NameI(baseDirp, spacep->data,
3902 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3903 userp, tidPathp, &req, &dscp);
3907 cm_FreeSpace(spacep);
3910 smb_ReleaseFID(baseFidp);
3915 cm_ReleaseUser(userp);
3920 if (!lastNamep) lastNamep = realPathp;
3923 if (!smb_IsLegalFilename(lastNamep))
3924 return CM_ERROR_BADNTFILENAME;
3927 if (createDisp == 2 || createDisp == 4)
3928 code = cm_Lookup(dscp, lastNamep,
3929 CM_FLAG_FOLLOW, userp, &req, &scp);
3931 code = cm_Lookup(dscp, lastNamep,
3932 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3934 if (code && code != CM_ERROR_NOSUCHFILE) {
3935 cm_ReleaseSCache(dscp);
3936 cm_ReleaseUser(userp);
3944 smb_ReleaseFID(baseFidp);
3947 cm_FreeSpace(spacep);
3950 /* if we get here, if code is 0, the file exists and is represented by
3951 * scp. Otherwise, we have to create it. The dir may be represented
3952 * by dscp, or we may have found the file directly. If code is non-zero,
3956 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3959 if (dscp) cm_ReleaseSCache(dscp);
3960 cm_ReleaseSCache(scp);
3961 cm_ReleaseUser(userp);
3966 if (createDisp == 2) {
3967 /* oops, file shouldn't be there */
3968 if (dscp) cm_ReleaseSCache(dscp);
3969 cm_ReleaseSCache(scp);
3970 cm_ReleaseUser(userp);
3972 return CM_ERROR_EXISTS;
3976 || createDisp == 5) {
3977 setAttr.mask = CM_ATTRMASK_LENGTH;
3978 setAttr.length.LowPart = 0;
3979 setAttr.length.HighPart = 0;
3980 code = cm_SetAttr(scp, &setAttr, userp, &req);
3981 openAction = 3; /* truncated existing file */
3983 else openAction = 1; /* found existing file */
3985 else if (createDisp == 1 || createDisp == 4) {
3986 /* don't create if not found */
3987 if (dscp) cm_ReleaseSCache(dscp);
3988 cm_ReleaseUser(userp);
3990 return CM_ERROR_NOSUCHFILE;
3992 else if (realDirFlag == 0 || realDirFlag == -1) {
3993 osi_assert(dscp != NULL);
3994 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
3995 osi_LogSaveString(smb_logp, lastNamep));
3996 openAction = 2; /* created file */
3997 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3998 setAttr.clientModTime = time(NULL);
3999 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4001 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4002 smb_NotifyChange(FILE_ACTION_ADDED,
4003 FILE_NOTIFY_CHANGE_FILE_NAME,
4004 dscp, lastNamep, NULL, TRUE);
4005 if (code == CM_ERROR_EXISTS && createDisp != 2) {
4006 /* Not an exclusive create, and someone else tried
4007 * creating it already, then we open it anyway. We
4008 * don't bother retrying after this, since if this next
4009 * fails, that means that the file was deleted after we
4010 * started this call.
4012 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4015 if (createDisp == 5) {
4016 setAttr.mask = CM_ATTRMASK_LENGTH;
4017 setAttr.length.LowPart = 0;
4018 setAttr.length.HighPart = 0;
4019 code = cm_SetAttr(scp, &setAttr, userp,
4022 } /* lookup succeeded */
4026 /* create directory */
4027 osi_assert(dscp != NULL);
4029 "smb_ReceiveNTTranCreate creating directory %s",
4030 osi_LogSaveString(smb_logp, lastNamep));
4031 openAction = 2; /* created directory */
4032 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4033 setAttr.clientModTime = time(NULL);
4034 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
4035 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4036 smb_NotifyChange(FILE_ACTION_ADDED,
4037 FILE_NOTIFY_CHANGE_DIR_NAME,
4038 dscp, lastNamep, NULL, TRUE);
4040 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
4041 /* Not an exclusive create, and someone else tried
4042 * creating it already, then we open it anyway. We
4043 * don't bother retrying after this, since if this next
4044 * fails, that means that the file was deleted after we
4045 * started this call.
4047 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4053 /* something went wrong creating or truncating the file */
4054 if (scp) cm_ReleaseSCache(scp);
4055 cm_ReleaseUser(userp);
4060 /* make sure we have file vs. dir right */
4061 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
4062 cm_ReleaseSCache(scp);
4063 cm_ReleaseUser(userp);
4065 return CM_ERROR_ISDIR;
4067 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
4068 cm_ReleaseSCache(scp);
4069 cm_ReleaseUser(userp);
4071 return CM_ERROR_NOTDIR;
4074 /* open the file itself */
4075 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4078 /* save a pointer to the vnode */
4081 fidp->flags = fidflags;
4083 /* save parent dir and pathname for deletion or change notification */
4084 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
4085 fidp->flags |= SMB_FID_NTOPEN;
4086 fidp->NTopen_dscp = dscp;
4087 cm_HoldSCache(dscp);
4088 fidp->NTopen_pathp = strdup(lastNamep);
4090 fidp->NTopen_wholepathp = realPathp;
4092 /* we don't need this any longer */
4093 if (dscp) cm_ReleaseSCache(dscp);
4095 cm_Open(scp, 0, userp);
4097 /* set inp->fid so that later read calls in same msg can find fid */
4098 inp->fid = fidp->fid;
4100 /* check whether we are required to send an extended response */
4101 if (!extendedRespRequired) {
4103 parmOffset = 8*4 + 39;
4104 parmOffset += 1; /* pad to 4 */
4105 dataOffset = parmOffset + 70;
4109 /* Total Parameter Count */
4110 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4111 /* Total Data Count */
4112 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4113 /* Parameter Count */
4114 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4115 /* Parameter Offset */
4116 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4117 /* Parameter Displacement */
4118 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4120 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4122 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4123 /* Data Displacement */
4124 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4125 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4126 smb_SetSMBDataLength(outp, 70);
4128 lock_ObtainMutex(&scp->mx);
4129 outData = smb_GetSMBData(outp, NULL);
4130 outData++; /* round to get to parmOffset */
4131 *outData = 0; outData++; /* oplock */
4132 *outData = 0; outData++; /* reserved */
4133 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4134 *((ULONG *)outData) = openAction; outData += 4;
4135 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
4136 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4137 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
4138 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
4139 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
4140 *((FILETIME *)outData) = ft; outData += 8; /* change time */
4141 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4142 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4143 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4144 *((USHORT *)outData) = 0; outData += 2; /* filetype */
4145 *((USHORT *)outData) = 0; outData += 2; /* dev state */
4146 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4147 outData += 2; /* is a dir? */
4148 lock_ReleaseMutex(&scp->mx);
4151 parmOffset = 8*4 + 39;
4152 parmOffset += 1; /* pad to 4 */
4153 dataOffset = parmOffset + 104;
4157 /* Total Parameter Count */
4158 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4159 /* Total Data Count */
4160 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4161 /* Parameter Count */
4162 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4163 /* Parameter Offset */
4164 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4165 /* Parameter Displacement */
4166 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4168 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4170 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4171 /* Data Displacement */
4172 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4173 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4174 smb_SetSMBDataLength(outp, 105);
4176 lock_ObtainMutex(&scp->mx);
4177 outData = smb_GetSMBData(outp, NULL);
4178 outData++; /* round to get to parmOffset */
4179 *outData = 0; outData++; /* oplock */
4180 *outData = 1; outData++; /* response type */
4181 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4182 *((ULONG *)outData) = openAction; outData += 4;
4183 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
4184 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4185 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
4186 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
4187 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
4188 *((FILETIME *)outData) = ft; outData += 8; /* change time */
4189 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4190 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4191 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4192 *((USHORT *)outData) = 0; outData += 2; /* filetype */
4193 *((USHORT *)outData) = 0; outData += 2; /* dev state */
4194 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4195 outData += 1; /* is a dir? */
4196 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
4197 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
4198 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
4199 lock_ReleaseMutex(&scp->mx);
4202 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
4204 smb_ReleaseFID(fidp);
4206 cm_ReleaseUser(userp);
4208 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
4209 /* leave scp held since we put it in fidp->scp */
4213 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
4216 smb_packet_t *savedPacketp;
4217 ULONG filter; USHORT fid, watchtree;
4221 filter = smb_GetSMBParm(inp, 19)
4222 | (smb_GetSMBParm(inp, 20) << 16);
4223 fid = smb_GetSMBParm(inp, 21);
4224 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
4226 fidp = smb_FindFID(vcp, fid, 0);
4228 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
4229 return CM_ERROR_BADFD;
4232 savedPacketp = smb_CopyPacket(inp);
4234 savedPacketp->vcp = vcp;
4235 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4236 savedPacketp->nextp = smb_Directory_Watches;
4237 smb_Directory_Watches = savedPacketp;
4238 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4240 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
4241 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
4244 lock_ObtainMutex(&scp->mx);
4246 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
4248 scp->flags |= CM_SCACHEFLAG_WATCHED;
4249 lock_ReleaseMutex(&scp->mx);
4250 smb_ReleaseFID(fidp);
4252 outp->flags |= SMB_PACKETFLAG_NOSEND;
4256 unsigned char nullSecurityDesc[36] = {
4257 0x01, /* security descriptor revision */
4258 0x00, /* reserved, should be zero */
4259 0x00, 0x80, /* security descriptor control;
4260 * 0x8000 : self-relative format */
4261 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
4262 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
4263 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
4264 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
4265 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4266 /* "null SID" owner SID */
4267 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4268 /* "null SID" group SID */
4271 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4273 int parmOffset, parmCount, dataOffset, dataCount;
4281 ULONG securityInformation;
4283 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4284 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4285 parmp = inp->data + parmOffset;
4286 sparmp = (USHORT *) parmp;
4287 lparmp = (ULONG *) parmp;
4290 securityInformation = lparmp[1];
4292 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
4293 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4301 parmOffset = 8*4 + 39;
4302 parmOffset += 1; /* pad to 4 */
4304 dataOffset = parmOffset + parmCount;
4308 /* Total Parameter Count */
4309 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4310 /* Total Data Count */
4311 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4312 /* Parameter Count */
4313 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4314 /* Parameter Offset */
4315 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4316 /* Parameter Displacement */
4317 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4319 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4321 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4322 /* Data Displacement */
4323 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4324 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4325 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
4327 outData = smb_GetSMBData(outp, NULL);
4328 outData++; /* round to get to parmOffset */
4329 *((ULONG *)outData) = 36; outData += 4; /* length */
4331 if (maxData >= 36) {
4332 memcpy(outData, nullSecurityDesc, 36);
4336 return CM_ERROR_BUFFERTOOSMALL;
4339 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4341 unsigned short function;
4343 function = smb_GetSMBParm(inp, 18);
4345 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
4347 /* We can handle long names */
4348 if (vcp->flags & SMB_VCFLAG_USENT)
4349 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
4353 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
4355 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
4357 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
4359 default: return CM_ERROR_INVAL;
4364 * smb_NotifyChange -- find relevant change notification messages and
4367 * If we don't know the file name (i.e. a callback break), filename is
4368 * NULL, and we return a zero-length list.
4370 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
4371 cm_scache_t *dscp, char *filename, char *otherFilename,
4372 BOOL isDirectParent)
4374 smb_packet_t *watch, *lastWatch, *nextWatch;
4375 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
4376 char *outData, *oldOutData;
4380 BOOL twoEntries = FALSE;
4381 ULONG otherNameLen, oldParmCount = 0;
4386 /* Get ready for rename within directory */
4387 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
4389 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
4392 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4393 watch = smb_Directory_Watches;
4395 filter = smb_GetSMBParm(watch, 19)
4396 | (smb_GetSMBParm(watch, 20) << 16);
4397 fid = smb_GetSMBParm(watch, 21);
4398 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
4399 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
4400 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
4404 * Strange hack - bug in NT Client and NT Server that we
4407 if (filter == 3 && wtree)
4410 fidp = smb_FindFID(vcp, fid, 0);
4413 watch = watch->nextp;
4416 if (fidp->scp != dscp
4417 || (filter & notifyFilter) == 0
4418 || (!isDirectParent && !wtree)) {
4419 smb_ReleaseFID(fidp);
4421 watch = watch->nextp;
4424 smb_ReleaseFID(fidp);
4427 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
4428 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
4430 nextWatch = watch->nextp;
4431 if (watch == smb_Directory_Watches)
4432 smb_Directory_Watches = nextWatch;
4434 lastWatch->nextp = nextWatch;
4436 /* Turn off WATCHED flag in dscp */
4437 lock_ObtainMutex(&dscp->mx);
4439 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4441 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
4442 lock_ReleaseMutex(&dscp->mx);
4444 /* Convert to response packet */
4445 ((smb_t *) watch)->reb = 0x80;
4446 ((smb_t *) watch)->wct = 0;
4449 if (filename == NULL)
4452 nameLen = strlen(filename);
4453 parmCount = 3*4 + nameLen*2;
4454 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4456 otherNameLen = strlen(otherFilename);
4457 oldParmCount = parmCount;
4458 parmCount += 3*4 + otherNameLen*2;
4459 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4461 if (maxLen < parmCount)
4462 parmCount = 0; /* not enough room */
4464 parmOffset = 8*4 + 39;
4465 parmOffset += 1; /* pad to 4 */
4466 dataOffset = parmOffset + parmCount;
4470 /* Total Parameter Count */
4471 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4472 /* Total Data Count */
4473 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4474 /* Parameter Count */
4475 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4476 /* Parameter Offset */
4477 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
4478 /* Parameter Displacement */
4479 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4481 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4483 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
4484 /* Data Displacement */
4485 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4486 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
4487 smb_SetSMBDataLength(watch, parmCount + 1);
4489 if (parmCount != 0) {
4490 outData = smb_GetSMBData(watch, NULL);
4491 outData++; /* round to get to parmOffset */
4492 oldOutData = outData;
4493 *((DWORD *)outData) = oldParmCount; outData += 4;
4494 /* Next Entry Offset */
4495 *((DWORD *)outData) = action; outData += 4;
4497 *((DWORD *)outData) = nameLen*2; outData += 4;
4498 /* File Name Length */
4499 mbstowcs((WCHAR *)outData, filename, nameLen);
4502 outData = oldOutData + oldParmCount;
4503 *((DWORD *)outData) = 0; outData += 4;
4504 /* Next Entry Offset */
4505 *((DWORD *)outData) = otherAction; outData += 4;
4507 *((DWORD *)outData) = otherNameLen*2;
4508 outData += 4; /* File Name Length */
4509 mbstowcs((WCHAR *)outData, otherFilename,
4510 otherNameLen); /* File Name */
4515 * If filename is null, we don't know the cause of the
4516 * change notification. We return zero data (see above),
4517 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4518 * (= 0x010C). We set the error code here by hand, without
4519 * modifying wct and bcc.
4521 if (filename == NULL) {
4522 ((smb_t *) watch)->rcls = 0x0C;
4523 ((smb_t *) watch)->reh = 0x01;
4524 ((smb_t *) watch)->errLow = 0;
4525 ((smb_t *) watch)->errHigh = 0;
4526 /* Set NT Status codes flag */
4527 ((smb_t *) watch)->flg2 |= 0x4000;
4530 smb_SendPacket(vcp, watch);
4532 smb_FreePacket(watch);
4535 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4538 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4540 unsigned char *replyWctp;
4541 smb_packet_t *watch, *lastWatch;
4542 USHORT fid, watchtree;
4546 osi_Log0(smb_logp, "SMB3 receive NT cancel");
4548 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4549 watch = smb_Directory_Watches;
4551 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4552 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4553 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4554 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4555 if (watch == smb_Directory_Watches)
4556 smb_Directory_Watches = watch->nextp;
4558 lastWatch->nextp = watch->nextp;
4559 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4561 /* Turn off WATCHED flag in scp */
4562 fid = smb_GetSMBParm(watch, 21);
4563 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4565 if (vcp != watch->vcp)
4566 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
4569 fidp = smb_FindFID(vcp, fid, 0);
4571 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
4573 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
4576 lock_ObtainMutex(&scp->mx);
4578 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4580 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4581 lock_ReleaseMutex(&scp->mx);
4582 smb_ReleaseFID(fidp);
4584 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
4587 /* assume STATUS32; return 0xC0000120 (CANCELED) */
4588 replyWctp = watch->wctp;
4592 ((smb_t *)watch)->rcls = 0x20;
4593 ((smb_t *)watch)->reh = 0x1;
4594 ((smb_t *)watch)->errLow = 0;
4595 ((smb_t *)watch)->errHigh = 0xC0;
4596 ((smb_t *)watch)->flg2 |= 0x4000;
4597 smb_SendPacket(vcp, watch);
4599 smb_ReleaseVC(watch->vcp);
4600 smb_FreePacket(watch);
4604 watch = watch->nextp;
4606 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4613 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4616 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4619 smb_username_t *unp;
4621 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4623 lock_ObtainMutex(&unp->mx);
4624 unp->userp = cm_NewUser();
4625 lock_ReleaseMutex(&unp->mx);
4626 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
4628 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);