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 == '*') return 1;
99 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
102 /* skip over null-terminated string */
103 *chainpp = inp + strlen(inp) + 1;
108 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
111 char *usern, *pwd, *pwdx;
113 unsigned short newUid;
119 /* Check for bad conns */
120 if (vcp->flags & SMB_VCFLAG_REMOTECONN)
121 return CM_ERROR_REMOTECONN;
123 /* For NT LM 0.12 and up, get capabilities */
124 if (vcp->flags & SMB_VCFLAG_USENT) {
125 caps = smb_GetSMBParm(inp, 11);
127 vcp->flags |= SMB_VCFLAG_STATUS32;
128 /* for now, ignore other capability bits */
132 tp = smb_GetSMBData(inp, NULL);
133 if (vcp->flags & SMB_VCFLAG_USENT)
134 pwdx = smb_ParseString(tp, &tp);
135 pwd = smb_ParseString(tp, &tp);
136 usern = smb_ParseString(tp, &tp);
138 /* On Windows 2000, this function appears to be called more often than
139 it is expected to be called. This resulted in multiple smb_user_t
140 records existing all for the same user session which results in all
141 of the users tokens disappearing.
143 To avoid this problem, we look for an existing smb_user_t record
144 based on the users name, and use that one if we find it.
147 uidp = smb_FindUserByNameThisSession(vcp, usern);
148 if (uidp) { /* already there, so don't create a new one */
151 newUid = (unsigned short)uidp->userID; /* For some reason these are different types!*/
152 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
153 osi_Log3(afsd_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
154 smb_ReleaseUID(uidp);
157 /* do a global search for the username/machine name pair */
158 unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
160 /* Create a new UID and cm_user_t structure */
163 userp = cm_NewUser();
164 lock_ObtainMutex(&vcp->mx);
165 if (!vcp->uidCounter)
166 vcp->uidCounter++; /* handle unlikely wraparounds */
167 newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
168 lock_ReleaseMutex(&vcp->mx);
170 /* Create a new smb_user_t structure and connect them up */
171 lock_ObtainMutex(&unp->mx);
173 lock_ReleaseMutex(&unp->mx);
175 uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
176 lock_ObtainMutex(&uidp->mx);
178 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);
179 osi_Log4(afsd_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
180 lock_ReleaseMutex(&uidp->mx);
181 smb_ReleaseUID(uidp);
184 /* Return UID to the client */
185 ((smb_t *)outp)->uid = newUid;
186 /* Also to the next chained message */
187 ((smb_t *)inp)->uid = newUid;
189 osi_Log3(afsd_logp, "SMB3 session setup name %s creating ID %d%s",
190 osi_LogSaveString(afsd_logp, usern), newUid, osi_LogSaveString(afsd_logp, s1));
191 smb_SetSMBParm(outp, 2, 0);
192 smb_SetSMBDataLength(outp, 0);
196 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
200 /* don't get tokens from this VC */
201 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
203 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
205 /* find the tree and free it */
206 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
207 /* TODO: smb_ReleaseUID() ? */
209 char *s1 = NULL, *s2 = NULL;
211 if (s2 == NULL) s2 = " ";
212 if (s1 == NULL) {s1 = s2; s2 = " ";}
214 osi_Log4(afsd_logp, "SMB3 user logoffX uid %d name %s%s%s",
216 osi_LogSaveString(afsd_logp,
217 (uidp->unp) ? uidp->unp->name: " "), s1, s2);
219 lock_ObtainMutex(&uidp->mx);
220 uidp->flags |= SMB_USERFLAG_DELETE;
222 * it doesn't get deleted right away
223 * because the vcp points to it
225 lock_ReleaseMutex(&uidp->mx);
228 osi_Log0(afsd_logp, "SMB3 user logoffX");
230 smb_SetSMBDataLength(outp, 0);
234 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
237 unsigned short newTid;
247 osi_Log0(afsd_logp, "SMB3 receive tree connect");
249 /* parse input parameters */
250 tp = smb_GetSMBData(inp, NULL);
251 passwordp = smb_ParseString(tp, &tp);
252 pathp = smb_ParseString(tp, &tp);
253 servicep = smb_ParseString(tp, &tp);
255 tp = strrchr(pathp, '\\');
257 return CM_ERROR_BADSMB;
259 strcpy(shareName, tp+1);
261 if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
262 return CM_ERROR_NOIPC;
264 userp = smb_GetUser(vcp, inp);
266 lock_ObtainMutex(&vcp->mx);
267 newTid = vcp->tidCounter++;
268 lock_ReleaseMutex(&vcp->mx);
270 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
271 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
273 smb_ReleaseTID(tidp);
274 return CM_ERROR_BADSHARENAME;
276 lock_ObtainMutex(&tidp->mx);
278 tidp->pathname = sharePath;
279 lock_ReleaseMutex(&tidp->mx);
280 smb_ReleaseTID(tidp);
282 if (vcp->flags & SMB_VCFLAG_USENT)
283 smb_SetSMBParm(outp, 2, 0); /* OptionalSupport bits */
285 ((smb_t *)outp)->tid = newTid;
286 ((smb_t *)inp)->tid = newTid;
287 tp = smb_GetSMBData(outp, NULL);
291 smb_SetSMBDataLength(outp, 3);
293 osi_Log1(afsd_logp, "SMB3 tree connect created ID %d", newTid);
297 /* must be called with global tran lock held */
298 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
300 smb_tran2Packet_t *tp;
303 smbp = (smb_t *) inp->data;
304 for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
305 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
311 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
312 int totalParms, int totalData)
314 smb_tran2Packet_t *tp;
317 smbp = (smb_t *) inp->data;
318 tp = malloc(sizeof(*tp));
319 memset(tp, 0, sizeof(*tp));
322 tp->curData = tp->curParms = 0;
323 tp->totalData = totalData;
324 tp->totalParms = totalParms;
329 tp->res[0] = smbp->res[0];
330 osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
331 tp->opcode = smb_GetSMBParm(inp, 14);
333 tp->parmsp = malloc(totalParms);
335 tp->datap = malloc(totalData);
336 tp->flags |= SMB_TRAN2PFLAG_ALLOC;
340 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
341 smb_tran2Packet_t *inp, smb_packet_t *outp,
342 int totalParms, int totalData)
344 smb_tran2Packet_t *tp;
345 unsigned short parmOffset;
346 unsigned short dataOffset;
347 unsigned short dataAlign;
349 tp = malloc(sizeof(*tp));
350 memset(tp, 0, sizeof(*tp));
352 tp->curData = tp->curParms = 0;
353 tp->totalData = totalData;
354 tp->totalParms = totalParms;
355 tp->oldTotalParms = totalParms;
360 tp->res[0] = inp->res[0];
361 tp->opcode = inp->opcode;
364 * We calculate where the parameters and data will start.
365 * This calculation must parallel the calculation in
366 * smb_SendTran2Packet.
369 parmOffset = 10*2 + 35;
370 parmOffset++; /* round to even */
371 tp->parmsp = (unsigned short *) (outp->data + parmOffset);
373 dataOffset = parmOffset + totalParms;
374 dataAlign = dataOffset & 2; /* quad-align */
375 dataOffset += dataAlign;
376 tp->datap = outp->data + dataOffset;
381 /* free a tran2 packet; must be called with smb_globalLock held */
382 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
384 if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
385 if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
394 /* called with a VC, an input packet to respond to, and an error code.
395 * sends an error response.
397 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
398 smb_packet_t *tp, long code)
401 unsigned short errCode;
402 unsigned char errClass;
403 unsigned long NTStatus;
405 if (vcp->flags & SMB_VCFLAG_STATUS32)
406 smb_MapNTError(code, &NTStatus);
408 smb_MapCoreError(code, vcp, &errCode, &errClass);
410 smb_FormatResponsePacket(vcp, NULL, tp);
413 /* We can handle long names */
414 if (vcp->flags & SMB_VCFLAG_USENT)
415 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
417 /* now copy important fields from the tran 2 packet */
418 smbp->com = 0x32; /* tran 2 response */
419 smbp->tid = t2p->tid;
420 smbp->mid = t2p->mid;
421 smbp->pid = t2p->pid;
422 smbp->uid = t2p->uid;
423 smbp->res[0] = t2p->res[0];
424 if (vcp->flags & SMB_VCFLAG_STATUS32) {
425 smbp->rcls = (unsigned char) (NTStatus & 0xff);
426 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
427 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
428 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
429 smbp->flg2 |= 0x4000;
432 smbp->rcls = errClass;
433 smbp->errLow = (unsigned char) (errCode & 0xff);
434 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
438 smb_SendPacket(vcp, tp);
441 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
444 unsigned short parmOffset;
445 unsigned short dataOffset;
446 unsigned short totalLength;
447 unsigned short dataAlign;
450 smb_FormatResponsePacket(vcp, NULL, tp);
453 /* We can handle long names */
454 if (vcp->flags & SMB_VCFLAG_USENT)
455 smbp->flg2 |= 0x40; /* IS_LONG_NAME */
457 /* now copy important fields from the tran 2 packet */
458 smbp->com = 0x32; /* tran 2 response */
459 smbp->tid = t2p->tid;
460 smbp->mid = t2p->mid;
461 smbp->pid = t2p->pid;
462 smbp->uid = t2p->uid;
463 smbp->res[0] = t2p->res[0];
465 totalLength = 1 + t2p->totalData + t2p->totalParms;
467 /* now add the core parameters (tran2 info) to the packet */
468 smb_SetSMBParm(tp, 0, t2p->totalParms); /* parm bytes */
469 smb_SetSMBParm(tp, 1, t2p->totalData); /* data bytes */
470 smb_SetSMBParm(tp, 2, 0); /* reserved */
471 smb_SetSMBParm(tp, 3, t2p->totalParms); /* parm bytes in this packet */
472 parmOffset = 10*2 + 35; /* parm offset in packet */
473 parmOffset++; /* round to even */
474 smb_SetSMBParm(tp, 4, parmOffset); /* 11 parm words plus *
475 * hdr, bcc and wct */
476 smb_SetSMBParm(tp, 5, 0); /* parm displacement */
477 smb_SetSMBParm(tp, 6, t2p->totalData); /* data in this packet */
478 dataOffset = parmOffset + t2p->oldTotalParms;
479 dataAlign = dataOffset & 2; /* quad-align */
480 dataOffset += dataAlign;
481 smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
482 smb_SetSMBParm(tp, 8, 0); /* data displacement */
483 smb_SetSMBParm(tp, 9, 0); /* low: setup word count *
486 datap = smb_GetSMBData(tp, NULL);
487 *datap++ = 0; /* we rounded to even */
489 totalLength += dataAlign;
490 smb_SetSMBDataLength(tp, totalLength);
492 /* next, send the datagram */
493 smb_SendPacket(vcp, tp);
496 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
498 smb_tran2Packet_t *asp;
510 /* We sometimes see 0 word count. What to do? */
511 if (*inp->wctp == 0) {
516 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
518 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
519 ptbuf[0] = "Transaction2 word count = 0";
520 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
521 1, inp->ncb_length, ptbuf, inp);
522 DeregisterEventSource(h);
524 osi_Log0(afsd_logp, "TRANSACTION2 word count = 0");
527 smb_SetSMBDataLength(outp, 0);
528 smb_SendPacket(vcp, outp);
532 totalParms = smb_GetSMBParm(inp, 0);
533 totalData = smb_GetSMBParm(inp, 1);
535 firstPacket = (inp->inCom == 0x32);
537 /* find the packet we're reassembling */
538 lock_ObtainWrite(&smb_globalLock);
539 asp = smb_FindTran2Packet(vcp, inp);
541 asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
543 lock_ReleaseWrite(&smb_globalLock);
545 /* now merge in this latest packet; start by looking up offsets */
547 parmDisp = dataDisp = 0;
548 parmOffset = smb_GetSMBParm(inp, 10);
549 dataOffset = smb_GetSMBParm(inp, 12);
550 parmCount = smb_GetSMBParm(inp, 9);
551 dataCount = smb_GetSMBParm(inp, 11);
552 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
553 asp->maxReturnData = smb_GetSMBParm(inp, 3);
555 osi_Log3(afsd_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
556 totalData, dataCount, asp->maxReturnData);
559 parmDisp = smb_GetSMBParm(inp, 4);
560 parmOffset = smb_GetSMBParm(inp, 3);
561 dataDisp = smb_GetSMBParm(inp, 7);
562 dataOffset = smb_GetSMBParm(inp, 6);
563 parmCount = smb_GetSMBParm(inp, 2);
564 dataCount = smb_GetSMBParm(inp, 5);
566 osi_Log2(afsd_logp, "SMB3 received T2 aux packet parms %d, data %d",
567 parmCount, dataCount);
570 /* now copy the parms and data */
571 if ( parmCount != 0 )
573 memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
575 if ( dataCount != 0 ) {
576 memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
579 /* account for new bytes */
580 asp->curData += dataCount;
581 asp->curParms += parmCount;
583 /* finally, if we're done, remove the packet from the queue and dispatch it */
584 if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
585 /* we've received it all */
586 lock_ObtainWrite(&smb_globalLock);
587 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
588 lock_ReleaseWrite(&smb_globalLock);
590 /* now dispatch it */
591 if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
592 osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
593 osi_Log4(afsd_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
594 code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
597 osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
598 osi_Log4(afsd_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
599 code = CM_ERROR_BADOP;
602 /* if an error is returned, we're supposed to send an error packet,
603 * otherwise the dispatched function already did the data sending.
604 * We give dispatched proc the responsibility since it knows how much
608 smb_SendTran2Error(vcp, asp, outp, code);
611 /* free the input tran 2 packet */
612 lock_ObtainWrite(&smb_globalLock);
613 smb_FreeTran2Packet(asp);
614 lock_ReleaseWrite(&smb_globalLock);
616 else if (firstPacket) {
617 /* the first packet in a multi-packet request, we need to send an
618 * ack to get more data.
620 smb_SetSMBDataLength(outp, 0);
621 smb_SendPacket(vcp, outp);
627 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
630 smb_tran2Packet_t *outp;
635 cm_scache_t *dscp; /* dir we're dealing with */
636 cm_scache_t *scp; /* file we're creating */
648 int parmSlot; /* which parm we're dealing with */
657 extraInfo = (p->parmsp[0] & 1); /* return extra info */
658 returnEALength = (p->parmsp[0] & 8); /* return extended attr length */
660 openFun = p->parmsp[6]; /* open function */
661 excl = ((openFun & 3) == 0);
662 trunc = ((openFun & 3) == 2); /* truncate it */
663 openMode = (p->parmsp[1] & 0x7);
664 openAction = 0; /* tracks what we did */
666 attributes = p->parmsp[3];
667 dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
669 /* compute initial mode bits based on read-only flag in attributes */
670 initialModeBits = 0666;
671 if (attributes & 1) initialModeBits &= ~0222;
673 pathp = (char *) (&p->parmsp[14]);
675 outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
677 spacep = cm_GetSpace();
678 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
680 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
681 /* special case magic file name for receiving IOCTL requests
682 * (since IOCTL calls themselves aren't getting through).
684 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
685 smb_SetupIoctlFid(fidp, spacep);
687 /* copy out remainder of the parms */
689 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
691 outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
692 outp->parmsp[parmSlot] = 0; parmSlot++; /* mod time */
693 outp->parmsp[parmSlot] = 0; parmSlot++;
694 outp->parmsp[parmSlot] = 0; parmSlot++; /* len */
695 outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
696 outp->parmsp[parmSlot] = openMode; parmSlot++;
697 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
698 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
700 /* and the final "always present" stuff */
701 outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
702 /* next write out the "unique" ID */
703 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
704 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
705 outp->parmsp[parmSlot] = 0; parmSlot++;
706 if (returnEALength) {
707 outp->parmsp[parmSlot] = 0; parmSlot++;
708 outp->parmsp[parmSlot] = 0; parmSlot++;
712 outp->totalParms = parmSlot * 2;
714 smb_SendTran2Packet(vcp, outp, op);
716 smb_FreeTran2Packet(outp);
718 /* and clean up fid reference */
719 smb_ReleaseFID(fidp);
726 asciip = (lastNamep ? lastNamep : pathp);
727 hexp = osi_HexifyString( asciip );
728 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
733 userp = smb_GetTran2User(vcp, p);
734 /* In the off chance that userp is NULL, we log and abandon */
736 osi_Log1(afsd_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
737 smb_FreeTran2Packet(outp);
738 return CM_ERROR_BADSMB;
741 tidPathp = smb_GetTIDPath(vcp, p->tid);
744 code = cm_NameI(cm_rootSCachep, pathp,
745 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
746 userp, tidPathp, &req, &scp);
748 code = cm_NameI(cm_rootSCachep, spacep->data,
749 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
750 userp, tidPathp, &req, &dscp);
751 cm_FreeSpace(spacep);
754 cm_ReleaseUser(userp);
755 smb_FreeTran2Packet(outp);
759 /* otherwise, scp points to the parent directory. Do a lookup,
760 * and truncate the file if we find it, otherwise we create the
763 if (!lastNamep) lastNamep = pathp;
765 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
767 if (code && code != CM_ERROR_NOSUCHFILE) {
768 cm_ReleaseSCache(dscp);
769 cm_ReleaseUser(userp);
770 smb_FreeTran2Packet(outp);
775 cm_FreeSpace(spacep);
778 /* if we get here, if code is 0, the file exists and is represented by
779 * scp. Otherwise, we have to create it.
782 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
784 if (dscp) cm_ReleaseSCache(dscp);
785 cm_ReleaseSCache(scp);
786 cm_ReleaseUser(userp);
787 smb_FreeTran2Packet(outp);
792 /* oops, file shouldn't be there */
793 if (dscp) cm_ReleaseSCache(dscp);
794 cm_ReleaseSCache(scp);
795 cm_ReleaseUser(userp);
796 smb_FreeTran2Packet(outp);
797 return CM_ERROR_EXISTS;
801 setAttr.mask = CM_ATTRMASK_LENGTH;
802 setAttr.length.LowPart = 0;
803 setAttr.length.HighPart = 0;
804 code = cm_SetAttr(scp, &setAttr, userp, &req);
805 openAction = 3; /* truncated existing file */
807 else openAction = 1; /* found existing file */
809 else if (!(openFun & SMB_ATTR_DIRECTORY)) {
810 /* don't create if not found */
811 if (dscp) cm_ReleaseSCache(dscp);
812 osi_assert(scp == NULL);
813 cm_ReleaseUser(userp);
814 smb_FreeTran2Packet(outp);
815 return CM_ERROR_NOSUCHFILE;
818 osi_assert(dscp != NULL && scp == NULL);
819 openAction = 2; /* created file */
820 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
821 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
822 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
824 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
825 smb_NotifyChange(FILE_ACTION_ADDED,
826 FILE_NOTIFY_CHANGE_FILE_NAME,
827 dscp, lastNamep, NULL, TRUE);
828 if (!excl && code == CM_ERROR_EXISTS) {
829 /* not an exclusive create, and someone else tried
830 * creating it already, then we open it anyway. We
831 * don't bother retrying after this, since if this next
832 * fails, that means that the file was deleted after we
835 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
839 setAttr.mask = CM_ATTRMASK_LENGTH;
840 setAttr.length.LowPart = 0;
841 setAttr.length.HighPart = 0;
842 code = cm_SetAttr(scp, &setAttr, userp,
845 } /* lookup succeeded */
849 /* we don't need this any longer */
850 if (dscp) cm_ReleaseSCache(dscp);
853 /* something went wrong creating or truncating the file */
854 if (scp) cm_ReleaseSCache(scp);
855 cm_ReleaseUser(userp);
856 smb_FreeTran2Packet(outp);
860 /* make sure we're about to open a file */
861 if (scp->fileType != CM_SCACHETYPE_FILE) {
862 cm_ReleaseSCache(scp);
863 cm_ReleaseUser(userp);
864 smb_FreeTran2Packet(outp);
865 return CM_ERROR_ISDIR;
868 /* now all we have to do is open the file itself */
869 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
872 /* save a pointer to the vnode */
875 /* compute open mode */
876 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
877 if (openMode == 1 || openMode == 2)
878 fidp->flags |= SMB_FID_OPENWRITE;
880 smb_ReleaseFID(fidp);
882 cm_Open(scp, 0, userp);
884 /* copy out remainder of the parms */
886 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
887 lock_ObtainMutex(&scp->mx);
889 outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
890 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
891 outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
892 outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
893 outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
895 outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
897 outp->parmsp[parmSlot] = openMode; parmSlot++;
898 outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
899 outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
901 /* and the final "always present" stuff */
902 outp->parmsp[parmSlot] = openAction; parmSlot++;
903 /* next write out the "unique" ID */
904 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
905 outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
906 outp->parmsp[parmSlot] = 0; parmSlot++;
907 if (returnEALength) {
908 outp->parmsp[parmSlot] = 0; parmSlot++;
909 outp->parmsp[parmSlot] = 0; parmSlot++;
911 lock_ReleaseMutex(&scp->mx);
912 outp->totalData = 0; /* total # of data bytes */
913 outp->totalParms = parmSlot * 2; /* shorts are two bytes */
915 smb_SendTran2Packet(vcp, outp, op);
917 smb_FreeTran2Packet(outp);
919 cm_ReleaseUser(userp);
920 /* leave scp held since we put it in fidp->scp */
924 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
926 return CM_ERROR_BADOP;
929 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
931 return CM_ERROR_BADOP;
934 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
936 smb_tran2Packet_t *outp;
937 smb_tran2QFSInfo_t qi;
940 static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
942 osi_Log1(afsd_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
944 switch (p->parmsp[0]) {
945 case 1: responseSize = sizeof(qi.u.allocInfo); break;
946 case 2: responseSize = sizeof(qi.u.volumeInfo); break;
947 case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
948 case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
949 case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
950 case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
951 default: return CM_ERROR_INVAL;
954 outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
955 switch (p->parmsp[0]) {
958 qi.u.allocInfo.FSID = 0;
959 qi.u.allocInfo.sectorsPerAllocUnit = 1;
960 qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
961 qi.u.allocInfo.availAllocUnits = 0x3fffffff;
962 qi.u.allocInfo.bytesPerSector = 1024;
967 qi.u.volumeInfo.vsn = 1234;
968 qi.u.volumeInfo.vnCount = 4;
969 /* we're supposed to pad it out with zeroes to the end */
970 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
971 memcpy(qi.u.volumeInfo.label, "AFS", 4);
976 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
977 qi.u.FSvolumeInfo.vsn = 1234;
978 qi.u.FSvolumeInfo.vnCount = 8;
979 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
985 temp.LowPart = 0x7fffffff;
986 qi.u.FSsizeInfo.totalAllocUnits = temp;
987 temp.LowPart = 0x3fffffff;
988 qi.u.FSsizeInfo.availAllocUnits = temp;
989 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
990 qi.u.FSsizeInfo.bytesPerSector = 1024;
995 qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
996 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1000 /* FS attribute info */
1001 /* attributes, defined in WINNT.H:
1002 * FILE_CASE_SENSITIVE_SEARCH 0x1
1003 * FILE_CASE_PRESERVED_NAMES 0x2
1004 * <no name defined> 0x4000
1005 * If bit 0x4000 is not set, Windows 95 thinks
1006 * we can't handle long (non-8.3) names,
1007 * despite our protestations to the contrary.
1009 qi.u.FSattributeInfo.attributes = 0x4003;
1010 qi.u.FSattributeInfo.maxCompLength = 255;
1011 qi.u.FSattributeInfo.FSnameLength = 6;
1012 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1016 /* copy out return data, and set corresponding sizes */
1017 outp->totalParms = 0;
1018 outp->totalData = responseSize;
1019 memcpy(outp->datap, &qi, responseSize);
1021 /* send and free the packets */
1022 smb_SendTran2Packet(vcp, outp, op);
1023 smb_FreeTran2Packet(outp);
1028 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1030 return CM_ERROR_BADOP;
1033 struct smb_ShortNameRock {
1037 size_t shortNameLen;
1040 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1043 struct smb_ShortNameRock *rockp;
1047 /* compare both names and vnodes, though probably just comparing vnodes
1048 * would be safe enough.
1050 if (stricmp(dep->name, rockp->maskp) != 0)
1052 if (ntohl(dep->fid.vnode) != rockp->vnode)
1054 /* This is the entry */
1055 cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1056 rockp->shortNameLen = shortNameEnd - rockp->shortName;
1057 return CM_ERROR_STOPNOW;
1060 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1061 char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1063 struct smb_ShortNameRock rock;
1067 int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1071 spacep = cm_GetSpace();
1072 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1074 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1076 cm_FreeSpace(spacep);
1077 if (code) return code;
1079 if (!lastNamep) lastNamep = pathp;
1082 thyper.HighPart = 0;
1083 rock.shortName = shortName;
1085 rock.maskp = lastNamep;
1086 code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1089 cm_ReleaseSCache(dscp);
1092 return CM_ERROR_NOSUCHFILE;
1093 if (code == CM_ERROR_STOPNOW) {
1094 *shortNameLenp = rock.shortNameLen;
1100 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1102 smb_tran2Packet_t *outp;
1103 unsigned long dosTime;
1105 unsigned short infoLevel;
1107 unsigned short attributes;
1108 unsigned long extAttributes;
1113 cm_scache_t *scp, *dscp;
1122 infoLevel = p->parmsp[0];
1123 if (infoLevel == 6) nbytesRequired = 0;
1124 else if (infoLevel == 1) nbytesRequired = 22;
1125 else if (infoLevel == 2) nbytesRequired = 26;
1126 else if (infoLevel == 0x101) nbytesRequired = 40;
1127 else if (infoLevel == 0x102) nbytesRequired = 24;
1128 else if (infoLevel == 0x103) nbytesRequired = 4;
1129 else if (infoLevel == 0x108) nbytesRequired = 30;
1131 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1132 p->opcode, infoLevel);
1133 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1136 osi_Log2(afsd_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1137 osi_LogSaveString(afsd_logp, (char *)(&p->parmsp[3])));
1139 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1141 if (infoLevel > 0x100)
1142 outp->totalParms = 2;
1144 outp->totalParms = 0;
1145 outp->totalData = nbytesRequired;
1147 /* now, if we're at infoLevel 6, we're only being asked to check
1148 * the syntax, so we just OK things now. In particular, we're *not*
1149 * being asked to verify anything about the state of any parent dirs.
1151 if (infoLevel == 6) {
1152 smb_SendTran2Packet(vcp, outp, opx);
1153 smb_FreeTran2Packet(outp);
1157 userp = smb_GetTran2User(vcp, p);
1159 osi_Log1(afsd_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1160 smb_FreeTran2Packet(outp);
1161 return CM_ERROR_BADSMB;
1164 tidPathp = smb_GetTIDPath(vcp, p->tid);
1167 * XXX Strange hack XXX
1169 * As of Patch 7 (13 January 98), we are having the following problem:
1170 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1171 * requests to look up "desktop.ini" in all the subdirectories.
1172 * This can cause zillions of timeouts looking up non-existent cells
1173 * and volumes, especially in the top-level directory.
1175 * We have not found any way to avoid this or work around it except
1176 * to explicitly ignore the requests for mount points that haven't
1177 * yet been evaluated and for directories that haven't yet been
1180 if (infoLevel == 0x101) {
1181 spacep = cm_GetSpace();
1182 smb_StripLastComponent(spacep->data, &lastComp,
1183 (char *)(&p->parmsp[3]));
1184 /* Make sure that lastComp is not NULL */
1186 if (strcmp(lastComp, "\\desktop.ini") == 0) {
1187 code = cm_NameI(cm_rootSCachep, spacep->data,
1191 userp, tidPathp, &req, &dscp);
1193 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1194 && !dscp->mountRootFidp)
1195 code = CM_ERROR_NOSUCHFILE;
1196 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1197 cm_buf_t *bp = buf_Find(dscp, &hzero);
1201 code = CM_ERROR_NOSUCHFILE;
1203 cm_ReleaseSCache(dscp);
1205 cm_FreeSpace(spacep);
1206 cm_ReleaseUser(userp);
1207 smb_SendTran2Error(vcp, p, opx, code);
1208 smb_FreeTran2Packet(outp);
1214 cm_FreeSpace(spacep);
1217 /* now do namei and stat, and copy out the info */
1218 code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1219 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1222 cm_ReleaseUser(userp);
1223 smb_SendTran2Error(vcp, p, opx, code);
1224 smb_FreeTran2Packet(outp);
1228 lock_ObtainMutex(&scp->mx);
1229 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1230 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1231 if (code) goto done;
1233 /* now we have the status in the cache entry, and everything is locked.
1234 * Marshall the output data.
1237 /* for info level 108, figure out short name */
1238 if (infoLevel == 0x108) {
1239 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1240 tidPathp, scp->fid.vnode, shortName,
1247 *((u_long *)op) = len * 2; op += 4;
1248 mbstowcs((unsigned short *)op, shortName, len);
1253 if (infoLevel == 1 || infoLevel == 2) {
1254 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1255 *((u_long *)op) = dosTime; op += 4; /* creation time */
1256 *((u_long *)op) = dosTime; op += 4; /* access time */
1257 *((u_long *)op) = dosTime; op += 4; /* write time */
1258 *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1259 *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1260 attributes = smb_Attributes(scp);
1261 *((u_short *)op) = attributes; op += 2; /* attributes */
1263 else if (infoLevel == 0x101) {
1264 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1265 *((FILETIME *)op) = ft; op += 8; /* creation time */
1266 *((FILETIME *)op) = ft; op += 8; /* last access time */
1267 *((FILETIME *)op) = ft; op += 8; /* last write time */
1268 *((FILETIME *)op) = ft; op += 8; /* last change time */
1269 extAttributes = smb_ExtAttributes(scp);
1270 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1271 *((u_long *)op) = 0; op += 4; /* don't know what this is */
1273 else if (infoLevel == 0x102) {
1274 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1275 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1276 *((u_long *)op) = scp->linkCount; op += 4;
1279 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1282 else if (infoLevel == 0x103) {
1283 memset(op, 0, 4); op += 4; /* EA size */
1286 /* now, if we are being asked about extended attrs, return a 0 size */
1287 if (infoLevel == 2) {
1288 *((u_long *)op) = 0; op += 4;
1292 /* send and free the packets */
1294 lock_ReleaseMutex(&scp->mx);
1295 cm_ReleaseSCache(scp);
1296 cm_ReleaseUser(userp);
1297 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1298 else smb_SendTran2Error(vcp, p, opx, code);
1299 smb_FreeTran2Packet(outp);
1304 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1306 return CM_ERROR_BADOP;
1309 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1311 smb_tran2Packet_t *outp;
1313 unsigned long attributes;
1314 unsigned short infoLevel;
1327 fidp = smb_FindFID(vcp, fid, 0);
1330 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
1334 infoLevel = p->parmsp[1];
1335 if (infoLevel == 0x101) nbytesRequired = 40;
1336 else if (infoLevel == 0x102) nbytesRequired = 24;
1337 else if (infoLevel == 0x103) nbytesRequired = 4;
1338 else if (infoLevel == 0x104) nbytesRequired = 6;
1340 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1341 p->opcode, infoLevel);
1342 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1345 osi_Log2(afsd_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
1347 outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1349 if (infoLevel > 0x100)
1350 outp->totalParms = 2;
1352 outp->totalParms = 0;
1353 outp->totalData = nbytesRequired;
1355 userp = smb_GetTran2User(vcp, p);
1357 osi_Log1(afsd_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
1358 code = CM_ERROR_BADSMB;
1363 lock_ObtainMutex(&scp->mx);
1364 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1365 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1366 if (code) goto done;
1368 /* now we have the status in the cache entry, and everything is locked.
1369 * Marshall the output data.
1372 if (infoLevel == 0x101) {
1373 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1374 *((FILETIME *)op) = ft; op += 8; /* creation time */
1375 *((FILETIME *)op) = ft; op += 8; /* last access time */
1376 *((FILETIME *)op) = ft; op += 8; /* last write time */
1377 *((FILETIME *)op) = ft; op += 8; /* last change time */
1378 attributes = smb_ExtAttributes(scp);
1379 *((u_long *)op) = attributes; op += 4;
1380 *((u_long *)op) = 0; op += 4;
1382 else if (infoLevel == 0x102) {
1383 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
1384 *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
1385 *((u_long *)op) = scp->linkCount; op += 4;
1386 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
1387 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1391 else if (infoLevel == 0x103) {
1392 *((u_long *)op) = 0; op += 4;
1394 else if (infoLevel == 0x104) {
1398 if (fidp->NTopen_wholepathp)
1399 name = fidp->NTopen_wholepathp;
1401 name = "\\"; /* probably can't happen */
1403 outp->totalData = (len*2) + 4; /* this is actually what we want to return */
1404 *((u_long *)op) = len * 2; op += 4;
1405 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
1408 /* send and free the packets */
1410 lock_ReleaseMutex(&scp->mx);
1411 cm_ReleaseUser(userp);
1412 smb_ReleaseFID(fidp);
1413 if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
1414 else smb_SendTran2Error(vcp, p, opx, code);
1415 smb_FreeTran2Packet(outp);
1420 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1425 unsigned short infoLevel;
1426 smb_tran2Packet_t *outp;
1434 fidp = smb_FindFID(vcp, fid, 0);
1437 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
1441 infoLevel = p->parmsp[1];
1442 if (infoLevel > 0x104 || infoLevel < 0x101) {
1443 osi_Log2(afsd_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1444 p->opcode, infoLevel);
1445 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
1449 if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
1450 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1453 if ((infoLevel == 0x103 || infoLevel == 0x104)
1454 && !(fidp->flags & SMB_FID_OPENWRITE)) {
1455 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
1459 osi_Log1(afsd_logp, "T2 SFileInfo type 0x%x", infoLevel);
1461 outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
1463 outp->totalParms = 2;
1464 outp->totalData = 0;
1466 userp = smb_GetTran2User(vcp, p);
1468 osi_Log1(afsd_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
1469 code = CM_ERROR_BADSMB;
1475 if (infoLevel == 0x101) {
1477 unsigned int attribute;
1480 /* lock the vnode with a callback; we need the current status
1481 * to determine what the new status is, in some cases.
1483 lock_ObtainMutex(&scp->mx);
1484 code = cm_SyncOp(scp, NULL, userp, &req, 0,
1485 CM_SCACHESYNC_GETSTATUS
1486 | CM_SCACHESYNC_NEEDCALLBACK);
1488 lock_ReleaseMutex(&scp->mx);
1492 /* prepare for setattr call */
1495 lastMod = *((FILETIME *)(p->datap + 16));
1496 /* when called as result of move a b, lastMod is (-1, -1).
1497 * If the check for -1 is not present, timestamp
1498 * of the resulting file will be 1969 (-1)
1500 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
1501 lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
1502 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1503 smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
1505 fidp->flags |= SMB_FID_MTIMESETDONE;
1508 attribute = *((u_long *)(p->datap + 32));
1509 if (attribute != 0) {
1510 if ((scp->unixModeBits & 0222)
1511 && (attribute & 1) != 0) {
1512 /* make a writable file read-only */
1513 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1514 attr.unixModeBits = scp->unixModeBits & ~0222;
1516 else if ((scp->unixModeBits & 0222) == 0
1517 && (attribute & 1) == 0) {
1518 /* make a read-only file writable */
1519 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1520 attr.unixModeBits = scp->unixModeBits | 0222;
1523 lock_ReleaseMutex(&scp->mx);
1527 code = cm_SetAttr(scp, &attr, userp, &req);
1531 else if (infoLevel == 0x103 || infoLevel == 0x104) {
1532 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
1535 attr.mask = CM_ATTRMASK_LENGTH;
1536 attr.length.LowPart = size.LowPart;
1537 attr.length.HighPart = size.HighPart;
1538 code = cm_SetAttr(scp, &attr, userp, &req);
1540 else if (infoLevel == 0x102) {
1541 if (*((char *)(p->datap))) {
1542 code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
1545 fidp->flags |= SMB_FID_DELONCLOSE;
1549 fidp->flags &= ~SMB_FID_DELONCLOSE;
1553 cm_ReleaseUser(userp);
1554 smb_ReleaseFID(fidp);
1555 if (code == 0) smb_SendTran2Packet(vcp, outp, op);
1556 else smb_SendTran2Error(vcp, p, op, code);
1557 smb_FreeTran2Packet(outp);
1562 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1564 return CM_ERROR_BADOP;
1567 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1569 return CM_ERROR_BADOP;
1572 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1574 return CM_ERROR_BADOP;
1577 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1579 return CM_ERROR_BADOP;
1582 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1584 return CM_ERROR_BADOP;
1587 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
1588 smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
1593 cm_scache_t *targetScp; /* target if scp is a symlink */
1598 unsigned short attr;
1599 unsigned long lattr;
1600 smb_dirListPatch_t *patchp;
1601 smb_dirListPatch_t *npatchp;
1603 for(patchp = *dirPatchespp; patchp; patchp =
1604 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
1605 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
1607 lock_ObtainMutex(&scp->mx);
1608 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
1609 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1611 lock_ReleaseMutex(&scp->mx);
1612 cm_ReleaseSCache(scp);
1616 /* now watch for a symlink */
1617 if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
1618 lock_ReleaseMutex(&scp->mx);
1619 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp,
1622 /* we have a more accurate file to use (the
1623 * target of the symbolic link). Otherwise,
1624 * we'll just use the symlink anyway.
1626 osi_Log2(afsd_logp, "symlink vp %x to vp %x",
1628 cm_ReleaseSCache(scp);
1631 lock_ObtainMutex(&scp->mx);
1634 dptr = patchp->dptr;
1636 if (infoLevel >= 0x101) {
1638 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1640 /* copy to Creation Time */
1641 *((FILETIME *)dptr) = ft;
1644 /* copy to Last Access Time */
1645 *((FILETIME *)dptr) = ft;
1648 /* copy to Last Write Time */
1649 *((FILETIME *)dptr) = ft;
1652 /* copy to Change Time */
1653 *((FILETIME *)dptr) = ft;
1656 /* Use length for both file length and alloc length */
1657 *((LARGE_INTEGER *)dptr) = scp->length;
1659 *((LARGE_INTEGER *)dptr) = scp->length;
1662 /* Copy attributes */
1663 lattr = smb_ExtAttributes(scp);
1664 /* merge in hidden (dot file) attribute */
1665 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1666 lattr |= SMB_ATTR_HIDDEN;
1667 *((u_long *)dptr) = lattr;
1672 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1674 /* and copy out date */
1675 shortTemp = (dosTime>>16) & 0xffff;
1676 *((u_short *)dptr) = shortTemp;
1679 /* copy out creation time */
1680 shortTemp = dosTime & 0xffff;
1681 *((u_short *)dptr) = shortTemp;
1684 /* and copy out date */
1685 shortTemp = (dosTime>>16) & 0xffff;
1686 *((u_short *)dptr) = shortTemp;
1689 /* copy out access time */
1690 shortTemp = dosTime & 0xffff;
1691 *((u_short *)dptr) = shortTemp;
1694 /* and copy out date */
1695 shortTemp = (dosTime>>16) & 0xffff;
1696 *((u_short *)dptr) = shortTemp;
1699 /* copy out mod time */
1700 shortTemp = dosTime & 0xffff;
1701 *((u_short *)dptr) = shortTemp;
1704 /* copy out file length and alloc length,
1705 * using the same for both
1707 *((u_long *)dptr) = scp->length.LowPart;
1709 *((u_long *)dptr) = scp->length.LowPart;
1712 /* finally copy out attributes as short */
1713 attr = smb_Attributes(scp);
1714 /* merge in hidden (dot file) attribute */
1715 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
1716 attr |= SMB_ATTR_HIDDEN;
1717 *dptr++ = attr & 0xff;
1718 *dptr++ = (attr >> 8) & 0xff;
1721 lock_ReleaseMutex(&scp->mx);
1722 cm_ReleaseSCache(scp);
1725 /* now free the patches */
1726 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
1727 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
1731 /* and mark the list as empty */
1732 *dirPatchespp = NULL;
1737 /* do a case-folding search of the star name mask with the name in namep.
1738 * Return 1 if we match, otherwise 0.
1740 int smb_V3MatchMask(char *namep, char *maskp, int flags)
1742 unsigned char tcp1, tcp2; /* Pattern characters */
1743 unsigned char tcn1; /* Name characters */
1744 int sawDot = 0, sawStar = 0;
1745 char *starNamep, *starMaskp;
1746 static char nullCharp[] = {0};
1748 /* make sure we only match 8.3 names, if requested */
1749 if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) return 0;
1753 /* Next pattern character */
1756 /* Next name character */
1760 /* 0 - end of pattern */
1766 else if (tcp1 == '.' || tcp1 == '"') {
1776 * first dot in pattern;
1777 * must match dot or end of name
1782 else if (tcn1 == '.') {
1791 else if (tcp1 == '?') {
1792 if (tcn1 == 0 || tcn1 == '.')
1797 else if (tcp1 == '>') {
1798 if (tcn1 != 0 && tcn1 != '.')
1802 else if (tcp1 == '*' || tcp1 == '<') {
1806 else if (tcp2 == '.' || tcp2 == '"') {
1807 while (tcn1 != '.' && tcn1 != 0)
1822 * pattern character after '*' is not null or
1823 * period. If it is '?' or '>', we are not
1824 * going to understand it. If it is '*' or
1825 * '<', we are going to skip over it. None of
1826 * these are likely, I hope.
1828 /* skip over '*' and '<' */
1829 while (tcp2 == '*' || tcp2 == '<')
1832 /* skip over characters that don't match tcp2 */
1833 while (tcn1 != '.' && tcn1 != 0
1834 && cm_foldUpper[tcn1] != cm_foldUpper[tcp2])
1838 if (tcn1 == '.' || tcn1 == 0)
1841 /* Remember where we are */
1851 /* tcp1 is not a wildcard */
1852 if (cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) {
1857 /* if trying to match a star pattern, go back */
1859 maskp = starMaskp - 2;
1860 namep = starNamep + 1;
1870 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1879 smb_dirListPatch_t *dirListPatchesp;
1880 smb_dirListPatch_t *curPatchp;
1883 long orbytes; /* # of bytes in this output record */
1884 long ohbytes; /* # of bytes, except file name */
1885 long onbytes; /* # of bytes in name, incl. term. null */
1886 osi_hyper_t dirLength;
1887 osi_hyper_t bufferOffset;
1888 osi_hyper_t curOffset;
1890 smb_dirSearch_t *dsp;
1894 cm_pageHeader_t *pageHeaderp;
1895 cm_user_t *userp = NULL;
1898 long nextEntryCookie;
1899 int numDirChunks; /* # of 32 byte dir chunks in this entry */
1900 char *op; /* output data ptr */
1901 char *origOp; /* original value of op */
1902 cm_space_t *spacep; /* for pathname buffer */
1903 long maxReturnData; /* max # of return data */
1904 long maxReturnParms; /* max # of return parms */
1905 long bytesInBuffer; /* # data bytes in the output buffer */
1907 char *maskp; /* mask part of path */
1911 smb_tran2Packet_t *outp; /* response packet */
1914 char shortName[13]; /* 8.3 name if needed */
1925 if (p->opcode == 1) {
1926 /* find first; obtain basic parameters from request */
1927 attribute = p->parmsp[0];
1928 maxCount = p->parmsp[1];
1929 infoLevel = p->parmsp[3];
1930 searchFlags = p->parmsp[2];
1931 dsp = smb_NewDirSearch(1);
1932 dsp->attribute = attribute;
1933 pathp = ((char *) p->parmsp) + 12; /* points to path */
1935 maskp = strrchr(pathp, '\\');
1936 if (maskp == NULL) maskp = pathp;
1937 else maskp++; /* skip over backslash */
1938 strcpy(dsp->mask, maskp); /* and save mask */
1939 /* track if this is likely to match a lot of entries */
1940 starPattern = smb_V3IsStarMask(maskp);
1943 osi_assert(p->opcode == 2);
1944 /* find next; obtain basic parameters from request or open dir file */
1945 dsp = smb_FindDirSearch(p->parmsp[0]);
1946 if (!dsp) return CM_ERROR_BADFD;
1947 attribute = dsp->attribute;
1948 maxCount = p->parmsp[1];
1949 infoLevel = p->parmsp[2];
1950 searchFlags = p->parmsp[5];
1952 nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
1954 starPattern = 1; /* assume, since required a Find Next */
1958 "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
1959 attribute, infoLevel, maxCount, searchFlags);
1961 osi_Log2(afsd_logp, "...T2 search op %d, nextCookie 0x%x",
1962 p->opcode, nextCookie);
1964 if (infoLevel >= 0x101)
1965 searchFlags &= ~4; /* no resume keys */
1967 dirListPatchesp = NULL;
1969 maxReturnData = p->maxReturnData;
1970 if (p->opcode == 1) /* find first */
1971 maxReturnParms = 10; /* bytes */
1973 maxReturnParms = 8; /* bytes */
1975 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
1976 if (maxReturnData > 6000) maxReturnData = 6000;
1977 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
1979 outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
1982 osi_Log1(afsd_logp, "T2 receive search dir %s",
1983 osi_LogSaveString(afsd_logp, pathp));
1985 /* bail out if request looks bad */
1986 if (p->opcode == 1 && !pathp) {
1987 smb_ReleaseDirSearch(dsp);
1988 smb_FreeTran2Packet(outp);
1989 return CM_ERROR_BADSMB;
1992 osi_Log2(afsd_logp, "T2 dir search cookie 0x%x, connection %d",
1993 nextCookie, dsp->cookie);
1995 userp = smb_GetTran2User(vcp, p);
1997 osi_Log1(afsd_logp, "T2 dir search unable to resolve user [%d]", p->uid);
1998 smb_ReleaseDirSearch(dsp);
1999 smb_FreeTran2Packet(outp);
2000 return CM_ERROR_BADSMB;
2003 /* try to get the vnode for the path name next */
2004 lock_ObtainMutex(&dsp->mx);
2011 spacep = cm_GetSpace();
2012 smb_StripLastComponent(spacep->data, NULL, pathp);
2013 lock_ReleaseMutex(&dsp->mx);
2015 tidPathp = smb_GetTIDPath(vcp, p->tid);
2016 code = cm_NameI(cm_rootSCachep, spacep->data,
2017 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2018 userp, tidPathp, &req, &scp);
2019 cm_FreeSpace(spacep);
2021 lock_ObtainMutex(&dsp->mx);
2023 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2025 /* we need one hold for the entry we just stored into,
2026 * and one for our own processing. When we're done
2027 * with this function, we'll drop the one for our own
2028 * processing. We held it once from the namei call,
2029 * and so we do another hold now.
2032 lock_ObtainMutex(&scp->mx);
2033 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2034 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2035 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2036 dsp->flags |= SMB_DIRSEARCH_BULKST;
2038 lock_ReleaseMutex(&scp->mx);
2041 lock_ReleaseMutex(&dsp->mx);
2043 cm_ReleaseUser(userp);
2044 smb_FreeTran2Packet(outp);
2045 smb_DeleteDirSearch(dsp);
2046 smb_ReleaseDirSearch(dsp);
2050 /* get the directory size */
2051 lock_ObtainMutex(&scp->mx);
2052 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2053 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2055 lock_ReleaseMutex(&scp->mx);
2056 cm_ReleaseSCache(scp);
2057 cm_ReleaseUser(userp);
2058 smb_FreeTran2Packet(outp);
2059 smb_DeleteDirSearch(dsp);
2060 smb_ReleaseDirSearch(dsp);
2064 dirLength = scp->length;
2066 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2067 curOffset.HighPart = 0;
2068 curOffset.LowPart = nextCookie;
2069 origOp = outp->datap;
2076 if (searchFlags & 4)
2077 /* skip over resume key */
2080 /* make sure that curOffset.LowPart doesn't point to the first
2081 * 32 bytes in the 2nd through last dir page, and that it doesn't
2082 * point at the first 13 32-byte chunks in the first dir page,
2083 * since those are dir and page headers, and don't contain useful
2086 temp = curOffset.LowPart & (2048-1);
2087 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2088 /* we're in the first page */
2089 if (temp < 13*32) temp = 13*32;
2092 /* we're in a later dir page */
2093 if (temp < 32) temp = 32;
2096 /* make sure the low order 5 bits are zero */
2099 /* now put temp bits back ito curOffset.LowPart */
2100 curOffset.LowPart &= ~(2048-1);
2101 curOffset.LowPart |= temp;
2103 /* check if we've passed the dir's EOF */
2104 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2109 /* check if we've returned all the names that will fit in the
2110 * response packet; we check return count as well as the number
2111 * of bytes requested. We check the # of bytes after we find
2112 * the dir entry, since we'll need to check its size.
2114 if (returnedNames >= maxCount) {
2118 /* see if we can use the bufferp we have now; compute in which
2119 * page the current offset would be, and check whether that's
2120 * the offset of the buffer we have. If not, get the buffer.
2122 thyper.HighPart = curOffset.HighPart;
2123 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2124 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2127 buf_Release(bufferp);
2130 lock_ReleaseMutex(&scp->mx);
2131 lock_ObtainRead(&scp->bufCreateLock);
2132 code = buf_Get(scp, &thyper, &bufferp);
2133 lock_ReleaseRead(&scp->bufCreateLock);
2135 /* now, if we're doing a star match, do bulk fetching
2136 * of all of the status info for files in the dir.
2139 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2142 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2143 && LargeIntegerGreaterThanOrEqualTo(
2144 thyper, scp->bulkStatProgress)) {
2145 /* Don't bulk stat if risking timeout */
2146 int now = GetCurrentTime();
2147 if (now - req.startTime > 5000) {
2148 scp->bulkStatProgress = thyper;
2149 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2150 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2152 cm_TryBulkStat(scp, &thyper,
2157 lock_ObtainMutex(&scp->mx);
2159 bufferOffset = thyper;
2161 /* now get the data in the cache */
2163 code = cm_SyncOp(scp, bufferp, userp, &req,
2165 CM_SCACHESYNC_NEEDCALLBACK
2166 | CM_SCACHESYNC_READ);
2169 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2171 /* otherwise, load the buffer and try again */
2172 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2177 buf_Release(bufferp);
2181 } /* if (wrong buffer) ... */
2183 /* now we have the buffer containing the entry we're interested
2184 * in; copy it out if it represents a non-deleted entry.
2186 entryInDir = curOffset.LowPart & (2048-1);
2187 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2189 /* page header will help tell us which entries are free. Page
2190 * header can change more often than once per buffer, since
2191 * AFS 3 dir page size may be less than (but not more than)
2192 * a buffer package buffer.
2194 /* only look intra-buffer */
2195 temp = curOffset.LowPart & (buf_bufferSize - 1);
2196 temp &= ~(2048 - 1); /* turn off intra-page bits */
2197 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2199 /* now determine which entry we're looking at in the page.
2200 * If it is free (there's a free bitmap at the start of the
2201 * dir), we should skip these 32 bytes.
2203 slotInPage = (entryInDir & 0x7e0) >> 5;
2204 if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2205 & (1 << (slotInPage & 0x7)))) {
2206 /* this entry is free */
2207 numDirChunks = 1; /* only skip this guy */
2211 tp = bufferp->datap + entryInBuffer;
2212 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
2214 /* while we're here, compute the next entry's location, too,
2215 * since we'll need it when writing out the cookie into the dir
2218 * XXXX Probably should do more sanity checking.
2220 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2222 /* compute offset of cookie representing next entry */
2223 nextEntryCookie = curOffset.LowPart
2224 + (CM_DIR_CHUNKSIZE * numDirChunks);
2226 /* Need 8.3 name? */
2228 if (infoLevel == 0x104
2229 && dep->fid.vnode != 0
2230 && !cm_Is8Dot3(dep->name)) {
2231 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2235 if (dep->fid.vnode != 0
2236 && (smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)
2238 && smb_V3MatchMask(shortName, maskp,
2239 CM_FLAG_CASEFOLD)))) {
2241 /* Eliminate entries that don't match requested
2243 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
2244 smb_IsDotFile(dep->name))
2245 goto nextEntry; /* no hidden files */
2247 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
2249 /* We have already done the cm_TryBulkStat above */
2250 fid.cell = scp->fid.cell;
2251 fid.volume = scp->fid.volume;
2252 fid.vnode = ntohl(dep->fid.vnode);
2253 fid.unique = ntohl(dep->fid.unique);
2254 fileType = cm_FindFileType(&fid);
2255 /*osi_Log2(afsd_logp, "smb_ReceiveTran2SearchDir: file %s "
2256 "has filetype %d", dep->name,
2258 if (fileType == CM_SCACHETYPE_DIRECTORY)
2262 /* finally check if this name will fit */
2264 /* standard dir entry stuff */
2265 if (infoLevel < 0x101)
2266 ohbytes = 23; /* pre-NT */
2267 else if (infoLevel == 0x103)
2268 ohbytes = 12; /* NT names only */
2270 ohbytes = 64; /* NT */
2272 if (infoLevel == 0x104)
2273 ohbytes += 26; /* Short name & length */
2275 if (searchFlags & 4) {
2276 ohbytes += 4; /* if resume key required */
2280 && infoLevel != 0x101
2281 && infoLevel != 0x103)
2282 ohbytes += 4; /* EASIZE */
2284 /* add header to name & term. null */
2285 orbytes = onbytes + ohbytes + 1;
2287 /* now, we round up the record to a 4 byte alignment,
2288 * and we make sure that we have enough room here for
2289 * even the aligned version (so we don't have to worry
2290 * about an * overflow when we pad things out below).
2291 * That's the reason for the alignment arithmetic below.
2293 if (infoLevel >= 0x101)
2294 align = (4 - (orbytes & 3)) & 3;
2297 if (orbytes + bytesInBuffer + align > maxReturnData)
2300 /* this is one of the entries to use: it is not deleted
2301 * and it matches the star pattern we're looking for.
2302 * Put out the name, preceded by its length.
2304 /* First zero everything else */
2305 memset(origOp, 0, ohbytes);
2307 if (infoLevel <= 0x101)
2308 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
2309 else if (infoLevel == 0x103)
2310 *((u_long *)(op + 8)) = onbytes;
2312 *((u_long *)(op + 60)) = onbytes;
2313 strcpy(origOp+ohbytes, dep->name);
2315 /* Short name if requested and needed */
2316 if (infoLevel == 0x104) {
2317 if (NeedShortName) {
2318 strcpy(op + 70, shortName);
2319 *(op + 68) = shortNameEnd - shortName;
2323 /* now, adjust the # of entries copied */
2326 /* NextEntryOffset and FileIndex */
2327 if (infoLevel >= 101) {
2328 int entryOffset = orbytes + align;
2329 *((u_long *)op) = entryOffset;
2330 *((u_long *)(op+4)) = nextEntryCookie;
2333 /* now we emit the attribute. This is tricky, since
2334 * we need to really stat the file to find out what
2335 * type of entry we've got. Right now, we're copying
2336 * out data from * a buffer, while holding the scp
2337 * locked, so it isn't really convenient to stat
2338 * something now. We'll put in a place holder
2339 * now, and make a second pass before returning this
2340 * to get the real attributes. So, we just skip the
2341 * data for now, and adjust it later. We allocate a
2342 * patch record to make it easy to find this point
2343 * later. The replay will happen at a time when it is
2344 * safe to unlock the directory.
2346 if (infoLevel != 0x103) {
2347 curPatchp = malloc(sizeof(*curPatchp));
2348 osi_QAdd((osi_queue_t **) &dirListPatchesp,
2350 curPatchp->dptr = op;
2351 if (infoLevel >= 0x101)
2352 curPatchp->dptr += 8;
2354 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
2355 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
2358 curPatchp->flags = 0;
2360 curPatchp->fid.cell = scp->fid.cell;
2361 curPatchp->fid.volume = scp->fid.volume;
2362 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2363 curPatchp->fid.unique = ntohl(dep->fid.unique);
2366 curPatchp->dep = dep;
2369 if (searchFlags & 4)
2370 /* put out resume key */
2371 *((u_long *)origOp) = nextEntryCookie;
2373 /* Adjust byte ptr and count */
2374 origOp += orbytes; /* skip entire record */
2375 bytesInBuffer += orbytes;
2377 /* and pad the record out */
2378 while (--align >= 0) {
2383 } /* if we're including this name */
2386 /* and adjust curOffset to be where the new cookie is */
2387 thyper.HighPart = 0;
2388 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2389 curOffset = LargeIntegerAdd(thyper, curOffset);
2390 } /* while copying data for dir listing */
2392 /* release the mutex */
2393 lock_ReleaseMutex(&scp->mx);
2394 if (bufferp) buf_Release(bufferp);
2396 /* apply and free last set of patches; if not doing a star match, this
2397 * will be empty, but better safe (and freeing everything) than sorry.
2399 smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
2402 /* now put out the final parameters */
2403 if (returnedNames == 0) eos = 1;
2404 if (p->opcode == 1) {
2406 outp->parmsp[0] = (unsigned short) dsp->cookie;
2407 outp->parmsp[1] = returnedNames;
2408 outp->parmsp[2] = eos;
2409 outp->parmsp[3] = 0; /* nothing wrong with EAS */
2410 outp->parmsp[4] = 0; /* don't need last name to continue
2411 * search, cookie is enough. Normally,
2412 * this is the offset of the file name
2413 * of the last entry returned.
2415 outp->totalParms = 10; /* in bytes */
2419 outp->parmsp[0] = returnedNames;
2420 outp->parmsp[1] = eos;
2421 outp->parmsp[2] = 0; /* EAS error */
2422 outp->parmsp[3] = 0; /* last name, as above */
2423 outp->totalParms = 8; /* in bytes */
2426 /* return # of bytes in the buffer */
2427 outp->totalData = bytesInBuffer;
2429 osi_Log2(afsd_logp, "T2 search dir done, %d names, code %d",
2430 returnedNames, code);
2432 /* Return error code if unsuccessful on first request */
2433 if (code == 0 && p->opcode == 1 && returnedNames == 0)
2434 code = CM_ERROR_NOSUCHFILE;
2436 /* if we're supposed to close the search after this request, or if
2437 * we're supposed to close the search if we're done, and we're done,
2438 * or if something went wrong, close the search.
2440 /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
2441 if ((searchFlags & 1) || (returnedNames == 0) || ((searchFlags & 2) &&
2443 smb_DeleteDirSearch(dsp);
2445 smb_SendTran2Error(vcp, p, opx, code);
2447 smb_SendTran2Packet(vcp, outp, opx);
2449 smb_FreeTran2Packet(outp);
2450 smb_ReleaseDirSearch(dsp);
2451 cm_ReleaseSCache(scp);
2452 cm_ReleaseUser(userp);
2456 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2459 smb_dirSearch_t *dsp;
2461 dirHandle = smb_GetSMBParm(inp, 0);
2463 osi_Log1(afsd_logp, "SMB3 find close handle %d", dirHandle);
2465 dsp = smb_FindDirSearch(dirHandle);
2468 return CM_ERROR_BADFD;
2470 /* otherwise, we have an FD to destroy */
2471 smb_DeleteDirSearch(dsp);
2472 smb_ReleaseDirSearch(dsp);
2474 /* and return results */
2475 smb_SetSMBDataLength(outp, 0);
2480 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2482 smb_SetSMBDataLength(outp, 0);
2486 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2493 cm_scache_t *dscp; /* dir we're dealing with */
2494 cm_scache_t *scp; /* file we're creating */
2496 int initialModeBits;
2506 int parmSlot; /* which parm we're dealing with */
2514 extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
2515 openFun = smb_GetSMBParm(inp, 8); /* open function */
2516 excl = ((openFun & 3) == 0);
2517 trunc = ((openFun & 3) == 2); /* truncate it */
2518 openMode = (smb_GetSMBParm(inp, 3) & 0x7);
2519 openAction = 0; /* tracks what we did */
2521 attributes = smb_GetSMBParm(inp, 5);
2522 dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
2524 /* compute initial mode bits based on read-only flag in attributes */
2525 initialModeBits = 0666;
2526 if (attributes & 1) initialModeBits &= ~0222;
2528 pathp = smb_GetSMBData(inp, NULL);
2530 spacep = inp->spacep;
2531 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2533 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2534 /* special case magic file name for receiving IOCTL requests
2535 * (since IOCTL calls themselves aren't getting through).
2538 osi_Log0(afsd_logp, "IOCTL Open");
2541 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2542 smb_SetupIoctlFid(fidp, spacep);
2544 /* set inp->fid so that later read calls in same msg can find fid */
2545 inp->fid = fidp->fid;
2547 /* copy out remainder of the parms */
2549 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2551 smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
2552 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* mod time */
2553 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2554 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* len */
2555 smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
2556 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2557 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2558 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2560 /* and the final "always present" stuff */
2561 smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
2562 /* next write out the "unique" ID */
2563 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
2564 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
2565 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2566 smb_SetSMBDataLength(outp, 0);
2568 /* and clean up fid reference */
2569 smb_ReleaseFID(fidp);
2573 #ifdef DEBUG_VERBOSE
2575 char *hexp, *asciip;
2576 asciip = (lastNamep ? lastNamep : pathp );
2577 hexp = osi_HexifyString(asciip);
2578 DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
2582 userp = smb_GetUser(vcp, inp);
2585 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2586 code = cm_NameI(cm_rootSCachep, pathp,
2587 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2588 userp, tidPathp, &req, &scp);
2590 code = cm_NameI(cm_rootSCachep, spacep->data,
2591 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2592 userp, tidPathp, &req, &dscp);
2595 cm_ReleaseUser(userp);
2599 /* otherwise, scp points to the parent directory. Do a lookup,
2600 * and truncate the file if we find it, otherwise we create the
2603 if (!lastNamep) lastNamep = pathp;
2605 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2607 if (code && code != CM_ERROR_NOSUCHFILE) {
2608 cm_ReleaseSCache(dscp);
2609 cm_ReleaseUser(userp);
2614 /* if we get here, if code is 0, the file exists and is represented by
2615 * scp. Otherwise, we have to create it. The dir may be represented
2616 * by dscp, or we may have found the file directly. If code is non-zero,
2620 code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2622 if (dscp) cm_ReleaseSCache(dscp);
2623 cm_ReleaseSCache(scp);
2624 cm_ReleaseUser(userp);
2629 /* oops, file shouldn't be there */
2630 if (dscp) cm_ReleaseSCache(dscp);
2631 cm_ReleaseSCache(scp);
2632 cm_ReleaseUser(userp);
2633 return CM_ERROR_EXISTS;
2637 setAttr.mask = CM_ATTRMASK_LENGTH;
2638 setAttr.length.LowPart = 0;
2639 setAttr.length.HighPart = 0;
2640 code = cm_SetAttr(scp, &setAttr, userp, &req);
2641 openAction = 3; /* truncated existing file */
2643 else openAction = 1; /* found existing file */
2645 else if (!(openFun & 0x10)) {
2646 /* don't create if not found */
2647 if (dscp) cm_ReleaseSCache(dscp);
2648 cm_ReleaseUser(userp);
2649 return CM_ERROR_NOSUCHFILE;
2652 osi_assert(dscp != NULL);
2653 osi_Log1(afsd_logp, "smb_ReceiveV3OpenX creating file %s",
2654 osi_LogSaveString(afsd_logp, lastNamep));
2655 openAction = 2; /* created file */
2656 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2657 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
2658 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2660 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2661 smb_NotifyChange(FILE_ACTION_ADDED,
2662 FILE_NOTIFY_CHANGE_FILE_NAME,
2663 dscp, lastNamep, NULL, TRUE);
2664 if (!excl && code == CM_ERROR_EXISTS) {
2665 /* not an exclusive create, and someone else tried
2666 * creating it already, then we open it anyway. We
2667 * don't bother retrying after this, since if this next
2668 * fails, that means that the file was deleted after we
2669 * started this call.
2671 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2675 setAttr.mask = CM_ATTRMASK_LENGTH;
2676 setAttr.length.LowPart = 0;
2677 setAttr.length.HighPart = 0;
2678 code = cm_SetAttr(scp, &setAttr, userp,
2681 } /* lookup succeeded */
2685 /* we don't need this any longer */
2686 if (dscp) cm_ReleaseSCache(dscp);
2689 /* something went wrong creating or truncating the file */
2690 if (scp) cm_ReleaseSCache(scp);
2691 cm_ReleaseUser(userp);
2695 /* make sure we're about to open a file */
2696 if (scp->fileType != CM_SCACHETYPE_FILE) {
2697 cm_ReleaseSCache(scp);
2698 cm_ReleaseUser(userp);
2699 return CM_ERROR_ISDIR;
2702 /* now all we have to do is open the file itself */
2703 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2706 /* save a pointer to the vnode */
2709 /* compute open mode */
2710 if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2711 if (openMode == 1 || openMode == 2)
2712 fidp->flags |= SMB_FID_OPENWRITE;
2714 smb_ReleaseFID(fidp);
2716 cm_Open(scp, 0, userp);
2718 /* set inp->fid so that later read calls in same msg can find fid */
2719 inp->fid = fidp->fid;
2721 /* copy out remainder of the parms */
2723 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
2724 lock_ObtainMutex(&scp->mx);
2726 smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
2727 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
2728 smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
2729 smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
2730 smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
2731 smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
2732 smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
2733 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
2734 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
2736 /* and the final "always present" stuff */
2737 smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
2738 /* next write out the "unique" ID */
2739 smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
2740 smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
2741 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
2742 lock_ReleaseMutex(&scp->mx);
2743 smb_SetSMBDataLength(outp, 0);
2745 osi_Log1(afsd_logp, "SMB OpenX opening fid %d", fidp->fid);
2747 cm_ReleaseUser(userp);
2748 /* leave scp held since we put it in fidp->scp */
2752 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2759 unsigned char LockType;
2760 unsigned short NumberOfUnlocks, NumberOfLocks;
2761 unsigned long Timeout;
2763 LARGE_INTEGER LOffset, LLength;
2764 smb_waitingLock_t *waitingLock;
2771 fid = smb_GetSMBParm(inp, 2);
2772 fid = smb_ChainFID(fid, inp);
2774 fidp = smb_FindFID(vcp, fid, 0);
2775 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2776 return CM_ERROR_BADFD;
2778 /* set inp->fid so that later read calls in same msg can find fid */
2781 userp = smb_GetUser(vcp, inp);
2785 lock_ObtainMutex(&scp->mx);
2786 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2787 CM_SCACHESYNC_NEEDCALLBACK
2788 | CM_SCACHESYNC_GETSTATUS
2789 | CM_SCACHESYNC_LOCK);
2790 if (code) goto doneSync;
2792 LockType = smb_GetSMBParm(inp, 3) & 0xff;
2793 Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
2794 NumberOfUnlocks = smb_GetSMBParm(inp, 6);
2795 NumberOfLocks = smb_GetSMBParm(inp, 7);
2797 op = smb_GetSMBData(inp, NULL);
2799 for (i=0; i<NumberOfUnlocks; i++) {
2800 if (LockType & 0x10) {
2802 LOffset.HighPart = *((LONG *)(op + 4));
2803 LOffset.LowPart = *((DWORD *)(op + 8));
2804 LLength.HighPart = *((LONG *)(op + 12));
2805 LLength.LowPart = *((DWORD *)(op + 16));
2809 /* Not Large Files */
2810 LOffset.HighPart = 0;
2811 LOffset.LowPart = *((DWORD *)(op + 2));
2812 LLength.HighPart = 0;
2813 LLength.LowPart = *((DWORD *)(op + 6));
2816 if (LargeIntegerNotEqualToZero(LOffset))
2818 /* Do not check length -- length check done in cm_Unlock */
2820 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
2821 if (code) goto done;
2824 for (i=0; i<NumberOfLocks; i++) {
2825 if (LockType & 0x10) {
2827 LOffset.HighPart = *((LONG *)(op + 4));
2828 LOffset.LowPart = *((DWORD *)(op + 8));
2829 LLength.HighPart = *((LONG *)(op + 12));
2830 LLength.LowPart = *((DWORD *)(op + 16));
2834 /* Not Large Files */
2835 LOffset.HighPart = 0;
2836 LOffset.LowPart = *((DWORD *)(op + 2));
2837 LLength.HighPart = 0;
2838 LLength.LowPart = *((DWORD *)(op + 6));
2841 if (LargeIntegerNotEqualToZero(LOffset))
2843 if (LargeIntegerLessThan(LOffset, scp->length))
2846 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
2847 userp, &req, &lockp);
2848 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
2849 /* Put on waiting list */
2850 waitingLock = malloc(sizeof(smb_waitingLock_t));
2851 waitingLock->vcp = vcp;
2852 waitingLock->inp = smb_CopyPacket(inp);
2853 waitingLock->outp = smb_CopyPacket(outp);
2854 waitingLock->timeRemaining = Timeout;
2855 waitingLock->lockp = lockp;
2856 lock_ObtainWrite(&smb_globalLock);
2857 osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
2859 osi_Wakeup((long) &smb_allWaitingLocks);
2860 lock_ReleaseWrite(&smb_globalLock);
2861 /* don't send reply immediately */
2862 outp->flags |= SMB_PACKETFLAG_NOSEND;
2868 /* release any locks acquired before the failure */
2871 smb_SetSMBDataLength(outp, 0);
2873 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2875 lock_ReleaseMutex(&scp->mx);
2876 cm_ReleaseUser(userp);
2877 smb_ReleaseFID(fidp);
2882 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2894 fid = smb_GetSMBParm(inp, 0);
2895 fid = smb_ChainFID(fid, inp);
2897 fidp = smb_FindFID(vcp, fid, 0);
2898 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2899 return CM_ERROR_BADFD;
2902 userp = smb_GetUser(vcp, inp);
2906 /* otherwise, stat the file */
2907 lock_ObtainMutex(&scp->mx);
2908 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2909 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2910 if (code) goto done;
2912 /* decode times. We need a search time, but the response to this
2913 * call provides the date first, not the time, as returned in the
2914 * searchTime variable. So we take the high-order bits first.
2916 smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
2917 smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff); /* ctime */
2918 smb_SetSMBParm(outp, 1, searchTime & 0xffff);
2919 smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff); /* atime */
2920 smb_SetSMBParm(outp, 3, searchTime & 0xffff);
2921 smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff); /* mtime */
2922 smb_SetSMBParm(outp, 5, searchTime & 0xffff);
2924 /* now handle file size and allocation size */
2925 smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff); /* file size */
2926 smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
2927 smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff); /* alloc size */
2928 smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
2930 /* file attribute */
2931 smb_SetSMBParm(outp, 10, smb_Attributes(scp));
2933 /* and finalize stuff */
2934 smb_SetSMBDataLength(outp, 0);
2938 lock_ReleaseMutex(&scp->mx);
2939 cm_ReleaseUser(userp);
2940 smb_ReleaseFID(fidp);
2944 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2958 fid = smb_GetSMBParm(inp, 0);
2959 fid = smb_ChainFID(fid, inp);
2961 fidp = smb_FindFID(vcp, fid, 0);
2962 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
2963 return CM_ERROR_BADFD;
2966 userp = smb_GetUser(vcp, inp);
2970 /* now prepare to call cm_setattr. This message only sets various times,
2971 * and AFS only implements mtime, and we'll set the mtime if that's
2972 * requested. The others we'll ignore.
2974 searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
2976 if (searchTime != 0) {
2977 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
2979 if ( unixTime != -1 ) {
2980 attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
2981 attrs.clientModTime = unixTime;
2982 code = cm_SetAttr(scp, &attrs, userp, &req);
2984 osi_Log1(afsd_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
2986 osi_Log1(afsd_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
2991 cm_ReleaseUser(userp);
2992 smb_ReleaseFID(fidp);
2997 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3000 long count, finalCount;
3007 fd = smb_GetSMBParm(inp, 2);
3008 count = smb_GetSMBParm(inp, 5);
3009 offset.HighPart = 0; /* too bad */
3010 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3012 osi_Log3(afsd_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3013 fd, offset.LowPart, count);
3015 fd = smb_ChainFID(fd, inp);
3016 fidp = smb_FindFID(vcp, fd, 0);
3018 return CM_ERROR_BADFD;
3020 /* set inp->fid so that later read calls in same msg can find fid */
3023 if (fidp->flags & SMB_FID_IOCTL) {
3024 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3027 userp = smb_GetUser(vcp, inp);
3029 /* 0 and 1 are reserved for request chaining, were setup by our caller,
3030 * and will be further filled in after we return.
3032 smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3033 smb_SetSMBParm(outp, 3, 0); /* resvd */
3034 smb_SetSMBParm(outp, 4, 0); /* resvd */
3035 smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3036 /* fill in #6 when we have all the parameters' space reserved */
3037 smb_SetSMBParm(outp, 7, 0); /* resv'd */
3038 smb_SetSMBParm(outp, 8, 0); /* resv'd */
3039 smb_SetSMBParm(outp, 9, 0); /* resv'd */
3040 smb_SetSMBParm(outp, 10, 0); /* resv'd */
3041 smb_SetSMBParm(outp, 11, 0); /* reserved */
3043 /* get op ptr after putting in the parms, since otherwise we don't
3044 * know where the data really is.
3046 op = smb_GetSMBData(outp, NULL);
3048 /* now fill in offset from start of SMB header to first data byte (to op) */
3049 smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3051 /* set the packet data length the count of the # of bytes */
3052 smb_SetSMBDataLength(outp, count);
3055 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3057 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3060 /* fix some things up */
3061 smb_SetSMBParm(outp, 5, finalCount);
3062 smb_SetSMBDataLength(outp, finalCount);
3064 smb_ReleaseFID(fidp);
3066 cm_ReleaseUser(userp);
3071 * Values for createDisp, copied from NTDDK.H
3073 * FILE_SUPERSEDE 0 (???)
3074 * FILE_OPEN 1 (open)
3075 * FILE_CREATE 2 (exclusive)
3076 * FILE_OPEN_IF 3 (non-exclusive)
3077 * FILE_OVERWRITE 4 (open & truncate, but do not create)
3078 * FILE_OVERWRITE_IF 5 (open & truncate, or create)
3081 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3083 char *pathp, *realPathp;
3087 cm_scache_t *dscp; /* parent dir */
3088 cm_scache_t *scp; /* file to create or open */
3092 unsigned short nameLength;
3094 unsigned int requestOpLock;
3095 unsigned int requestBatchOpLock;
3096 unsigned int mustBeDir;
3097 unsigned int treeCreate;
3099 unsigned int desiredAccess;
3100 unsigned int extAttributes;
3101 unsigned int createDisp;
3102 unsigned int createOptions;
3103 int initialModeBits;
3104 unsigned short baseFid;
3105 smb_fid_t *baseFidp;
3107 cm_scache_t *baseDirp;
3108 unsigned short openAction;
3123 nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3124 flags = smb_GetSMBOffsetParm(inp, 3, 1)
3125 | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3126 requestOpLock = flags & 0x02;
3127 requestBatchOpLock = flags & 0x04;
3128 mustBeDir = flags & 0x08;
3131 * Why all of a sudden 32-bit FID?
3132 * We will reject all bits higher than 16.
3134 if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3135 return CM_ERROR_INVAL;
3136 baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3137 desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3138 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3139 extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3140 | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3141 createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3142 | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3143 createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3144 | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3146 /* mustBeDir is never set; createOptions directory bit seems to be
3149 if (createOptions & 1)
3151 else if (createOptions & 0x40)
3157 * compute initial mode bits based on read-only flag in
3158 * extended attributes
3160 initialModeBits = 0666;
3161 if (extAttributes & 1) initialModeBits &= ~0222;
3163 pathp = smb_GetSMBData(inp, NULL);
3164 /* Sometimes path is not null-terminated, so we make a copy. */
3165 realPathp = malloc(nameLength+1);
3166 memcpy(realPathp, pathp, nameLength);
3167 realPathp[nameLength] = 0;
3169 spacep = inp->spacep;
3170 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3172 osi_Log1(afsd_logp,"NTCreateX for [%s]",osi_LogSaveString(afsd_logp,realPathp));
3173 osi_Log4(afsd_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3175 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3176 /* special case magic file name for receiving IOCTL requests
3177 * (since IOCTL calls themselves aren't getting through).
3179 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3180 smb_SetupIoctlFid(fidp, spacep);
3182 /* set inp->fid so that later read calls in same msg can find fid */
3183 inp->fid = fidp->fid;
3187 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3188 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3189 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3191 memset(&ft, 0, sizeof(ft));
3192 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3193 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3194 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3195 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3196 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3197 sz.HighPart = 0x7fff; sz.LowPart = 0;
3198 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3199 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3200 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3201 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3202 smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
3203 smb_SetSMBDataLength(outp, 0);
3205 /* clean up fid reference */
3206 smb_ReleaseFID(fidp);
3211 #ifdef DEBUG_VERBOSE
3213 char *hexp, *asciip;
3214 asciip = (lastNamep? lastNamep : realPathp);
3215 hexp = osi_HexifyString( asciip );
3216 DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
3220 userp = smb_GetUser(vcp, inp);
3222 osi_Log1(afsd_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
3224 return CM_ERROR_INVAL;
3228 baseDirp = cm_rootSCachep;
3229 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3232 baseFidp = smb_FindFID(vcp, baseFid, 0);
3234 osi_Log1(afsd_logp, "NTCreateX Invalid base fid [%d]", baseFid);
3236 cm_ReleaseUser(userp);
3237 return CM_ERROR_INVAL;
3239 baseDirp = baseFidp->scp;
3243 osi_Log1(afsd_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(afsd_logp,tidPathp));
3245 /* compute open mode */
3247 if (desiredAccess & DELETE)
3248 fidflags |= SMB_FID_OPENDELETE;
3249 if (desiredAccess & AFS_ACCESS_READ)
3250 fidflags |= SMB_FID_OPENREAD;
3251 if (desiredAccess & AFS_ACCESS_WRITE)
3252 fidflags |= SMB_FID_OPENWRITE;
3256 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3257 userp, tidPathp, &req, &scp);
3258 if (code == 0) foundscp = TRUE;
3260 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3261 /* look up parent directory */
3262 /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
3263 the immediate parent. We have to work our way up realPathp until we hit something that we
3270 code = cm_NameI(baseDirp, spacep->data,
3271 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3272 userp, tidPathp, &req, &dscp);
3275 (tp = strrchr(spacep->data,'\\')) &&
3276 (createDisp == 2) &&
3277 (realDirFlag == 1)) {
3280 treeStartp = realPathp + (tp - spacep->data);
3282 if(*tp && !smb_IsLegalFilename(tp)) {
3283 if(baseFid != 0) smb_ReleaseFID(baseFidp);
3284 cm_ReleaseUser(userp);
3286 return CM_ERROR_BADNTFILENAME;
3293 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3296 osi_Log0(afsd_logp,"NTCreateX parent not found");
3297 cm_ReleaseUser(userp);
3302 if(treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
3303 /* A file exists where we want a directory. */
3304 cm_ReleaseSCache(dscp);
3305 cm_ReleaseUser(userp);
3307 return CM_ERROR_EXISTS;
3310 if (!lastNamep) lastNamep = realPathp;
3313 if (!smb_IsLegalFilename(lastNamep)) {
3314 cm_ReleaseSCache(dscp);
3315 cm_ReleaseUser(userp);
3317 return CM_ERROR_BADNTFILENAME;
3320 if (!foundscp && !treeCreate) {
3321 code = cm_Lookup(dscp, lastNamep,
3322 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3324 if (code && code != CM_ERROR_NOSUCHFILE) {
3325 cm_ReleaseSCache(dscp);
3326 cm_ReleaseUser(userp);
3333 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3336 /* if we get here, if code is 0, the file exists and is represented by
3337 * scp. Otherwise, we have to create it. The dir may be represented
3338 * by dscp, or we may have found the file directly. If code is non-zero,
3341 if (code == 0 && !treeCreate) {
3342 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3345 if (dscp) cm_ReleaseSCache(dscp);
3346 cm_ReleaseSCache(scp);
3347 cm_ReleaseUser(userp);
3352 if (createDisp == 2) {
3353 /* oops, file shouldn't be there */
3354 if (dscp) cm_ReleaseSCache(dscp);
3355 cm_ReleaseSCache(scp);
3356 cm_ReleaseUser(userp);
3358 return CM_ERROR_EXISTS;
3362 || createDisp == 5) {
3363 setAttr.mask = CM_ATTRMASK_LENGTH;
3364 setAttr.length.LowPart = 0;
3365 setAttr.length.HighPart = 0;
3366 code = cm_SetAttr(scp, &setAttr, userp, &req);
3367 openAction = 3; /* truncated existing file */
3369 else openAction = 1; /* found existing file */
3371 else if (createDisp == 1 || createDisp == 4) {
3372 /* don't create if not found */
3373 if (dscp) cm_ReleaseSCache(dscp);
3374 cm_ReleaseUser(userp);
3376 return CM_ERROR_NOSUCHFILE;
3378 else if (realDirFlag == 0 || realDirFlag == -1) {
3379 osi_assert(dscp != NULL);
3380 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating file %s",
3381 osi_LogSaveString(afsd_logp, lastNamep));
3382 openAction = 2; /* created file */
3383 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3384 setAttr.clientModTime = time(NULL);
3385 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3387 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3388 smb_NotifyChange(FILE_ACTION_ADDED,
3389 FILE_NOTIFY_CHANGE_FILE_NAME,
3390 dscp, lastNamep, NULL, TRUE);
3391 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3392 /* Not an exclusive create, and someone else tried
3393 * creating it already, then we open it anyway. We
3394 * don't bother retrying after this, since if this next
3395 * fails, that means that the file was deleted after we
3396 * started this call.
3398 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3401 if (createDisp == 5) {
3402 setAttr.mask = CM_ATTRMASK_LENGTH;
3403 setAttr.length.LowPart = 0;
3404 setAttr.length.HighPart = 0;
3405 code = cm_SetAttr(scp, &setAttr, userp,
3408 } /* lookup succeeded */
3413 char *cp; /* This component */
3414 int clen; /* length of component */
3418 /* create directory */
3419 if ( !treeCreate ) treeStartp = lastNamep;
3420 osi_assert(dscp != NULL);
3421 osi_Log1(afsd_logp, "smb_ReceiveNTCreateX creating directory [%s]",
3422 osi_LogSaveString(afsd_logp, treeStartp));
3423 openAction = 2; /* created directory */
3425 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3426 setAttr.clientModTime = time(NULL);
3433 tp = strchr(pp, '\\');
3436 isLast = 1; /* indicate last component. the supplied path never ends in a slash */
3440 strncpy(cp,pp,clen);
3446 if(clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
3448 /* cp is the next component to be created. */
3449 code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
3450 if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
3451 smb_NotifyChange(FILE_ACTION_ADDED,
3452 FILE_NOTIFY_CHANGE_DIR_NAME,
3453 tscp, cp, NULL, TRUE);
3455 (code == CM_ERROR_EXISTS && createDisp != 2)) {
3456 /* Not an exclusive create, and someone else tried
3457 * creating it already, then we open it anyway. We
3458 * don't bother retrying after this, since if this next
3459 * fails, that means that the file was deleted after we
3460 * started this call.
3462 code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
3467 if(!isLast) { /* for anything other than dscp, release it unless it's the last one */
3468 cm_ReleaseSCache(tscp);
3469 tscp = scp; /* Newly created directory will be next parent */
3474 if we get here and code == 0, then scp is the last directory created, and tscp is the
3475 parent of scp. dscp got released if dscp != tscp. both tscp and scp are held.
3481 /* something went wrong creating or truncating the file */
3482 if (scp) cm_ReleaseSCache(scp);
3483 if (dscp) cm_ReleaseSCache(dscp);
3484 cm_ReleaseUser(userp);
3489 /* make sure we have file vs. dir right (only applies for single component case) */
3490 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3491 cm_ReleaseSCache(scp);
3492 if (dscp) cm_ReleaseSCache(dscp);
3493 cm_ReleaseUser(userp);
3495 return CM_ERROR_ISDIR;
3497 /* (only applies to single component case) */
3498 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3499 cm_ReleaseSCache(scp);
3500 if (dscp) cm_ReleaseSCache(dscp);
3501 cm_ReleaseUser(userp);
3503 return CM_ERROR_NOTDIR;
3506 /* open the file itself */
3507 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3509 /* save a pointer to the vnode */
3512 fidp->flags = fidflags;
3514 /* save parent dir and pathname for delete or change notification */
3515 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3516 fidp->flags |= SMB_FID_NTOPEN;
3517 fidp->NTopen_dscp = dscp;
3518 cm_HoldSCache(dscp);
3519 fidp->NTopen_pathp = strdup(lastNamep);
3521 fidp->NTopen_wholepathp = realPathp;
3523 /* we don't need this any longer */
3524 if (dscp) cm_ReleaseSCache(dscp);
3525 cm_Open(scp, 0, userp);
3527 /* set inp->fid so that later read calls in same msg can find fid */
3528 inp->fid = fidp->fid;
3532 lock_ObtainMutex(&scp->mx);
3533 smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
3534 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3535 smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
3536 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3537 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3538 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3539 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3540 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3541 smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
3543 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3544 smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
3545 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
3546 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
3547 smb_SetSMBParmByte(outp, parmSlot,
3548 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
3549 lock_ReleaseMutex(&scp->mx);
3550 smb_SetSMBDataLength(outp, 0);
3552 osi_Log2(afsd_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
3553 osi_LogSaveString(afsd_logp, realPathp));
3555 smb_ReleaseFID(fidp);
3557 cm_ReleaseUser(userp);
3559 /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
3561 /* leave scp held since we put it in fidp->scp */
3566 * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
3567 * Instead, ultimately, would like to use a subroutine for common code.
3569 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3571 char *pathp, *realPathp;
3575 cm_scache_t *dscp; /* parent dir */
3576 cm_scache_t *scp; /* file to create or open */
3579 unsigned long nameLength;
3581 unsigned int requestOpLock;
3582 unsigned int requestBatchOpLock;
3583 unsigned int mustBeDir;
3584 unsigned int extendedRespRequired;
3586 unsigned int desiredAccess;
3587 #ifdef DEBUG_VERBOSE
3588 unsigned int allocSize;
3589 unsigned int shareAccess;
3591 unsigned int extAttributes;
3592 unsigned int createDisp;
3593 #ifdef DEBUG_VERBOSE
3596 unsigned int createOptions;
3597 int initialModeBits;
3598 unsigned short baseFid;
3599 smb_fid_t *baseFidp;
3601 cm_scache_t *baseDirp;
3602 unsigned short openAction;
3608 int parmOffset, dataOffset;
3619 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
3620 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
3621 parmp = inp->data + parmOffset;
3622 lparmp = (ULONG *) parmp;
3625 requestOpLock = flags & 0x02;
3626 requestBatchOpLock = flags & 0x04;
3627 mustBeDir = flags & 0x08;
3628 extendedRespRequired = flags & 0x10;
3631 * Why all of a sudden 32-bit FID?
3632 * We will reject all bits higher than 16.
3634 if (lparmp[1] & 0xFFFF0000)
3635 return CM_ERROR_INVAL;
3636 baseFid = (unsigned short)lparmp[1];
3637 desiredAccess = lparmp[2];
3638 #ifdef DEBUG_VERBOSE
3639 allocSize = lparmp[3];
3640 #endif /* DEBUG_VERSOSE */
3641 extAttributes = lparmp[5];
3643 shareAccess = lparmp[6];
3645 createDisp = lparmp[7];
3646 createOptions = lparmp[8];
3647 #ifdef DEBUG_VERBOSE
3650 nameLength = lparmp[11];
3652 #ifdef DEBUG_VERBOSE
3653 osi_Log4(afsd_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
3654 osi_Log2(afsd_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
3655 osi_Log1(afsd_logp,"... flags[%x]",flags);
3658 /* mustBeDir is never set; createOptions directory bit seems to be
3661 if (createOptions & 1)
3663 else if (createOptions & 0x40)
3669 * compute initial mode bits based on read-only flag in
3670 * extended attributes
3672 initialModeBits = 0666;
3673 if (extAttributes & 1) initialModeBits &= ~0222;
3675 pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
3676 /* Sometimes path is not null-terminated, so we make a copy. */
3677 realPathp = malloc(nameLength+1);
3678 memcpy(realPathp, pathp, nameLength);
3679 realPathp[nameLength] = 0;
3681 spacep = cm_GetSpace();
3682 smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3685 * Nothing here to handle SMB_IOCTL_FILENAME.
3686 * Will add it if necessary.
3689 #ifdef DEBUG_VERBOSE
3691 char *hexp, *asciip;
3692 asciip = (lastNamep? lastNamep : realPathp);
3693 hexp = osi_HexifyString( asciip );
3694 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
3699 userp = smb_GetUser(vcp, inp);
3701 osi_Log1(afsd_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
3703 return CM_ERROR_INVAL;
3707 baseDirp = cm_rootSCachep;
3708 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3711 baseFidp = smb_FindFID(vcp, baseFid, 0);
3713 osi_Log1(afsd_logp, "NTTranCreate Invalid fid [%d]", baseFid);
3715 cm_ReleaseUser(userp);
3716 return CM_ERROR_INVAL;
3718 baseDirp = baseFidp->scp;
3722 /* compute open mode */
3724 if (desiredAccess & DELETE)
3725 fidflags |= SMB_FID_OPENDELETE;
3726 if (desiredAccess & AFS_ACCESS_READ)
3727 fidflags |= SMB_FID_OPENREAD;
3728 if (desiredAccess & AFS_ACCESS_WRITE)
3729 fidflags |= SMB_FID_OPENWRITE;
3733 code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3734 userp, tidPathp, &req, &scp);
3735 if (code == 0) foundscp = TRUE;
3737 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
3738 /* look up parent directory */
3739 code = cm_NameI(baseDirp, spacep->data,
3740 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3741 userp, tidPathp, &req, &dscp);
3742 cm_FreeSpace(spacep);
3744 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3747 cm_ReleaseUser(userp);
3752 if (!lastNamep) lastNamep = realPathp;
3755 if (!smb_IsLegalFilename(lastNamep))
3756 return CM_ERROR_BADNTFILENAME;
3759 code = cm_Lookup(dscp, lastNamep,
3760 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3762 if (code && code != CM_ERROR_NOSUCHFILE) {
3763 cm_ReleaseSCache(dscp);
3764 cm_ReleaseUser(userp);
3771 if (baseFid != 0) smb_ReleaseFID(baseFidp);
3772 cm_FreeSpace(spacep);
3775 /* if we get here, if code is 0, the file exists and is represented by
3776 * scp. Otherwise, we have to create it. The dir may be represented
3777 * by dscp, or we may have found the file directly. If code is non-zero,
3781 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
3784 if (dscp) cm_ReleaseSCache(dscp);
3785 cm_ReleaseSCache(scp);
3786 cm_ReleaseUser(userp);
3791 if (createDisp == 2) {
3792 /* oops, file shouldn't be there */
3793 if (dscp) cm_ReleaseSCache(dscp);
3794 cm_ReleaseSCache(scp);
3795 cm_ReleaseUser(userp);
3797 return CM_ERROR_EXISTS;
3801 || createDisp == 5) {
3802 setAttr.mask = CM_ATTRMASK_LENGTH;
3803 setAttr.length.LowPart = 0;
3804 setAttr.length.HighPart = 0;
3805 code = cm_SetAttr(scp, &setAttr, userp, &req);
3806 openAction = 3; /* truncated existing file */
3808 else openAction = 1; /* found existing file */
3810 else if (createDisp == 1 || createDisp == 4) {
3811 /* don't create if not found */
3812 if (dscp) cm_ReleaseSCache(dscp);
3813 cm_ReleaseUser(userp);
3815 return CM_ERROR_NOSUCHFILE;
3817 else if (realDirFlag == 0 || realDirFlag == -1) {
3818 osi_assert(dscp != NULL);
3819 osi_Log1(afsd_logp, "smb_ReceiveNTTranCreate creating file %s",
3820 osi_LogSaveString(afsd_logp, lastNamep));
3821 openAction = 2; /* created file */
3822 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3823 setAttr.clientModTime = time(NULL);
3824 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3826 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3827 smb_NotifyChange(FILE_ACTION_ADDED,
3828 FILE_NOTIFY_CHANGE_FILE_NAME,
3829 dscp, lastNamep, NULL, TRUE);
3830 if (code == CM_ERROR_EXISTS && createDisp != 2) {
3831 /* Not an exclusive create, and someone else tried
3832 * creating it already, then we open it anyway. We
3833 * don't bother retrying after this, since if this next
3834 * fails, that means that the file was deleted after we
3835 * started this call.
3837 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3840 if (createDisp == 5) {
3841 setAttr.mask = CM_ATTRMASK_LENGTH;
3842 setAttr.length.LowPart = 0;
3843 setAttr.length.HighPart = 0;
3844 code = cm_SetAttr(scp, &setAttr, userp,
3847 } /* lookup succeeded */
3851 /* create directory */
3852 osi_assert(dscp != NULL);
3854 "smb_ReceiveNTTranCreate creating directory %s",
3855 osi_LogSaveString(afsd_logp, lastNamep));
3856 openAction = 2; /* created directory */
3857 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3858 setAttr.clientModTime = time(NULL);
3859 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
3860 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3861 smb_NotifyChange(FILE_ACTION_ADDED,
3862 FILE_NOTIFY_CHANGE_DIR_NAME,
3863 dscp, lastNamep, NULL, TRUE);
3865 || (code == CM_ERROR_EXISTS && createDisp != 2)) {
3866 /* Not an exclusive create, and someone else tried
3867 * creating it already, then we open it anyway. We
3868 * don't bother retrying after this, since if this next
3869 * fails, that means that the file was deleted after we
3870 * started this call.
3872 code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3878 /* something went wrong creating or truncating the file */
3879 if (scp) cm_ReleaseSCache(scp);
3880 cm_ReleaseUser(userp);
3885 /* make sure we have file vs. dir right */
3886 if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
3887 cm_ReleaseSCache(scp);
3888 cm_ReleaseUser(userp);
3890 return CM_ERROR_ISDIR;
3892 if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
3893 cm_ReleaseSCache(scp);
3894 cm_ReleaseUser(userp);
3896 return CM_ERROR_NOTDIR;
3899 /* open the file itself */
3900 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3903 /* save a pointer to the vnode */
3906 fidp->flags = fidflags;
3908 /* save parent dir and pathname for deletion or change notification */
3909 if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
3910 fidp->flags |= SMB_FID_NTOPEN;
3911 fidp->NTopen_dscp = dscp;
3912 cm_HoldSCache(dscp);
3913 fidp->NTopen_pathp = strdup(lastNamep);
3915 fidp->NTopen_wholepathp = realPathp;
3917 /* we don't need this any longer */
3918 if (dscp) cm_ReleaseSCache(dscp);
3920 cm_Open(scp, 0, userp);
3922 /* set inp->fid so that later read calls in same msg can find fid */
3923 inp->fid = fidp->fid;
3925 /* check whether we are required to send an extended response */
3926 if (!extendedRespRequired) {
3928 parmOffset = 8*4 + 39;
3929 parmOffset += 1; /* pad to 4 */
3930 dataOffset = parmOffset + 70;
3934 /* Total Parameter Count */
3935 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3936 /* Total Data Count */
3937 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3938 /* Parameter Count */
3939 smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
3940 /* Parameter Offset */
3941 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3942 /* Parameter Displacement */
3943 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3945 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3947 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3948 /* Data Displacement */
3949 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3950 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3951 smb_SetSMBDataLength(outp, 70);
3953 lock_ObtainMutex(&scp->mx);
3954 outData = smb_GetSMBData(outp, NULL);
3955 outData++; /* round to get to parmOffset */
3956 *outData = 0; outData++; /* oplock */
3957 *outData = 0; outData++; /* reserved */
3958 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
3959 *((ULONG *)outData) = openAction; outData += 4;
3960 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
3961 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3962 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
3963 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
3964 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
3965 *((FILETIME *)outData) = ft; outData += 8; /* change time */
3966 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
3967 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
3968 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
3969 *((USHORT *)outData) = 0; outData += 2; /* filetype */
3970 *((USHORT *)outData) = 0; outData += 2; /* dev state */
3971 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
3972 outData += 2; /* is a dir? */
3973 lock_ReleaseMutex(&scp->mx);
3976 parmOffset = 8*4 + 39;
3977 parmOffset += 1; /* pad to 4 */
3978 dataOffset = parmOffset + 104;
3982 /* Total Parameter Count */
3983 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
3984 /* Total Data Count */
3985 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3986 /* Parameter Count */
3987 smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
3988 /* Parameter Offset */
3989 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
3990 /* Parameter Displacement */
3991 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3993 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3995 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
3996 /* Data Displacement */
3997 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
3998 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
3999 smb_SetSMBDataLength(outp, 105);
4001 lock_ObtainMutex(&scp->mx);
4002 outData = smb_GetSMBData(outp, NULL);
4003 outData++; /* round to get to parmOffset */
4004 *outData = 0; outData++; /* oplock */
4005 *outData = 1; outData++; /* response type */
4006 *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4007 *((ULONG *)outData) = openAction; outData += 4;
4008 *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
4009 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4010 *((FILETIME *)outData) = ft; outData += 8; /* creation time */
4011 *((FILETIME *)outData) = ft; outData += 8; /* last access time */
4012 *((FILETIME *)outData) = ft; outData += 8; /* last write time */
4013 *((FILETIME *)outData) = ft; outData += 8; /* change time */
4014 *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4015 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4016 *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4017 *((USHORT *)outData) = 0; outData += 2; /* filetype */
4018 *((USHORT *)outData) = 0; outData += 2; /* dev state */
4019 *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4020 outData += 1; /* is a dir? */
4021 memset(outData,0,24); outData += 24; /* Volume ID and file ID */
4022 *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
4023 *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
4024 lock_ReleaseMutex(&scp->mx);
4027 osi_Log1(afsd_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
4029 smb_ReleaseFID(fidp);
4031 cm_ReleaseUser(userp);
4033 /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
4034 /* leave scp held since we put it in fidp->scp */
4038 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
4041 smb_packet_t *savedPacketp;
4042 ULONG filter; USHORT fid, watchtree;
4046 filter = smb_GetSMBParm(inp, 19)
4047 | (smb_GetSMBParm(inp, 20) << 16);
4048 fid = smb_GetSMBParm(inp, 21);
4049 watchtree = smb_GetSMBParm(inp, 22) && 0xffff; /* TODO: should this be 0xff ? */
4051 fidp = smb_FindFID(vcp, fid, 0);
4053 osi_Log1(afsd_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
4054 return CM_ERROR_BADFD;
4057 savedPacketp = smb_CopyPacket(inp);
4058 savedPacketp->vcp = vcp; /* TODO: refcount vcp? */
4059 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4060 savedPacketp->nextp = smb_Directory_Watches;
4061 smb_Directory_Watches = savedPacketp;
4062 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4064 fidp = smb_FindFID(vcp, fid, 0);
4067 osi_Log4(afsd_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
4068 filter, fid, watchtree, osi_LogSaveString(afsd_logp, fidp->NTopen_wholepathp));
4071 lock_ObtainMutex(&scp->mx);
4073 scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
4075 scp->flags |= CM_SCACHEFLAG_WATCHED;
4076 lock_ReleaseMutex(&scp->mx);
4077 smb_ReleaseFID(fidp);
4081 /* nothing - just a warning to main log file ... */
4082 afsi_log("Warning: cannot find fidp vcp = 0x%X, fid = %d", vcp, fid);
4085 outp->flags |= SMB_PACKETFLAG_NOSEND;
4090 unsigned char nullSecurityDesc[36] = {
4091 0x01, /* security descriptor revision */
4092 0x00, /* reserved, should be zero */
4093 0x00, 0x80, /* security descriptor control;
4094 * 0x8000 : self-relative format */
4095 0x14, 0x00, 0x00, 0x00, /* offset of owner SID */
4096 0x1c, 0x00, 0x00, 0x00, /* offset of group SID */
4097 0x00, 0x00, 0x00, 0x00, /* offset of DACL would go here */
4098 0x00, 0x00, 0x00, 0x00, /* offset of SACL would go here */
4099 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4100 /* "null SID" owner SID */
4101 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4102 /* "null SID" group SID */
4105 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4107 int parmOffset, parmCount, dataOffset, dataCount;
4115 ULONG securityInformation;
4117 parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4118 | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4119 parmp = inp->data + parmOffset;
4120 sparmp = (USHORT *) parmp;
4121 lparmp = (ULONG *) parmp;
4124 securityInformation = lparmp[1];
4126 maxData = smb_GetSMBOffsetParm(inp, 7, 1)
4127 | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4135 parmOffset = 8*4 + 39;
4136 parmOffset += 1; /* pad to 4 */
4138 dataOffset = parmOffset + parmCount;
4142 /* Total Parameter Count */
4143 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4144 /* Total Data Count */
4145 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4146 /* Parameter Count */
4147 smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
4148 /* Parameter Offset */
4149 smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4150 /* Parameter Displacement */
4151 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4153 smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
4155 smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4156 /* Data Displacement */
4157 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4158 smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
4159 smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
4161 outData = smb_GetSMBData(outp, NULL);
4162 outData++; /* round to get to parmOffset */
4163 *((ULONG *)outData) = 36; outData += 4; /* length */
4165 if (maxData >= 36) {
4166 memcpy(outData, nullSecurityDesc, 36);
4170 return CM_ERROR_BUFFERTOOSMALL;
4173 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4175 unsigned short function;
4177 function = smb_GetSMBParm(inp, 18);
4179 osi_Log1(afsd_logp, "SMB NT Transact function %d", function);
4181 /* We can handle long names */
4182 if (vcp->flags & SMB_VCFLAG_USENT)
4183 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
4187 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
4189 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
4191 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
4193 default: return CM_ERROR_INVAL;
4198 * smb_NotifyChange -- find relevant change notification messages and
4201 * If we don't know the file name (i.e. a callback break), filename is
4202 * NULL, and we return a zero-length list.
4204 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
4205 cm_scache_t *dscp, char *filename, char *otherFilename,
4206 BOOL isDirectParent)
4208 smb_packet_t *watch, *lastWatch, *nextWatch;
4209 ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
4210 char *outData, *oldOutData;
4214 BOOL twoEntries = FALSE;
4215 ULONG otherNameLen, oldParmCount = 0;
4220 /* Get ready for rename within directory */
4221 if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
4223 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
4226 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4227 watch = smb_Directory_Watches;
4229 filter = smb_GetSMBParm(watch, 19)
4230 | (smb_GetSMBParm(watch, 20) << 16);
4231 fid = smb_GetSMBParm(watch, 21);
4232 wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
4233 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
4234 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
4238 * Strange hack - bug in NT Client and NT Server that we
4241 if (filter == 3 && wtree)
4244 fidp = smb_FindFID(vcp, fid, 0);
4247 watch = watch->nextp;
4250 if (fidp->scp != dscp
4251 || (filter & notifyFilter) == 0
4252 || (!isDirectParent && !wtree)) {
4253 smb_ReleaseFID(fidp);
4255 watch = watch->nextp;
4258 smb_ReleaseFID(fidp);
4261 "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
4262 fid, filter, wtree, osi_LogSaveString(afsd_logp, filename));
4264 nextWatch = watch->nextp;
4265 if (watch == smb_Directory_Watches)
4266 smb_Directory_Watches = nextWatch;
4268 lastWatch->nextp = nextWatch;
4270 /* Turn off WATCHED flag in dscp */
4271 lock_ObtainMutex(&dscp->mx);
4273 dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4275 dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
4276 lock_ReleaseMutex(&dscp->mx);
4278 /* Convert to response packet */
4279 ((smb_t *) watch)->reb = 0x80;
4280 ((smb_t *) watch)->wct = 0;
4283 if (filename == NULL)
4286 nameLen = strlen(filename);
4287 parmCount = 3*4 + nameLen*2;
4288 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4290 otherNameLen = strlen(otherFilename);
4291 oldParmCount = parmCount;
4292 parmCount += 3*4 + otherNameLen*2;
4293 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
4295 if (maxLen < parmCount)
4296 parmCount = 0; /* not enough room */
4298 parmOffset = 8*4 + 39;
4299 parmOffset += 1; /* pad to 4 */
4300 dataOffset = parmOffset + parmCount;
4304 /* Total Parameter Count */
4305 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4306 /* Total Data Count */
4307 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4308 /* Parameter Count */
4309 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
4310 /* Parameter Offset */
4311 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
4312 /* Parameter Displacement */
4313 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4315 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4317 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
4318 /* Data Displacement */
4319 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
4320 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
4321 smb_SetSMBDataLength(watch, parmCount + 1);
4323 if (parmCount != 0) {
4324 outData = smb_GetSMBData(watch, NULL);
4325 outData++; /* round to get to parmOffset */
4326 oldOutData = outData;
4327 *((DWORD *)outData) = oldParmCount; outData += 4;
4328 /* Next Entry Offset */
4329 *((DWORD *)outData) = action; outData += 4;
4331 *((DWORD *)outData) = nameLen*2; outData += 4;
4332 /* File Name Length */
4333 mbstowcs((WCHAR *)outData, filename, nameLen);
4336 outData = oldOutData + oldParmCount;
4337 *((DWORD *)outData) = 0; outData += 4;
4338 /* Next Entry Offset */
4339 *((DWORD *)outData) = otherAction; outData += 4;
4341 *((DWORD *)outData) = otherNameLen*2;
4342 outData += 4; /* File Name Length */
4343 mbstowcs((WCHAR *)outData, otherFilename,
4344 otherNameLen); /* File Name */
4349 * If filename is null, we don't know the cause of the
4350 * change notification. We return zero data (see above),
4351 * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
4352 * (= 0x010C). We set the error code here by hand, without
4353 * modifying wct and bcc.
4355 if (filename == NULL) {
4356 ((smb_t *) watch)->rcls = 0x0C;
4357 ((smb_t *) watch)->reh = 0x01;
4358 ((smb_t *) watch)->errLow = 0;
4359 ((smb_t *) watch)->errHigh = 0;
4360 /* Set NT Status codes flag */
4361 ((smb_t *) watch)->flg2 |= 0x4000;
4364 smb_SendPacket(vcp, watch);
4365 smb_FreePacket(watch);
4368 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4371 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4373 unsigned char *replyWctp;
4374 smb_packet_t *watch, *lastWatch;
4375 USHORT fid, watchtree;
4379 osi_Log0(afsd_logp, "SMB3 receive NT cancel");
4381 lock_ObtainMutex(&smb_Dir_Watch_Lock);
4382 watch = smb_Directory_Watches;
4384 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
4385 && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
4386 && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
4387 && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
4388 if (watch == smb_Directory_Watches)
4389 smb_Directory_Watches = watch->nextp;
4391 lastWatch->nextp = watch->nextp;
4392 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4394 /* Turn off WATCHED flag in scp */
4395 fid = smb_GetSMBParm(watch, 21);
4396 watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
4398 fidp = smb_FindFID(vcp, fid, 0);
4400 osi_Log3(afsd_logp, "Cancelling change notification for fid %d wtree %d file %s",
4402 osi_LogSaveString(afsd_logp, (fidp)?fidp->NTopen_wholepathp:""));
4405 lock_ObtainMutex(&scp->mx);
4407 scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
4409 scp->flags &= ~CM_SCACHEFLAG_WATCHED;
4410 lock_ReleaseMutex(&scp->mx);
4411 smb_ReleaseFID(fidp);
4413 osi_Log2(afsd_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
4416 /* assume STATUS32; return 0xC0000120 (CANCELED) */
4417 replyWctp = watch->wctp;
4421 ((smb_t *)watch)->rcls = 0x20;
4422 ((smb_t *)watch)->reh = 0x1;
4423 ((smb_t *)watch)->errLow = 0;
4424 ((smb_t *)watch)->errHigh = 0xC0;
4425 ((smb_t *)watch)->flg2 |= 0x4000;
4426 smb_SendPacket(vcp, watch);
4427 smb_FreePacket(watch);
4431 watch = watch->nextp;
4433 lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4440 lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
4443 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
4446 smb_username_t *unp;
4448 unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
4450 lock_ObtainMutex(&unp->mx);
4451 unp->userp = cm_NewUser();
4452 lock_ReleaseMutex(&unp->mx);
4453 osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
4455 osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);