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 (stricmp(dep->name, rockp->maskp) != 0)
1058 if (ntohl(dep->fid.vnode) != rockp->vnode)
1060 /* This is the entry */
1061 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1062 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1063 return CM_ERROR_STOPNOW;
1066 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1067 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1069 struct smb_ShortNameRock rock;
1073 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1077 spacep = cm_GetSpace();
1078 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1080 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1082 cm_FreeSpace(spacep);
1083 if (code) return code;
1085 if (!lastNamep) lastNamep = pathp;
1088 thyper.HighPart = 0;
1089 rock.shortName = shortName;
1091 rock.maskp = lastNamep;
1092 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1095 cm_ReleaseSCache(dscp);
1098 return CM_ERROR_NOSUCHFILE;
1099 if (code == CM_ERROR_STOPNOW) {
1100 *shortNameLenp = rock.shortNameLen;
1106 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1108 smb_tran2Packet_t *outp;
1109 unsigned long dosTime;
1111 unsigned short infoLevel;
1113 unsigned short attributes;
1114 unsigned long extAttributes;
1119 cm_scache_t *scp, *dscp;
1128 infoLevel = p->parmsp[0];
1129 if (infoLevel == 6) nbytesRequired = 0;
1130 else if (infoLevel == 1) nbytesRequired = 22;
1131 else if (infoLevel == 2) nbytesRequired = 26;
1132 else if (infoLevel == 0x101) nbytesRequired = 40;
1133 else if (infoLevel == 0x102) nbytesRequired = 24;
1134 else if (infoLevel == 0x103) nbytesRequired = 4;
1135 else if (infoLevel == 0x108) nbytesRequired = 30;
1137 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1138 p->opcode, infoLevel);
1139 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1142 osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1143 osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
1145 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1147 if (infoLevel > 0x100)
1148 outp->totalParms = 2;
1150 outp->totalParms = 0;
1151 outp->totalData = nbytesRequired;
1153 /* now, if we're at infoLevel 6, we're only being asked to check
1154 * the syntax, so we just OK things now. In particular, we're *not*
1155 * being asked to verify anything about the state of any parent dirs.
1157 if (infoLevel == 6) {
1158 smb_SendTran2Packet(vcp, outp, opx);
1159 smb_FreeTran2Packet(outp);
1163 userp = smb_GetTran2User(vcp, p);
1165 osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1166 smb_FreeTran2Packet(outp);
1167 return CM_ERROR_BADSMB;
1170 tidPathp = smb_GetTIDPath(vcp, p->tid);
1173 * XXX Strange hack XXX
1175 * As of Patch 7 (13 January 98), we are having the following problem:
1176 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1177 * requests to look up "desktop.ini" in all the subdirectories.
1178 * This can cause zillions of timeouts looking up non-existent cells
1179 * and volumes, especially in the top-level directory.
1181 * We have not found any way to avoid this or work around it except
1182 * to explicitly ignore the requests for mount points that haven't
1183 * yet been evaluated and for directories that haven't yet been
1186 if (infoLevel == 0x101) {
1187 spacep = cm_GetSpace();
1188 smb_StripLastComponent(spacep->data, &lastComp,
1189 (char *)(&p->parmsp[3]));
1190 /* Make sure that lastComp is not NULL */
1192 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1193 code = cm_NameI(cm_rootSCachep, spacep->data,
1197 userp, tidPathp, &req, &dscp);
1199 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1200 && !dscp->mountRootFidp)
1201 code = CM_ERROR_NOSUCHFILE;
1202 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1203 cm_buf_t *bp = buf_Find(dscp, &hzero);
1207 code = CM_ERROR_NOSUCHFILE;
1209 cm_ReleaseSCache(dscp);
1211 cm_FreeSpace(spacep);
1212 cm_ReleaseUser(userp);
1213 smb_SendTran2Error(vcp, p, opx, code);
1214 smb_FreeTran2Packet(outp);
1220 cm_FreeSpace(spacep);
1223 /* now do namei and stat, and copy out the info */
1224 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1225 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1228 cm_ReleaseUser(userp);
1229 smb_SendTran2Error(vcp, p, opx, code);
1230 smb_FreeTran2Packet(outp);
1234 lock_ObtainMutex(&scp->mx);
1235 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1236 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1237 if (code) goto done;
1239 /* now we have the status in the cache entry, and everything is locked.
1240 * Marshall the output data.
1243 /* for info level 108, figure out short name */
1244 if (infoLevel == 0x108) {
1245 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1246 tidPathp, scp->fid.vnode, shortName,
1253 *((u_long *)op) = len * 2; op += 4;
1254 mbstowcs((unsigned short *)op, shortName, len);
1259 if (infoLevel == 1 || infoLevel == 2) {
1260 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1261 *((u_long *)op) = dosTime; op += 4; /* creation time */
1262 *((u_long *)op) = dosTime; op += 4; /* access time */
1263 *((u_long *)op) = dosTime; op += 4; /* write time */
1264 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1265 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1266 attributes = smb_Attributes(scp);
1267 *((u_short *)op) = attributes; op += 2; /* attributes */
1269 else if (infoLevel == 0x101) {
1270 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1271 *((FILETIME *)op) = ft; op += 8; /* creation time */
1272 *((FILETIME *)op) = ft; op += 8; /* last access time */
1273 *((FILETIME *)op) = ft; op += 8; /* last write time */
1274 *((FILETIME *)op) = ft; op += 8; /* last change time */
1275 extAttributes = smb_ExtAttributes(scp);
1276 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1277 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1279 else if (infoLevel == 0x102) {
1280 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1281 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1282 *((u_long *)op) = scp->linkCount; op += 4;
1285 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1288 else if (infoLevel == 0x103) {
1289 memset(op, 0, 4); op += 4; /* EA size */
1292 /* now, if we are being asked about extended attrs, return a 0 size */
1293 if (infoLevel == 2) {
1294 *((u_long *)op) = 0; op += 4;
1298 /* send and free the packets */
1300 lock_ReleaseMutex(&scp->mx);
1301 cm_ReleaseSCache(scp);
1302 cm_ReleaseUser(userp);
1304 smb_SendTran2Packet(vcp, outp, opx);
1306 smb_SendTran2Error(vcp, p, opx, code);
1307 smb_FreeTran2Packet(outp);
1312 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1314 return CM_ERROR_BADOP;
1317 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1319 smb_tran2Packet_t *outp;
1321 unsigned long attributes;
1322 unsigned short infoLevel;
1335 fidp = smb_FindFID(vcp, fid, 0);
1338 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1342 infoLevel = p->parmsp[1];
1343 if (infoLevel == 0x101) nbytesRequired = 40;
1344 else if (infoLevel == 0x102) nbytesRequired = 24;
1345 else if (infoLevel == 0x103) nbytesRequired = 4;
1346 else if (infoLevel == 0x104) nbytesRequired = 6;
1348 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1349 p->opcode, infoLevel);
1350 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1351 smb_ReleaseFID(fidp);
1354 osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1356 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1358 if (infoLevel > 0x100)
1359 outp->totalParms = 2;
1361 outp->totalParms = 0;
1362 outp->totalData = nbytesRequired;
1364 userp = smb_GetTran2User(vcp, p);
1366 osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
1367 code = CM_ERROR_BADSMB;
1372 lock_ObtainMutex(&scp->mx);
1373 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1374 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1375 if (code) goto done;
1377 /* now we have the status in the cache entry, and everything is locked.
1378 * Marshall the output data.
1381 if (infoLevel == 0x101) {
1382 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1383 *((FILETIME *)op) = ft; op += 8; /* creation time */
1384 *((FILETIME *)op) = ft; op += 8; /* last access time */
1385 *((FILETIME *)op) = ft; op += 8; /* last write time */
1386 *((FILETIME *)op) = ft; op += 8; /* last change time */
1387 attributes = smb_ExtAttributes(scp);
1388 *((u_long *)op) = attributes; op += 4;
1389 *((u_long *)op) = 0; op += 4;
1391 else if (infoLevel == 0x102) {
1392 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1393 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1394 *((u_long *)op) = scp->linkCount; op += 4;
1395 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1396 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1400 else if (infoLevel == 0x103) {
1401 *((u_long *)op) = 0; op += 4;
1403 else if (infoLevel == 0x104) {
1407 if (fidp->NTopen_wholepathp)
1408 name = fidp->NTopen_wholepathp;
1410 name = "\\"; /* probably can't happen */
1412 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1413 *((u_long *)op) = len * 2; op += 4;
1414 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1417 /* send and free the packets */
1419 lock_ReleaseMutex(&scp->mx);
1420 cm_ReleaseUser(userp);
1421 smb_ReleaseFID(fidp);
1422 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1423 else smb_SendTran2Error(vcp, p, opx, code);
1424 smb_FreeTran2Packet(outp);
1429 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1434 unsigned short infoLevel;
1435 smb_tran2Packet_t *outp;
1443 fidp = smb_FindFID(vcp, fid, 0);
1446 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1450 infoLevel = p->parmsp[1];
1451 if (infoLevel > 0x104 || infoLevel < 0x101) {
1452 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1453 p->opcode, infoLevel);
1454 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1455 smb_ReleaseFID(fidp);
1459 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1460 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1461 smb_ReleaseFID(fidp);
1464 if ((infoLevel == 0x103 || infoLevel == 0x104)
1465 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1466 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1467 smb_ReleaseFID(fidp);
1471 osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
1473 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1475 outp->totalParms = 2;
1476 outp->totalData = 0;
1478 userp = smb_GetTran2User(vcp, p);
1480 osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
1481 code = CM_ERROR_BADSMB;
1487 if (infoLevel == 0x101) {
1489 unsigned int attribute;
1492 /* lock the vnode with a callback; we need the current status
1493 * to determine what the new status is, in some cases.
1495 lock_ObtainMutex(&scp->mx);
1496 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1497 CM_SCACHESYNC_GETSTATUS
1498 | CM_SCACHESYNC_NEEDCALLBACK);
1500 lock_ReleaseMutex(&scp->mx);
1504 /* prepare for setattr call */
1507 lastMod = *((FILETIME *)(p->datap + 16));
1508 /* when called as result of move a b, lastMod is (-1, -1).
1509 * If the check for -1 is not present, timestamp
1510 * of the resulting file will be 1969 (-1)
1512 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
1513 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1514 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1515 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1517 fidp->flags |= SMB_FID_MTIMESETDONE;
1520 attribute = *((u_long *)(p->datap + 32));
1521 if (attribute != 0) {
1522 if ((scp->unixModeBits & 0222)
1523 && (attribute & 1) != 0) {
1524 /* make a writable file read-only */
1525 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1526 attr.unixModeBits = scp->unixModeBits & ~0222;
1528 else if ((scp->unixModeBits & 0222) == 0
1529 && (attribute & 1) == 0) {
1530 /* make a read-only file writable */
1531 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1532 attr.unixModeBits = scp->unixModeBits | 0222;
1535 lock_ReleaseMutex(&scp->mx);
1539 code = cm_SetAttr(scp, &attr, userp, &req);
1543 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1544 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1547 attr.mask = CM_ATTRMASK_LENGTH;
1548 attr.length.LowPart = size.LowPart;
1549 attr.length.HighPart = size.HighPart;
1550 code = cm_SetAttr(scp, &attr, userp, &req);
1552 else if (infoLevel == 0x102) {
1553 if (*((char *)(p->datap))) {
1554 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1557 fidp->flags |= SMB_FID_DELONCLOSE;
1561 fidp->flags &= ~SMB_FID_DELONCLOSE;
1565 cm_ReleaseUser(userp);
1566 smb_ReleaseFID(fidp);
1567 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1568 else smb_SendTran2Error(vcp, p, op, code);
1569 smb_FreeTran2Packet(outp);
1574 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1576 return CM_ERROR_BADOP;
1579 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1581 return CM_ERROR_BADOP;
1584 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1586 return CM_ERROR_BADOP;
1589 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1591 return CM_ERROR_BADOP;
1594 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1596 return CM_ERROR_BADOP;
1599 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1600 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1605 cm_scache_t *targetScp; /* target if scp is a symlink */
1610 unsigned short attr;
1611 unsigned long lattr;
1612 smb_dirListPatch_t *patchp;
1613 smb_dirListPatch_t *npatchp;
1615 for(patchp = *dirPatchespp; patchp; patchp =
1616 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1617 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1619 lock_ObtainMutex(&scp->mx);
1620 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1621 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1623 lock_ReleaseMutex(&scp->mx);
1624 cm_ReleaseSCache(scp);
1628 /* now watch for a symlink */
1629 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1630 lock_ReleaseMutex(&scp->mx);
1631 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
1633 /* we have a more accurate file to use (the
1634 * target of the symbolic link). Otherwise,
1635 * we'll just use the symlink anyway.
1637 osi_Log2(smb_logp, "symlink vp %x to vp %x",
1639 cm_ReleaseSCache(scp);
1642 lock_ObtainMutex(&scp->mx);
1645 dptr = patchp->dptr;
1647 if (infoLevel >= 0x101) {
1649 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1651 /* copy to Creation Time */
1652 *((FILETIME *)dptr) = ft;
1655 /* copy to Last Access Time */
1656 *((FILETIME *)dptr) = ft;
1659 /* copy to Last Write Time */
1660 *((FILETIME *)dptr) = ft;
1663 /* copy to Change Time */
1664 *((FILETIME *)dptr) = ft;
1667 /* Use length for both file length and alloc length */
1668 *((LARGE_INTEGER *)dptr) = scp->length;
1670 *((LARGE_INTEGER *)dptr) = scp->length;
1673 /* Copy attributes */
1674 lattr = smb_ExtAttributes(scp);
1675 /* merge in hidden (dot file) attribute */
1676 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1677 lattr |= SMB_ATTR_HIDDEN;
1678 *((u_long *)dptr) = lattr;
1683 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1685 /* and copy out date */
1686 shortTemp = (dosTime>>16) & 0xffff;
1687 *((u_short *)dptr) = shortTemp;
1690 /* copy out creation time */
1691 shortTemp = dosTime & 0xffff;
1692 *((u_short *)dptr) = shortTemp;
1695 /* and copy out date */
1696 shortTemp = (dosTime>>16) & 0xffff;
1697 *((u_short *)dptr) = shortTemp;
1700 /* copy out access time */
1701 shortTemp = dosTime & 0xffff;
1702 *((u_short *)dptr) = shortTemp;
1705 /* and copy out date */
1706 shortTemp = (dosTime>>16) & 0xffff;
1707 *((u_short *)dptr) = shortTemp;
1710 /* copy out mod time */
1711 shortTemp = dosTime & 0xffff;
1712 *((u_short *)dptr) = shortTemp;
1715 /* copy out file length and alloc length,
1716 * using the same for both
1718 *((u_long *)dptr) = scp->length.LowPart;
1720 *((u_long *)dptr) = scp->length.LowPart;
1723 /* finally copy out attributes as short */
1724 attr = smb_Attributes(scp);
1725 /* merge in hidden (dot file) attribute */
1726 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1727 attr |= SMB_ATTR_HIDDEN;
1728 *dptr++ = attr & 0xff;
1729 *dptr++ = (attr >> 8) & 0xff;
1732 lock_ReleaseMutex(&scp->mx);
1733 cm_ReleaseSCache(scp);
1736 /* now free the patches */
1737 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1738 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1742 /* and mark the list as empty */
1743 *dirPatchespp = NULL;
1748 /* do a case-folding search of the star name mask with the name in namep.
1749 * Return 1 if we match, otherwise 0.
1751 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1753 unsigned char tcp1, tcp2; /* Pattern characters */
1754 unsigned char tcn1; /* Name characters */
1755 int sawDot = 0, sawStar = 0, req8dot3 = 0;
1756 char *starNamep, *starMaskp;
1757 static char nullCharp[] = {0};
1759 /* make sure we only match 8.3 names, if requested */
1760 req8dot3 = (flags & CM_FLAG_8DOT3);
1761 if (req8dot3 && !cm_Is8Dot3(namep))
1766 /* Next pattern character */
1769 /* Next name character */
1773 /* 0 - end of pattern */
1779 else if (tcp1 == '.' || tcp1 == '"') {
1789 * first dot in pattern;
1790 * must match dot or end of name
1795 else if (tcn1 == '.') {
1804 else if (tcp1 == '?') {
1805 if (tcn1 == 0 || tcn1 == '.')
1810 else if (tcp1 == '>') {
1811 if (tcn1 != 0 && tcn1 != '.')
1815 else if (tcp1 == '*' || tcp1 == '<') {
1819 else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
1820 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
1835 * pattern character after '*' is not null or
1836 * period. If it is '?' or '>', we are not
1837 * going to understand it. If it is '*' or
1838 * '<', we are going to skip over it. None of
1839 * these are likely, I hope.
1841 /* skip over '*' and '<' */
1842 while (tcp2 == '*' || tcp2 == '<')
1845 /* skip over characters that don't match tcp2 */
1846 while (req8dot3 && tcn1 != '.' && tcn1 != 0
1847 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1851 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
1854 /* Remember where we are */
1864 /* tcp1 is not a wildcard */
1865 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1870 /* if trying to match a star pattern, go back */
1872 maskp = starMaskp - 2;
1873 namep = starNamep + 1;
1883 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1892 smb_dirListPatch_t *dirListPatchesp;
1893 smb_dirListPatch_t *curPatchp;
1896 long orbytes; /* # of bytes in this output record */
1897 long ohbytes; /* # of bytes, except file name */
1898 long onbytes; /* # of bytes in name, incl. term. null */
1899 osi_hyper_t dirLength;
1900 osi_hyper_t bufferOffset;
1901 osi_hyper_t curOffset;
1903 smb_dirSearch_t *dsp;
1907 cm_pageHeader_t *pageHeaderp;
1908 cm_user_t *userp = NULL;
1911 long nextEntryCookie;
1912 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1913 char *op; /* output data ptr */
1914 char *origOp; /* original value of op */
1915 cm_space_t *spacep; /* for pathname buffer */
1916 long maxReturnData; /* max # of return data */
1917 long maxReturnParms; /* max # of return parms */
1918 long bytesInBuffer; /* # data bytes in the output buffer */
1920 char *maskp; /* mask part of path */
1924 smb_tran2Packet_t *outp; /* response packet */
1927 char shortName[13]; /* 8.3 name if needed */
1938 if (p->opcode == 1) {
1939 /* find first; obtain basic parameters from request */
1940 attribute = p->parmsp[0];
1941 maxCount = p->parmsp[1];
1942 infoLevel = p->parmsp[3];
1943 searchFlags = p->parmsp[2];
1944 dsp = smb_NewDirSearch(1);
1945 dsp->attribute = attribute;
1946 pathp = ((char *) p->parmsp) + 12; /* points to path */
1948 maskp = strrchr(pathp, '\\');
1949 if (maskp == NULL) maskp = pathp;
1950 else maskp++; /* skip over backslash */
1951 strcpy(dsp->mask, maskp); /* and save mask */
1952 /* track if this is likely to match a lot of entries */
1953 starPattern = smb_V3IsStarMask(maskp);
1956 osi_assert(p->opcode == 2);
1957 /* find next; obtain basic parameters from request or open dir file */
1958 dsp = smb_FindDirSearch(p->parmsp[0]);
1959 if (!dsp) return CM_ERROR_BADFD;
1960 attribute = dsp->attribute;
1961 maxCount = p->parmsp[1];
1962 infoLevel = p->parmsp[2];
1963 searchFlags = p->parmsp[5];
1965 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1967 starPattern = 1; /* assume, since required a Find Next */
1971 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1972 attribute, infoLevel, maxCount, searchFlags);
1974 osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
1975 p->opcode, nextCookie);
1977 if (infoLevel >= 0x101)
1978 searchFlags &= ~4; /* no resume keys */
1980 dirListPatchesp = NULL;
1982 maxReturnData = p->maxReturnData;
1983 if (p->opcode == 1) /* find first */
1984 maxReturnParms = 10; /* bytes */
1986 maxReturnParms = 8; /* bytes */
1988 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1989 if (maxReturnData > 6000)
1990 maxReturnData = 6000;
1991 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1993 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1996 osi_Log1(smb_logp, "T2 receive search dir %s",
1997 osi_LogSaveString(smb_logp, pathp));
1999 /* bail out if request looks bad */
2000 if (p->opcode == 1 && !pathp) {
2001 smb_ReleaseDirSearch(dsp);
2002 smb_FreeTran2Packet(outp);
2003 return CM_ERROR_BADSMB;
2006 osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
2007 nextCookie, dsp->cookie);
2009 userp = smb_GetTran2User(vcp, p);
2011 osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2012 smb_ReleaseDirSearch(dsp);
2013 smb_FreeTran2Packet(outp);
2014 return CM_ERROR_BADSMB;
2017 /* try to get the vnode for the path name next */
2018 lock_ObtainMutex(&dsp->mx);
2025 spacep = cm_GetSpace();
2026 smb_StripLastComponent(spacep->data, NULL, pathp);
2027 lock_ReleaseMutex(&dsp->mx);
2029 tidPathp = smb_GetTIDPath(vcp, p->tid);
2030 code = cm_NameI(cm_rootSCachep, spacep->data,
2031 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2032 userp, tidPathp, &req, &scp);
2033 cm_FreeSpace(spacep);
2035 lock_ObtainMutex(&dsp->mx);
2037 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2039 /* we need one hold for the entry we just stored into,
2040 * and one for our own processing. When we're done
2041 * with this function, we'll drop the one for our own
2042 * processing. We held it once from the namei call,
2043 * and so we do another hold now.
2046 lock_ObtainMutex(&scp->mx);
2047 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2048 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2049 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2050 dsp->flags |= SMB_DIRSEARCH_BULKST;
2052 lock_ReleaseMutex(&scp->mx);
2055 lock_ReleaseMutex(&dsp->mx);
2057 cm_ReleaseUser(userp);
2058 smb_FreeTran2Packet(outp);
2059 smb_DeleteDirSearch(dsp);
2060 smb_ReleaseDirSearch(dsp);
2064 /* get the directory size */
2065 lock_ObtainMutex(&scp->mx);
2066 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2067 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2069 lock_ReleaseMutex(&scp->mx);
2070 cm_ReleaseSCache(scp);
2071 cm_ReleaseUser(userp);
2072 smb_FreeTran2Packet(outp);
2073 smb_DeleteDirSearch(dsp);
2074 smb_ReleaseDirSearch(dsp);
2078 dirLength = scp->length;
2080 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2081 curOffset.HighPart = 0;
2082 curOffset.LowPart = nextCookie;
2083 origOp = outp->datap;
2090 if (searchFlags & 4)
2091 /* skip over resume key */
2094 /* make sure that curOffset.LowPart doesn't point to the first
2095 * 32 bytes in the 2nd through last dir page, and that it doesn't
2096 * point at the first 13 32-byte chunks in the first dir page,
2097 * since those are dir and page headers, and don't contain useful
2100 temp = curOffset.LowPart & (2048-1);
2101 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2102 /* we're in the first page */
2103 if (temp < 13*32) temp = 13*32;
2106 /* we're in a later dir page */
2107 if (temp < 32) temp = 32;
2110 /* make sure the low order 5 bits are zero */
2113 /* now put temp bits back ito curOffset.LowPart */
2114 curOffset.LowPart &= ~(2048-1);
2115 curOffset.LowPart |= temp;
2117 /* check if we've passed the dir's EOF */
2118 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2123 /* check if we've returned all the names that will fit in the
2124 * response packet; we check return count as well as the number
2125 * of bytes requested. We check the # of bytes after we find
2126 * the dir entry, since we'll need to check its size.
2128 if (returnedNames >= maxCount) {
2132 /* see if we can use the bufferp we have now; compute in which
2133 * page the current offset would be, and check whether that's
2134 * the offset of the buffer we have. If not, get the buffer.
2136 thyper.HighPart = curOffset.HighPart;
2137 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2138 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2141 buf_Release(bufferp);
2144 lock_ReleaseMutex(&scp->mx);
2145 lock_ObtainRead(&scp->bufCreateLock);
2146 code = buf_Get(scp, &thyper, &bufferp);
2147 lock_ReleaseRead(&scp->bufCreateLock);
2149 /* now, if we're doing a star match, do bulk fetching
2150 * of all of the status info for files in the dir.
2153 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2156 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2157 && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
2158 /* Don't bulk stat if risking timeout */
2159 int now = GetCurrentTime();
2160 if (now - req.startTime > 5000) {
2161 scp->bulkStatProgress = thyper;
2162 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2163 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2165 cm_TryBulkStat(scp, &thyper, userp, &req);
2169 lock_ObtainMutex(&scp->mx);
2171 bufferOffset = thyper;
2173 /* now get the data in the cache */
2175 code = cm_SyncOp(scp, bufferp, userp, &req,
2177 CM_SCACHESYNC_NEEDCALLBACK
2178 | CM_SCACHESYNC_READ);
2181 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2183 /* otherwise, load the buffer and try again */
2184 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2189 buf_Release(bufferp);
2193 } /* if (wrong buffer) ... */
2195 /* now we have the buffer containing the entry we're interested
2196 * in; copy it out if it represents a non-deleted entry.
2198 entryInDir = curOffset.LowPart & (2048-1);
2199 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2201 /* page header will help tell us which entries are free. Page
2202 * header can change more often than once per buffer, since
2203 * AFS 3 dir page size may be less than (but not more than)
2204 * a buffer package buffer.
2206 /* only look intra-buffer */
2207 temp = curOffset.LowPart & (buf_bufferSize - 1);
2208 temp &= ~(2048 - 1); /* turn off intra-page bits */
2209 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2211 /* now determine which entry we're looking at in the page.
2212 * If it is free (there's a free bitmap at the start of the
2213 * dir), we should skip these 32 bytes.
2215 slotInPage = (entryInDir & 0x7e0) >> 5;
2216 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2217 & (1 << (slotInPage & 0x7)))) {
2218 /* this entry is free */
2219 numDirChunks = 1; /* only skip this guy */
2223 tp = bufferp->datap + entryInBuffer;
2224 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2226 /* while we're here, compute the next entry's location, too,
2227 * since we'll need it when writing out the cookie into the dir
2230 * XXXX Probably should do more sanity checking.
2232 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2234 /* compute offset of cookie representing next entry */
2235 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
2237 /* Need 8.3 name? */
2239 if (infoLevel == 0x104
2240 && dep->fid.vnode != 0
2241 && !cm_Is8Dot3(dep->name)) {
2242 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2246 if (dep->fid.vnode != 0
2247 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2249 && smb_V3MatchMask(shortName, maskp,
2250 CM_FLAG_CASEFOLD)))) {
2252 /* Eliminate entries that don't match requested attributes */
2253 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
2254 smb_IsDotFile(dep->name))
2255 goto nextEntry; /* no hidden files */
2257 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
2259 /* We have already done the cm_TryBulkStat above */
2260 fid.cell = scp->fid.cell;
2261 fid.volume = scp->fid.volume;
2262 fid.vnode = ntohl(dep->fid.vnode);
2263 fid.unique = ntohl(dep->fid.unique);
2264 fileType = cm_FindFileType(&fid);
2265 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
2266 "has filetype %d", dep->name,
2268 if (fileType == CM_SCACHETYPE_DIRECTORY)
2272 /* finally check if this name will fit */
2274 /* standard dir entry stuff */
2275 if (infoLevel < 0x101)
2276 ohbytes = 23; /* pre-NT */
2277 else if (infoLevel == 0x103)
2278 ohbytes = 12; /* NT names only */
2280 ohbytes = 64; /* NT */
2282 if (infoLevel == 0x104)
2283 ohbytes += 26; /* Short name & length */
2285 if (searchFlags & 4) {
2286 ohbytes += 4; /* if resume key required */
2290 && infoLevel != 0x101
2291 && infoLevel != 0x103)
2292 ohbytes += 4; /* EASIZE */
2294 /* add header to name & term. null */
2295 orbytes = onbytes + ohbytes + 1;
2297 /* now, we round up the record to a 4 byte alignment,
2298 * and we make sure that we have enough room here for
2299 * even the aligned version (so we don't have to worry
2300 * about an * overflow when we pad things out below).
2301 * That's the reason for the alignment arithmetic below.
2303 if (infoLevel >= 0x101)
2304 align = (4 - (orbytes & 3)) & 3;
2307 if (orbytes + bytesInBuffer + align > maxReturnData)
2310 /* this is one of the entries to use: it is not deleted
2311 * and it matches the star pattern we're looking for.
2312 * Put out the name, preceded by its length.
2314 /* First zero everything else */
2315 memset(origOp, 0, ohbytes);
2317 if (infoLevel <= 0x101)
2318 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2319 else if (infoLevel == 0x103)
2320 *((u_long *)(op + 8)) = onbytes;
2322 *((u_long *)(op + 60)) = onbytes;
2323 strcpy(origOp+ohbytes, dep->name);
2325 /* Short name if requested and needed */
2326 if (infoLevel == 0x104) {
2327 if (NeedShortName) {
2328 strcpy(op + 70, shortName);
2329 *(op + 68) = shortNameEnd - shortName;
2333 /* now, adjust the # of entries copied */
2336 /* NextEntryOffset and FileIndex */
2337 if (infoLevel >= 101) {
2338 int entryOffset = orbytes + align;
2339 *((u_long *)op) = entryOffset;
2340 *((u_long *)(op+4)) = nextEntryCookie;
2343 /* now we emit the attribute. This is tricky, since
2344 * we need to really stat the file to find out what
2345 * type of entry we've got. Right now, we're copying
2346 * out data from * a buffer, while holding the scp
2347 * locked, so it isn't really convenient to stat
2348 * something now. We'll put in a place holder
2349 * now, and make a second pass before returning this
2350 * to get the real attributes. So, we just skip the
2351 * data for now, and adjust it later. We allocate a
2352 * patch record to make it easy to find this point
2353 * later. The replay will happen at a time when it is
2354 * safe to unlock the directory.
2356 if (infoLevel != 0x103) {
2357 curPatchp = malloc(sizeof(*curPatchp));
2358 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2360 curPatchp->dptr = op;
2361 if (infoLevel >= 0x101)
2362 curPatchp->dptr += 8;
2364 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2365 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2368 curPatchp->flags = 0;
2370 curPatchp->fid.cell = scp->fid.cell;
2371 curPatchp->fid.volume = scp->fid.volume;
2372 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2373 curPatchp->fid.unique = ntohl(dep->fid.unique);
2376 curPatchp->dep = dep;
2379 if (searchFlags & 4)
2380 /* put out resume key */
2381 *((u_long *)origOp) = nextEntryCookie;
2383 /* Adjust byte ptr and count */
2384 origOp += orbytes; /* skip entire record */
2385 bytesInBuffer += orbytes;
2387 /* and pad the record out */
2388 while (--align >= 0) {
2393 } /* if we're including this name */
2396 /* and adjust curOffset to be where the new cookie is */
2397 thyper.HighPart = 0;
2398 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2399 curOffset = LargeIntegerAdd(thyper, curOffset);
2400 } /* while copying data for dir listing */
2402 /* release the mutex */
2403 lock_ReleaseMutex(&scp->mx);
2404 if (bufferp) buf_Release(bufferp);
2406 /* apply and free last set of patches; if not doing a star match, this
2407 * will be empty, but better safe (and freeing everything) than sorry.
2409 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2412 /* now put out the final parameters */
2413 if (returnedNames == 0) eos = 1;
2414 if (p->opcode == 1) {
2416 outp->parmsp[0] = (unsigned short) dsp->cookie;
2417 outp->parmsp[1] = returnedNames;
2418 outp->parmsp[2] = eos;
2419 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2420 outp->parmsp[4] = 0;
2421 /* don't need last name to continue
2422 * search, cookie is enough. Normally,
2423 * this is the offset of the file name
2424 * of the last entry returned.
2426 outp->totalParms = 10; /* in bytes */
2430 outp->parmsp[0] = returnedNames;
2431 outp->parmsp[1] = eos;
2432 outp->parmsp[2] = 0; /* EAS error */
2433 outp->parmsp[3] = 0; /* last name, as above */
2434 outp->totalParms = 8; /* in bytes */
2437 /* return # of bytes in the buffer */
2438 outp->totalData = bytesInBuffer;
2440 osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
2441 returnedNames, code);
2443 /* Return error code if unsuccessful on first request */
2444 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2445 code = CM_ERROR_NOSUCHFILE;
2447 /* if we're supposed to close the search after this request, or if
2448 * we're supposed to close the search if we're done, and we're done,
2449 * or if something went wrong, close the search.
2451 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2452 if ((searchFlags & 1) || (returnedNames == 0) ||
2453 ((searchFlags & 2) && eos) || code != 0)
2454 smb_DeleteDirSearch(dsp);
2456 smb_SendTran2Error(vcp, p, opx, code);
2458 smb_SendTran2Packet(vcp, outp, opx);
2460 smb_FreeTran2Packet(outp);
2461 smb_ReleaseDirSearch(dsp);
2462 cm_ReleaseSCache(scp);
2463 cm_ReleaseUser(userp);
2467 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2470 smb_dirSearch_t *dsp;
2472 dirHandle = smb_GetSMBParm(inp, 0);
2474 osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
2476 dsp = smb_FindDirSearch(dirHandle);
2479 return CM_ERROR_BADFD;
2481 /* otherwise, we have an FD to destroy */
2482 smb_DeleteDirSearch(dsp);
2483 smb_ReleaseDirSearch(dsp);
2485 /* and return results */
2486 smb_SetSMBDataLength(outp, 0);
2491 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2493 smb_SetSMBDataLength(outp, 0);
2497 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2504 cm_scache_t *dscp; /* dir we're dealing with */
2505 cm_scache_t *scp; /* file we're creating */
2507 int initialModeBits;
2517 int parmSlot; /* which parm we're dealing with */
2525 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2526 openFun = smb_GetSMBParm(inp, 8); /* open function */
2527 excl = ((openFun & 3) == 0);
2528 trunc = ((openFun & 3) == 2); /* truncate it */
2529 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2530 openAction = 0; /* tracks what we did */
2532 attributes = smb_GetSMBParm(inp, 5);
2533 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2535 /* compute initial mode bits based on read-only flag in attributes */
2536 initialModeBits = 0666;
2537 if (attributes & 1) initialModeBits &= ~0222;
2539 pathp = smb_GetSMBData(inp, NULL);
2541 spacep = inp->spacep;
2542 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2544 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2545 /* special case magic file name for receiving IOCTL requests
2546 * (since IOCTL calls themselves aren't getting through).
2549 osi_Log0(smb_logp, "IOCTL Open");
2552 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2553 smb_SetupIoctlFid(fidp, spacep);
2555 /* set inp->fid so that later read calls in same msg can find fid */
2556 inp->fid = fidp->fid;
2558 /* copy out remainder of the parms */
2560 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2562 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2563 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2564 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2565 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2566 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2567 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2568 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2569 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2571 /* and the final "always present" stuff */
2572 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2573 /* next write out the "unique" ID */
2574 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2575 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2576 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2577 smb_SetSMBDataLength(outp, 0);
2579 /* and clean up fid reference */
2580 smb_ReleaseFID(fidp);
2584 #ifdef DEBUG_VERBOSE
2586 char *hexp, *asciip;
2587 asciip = (lastNamep ? lastNamep : pathp );
2588 hexp = osi_HexifyString(asciip);
2589 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2593 userp = smb_GetUser(vcp, inp);
2596 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2597 code = cm_NameI(cm_rootSCachep, pathp,
2598 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2599 userp, tidPathp, &req, &scp);
2601 code = cm_NameI(cm_rootSCachep, spacep->data,
2602 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2603 userp, tidPathp, &req, &dscp);
2606 cm_ReleaseUser(userp);
2610 /* otherwise, scp points to the parent directory. Do a lookup,
2611 * and truncate the file if we find it, otherwise we create the
2614 if (!lastNamep) lastNamep = pathp;
2616 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2618 if (code && code != CM_ERROR_NOSUCHFILE) {
2619 cm_ReleaseSCache(dscp);
2620 cm_ReleaseUser(userp);
2625 /* if we get here, if code is 0, the file exists and is represented by
2626 * scp. Otherwise, we have to create it. The dir may be represented
2627 * by dscp, or we may have found the file directly. If code is non-zero,
2631 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2633 if (dscp) cm_ReleaseSCache(dscp);
2634 cm_ReleaseSCache(scp);
2635 cm_ReleaseUser(userp);
2640 /* oops, file shouldn't be there */
2641 if (dscp) cm_ReleaseSCache(dscp);
2642 cm_ReleaseSCache(scp);
2643 cm_ReleaseUser(userp);
2644 return CM_ERROR_EXISTS;
2648 setAttr.mask = CM_ATTRMASK_LENGTH;
2649 setAttr.length.LowPart = 0;
2650 setAttr.length.HighPart = 0;
2651 code = cm_SetAttr(scp, &setAttr, userp, &req);
2652 openAction = 3; /* truncated existing file */
2654 else openAction = 1; /* found existing file */
2656 else if (!(openFun & 0x10)) {
2657 /* don't create if not found */
2658 if (dscp) cm_ReleaseSCache(dscp);
2659 cm_ReleaseUser(userp);
2660 return CM_ERROR_NOSUCHFILE;
2663 osi_assert(dscp != NULL);
2664 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
2665 osi_LogSaveString(smb_logp, lastNamep));
2666 openAction = 2; /* created file */
2667 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2668 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2669 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2671 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2672 smb_NotifyChange(FILE_ACTION_ADDED,
2673 FILE_NOTIFY_CHANGE_FILE_NAME,
2674 dscp, lastNamep, NULL, TRUE);
2675 if (!excl && code == CM_ERROR_EXISTS) {
2676 /* not an exclusive create, and someone else tried
2677 * creating it already, then we open it anyway. We
2678 * don't bother retrying after this, since if this next
2679 * fails, that means that the file was deleted after we
2680 * started this call.
2682 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2686 setAttr.mask = CM_ATTRMASK_LENGTH;
2687 setAttr.length.LowPart = 0;
2688 setAttr.length.HighPart = 0;
2689 code = cm_SetAttr(scp, &setAttr, userp, &req);
2691 } /* lookup succeeded */
2695 /* we don't need this any longer */
2696 if (dscp) cm_ReleaseSCache(dscp);
2699 /* something went wrong creating or truncating the file */
2700 if (scp) cm_ReleaseSCache(scp);
2701 cm_ReleaseUser(userp);
2705 /* make sure we're about to open a file */
2706 if (scp->fileType != CM_SCACHETYPE_FILE) {
2707 cm_ReleaseSCache(scp);
2708 cm_ReleaseUser(userp);
2709 return CM_ERROR_ISDIR;
2712 /* now all we have to do is open the file itself */
2713 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2716 /* save a pointer to the vnode */
2719 /* compute open mode */
2720 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2721 if (openMode == 1 || openMode == 2)
2722 fidp->flags |= SMB_FID_OPENWRITE;
2724 smb_ReleaseFID(fidp);
2726 cm_Open(scp, 0, userp);
2728 /* set inp->fid so that later read calls in same msg can find fid */
2729 inp->fid = fidp->fid;
2731 /* copy out remainder of the parms */
2733 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2734 lock_ObtainMutex(&scp->mx);
2736 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2737 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2738 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2739 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2740 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2741 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2742 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2743 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2744 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2746 /* and the final "always present" stuff */
2747 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2748 /* next write out the "unique" ID */
2749 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2750 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2751 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2752 lock_ReleaseMutex(&scp->mx);
2753 smb_SetSMBDataLength(outp, 0);
2755 osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
2757 cm_ReleaseUser(userp);
2758 /* leave scp held since we put it in fidp->scp */
2762 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2769 unsigned char LockType;
2770 unsigned short NumberOfUnlocks, NumberOfLocks;
2771 unsigned long Timeout;
2773 LARGE_INTEGER LOffset, LLength;
2774 smb_waitingLock_t *waitingLock;
2781 fid = smb_GetSMBParm(inp, 2);
2782 fid = smb_ChainFID(fid, inp);
2784 fidp = smb_FindFID(vcp, fid, 0);
2785 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2786 return CM_ERROR_BADFD;
2788 /* set inp->fid so that later read calls in same msg can find fid */
2791 userp = smb_GetUser(vcp, inp);
2795 lock_ObtainMutex(&scp->mx);
2796 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2797 CM_SCACHESYNC_NEEDCALLBACK
2798 | CM_SCACHESYNC_GETSTATUS
2799 | CM_SCACHESYNC_LOCK);
2800 if (code) goto doneSync;
2802 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2803 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2804 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2805 NumberOfLocks = smb_GetSMBParm(inp, 7);
2807 op = smb_GetSMBData(inp, NULL);
2809 for (i=0; i<NumberOfUnlocks; i++) {
2810 if (LockType & 0x10) {
2812 LOffset.HighPart = *((LONG *)(op + 4));
2813 LOffset.LowPart = *((DWORD *)(op + 8));
2814 LLength.HighPart = *((LONG *)(op + 12));
2815 LLength.LowPart = *((DWORD *)(op + 16));
2819 /* Not Large Files */
2820 LOffset.HighPart = 0;
2821 LOffset.LowPart = *((DWORD *)(op + 2));
2822 LLength.HighPart = 0;
2823 LLength.LowPart = *((DWORD *)(op + 6));
2826 if (LargeIntegerNotEqualToZero(LOffset))
2828 /* Do not check length -- length check done in cm_Unlock */
2830 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2831 if (code) goto done;
2834 for (i=0; i<NumberOfLocks; i++) {
2835 if (LockType & 0x10) {
2837 LOffset.HighPart = *((LONG *)(op + 4));
2838 LOffset.LowPart = *((DWORD *)(op + 8));
2839 LLength.HighPart = *((LONG *)(op + 12));
2840 LLength.LowPart = *((DWORD *)(op + 16));
2844 /* Not Large Files */
2845 LOffset.HighPart = 0;
2846 LOffset.LowPart = *((DWORD *)(op + 2));
2847 LLength.HighPart = 0;
2848 LLength.LowPart = *((DWORD *)(op + 6));
2851 if (LargeIntegerNotEqualToZero(LOffset))
2853 if (LargeIntegerLessThan(LOffset, scp->length))
2856 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2857 userp, &req, &lockp);
2858 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2859 /* Put on waiting list */
2860 waitingLock = malloc(sizeof(smb_waitingLock_t));
2861 waitingLock->vcp = vcp;
2862 waitingLock->inp = smb_CopyPacket(inp);
2863 waitingLock->outp = smb_CopyPacket(outp);
2864 waitingLock->timeRemaining = Timeout;
2865 waitingLock->lockp = lockp;
2866 lock_ObtainWrite(&smb_globalLock);
2867 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2869 osi_Wakeup((long) &smb_allWaitingLocks);
2870 lock_ReleaseWrite(&smb_globalLock);
2871 /* don't send reply immediately */
2872 outp->flags |= SMB_PACKETFLAG_NOSEND;
2878 /* release any locks acquired before the failure */
2881 smb_SetSMBDataLength(outp, 0);
2883 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2885 lock_ReleaseMutex(&scp->mx);
2886 cm_ReleaseUser(userp);
2887 smb_ReleaseFID(fidp);
2892 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2904 fid = smb_GetSMBParm(inp, 0);
2905 fid = smb_ChainFID(fid, inp);
2907 fidp = smb_FindFID(vcp, fid, 0);
2908 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2909 return CM_ERROR_BADFD;
2912 userp = smb_GetUser(vcp, inp);
2916 /* otherwise, stat the file */
2917 lock_ObtainMutex(&scp->mx);
2918 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2919 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2920 if (code) goto done;
2922 /* decode times. We need a search time, but the response to this
2923 * call provides the date first, not the time, as returned in the
2924 * searchTime variable. So we take the high-order bits first.
2926 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2927 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2928 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2929 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2930 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2931 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2932 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2934 /* now handle file size and allocation size */
2935 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2936 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2937 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2938 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2940 /* file attribute */
2941 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2943 /* and finalize stuff */
2944 smb_SetSMBDataLength(outp, 0);
2948 lock_ReleaseMutex(&scp->mx);
2949 cm_ReleaseUser(userp);
2950 smb_ReleaseFID(fidp);
2954 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2968 fid = smb_GetSMBParm(inp, 0);
2969 fid = smb_ChainFID(fid, inp);
2971 fidp = smb_FindFID(vcp, fid, 0);
2972 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2973 return CM_ERROR_BADFD;
2976 userp = smb_GetUser(vcp, inp);
2980 /* now prepare to call cm_setattr. This message only sets various times,
2981 * and AFS only implements mtime, and we'll set the mtime if that's
2982 * requested. The others we'll ignore.
2984 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2986 if (searchTime != 0) {
2987 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2989 if ( unixTime != -1 ) {
2990 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2991 attrs.clientModTime = unixTime;
2992 code = cm_SetAttr(scp, &attrs, userp, &req);
2994 osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
2996 osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
3001 cm_ReleaseUser(userp);
3002 smb_ReleaseFID(fidp);
3007 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3010 long count, finalCount;
3017 fd = smb_GetSMBParm(inp, 2);
3018 count = smb_GetSMBParm(inp, 5);
3019 offset.HighPart = 0; /* too bad */
3020 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3022 osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3023 fd, offset.LowPart, count);
3025 fd = smb_ChainFID(fd, inp);
3026 fidp = smb_FindFID(vcp, fd, 0);
3028 return CM_ERROR_BADFD;
3030 /* set inp->fid so that later read calls in same msg can find fid */
3033 if (fidp->flags & SMB_FID_IOCTL) {
3034 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3037 userp = smb_GetUser(vcp, inp);
3039 /* 0 and 1 are reserved for request chaining, were setup by our caller,
3040 * and will be further filled in after we return.
3042 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3043 smb_SetSMBParm(outp, 3, 0); /* resvd */
3044 smb_SetSMBParm(outp, 4, 0); /* resvd */
3045 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3046 /* fill in #6 when we have all the parameters' space reserved */
3047 smb_SetSMBParm(outp, 7, 0); /* resv'd */
3048 smb_SetSMBParm(outp, 8, 0); /* resv'd */
3049 smb_SetSMBParm(outp, 9, 0); /* resv'd */
3050 smb_SetSMBParm(outp, 10, 0); /* resv'd */
3051 smb_SetSMBParm(outp, 11, 0); /* reserved */
3053 /* get op ptr after putting in the parms, since otherwise we don't
3054 * know where the data really is.
3056 op = smb_GetSMBData(outp, NULL);
3058 /* now fill in offset from start of SMB header to first data byte (to op) */
3059 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3061 /* set the packet data length the count of the # of bytes */
3062 smb_SetSMBDataLength(outp, count);
3065 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3067 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3070 /* fix some things up */
3071 smb_SetSMBParm(outp, 5, finalCount);
3072 smb_SetSMBDataLength(outp, finalCount);
3074 smb_ReleaseFID(fidp);
3076 cm_ReleaseUser(userp);
3081 * Values for createDisp, copied from NTDDK.H
3083 * FILE_SUPERSEDE 0 (???)
3084 * FILE_OPEN 1 (open)
3085 * FILE_CREATE 2 (exclusive)
3086 * FILE_OPEN_IF 3 (non-exclusive)
3087 * FILE_OVERWRITE 4 (open & truncate, but do not create)
3088 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
3091 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3093 char *pathp, *realPathp;
3097 cm_scache_t *dscp; /* parent dir */
3098 cm_scache_t *scp; /* file to create or open */
3102 unsigned short nameLength;
3104 unsigned int requestOpLock;
3105 unsigned int requestBatchOpLock;
3106 unsigned int mustBeDir;
3107 unsigned int treeCreate;
3109 unsigned int desiredAccess;
3110 unsigned int extAttributes;
3111 unsigned int createDisp;
3112 unsigned int createOptions;
3113 int initialModeBits;
3114 unsigned short baseFid;
3115 smb_fid_t *baseFidp;
3117 cm_scache_t *baseDirp;
3118 unsigned short openAction;
3133 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3134 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3135 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3136 requestOpLock = flags & 0x02;
3137 requestBatchOpLock = flags & 0x04;
3138 mustBeDir = flags & 0x08;
3141 * Why all of a sudden 32-bit FID?
3142 * We will reject all bits higher than 16.
3144 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3145 return CM_ERROR_INVAL;
3146 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3147 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3148 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3149 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3150 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3151 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3152 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3153 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3154 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3156 /* mustBeDir is never set; createOptions directory bit seems to be
3159 if (createOptions & 1)
3161 else if (createOptions & 0x40)
3167 * compute initial mode bits based on read-only flag in
3168 * extended attributes
3170 initialModeBits = 0666;
3171 if (extAttributes & 1) initialModeBits &= ~0222;
3173 pathp = smb_GetSMBData(inp, NULL);
3174 /* Sometimes path is not null-terminated, so we make a copy. */
3175 realPathp = malloc(nameLength+1);
3176 memcpy(realPathp, pathp, nameLength);
3177 realPathp[nameLength] = 0;
3179 spacep = inp->spacep;
3180 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3182 osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
3183 osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3185 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3186 /* special case magic file name for receiving IOCTL requests
3187 * (since IOCTL calls themselves aren't getting through).
3189 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3190 smb_SetupIoctlFid(fidp, spacep);
3192 /* set inp->fid so that later read calls in same msg can find fid */
3193 inp->fid = fidp->fid;
3197 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3198 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3199 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3201 memset(&ft, 0, sizeof(ft));
3202 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3203 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3204 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3205 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3206 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3207 sz.HighPart = 0x7fff; sz.LowPart = 0;
3208 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3209 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3210 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3211 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3212 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3213 smb_SetSMBDataLength(outp, 0);
3215 /* clean up fid reference */
3216 smb_ReleaseFID(fidp);
3221 #ifdef DEBUG_VERBOSE
3223 char *hexp, *asciip;
3224 asciip = (lastNamep? lastNamep : realPathp);
3225 hexp = osi_HexifyString( asciip );
3226 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3230 userp = smb_GetUser(vcp, inp);
3232 osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3234 return CM_ERROR_INVAL;
3238 baseDirp = cm_rootSCachep;
3239 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3242 baseFidp = smb_FindFID(vcp, baseFid, 0);
3244 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3246 cm_ReleaseUser(userp);
3247 return CM_ERROR_INVAL;
3249 baseDirp = baseFidp->scp;
3253 osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
3255 /* compute open mode */
3257 if (desiredAccess & DELETE)
3258 fidflags |= SMB_FID_OPENDELETE;
3259 if (desiredAccess & AFS_ACCESS_READ)
3260 fidflags |= SMB_FID_OPENREAD;
3261 if (desiredAccess & AFS_ACCESS_WRITE)
3262 fidflags |= SMB_FID_OPENWRITE;
3266 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3267 userp, tidPathp, &req, &scp);
3268 if (code == 0) foundscp = TRUE;
3270 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3271 /* look up parent directory */
3272 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3273 the immediate parent. We have to work our way up realPathp until we hit something that we
3280 code = cm_NameI(baseDirp, spacep->data,
3281 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3282 userp, tidPathp, &req, &dscp);
3285 (tp = strrchr(spacep->data,'\\')) &&
3286 (createDisp == 2) &&
3287 (realDirFlag == 1)) {
3290 treeStartp = realPathp + (tp - spacep->data);
3292 if (*tp && !smb_IsLegalFilename(tp)) {
3293 if(baseFid != 0) smb_ReleaseFID(baseFidp);
3294 cm_ReleaseUser(userp);
3296 return CM_ERROR_BADNTFILENAME;
3303 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3306 osi_Log0(smb_logp,"NTCreateX parent not found");
3307 cm_ReleaseUser(userp);
3312 if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3313 /* A file exists where we want a directory. */
3314 cm_ReleaseSCache(dscp);
3315 cm_ReleaseUser(userp);
3317 return CM_ERROR_EXISTS;
3320 if (!lastNamep) lastNamep = realPathp;
3323 if (!smb_IsLegalFilename(lastNamep)) {
3324 cm_ReleaseSCache(dscp);
3325 cm_ReleaseUser(userp);
3327 return CM_ERROR_BADNTFILENAME;
3330 if (!foundscp && !treeCreate) {
3331 code = cm_Lookup(dscp, lastNamep,
3332 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3334 if (code && code != CM_ERROR_NOSUCHFILE) {
3335 cm_ReleaseSCache(dscp);
3336 cm_ReleaseUser(userp);
3343 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3346 /* if we get here, if code is 0, the file exists and is represented by
3347 * scp. Otherwise, we have to create it. The dir may be represented
3348 * by dscp, or we may have found the file directly. If code is non-zero,
3351 if (code == 0 && !treeCreate) {
3352 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3355 if (dscp) cm_ReleaseSCache(dscp);
3356 cm_ReleaseSCache(scp);
3357 cm_ReleaseUser(userp);
3362 if (createDisp == 2) {
3363 /* oops, file shouldn't be there */
3364 if (dscp) cm_ReleaseSCache(dscp);
3365 cm_ReleaseSCache(scp);
3366 cm_ReleaseUser(userp);
3368 return CM_ERROR_EXISTS;
3372 || createDisp == 5) {
3373 setAttr.mask = CM_ATTRMASK_LENGTH;
3374 setAttr.length.LowPart = 0;
3375 setAttr.length.HighPart = 0;
3376 code = cm_SetAttr(scp, &setAttr, userp, &req);
3377 openAction = 3; /* truncated existing file */
3379 else openAction = 1; /* found existing file */
3381 else if (createDisp == 1 || createDisp == 4) {
3382 /* don't create if not found */
3383 if (dscp) cm_ReleaseSCache(dscp);
3384 cm_ReleaseUser(userp);
3386 return CM_ERROR_NOSUCHFILE;
3388 else if (realDirFlag == 0 || realDirFlag == -1) {
3389 osi_assert(dscp != NULL);
3390 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
3391 osi_LogSaveString(smb_logp, lastNamep));
3392 openAction = 2; /* created file */
3393 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3394 setAttr.clientModTime = time(NULL);
3395 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3397 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3398 smb_NotifyChange(FILE_ACTION_ADDED,
3399 FILE_NOTIFY_CHANGE_FILE_NAME,
3400 dscp, lastNamep, NULL, TRUE);
3401 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3402 /* Not an exclusive create, and someone else tried
3403 * creating it already, then we open it anyway. We
3404 * don't bother retrying after this, since if this next
3405 * fails, that means that the file was deleted after we
3406 * started this call.
3408 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3411 if (createDisp == 5) {
3412 setAttr.mask = CM_ATTRMASK_LENGTH;
3413 setAttr.length.LowPart = 0;
3414 setAttr.length.HighPart = 0;
3415 code = cm_SetAttr(scp, &setAttr, userp,
3418 } /* lookup succeeded */
3423 char *cp; /* This component */
3424 int clen = 0; /* length of component */
3428 /* create directory */
3429 if ( !treeCreate ) treeStartp = lastNamep;
3430 osi_assert(dscp != NULL);
3431 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3432 osi_LogSaveString(smb_logp, treeStartp));
3433 openAction = 2; /* created directory */
3435 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3436 setAttr.clientModTime = time(NULL);
3443 tp = strchr(pp, '\\');
3447 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
3451 strncpy(cp,pp,clen);
3457 if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3459 /* cp is the next component to be created. */
3460 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3461 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3462 smb_NotifyChange(FILE_ACTION_ADDED,
3463 FILE_NOTIFY_CHANGE_DIR_NAME,
3464 tscp, cp, NULL, TRUE);
3466 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3467 /* Not an exclusive create, and someone else tried
3468 * creating it already, then we open it anyway. We
3469 * don't bother retrying after this, since if this next
3470 * fails, that means that the file was deleted after we
3471 * started this call.
3473 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3478 if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3479 cm_ReleaseSCache(tscp);
3480 tscp = scp; /* Newly created directory will be next parent */
3485 if we get here and code == 0, then scp is the last directory created, and tscp is the
3486 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
3492 /* something went wrong creating or truncating the file */
3493 if (scp) cm_ReleaseSCache(scp);
3494 if (dscp) cm_ReleaseSCache(dscp);
3495 cm_ReleaseUser(userp);
3500 /* make sure we have file vs. dir right (only applies for single component case) */
3501 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3502 cm_ReleaseSCache(scp);
3503 if (dscp) cm_ReleaseSCache(dscp);
3504 cm_ReleaseUser(userp);
3506 return CM_ERROR_ISDIR;
3508 /* (only applies to single component case) */
3509 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3510 cm_ReleaseSCache(scp);
3511 if (dscp) cm_ReleaseSCache(dscp);
3512 cm_ReleaseUser(userp);
3514 return CM_ERROR_NOTDIR;
3517 /* open the file itself */
3518 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3520 /* save a pointer to the vnode */
3523 fidp->flags = fidflags;
3525 /* save parent dir and pathname for delete or change notification */
3526 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3527 fidp->flags |= SMB_FID_NTOPEN;
3528 fidp->NTopen_dscp = dscp;
3529 cm_HoldSCache(dscp);
3530 fidp->NTopen_pathp = strdup(lastNamep);
3532 fidp->NTopen_wholepathp = realPathp;
3534 /* we don't need this any longer */
3535 if (dscp) cm_ReleaseSCache(dscp);
3536 cm_Open(scp, 0, userp);
3538 /* set inp->fid so that later read calls in same msg can find fid */
3539 inp->fid = fidp->fid;
3543 lock_ObtainMutex(&scp->mx);
3544 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3545 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3546 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3547 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3548 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3549 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3550 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3551 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3552 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3554 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3555 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3556 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3557 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3558 smb_SetSMBParmByte(outp, parmSlot,
3559 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3560 lock_ReleaseMutex(&scp->mx);
3561 smb_SetSMBDataLength(outp, 0);
3563 osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3564 osi_LogSaveString(smb_logp, realPathp));
3566 smb_ReleaseFID(fidp);
3568 cm_ReleaseUser(userp);
3570 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3572 /* leave scp held since we put it in fidp->scp */
3577 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3578 * Instead, ultimately, would like to use a subroutine for common code.
3580 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3582 char *pathp, *realPathp;
3586 cm_scache_t *dscp; /* parent dir */
3587 cm_scache_t *scp; /* file to create or open */
3590 unsigned long nameLength;
3592 unsigned int requestOpLock;
3593 unsigned int requestBatchOpLock;
3594 unsigned int mustBeDir;
3595 unsigned int extendedRespRequired;
3597 unsigned int desiredAccess;
3598 #ifdef DEBUG_VERBOSE
3599 unsigned int allocSize;
3600 unsigned int shareAccess;
3602 unsigned int extAttributes;
3603 unsigned int createDisp;
3604 #ifdef DEBUG_VERBOSE
3607 unsigned int createOptions;
3608 int initialModeBits;
3609 unsigned short baseFid;
3610 smb_fid_t *baseFidp;
3612 cm_scache_t *baseDirp;
3613 unsigned short openAction;
3619 int parmOffset, dataOffset;
3630 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3631 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3632 parmp = inp->data + parmOffset;
3633 lparmp = (ULONG *) parmp;
3636 requestOpLock = flags & 0x02;
3637 requestBatchOpLock = flags & 0x04;
3638 mustBeDir = flags & 0x08;
3639 extendedRespRequired = flags & 0x10;
3642 * Why all of a sudden 32-bit FID?
3643 * We will reject all bits higher than 16.
3645 if (lparmp[1] & 0xFFFF0000)
3646 return CM_ERROR_INVAL;
3647 baseFid = (unsigned short)lparmp[1];
3648 desiredAccess = lparmp[2];
3649 #ifdef DEBUG_VERBOSE
3650 allocSize = lparmp[3];
3651 #endif /* DEBUG_VERSOSE */
3652 extAttributes = lparmp[5];
3654 shareAccess = lparmp[6];
3656 createDisp = lparmp[7];
3657 createOptions = lparmp[8];
3658 #ifdef DEBUG_VERBOSE
3661 nameLength = lparmp[11];
3663 #ifdef DEBUG_VERBOSE
3664 osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3665 osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3666 osi_Log1(smb_logp,"... flags[%x]",flags);
3669 /* mustBeDir is never set; createOptions directory bit seems to be
3672 if (createOptions & 1)
3674 else if (createOptions & 0x40)
3680 * compute initial mode bits based on read-only flag in
3681 * extended attributes
3683 initialModeBits = 0666;
3684 if (extAttributes & 1) initialModeBits &= ~0222;
3686 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3687 /* Sometimes path is not null-terminated, so we make a copy. */
3688 realPathp = malloc(nameLength+1);
3689 memcpy(realPathp, pathp, nameLength);
3690 realPathp[nameLength] = 0;
3692 spacep = cm_GetSpace();
3693 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3696 * Nothing here to handle SMB_IOCTL_FILENAME.
3697 * Will add it if necessary.
3700 #ifdef DEBUG_VERBOSE
3702 char *hexp, *asciip;
3703 asciip = (lastNamep? lastNamep : realPathp);
3704 hexp = osi_HexifyString( asciip );
3705 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3710 userp = smb_GetUser(vcp, inp);
3712 osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3714 return CM_ERROR_INVAL;
3718 baseDirp = cm_rootSCachep;
3719 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3722 baseFidp = smb_FindFID(vcp, baseFid, 0);
3724 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3726 cm_ReleaseUser(userp);
3727 return CM_ERROR_INVAL;
3729 baseDirp = baseFidp->scp;
3733 /* compute open mode */
3735 if (desiredAccess & DELETE)
3736 fidflags |= SMB_FID_OPENDELETE;
3737 if (desiredAccess & AFS_ACCESS_READ)
3738 fidflags |= SMB_FID_OPENREAD;
3739 if (desiredAccess & AFS_ACCESS_WRITE)
3740 fidflags |= SMB_FID_OPENWRITE;
3744 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3745 userp, tidPathp, &req, &scp);
3746 if (code == 0) foundscp = TRUE;
3748 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3749 /* look up parent directory */
3750 code = cm_NameI(baseDirp, spacep->data,
3751 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3752 userp, tidPathp, &req, &dscp);
3753 cm_FreeSpace(spacep);
3756 smb_ReleaseFID(baseFidp);
3761 cm_ReleaseUser(userp);
3766 if (!lastNamep) lastNamep = realPathp;
3769 if (!smb_IsLegalFilename(lastNamep))
3770 return CM_ERROR_BADNTFILENAME;
3773 code = cm_Lookup(dscp, lastNamep,
3774 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3776 if (code && code != CM_ERROR_NOSUCHFILE) {
3777 cm_ReleaseSCache(dscp);
3778 cm_ReleaseUser(userp);
3786 smb_ReleaseFID(baseFidp);
3789 cm_FreeSpace(spacep);
3792 /* if we get here, if code is 0, the file exists and is represented by
3793 * scp. Otherwise, we have to create it. The dir may be represented
3794 * by dscp, or we may have found the file directly. If code is non-zero,
3798 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3801 if (dscp) cm_ReleaseSCache(dscp);
3802 cm_ReleaseSCache(scp);
3803 cm_ReleaseUser(userp);
3808 if (createDisp == 2) {
3809 /* oops, file shouldn't be there */
3810 if (dscp) cm_ReleaseSCache(dscp);
3811 cm_ReleaseSCache(scp);
3812 cm_ReleaseUser(userp);
3814 return CM_ERROR_EXISTS;
3818 || createDisp == 5) {
3819 setAttr.mask = CM_ATTRMASK_LENGTH;
3820 setAttr.length.LowPart = 0;
3821 setAttr.length.HighPart = 0;
3822 code = cm_SetAttr(scp, &setAttr, userp, &req);
3823 openAction = 3; /* truncated existing file */
3825 else openAction = 1; /* found existing file */
3827 else if (createDisp == 1 || createDisp == 4) {
3828 /* don't create if not found */
3829 if (dscp) cm_ReleaseSCache(dscp);
3830 cm_ReleaseUser(userp);
3832 return CM_ERROR_NOSUCHFILE;
3834 else if (realDirFlag == 0 || realDirFlag == -1) {
3835 osi_assert(dscp != NULL);
3836 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
3837 osi_LogSaveString(smb_logp, lastNamep));
3838 openAction = 2; /* created file */
3839 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3840 setAttr.clientModTime = time(NULL);
3841 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3843 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3844 smb_NotifyChange(FILE_ACTION_ADDED,
3845 FILE_NOTIFY_CHANGE_FILE_NAME,
3846 dscp, lastNamep, NULL, TRUE);
3847 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3848 /* Not an exclusive create, and someone else tried
3849 * creating it already, then we open it anyway. We
3850 * don't bother retrying after this, since if this next
3851 * fails, that means that the file was deleted after we
3852 * started this call.
3854 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3857 if (createDisp == 5) {
3858 setAttr.mask = CM_ATTRMASK_LENGTH;
3859 setAttr.length.LowPart = 0;
3860 setAttr.length.HighPart = 0;
3861 code = cm_SetAttr(scp, &setAttr, userp,
3864 } /* lookup succeeded */
3868 /* create directory */
3869 osi_assert(dscp != NULL);
3871 "smb_ReceiveNTTranCreate creating directory %s",
3872 osi_LogSaveString(smb_logp, lastNamep));
3873 openAction = 2; /* created directory */
3874 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3875 setAttr.clientModTime = time(NULL);
3876 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3877 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3878 smb_NotifyChange(FILE_ACTION_ADDED,
3879 FILE_NOTIFY_CHANGE_DIR_NAME,
3880 dscp, lastNamep, NULL, TRUE);
3882 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3883 /* Not an exclusive create, and someone else tried
3884 * creating it already, then we open it anyway. We
3885 * don't bother retrying after this, since if this next
3886 * fails, that means that the file was deleted after we
3887 * started this call.
3889 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3895 /* something went wrong creating or truncating the file */
3896 if (scp) cm_ReleaseSCache(scp);
3897 cm_ReleaseUser(userp);
3902 /* make sure we have file vs. dir right */
3903 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3904 cm_ReleaseSCache(scp);
3905 cm_ReleaseUser(userp);
3907 return CM_ERROR_ISDIR;
3909 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3910 cm_ReleaseSCache(scp);
3911 cm_ReleaseUser(userp);
3913 return CM_ERROR_NOTDIR;
3916 /* open the file itself */
3917 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3920 /* save a pointer to the vnode */
3923 fidp->flags = fidflags;
3925 /* save parent dir and pathname for deletion or change notification */
3926 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3927 fidp->flags |= SMB_FID_NTOPEN;
3928 fidp->NTopen_dscp = dscp;
3929 cm_HoldSCache(dscp);
3930 fidp->NTopen_pathp = strdup(lastNamep);
3932 fidp->NTopen_wholepathp = realPathp;
3934 /* we don't need this any longer */
3935 if (dscp) cm_ReleaseSCache(dscp);
3937 cm_Open(scp, 0, userp);
3939 /* set inp->fid so that later read calls in same msg can find fid */
3940 inp->fid = fidp->fid;
3942 /* check whether we are required to send an extended response */
3943 if (!extendedRespRequired) {
3945 parmOffset = 8*4 + 39;
3946 parmOffset += 1; /* pad to 4 */
3947 dataOffset = parmOffset + 70;
3951 /* Total Parameter Count */
3952 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3953 /* Total Data Count */
3954 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3955 /* Parameter Count */
3956 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3957 /* Parameter Offset */
3958 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3959 /* Parameter Displacement */
3960 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3962 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3964 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3965 /* Data Displacement */
3966 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3967 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3968 smb_SetSMBDataLength(outp, 70);
3970 lock_ObtainMutex(&scp->mx);
3971 outData = smb_GetSMBData(outp, NULL);
3972 outData++; /* round to get to parmOffset */
3973 *outData = 0; outData++; /* oplock */
3974 *outData = 0; outData++; /* reserved */
3975 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
3976 *((ULONG *)outData) = openAction; outData += 4;
3977 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
3978 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3979 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
3980 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
3981 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
3982 *((FILETIME *)outData) = ft; outData += 8; /* change time */
3983 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
3984 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
3985 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
3986 *((USHORT *)outData) = 0; outData += 2; /* filetype */
3987 *((USHORT *)outData) = 0; outData += 2; /* dev state */
3988 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
3989 outData += 2; /* is a dir? */
3990 lock_ReleaseMutex(&scp->mx);
3993 parmOffset = 8*4 + 39;
3994 parmOffset += 1; /* pad to 4 */
3995 dataOffset = parmOffset + 104;
3999 /* Total Parameter Count */
4000 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4001 /* Total Data Count */
4002 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4003 /* Parameter Count */
4004 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4005 /* Parameter Offset */
4006 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4007 /* Parameter Displacement */
4008 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4010 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4012 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4013 /* Data Displacement */
4014 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4015 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4016 smb_SetSMBDataLength(outp, 105);
4018 lock_ObtainMutex(&scp->mx);
4019 outData = smb_GetSMBData(outp, NULL);
4020 outData++; /* round to get to parmOffset */
4021 *outData = 0; outData++; /* oplock */
4022 *outData = 1; outData++; /* response type */
4023 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4024 *((ULONG *)outData) = openAction; outData += 4;
4025 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
4026 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4027 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
4028 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
4029 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
4030 *((FILETIME *)outData) = ft; outData += 8; /* change time */
4031 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4032 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4033 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4034 *((USHORT *)outData) = 0; outData += 2; /* filetype */
4035 *((USHORT *)outData) = 0; outData += 2; /* dev state */
4036 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4037 outData += 1; /* is a dir? */
4038 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
4039 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
4040 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
4041 lock_ReleaseMutex(&scp->mx);
4044 osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
4046 smb_ReleaseFID(fidp);
4048 cm_ReleaseUser(userp);
4050 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
4051 /* leave scp held since we put it in fidp->scp */
4055 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
4058 smb_packet_t *savedPacketp;
4059 ULONG filter; USHORT fid, watchtree;
4063 filter = smb_GetSMBParm(inp, 19)
4064 | (smb_GetSMBParm(inp, 20) << 16);
4065 fid = smb_GetSMBParm(inp, 21);
4066 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
4068 fidp = smb_FindFID(vcp, fid, 0);
4070 osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
4071 return CM_ERROR_BADFD;
4074 savedPacketp = smb_CopyPacket(inp);
4075 savedPacketp->vcp = vcp; /* TODO: refcount vcp? */
4076 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4077 savedPacketp->nextp = smb_Directory_Watches;
4078 smb_Directory_Watches = savedPacketp;
4079 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4081 osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
4082 filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
4085 lock_ObtainMutex(&scp->mx);
4087 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
4089 scp->flags |= CM_SCACHEFLAG_WATCHED;
4090 lock_ReleaseMutex(&scp->mx);
4091 smb_ReleaseFID(fidp);
4093 outp->flags |= SMB_PACKETFLAG_NOSEND;
4097 unsigned char nullSecurityDesc[36] = {
4098 0x01, /* security descriptor revision */
4099 0x00, /* reserved, should be zero */
4100 0x00, 0x80, /* security descriptor control;
4101 * 0x8000 : self-relative format */
4102 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
4103 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
4104 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
4105 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
4106 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4107 /* "null SID" owner SID */
4108 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4109 /* "null SID" group SID */
4112 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4114 int parmOffset, parmCount, dataOffset, dataCount;
4122 ULONG securityInformation;
4124 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4125 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4126 parmp = inp->data + parmOffset;
4127 sparmp = (USHORT *) parmp;
4128 lparmp = (ULONG *) parmp;
4131 securityInformation = lparmp[1];
4133 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
4134 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4142 parmOffset = 8*4 + 39;
4143 parmOffset += 1; /* pad to 4 */
4145 dataOffset = parmOffset + parmCount;
4149 /* Total Parameter Count */
4150 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4151 /* Total Data Count */
4152 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4153 /* Parameter Count */
4154 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4155 /* Parameter Offset */
4156 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4157 /* Parameter Displacement */
4158 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4160 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4162 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4163 /* Data Displacement */
4164 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4165 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4166 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
4168 outData = smb_GetSMBData(outp, NULL);
4169 outData++; /* round to get to parmOffset */
4170 *((ULONG *)outData) = 36; outData += 4; /* length */
4172 if (maxData >= 36) {
4173 memcpy(outData, nullSecurityDesc, 36);
4177 return CM_ERROR_BUFFERTOOSMALL;
4180 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4182 unsigned short function;
4184 function = smb_GetSMBParm(inp, 18);
4186 osi_Log1(smb_logp, "SMB NT Transact function %d", function);
4188 /* We can handle long names */
4189 if (vcp->flags & SMB_VCFLAG_USENT)
4190 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
4194 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
4196 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
4198 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
4200 default: return CM_ERROR_INVAL;
4205 * smb_NotifyChange -- find relevant change notification messages and
4208 * If we don't know the file name (i.e. a callback break), filename is
4209 * NULL, and we return a zero-length list.
4211 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
4212 cm_scache_t *dscp, char *filename, char *otherFilename,
4213 BOOL isDirectParent)
4215 smb_packet_t *watch, *lastWatch, *nextWatch;
4216 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
4217 char *outData, *oldOutData;
4221 BOOL twoEntries = FALSE;
4222 ULONG otherNameLen, oldParmCount = 0;
4227 /* Get ready for rename within directory */
4228 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
4230 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
4233 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4234 watch = smb_Directory_Watches;
4236 filter = smb_GetSMBParm(watch, 19)
4237 | (smb_GetSMBParm(watch, 20) << 16);
4238 fid = smb_GetSMBParm(watch, 21);
4239 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
4240 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
4241 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
4245 * Strange hack - bug in NT Client and NT Server that we
4248 if (filter == 3 && wtree)
4251 fidp = smb_FindFID(vcp, fid, 0);
4254 watch = watch->nextp;
4257 if (fidp->scp != dscp
4258 || (filter & notifyFilter) == 0
4259 || (!isDirectParent && !wtree)) {
4260 smb_ReleaseFID(fidp);
4262 watch = watch->nextp;
4265 smb_ReleaseFID(fidp);
4268 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
4269 fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
4271 nextWatch = watch->nextp;
4272 if (watch == smb_Directory_Watches)
4273 smb_Directory_Watches = nextWatch;
4275 lastWatch->nextp = nextWatch;
4277 /* Turn off WATCHED flag in dscp */
4278 lock_ObtainMutex(&dscp->mx);
4280 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4282 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
4283 lock_ReleaseMutex(&dscp->mx);
4285 /* Convert to response packet */
4286 ((smb_t *) watch)->reb = 0x80;
4287 ((smb_t *) watch)->wct = 0;
4290 if (filename == NULL)
4293 nameLen = strlen(filename);
4294 parmCount = 3*4 + nameLen*2;
4295 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4297 otherNameLen = strlen(otherFilename);
4298 oldParmCount = parmCount;
4299 parmCount += 3*4 + otherNameLen*2;
4300 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4302 if (maxLen < parmCount)
4303 parmCount = 0; /* not enough room */
4305 parmOffset = 8*4 + 39;
4306 parmOffset += 1; /* pad to 4 */
4307 dataOffset = parmOffset + parmCount;
4311 /* Total Parameter Count */
4312 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4313 /* Total Data Count */
4314 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4315 /* Parameter Count */
4316 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4317 /* Parameter Offset */
4318 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
4319 /* Parameter Displacement */
4320 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4322 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4324 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
4325 /* Data Displacement */
4326 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4327 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
4328 smb_SetSMBDataLength(watch, parmCount + 1);
4330 if (parmCount != 0) {
4331 outData = smb_GetSMBData(watch, NULL);
4332 outData++; /* round to get to parmOffset */
4333 oldOutData = outData;
4334 *((DWORD *)outData) = oldParmCount; outData += 4;
4335 /* Next Entry Offset */
4336 *((DWORD *)outData) = action; outData += 4;
4338 *((DWORD *)outData) = nameLen*2; outData += 4;
4339 /* File Name Length */
4340 mbstowcs((WCHAR *)outData, filename, nameLen);
4343 outData = oldOutData + oldParmCount;
4344 *((DWORD *)outData) = 0; outData += 4;
4345 /* Next Entry Offset */
4346 *((DWORD *)outData) = otherAction; outData += 4;
4348 *((DWORD *)outData) = otherNameLen*2;
4349 outData += 4; /* File Name Length */
4350 mbstowcs((WCHAR *)outData, otherFilename,
4351 otherNameLen); /* File Name */
4356 * If filename is null, we don't know the cause of the
4357 * change notification. We return zero data (see above),
4358 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4359 * (= 0x010C). We set the error code here by hand, without
4360 * modifying wct and bcc.
4362 if (filename == NULL) {
4363 ((smb_t *) watch)->rcls = 0x0C;
4364 ((smb_t *) watch)->reh = 0x01;
4365 ((smb_t *) watch)->errLow = 0;
4366 ((smb_t *) watch)->errHigh = 0;
4367 /* Set NT Status codes flag */
4368 ((smb_t *) watch)->flg2 |= 0x4000;
4371 smb_SendPacket(vcp, watch);
4372 smb_FreePacket(watch);
4375 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4378 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4380 unsigned char *replyWctp;
4381 smb_packet_t *watch, *lastWatch;
4382 USHORT fid, watchtree;
4386 osi_Log0(smb_logp, "SMB3 receive NT cancel");
4388 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4389 watch = smb_Directory_Watches;
4391 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4392 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4393 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4394 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4395 if (watch == smb_Directory_Watches)
4396 smb_Directory_Watches = watch->nextp;
4398 lastWatch->nextp = watch->nextp;
4399 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4401 /* Turn off WATCHED flag in scp */
4402 fid = smb_GetSMBParm(watch, 21);
4403 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4405 fidp = smb_FindFID(vcp, fid, 0);
4407 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
4409 osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
4412 lock_ObtainMutex(&scp->mx);
4414 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4416 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4417 lock_ReleaseMutex(&scp->mx);
4418 smb_ReleaseFID(fidp);
4420 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
4423 /* assume STATUS32; return 0xC0000120 (CANCELED) */
4424 replyWctp = watch->wctp;
4428 ((smb_t *)watch)->rcls = 0x20;
4429 ((smb_t *)watch)->reh = 0x1;
4430 ((smb_t *)watch)->errLow = 0;
4431 ((smb_t *)watch)->errHigh = 0xC0;
4432 ((smb_t *)watch)->flg2 |= 0x4000;
4433 smb_SendPacket(vcp, watch);
4434 smb_FreePacket(watch);
4438 watch = watch->nextp;
4440 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4447 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4450 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4453 smb_username_t *unp;
4455 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4457 lock_ObtainMutex(&unp->mx);
4458 unp->userp = cm_NewUser();
4459 lock_ReleaseMutex(&unp->mx);
4460 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
4462 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);