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>
25 #include <rx/rx_prototypes.h>
26 #include <WINNT\afsreg.h>
29 #include "lanahelper.h"
31 /* These characters are illegal in Windows filenames */
32 static char *illegalChars = "\\/:*?\"<>|";
34 int smbShutdownFlag = 0;
36 int smb_LogoffTokenTransfer;
37 time_t smb_LogoffTransferTimeout;
39 int smb_StoreAnsiFilenames = 0;
41 DWORD last_msg_time = 0;
45 unsigned int sessionGen = 0;
47 extern void afsi_log(char *pattern, ...);
48 extern HANDLE afsi_file;
50 osi_hyper_t hzero = {0, 0};
51 osi_hyper_t hones = {0xFFFFFFFF, -1};
54 osi_rwlock_t smb_globalLock;
55 osi_rwlock_t smb_rctLock;
56 osi_mutex_t smb_ListenerLock;
59 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
62 long smb_maxObsConcurrentCalls=0;
63 long smb_concurrentCalls=0;
65 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
67 smb_packet_t *smb_packetFreeListp;
68 smb_ncb_t *smb_ncbFreeListp;
70 int smb_NumServerThreads;
72 int numNCBs, numSessions, numVCs;
74 int smb_maxVCPerServer;
75 int smb_maxMpxRequests;
77 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
79 ULONG smb_lsaSecPackage;
80 LSA_STRING smb_lsaLogonOrigin;
82 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
83 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
84 EVENT_HANDLE **NCBreturns;
85 EVENT_HANDLE **NCBShutdown;
86 EVENT_HANDLE *smb_ServerShutdown;
87 DWORD NCBsessions[NCB_MAX];
89 struct smb_packet *bufs[NCB_MAX];
91 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
92 EVENT_HANDLE SessionEvents[SESSION_MAX];
93 unsigned short LSNs[SESSION_MAX];
94 int lanas[SESSION_MAX];
95 BOOL dead_sessions[SESSION_MAX];
99 osi_mutex_t smb_RawBufLock;
102 #define SMB_MASKFLAG_TILDE 1
103 #define SMB_MASKFLAG_CASEFOLD 2
105 #define RAWTIMEOUT INFINITE
108 typedef struct raw_write_cont {
117 /* dir search stuff */
118 long smb_dirSearchCounter = 1;
119 smb_dirSearch_t *smb_firstDirSearchp;
120 smb_dirSearch_t *smb_lastDirSearchp;
122 /* hide dot files? */
123 int smb_hideDotFiles;
125 /* global state about V3 protocols */
126 int smb_useV3; /* try to negotiate V3 */
128 static showErrors = 0;
129 /* MessageBox or something like it */
130 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
133 * Time in Unix format of midnight, 1/1/1970 local time.
134 * When added to dosUTime, gives Unix (AFS) time.
136 time_t smb_localZero = 0;
138 #define USE_NUMERIC_TIME_CONV 1
140 #ifndef USE_NUMERIC_TIME_CONV
141 /* Time difference for converting to kludge-GMT */
142 afs_uint32 smb_NowTZ;
143 #endif /* USE_NUMERIC_TIME_CONV */
145 char *smb_localNamep = NULL;
147 smb_vc_t *smb_allVCsp;
148 smb_vc_t *smb_deadVCsp;
150 smb_username_t *usernamesp = NULL;
152 smb_waitingLockRequest_t *smb_allWaitingLocks;
154 DWORD smb_TlsRequestSlot = -1;
157 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
158 NCB *ncbp, raw_write_cont_t *rwcp);
159 void smb_NetbiosInit();
162 void smb_LogPacket(smb_packet_t *packet);
163 #endif /* LOG_PACKET */
165 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
166 int smb_ServerDomainNameLength = 0;
167 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
168 int smb_ServerOSLength = sizeof(smb_ServerOS);
169 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
170 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
172 /* Faux server GUID. This is never checked. */
173 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
175 void smb_ResetServerPriority()
177 void * p = TlsGetValue(smb_TlsRequestSlot);
180 TlsSetValue(smb_TlsRequestSlot, NULL);
181 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
185 void smb_SetRequestStartTime()
187 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
189 tp = malloc(sizeof(time_t));
193 if (!TlsSetValue(smb_TlsRequestSlot, tp))
198 void smb_UpdateServerPriority()
200 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
203 time_t now = osi_Time();
205 /* Give one priority boost for each 15 seconds */
206 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
211 const char * ncb_error_string(int code)
215 case 0x01: s = "llegal buffer length"; break;
216 case 0x03: s = "illegal command"; break;
217 case 0x05: s = "command timed out"; break;
218 case 0x06: s = "message incomplete, issue another command"; break;
219 case 0x07: s = "illegal buffer address"; break;
220 case 0x08: s = "session number out of range"; break;
221 case 0x09: s = "no resource available"; break;
222 case 0x0a: s = "session closed"; break;
223 case 0x0b: s = "command cancelled"; break;
224 case 0x0d: s = "duplicate name"; break;
225 case 0x0e: s = "name table full"; break;
226 case 0x0f: s = "no deletions, name has active sessions"; break;
227 case 0x11: s = "local session table full"; break;
228 case 0x12: s = "remote session table full"; break;
229 case 0x13: s = "illegal name number"; break;
230 case 0x14: s = "no callname"; break;
231 case 0x15: s = "cannot put * in NCB_NAME"; break;
232 case 0x16: s = "name in use on remote adapter"; break;
233 case 0x17: s = "name deleted"; break;
234 case 0x18: s = "session ended abnormally"; break;
235 case 0x19: s = "name conflict detected"; break;
236 case 0x21: s = "interface busy, IRET before retrying"; break;
237 case 0x22: s = "too many commands outstanding, retry later";break;
238 case 0x23: s = "ncb_lana_num field invalid"; break;
239 case 0x24: s = "command completed while cancel occurring "; break;
240 case 0x26: s = "command not valid to cancel"; break;
241 case 0x30: s = "name defined by anther local process"; break;
242 case 0x34: s = "environment undefined. RESET required"; break;
243 case 0x35: s = "required OS resources exhausted"; break;
244 case 0x36: s = "max number of applications exceeded"; break;
245 case 0x37: s = "no saps available for netbios"; break;
246 case 0x38: s = "requested resources are not available"; break;
247 case 0x39: s = "invalid ncb address or length > segment"; break;
248 case 0x3B: s = "invalid NCB DDID"; break;
249 case 0x3C: s = "lock of user area failed"; break;
250 case 0x3f: s = "NETBIOS not loaded"; break;
251 case 0x40: s = "system error"; break;
252 default: s = "unknown error";
258 char * myCrt_Dispatch(int i)
263 return "(00)ReceiveCoreMakeDir";
265 return "(01)ReceiveCoreRemoveDir";
267 return "(02)ReceiveCoreOpen";
269 return "(03)ReceiveCoreCreate";
271 return "(04)ReceiveCoreClose";
273 return "(05)ReceiveCoreFlush";
275 return "(06)ReceiveCoreUnlink";
277 return "(07)ReceiveCoreRename";
279 return "(08)ReceiveCoreGetFileAttributes";
281 return "(09)ReceiveCoreSetFileAttributes";
283 return "(0a)ReceiveCoreRead";
285 return "(0b)ReceiveCoreWrite";
287 return "(0c)ReceiveCoreLockRecord";
289 return "(0d)ReceiveCoreUnlockRecord";
291 return "(0e)SendCoreBadOp";
293 return "(0f)ReceiveCoreCreate";
295 return "(10)ReceiveCoreCheckPath";
297 return "(11)SendCoreBadOp";
299 return "(12)ReceiveCoreSeek";
301 return "(1a)ReceiveCoreReadRaw";
303 return "(1d)ReceiveCoreWriteRawDummy";
305 return "(22)ReceiveV3SetAttributes";
307 return "(23)ReceiveV3GetAttributes";
309 return "(24)ReceiveV3LockingX";
311 return "(25)ReceiveV3Trans";
313 return "(26)ReceiveV3Trans[aux]";
315 return "(29)SendCoreBadOp";
317 return "(2b)ReceiveCoreEcho";
319 return "(2d)ReceiveV3OpenX";
321 return "(2e)ReceiveV3ReadX";
323 return "(2f)ReceiveV3WriteX";
325 return "(32)ReceiveV3Tran2A";
327 return "(33)ReceiveV3Tran2A[aux]";
329 return "(34)ReceiveV3FindClose";
331 return "(35)ReceiveV3FindNotifyClose";
333 return "(70)ReceiveCoreTreeConnect";
335 return "(71)ReceiveCoreTreeDisconnect";
337 return "(72)ReceiveNegotiate";
339 return "(73)ReceiveV3SessionSetupX";
341 return "(74)ReceiveV3UserLogoffX";
343 return "(75)ReceiveV3TreeConnectX";
345 return "(80)ReceiveCoreGetDiskAttributes";
347 return "(81)ReceiveCoreSearchDir";
351 return "(83)FindUnique";
353 return "(84)FindClose";
355 return "(A0)ReceiveNTTransact";
357 return "(A2)ReceiveNTCreateX";
359 return "(A4)ReceiveNTCancel";
361 return "(A5)ReceiveNTRename";
363 return "(C0)OpenPrintFile";
365 return "(C1)WritePrintFile";
367 return "(C2)ClosePrintFile";
369 return "(C3)GetPrintQueue";
371 return "(D8)ReadBulk";
373 return "(D9)WriteBulk";
375 return "(DA)WriteBulkData";
377 return "unknown SMB op";
381 char * myCrt_2Dispatch(int i)
386 return "unknown SMB op-2";
388 return "S(00)CreateFile_ReceiveTran2Open";
390 return "S(01)FindFirst_ReceiveTran2SearchDir";
392 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
394 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
396 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
398 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
400 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
402 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
404 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
406 return "S(09)_ReceiveTran2FSCTL";
408 return "S(0a)_ReceiveTran2IOCTL";
410 return "S(0b)_ReceiveTran2FindNotifyFirst";
412 return "S(0c)_ReceiveTran2FindNotifyNext";
414 return "S(0d)_ReceiveTran2CreateDirectory";
416 return "S(0e)_ReceiveTran2SessionSetup";
418 return "S(0f)_QueryFileSystemInformationFid";
420 return "S(10)_ReceiveTran2GetDfsReferral";
422 return "S(11)_ReceiveTran2ReportDfsInconsistency";
426 char * myCrt_RapDispatch(int i)
431 return "unknown RAP OP";
433 return "RAP(0)NetShareEnum";
435 return "RAP(1)NetShareGetInfo";
437 return "RAP(13)NetServerGetInfo";
439 return "RAP(63)NetWkStaGetInfo";
443 /* scache must be locked */
444 unsigned int smb_Attributes(cm_scache_t *scp)
448 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
449 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
450 scp->fileType == CM_SCACHETYPE_INVALID)
452 attrs = SMB_ATTR_DIRECTORY;
453 #ifdef SPECIAL_FOLDERS
454 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
455 #endif /* SPECIAL_FOLDERS */
456 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
457 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
462 * We used to mark a file RO if it was in an RO volume, but that
463 * turns out to be impolitic in NT. See defect 10007.
466 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
467 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
469 if ((scp->unixModeBits & 0222) == 0)
470 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
476 /* Check if the named file/dir is a dotfile/dotdir */
477 /* String pointed to by lastComp can have leading slashes, but otherwise should have
478 no other patch components */
479 unsigned int smb_IsDotFile(char *lastComp) {
482 /* skip over slashes */
483 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
488 /* nulls, curdir and parent dir doesn't count */
494 if(*(s+1) == '.' && !*(s + 2))
501 static int ExtractBits(WORD bits, short start, short len)
508 num = bits << (16 - end);
509 num = num >> ((16 - end) + start);
514 void ShowUnixTime(char *FuncName, time_t unixTime)
519 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
521 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
522 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
524 int day, month, year, sec, min, hour;
527 day = ExtractBits(wDate, 0, 5);
528 month = ExtractBits(wDate, 5, 4);
529 year = ExtractBits(wDate, 9, 7) + 1980;
531 sec = ExtractBits(wTime, 0, 5);
532 min = ExtractBits(wTime, 5, 6);
533 hour = ExtractBits(wTime, 11, 5);
535 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
536 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
540 /* Determine if we are observing daylight savings time */
541 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
543 TIME_ZONE_INFORMATION timeZoneInformation;
544 SYSTEMTIME utc, local, localDST;
546 /* Get the time zone info. NT uses this to calc if we are in DST. */
547 GetTimeZoneInformation(&timeZoneInformation);
549 /* Return the daylight bias */
550 *pDstBias = timeZoneInformation.DaylightBias;
552 /* Return the bias */
553 *pBias = timeZoneInformation.Bias;
555 /* Now determine if DST is being observed */
557 /* Get the UTC (GMT) time */
560 /* Convert UTC time to local time using the time zone info. If we are
561 observing DST, the calculated local time will include this.
563 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
565 /* Set the daylight bias to 0. The daylight bias is the amount of change
566 * in time that we use for daylight savings time. By setting this to 0
567 * we cause there to be no change in time during daylight savings time.
569 timeZoneInformation.DaylightBias = 0;
571 /* Convert the utc time to local time again, but this time without any
572 adjustment for daylight savings time.
574 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
576 /* If the two times are different, then it means that the localDST that
577 we calculated includes the daylight bias, and therefore we are
578 observing daylight savings time.
580 *pDST = localDST.wHour != local.wHour;
584 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
586 BOOL dst; /* Will be TRUE if observing DST */
587 LONG dstBias; /* Offset from local time if observing DST */
588 LONG bias; /* Offset from GMT for local time */
591 * This function will adjust the last write time to compensate
592 * for two bugs in the smb client:
594 * 1) During Daylight Savings Time, the LastWriteTime is ahead
595 * in time by the DaylightBias (ignoring the sign - the
596 * DaylightBias is always stored as a negative number). If
597 * the DaylightBias is -60, then the LastWriteTime will be
598 * ahead by 60 minutes.
600 * 2) If the local time zone is a positive offset from GMT, then
601 * the LastWriteTime will be the correct local time plus the
602 * Bias (ignoring the sign - a positive offset from GMT is
603 * always stored as a negative Bias). If the Bias is -120,
604 * then the LastWriteTime will be ahead by 120 minutes.
606 * These bugs can occur at the same time.
609 GetTimeZoneInfo(&dst, &dstBias, &bias);
611 /* First adjust for DST */
613 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
615 /* Now adjust for a positive offset from GMT (a negative bias). */
617 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
620 #ifndef USE_NUMERIC_TIME_CONV
622 * Calculate the difference (in seconds) between local time and GMT.
623 * This enables us to convert file times to kludge-GMT.
629 struct tm gmt_tm, local_tm;
630 int days, hours, minutes, seconds;
633 gmt_tm = *(gmtime(&t));
634 local_tm = *(localtime(&t));
636 days = local_tm.tm_yday - gmt_tm.tm_yday;
637 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
638 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
639 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
643 #endif /* USE_NUMERIC_TIME_CONV */
645 #ifdef USE_NUMERIC_TIME_CONV
646 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
648 // Note that LONGLONG is a 64-bit value
651 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
652 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
653 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
656 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
661 time_t ersatz_unixTime;
664 * Must use kludge-GMT instead of real GMT.
665 * kludge-GMT is computed by adding time zone difference to localtime.
668 * ltp = gmtime(&unixTime);
670 ersatz_unixTime = unixTime - smb_NowTZ;
671 ltp = localtime(&ersatz_unixTime);
673 /* if we fail, make up something */
676 localJunk.tm_year = 89 - 20;
677 localJunk.tm_mon = 4;
678 localJunk.tm_mday = 12;
679 localJunk.tm_hour = 0;
680 localJunk.tm_min = 0;
681 localJunk.tm_sec = 0;
684 stm.wYear = ltp->tm_year + 1900;
685 stm.wMonth = ltp->tm_mon + 1;
686 stm.wDayOfWeek = ltp->tm_wday;
687 stm.wDay = ltp->tm_mday;
688 stm.wHour = ltp->tm_hour;
689 stm.wMinute = ltp->tm_min;
690 stm.wSecond = ltp->tm_sec;
691 stm.wMilliseconds = 0;
693 SystemTimeToFileTime(&stm, largeTimep);
695 #endif /* USE_NUMERIC_TIME_CONV */
697 #ifdef USE_NUMERIC_TIME_CONV
698 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
700 // Note that LONGLONG is a 64-bit value
703 ll = largeTimep->dwHighDateTime;
705 ll += largeTimep->dwLowDateTime;
707 ll -= 116444736000000000;
710 *unixTimep = (DWORD)ll;
712 #else /* USE_NUMERIC_TIME_CONV */
713 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
719 FileTimeToSystemTime(largeTimep, &stm);
721 lt.tm_year = stm.wYear - 1900;
722 lt.tm_mon = stm.wMonth - 1;
723 lt.tm_wday = stm.wDayOfWeek;
724 lt.tm_mday = stm.wDay;
725 lt.tm_hour = stm.wHour;
726 lt.tm_min = stm.wMinute;
727 lt.tm_sec = stm.wSecond;
730 save_timezone = _timezone;
731 _timezone += smb_NowTZ;
732 *unixTimep = mktime(<);
733 _timezone = save_timezone;
735 #endif /* USE_NUMERIC_TIME_CONV */
737 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
747 /* if we fail, make up something */
750 localJunk.tm_year = 89 - 20;
751 localJunk.tm_mon = 4;
752 localJunk.tm_mday = 12;
753 localJunk.tm_hour = 0;
754 localJunk.tm_min = 0;
755 localJunk.tm_sec = 0;
758 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
759 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
760 *searchTimep = (dosDate<<16) | dosTime;
763 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
765 unsigned short dosDate;
766 unsigned short dosTime;
769 dosDate = (unsigned short) (searchTime & 0xffff);
770 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
772 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
773 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
774 localTm.tm_mday = (dosDate) & 0x1f;
775 localTm.tm_hour = (dosTime>>11) & 0x1f;
776 localTm.tm_min = (dosTime >> 5) & 0x3f;
777 localTm.tm_sec = (dosTime & 0x1f) * 2;
778 localTm.tm_isdst = -1; /* compute whether DST in effect */
780 *unixTimep = mktime(&localTm);
783 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
785 time_t diff_t = unixTime - smb_localZero;
786 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
787 osi_assert(diff_t < _UI32_MAX);
789 *dosUTimep = (afs_uint32)diff_t;
792 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
794 *unixTimep = dosTime + smb_localZero;
797 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
801 lock_ObtainWrite(&smb_rctLock);
802 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
803 if (vcp->magic != SMB_VC_MAGIC)
804 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
807 if (lsn == vcp->lsn && lana == vcp->lana &&
808 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
809 smb_HoldVCNoLock(vcp);
813 if (!vcp && (flags & SMB_FLAG_CREATE)) {
814 vcp = malloc(sizeof(*vcp));
815 memset(vcp, 0, sizeof(*vcp));
816 lock_ObtainWrite(&smb_globalLock);
817 vcp->vcID = ++numVCs;
818 lock_ReleaseWrite(&smb_globalLock);
819 vcp->magic = SMB_VC_MAGIC;
820 vcp->refCount = 2; /* smb_allVCsp and caller */
823 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
824 vcp->nextp = smb_allVCsp;
826 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
831 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
832 /* We must obtain a challenge for extended auth
833 * in case the client negotiates smb v3
835 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
836 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
837 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
838 ULONG lsaRespSize = 0;
840 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
842 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
849 if (nts != STATUS_SUCCESS)
850 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
851 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
852 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
854 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
855 LsaFreeReturnBuffer(lsaResp);
858 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
860 if (numVCs >= CM_SESSION_RESERVED) {
861 lock_ObtainWrite(&smb_globalLock);
863 lock_ReleaseWrite(&smb_globalLock);
864 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
867 lock_ReleaseWrite(&smb_rctLock);
871 int smb_IsStarMask(char *maskp)
876 for(i=0; i<11; i++) {
878 if (tc == '?' || tc == '*' || tc == '>')
884 void smb_ReleaseVCInternal(smb_vc_t *vcp)
891 if (vcp->refCount == 0) {
892 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
893 /* remove VCP from smb_deadVCsp */
894 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
900 lock_FinalizeMutex(&vcp->mx);
901 memset(vcp,0,sizeof(smb_vc_t));
904 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
908 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
909 avcp?"not ":"",vcp, vcp->refCount);
911 GenerateMiniDump(NULL);
913 /* This is a wrong. However, I suspect that there is an undercount
914 * and I don't want to release 1.4.1 in a state that will allow
915 * smb_vc_t objects to be deallocated while still in the
916 * smb_allVCsp list. The list is supposed to keep a reference
917 * to the smb_vc_t. Put it back.
924 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
926 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
927 smb_ReleaseVCInternal(vcp);
930 void smb_ReleaseVC(smb_vc_t *vcp)
932 lock_ObtainWrite(&smb_rctLock);
933 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
934 smb_ReleaseVCInternal(vcp);
935 lock_ReleaseWrite(&smb_rctLock);
938 void smb_HoldVCNoLock(smb_vc_t *vcp)
941 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
944 void smb_HoldVC(smb_vc_t *vcp)
946 lock_ObtainWrite(&smb_rctLock);
948 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
949 lock_ReleaseWrite(&smb_rctLock);
952 void smb_CleanupDeadVC(smb_vc_t *vcp)
960 smb_user_t *uidpIter;
961 smb_user_t *uidpNext;
965 lock_ObtainMutex(&vcp->mx);
966 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
967 lock_ReleaseMutex(&vcp->mx);
968 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
971 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
972 lock_ReleaseMutex(&vcp->mx);
973 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
975 lock_ObtainWrite(&smb_rctLock);
976 /* remove VCP from smb_allVCsp */
977 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
978 if ((*vcpp)->magic != SMB_VC_MAGIC)
979 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
983 vcp->nextp = smb_deadVCsp;
985 /* Hold onto the reference until we are done with this function */
990 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
991 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
993 if (fidpIter->delete)
997 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
999 smb_HoldFIDNoLock(fidpIter);
1000 lock_ReleaseWrite(&smb_rctLock);
1002 smb_CloseFID(vcp, fidpIter, NULL, 0);
1003 smb_ReleaseFID(fidpIter);
1005 lock_ObtainWrite(&smb_rctLock);
1006 fidpNext = vcp->fidsp;
1009 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1010 tidpNext = tidpIter->nextp;
1011 if (tidpIter->delete)
1013 tidpIter->delete = 1;
1015 tid = tidpIter->tid;
1016 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1018 smb_HoldTIDNoLock(tidpIter);
1019 lock_ReleaseWrite(&smb_rctLock);
1021 smb_ReleaseTID(tidpIter);
1023 lock_ObtainWrite(&smb_rctLock);
1024 tidpNext = vcp->tidsp;
1027 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1028 uidpNext = uidpIter->nextp;
1029 if (uidpIter->delete)
1031 uidpIter->delete = 1;
1033 /* do not add an additional reference count for the smb_user_t
1034 * as the smb_vc_t already is holding a reference */
1035 lock_ReleaseWrite(&smb_rctLock);
1037 smb_ReleaseUID(uidpIter);
1039 lock_ObtainWrite(&smb_rctLock);
1040 uidpNext = vcp->usersp;
1043 /* The vcp is now on the deadVCsp list. We intentionally drop the
1044 * reference so that the refcount can reach 0 and we can delete it */
1045 smb_ReleaseVCNoLock(vcp);
1047 lock_ReleaseWrite(&smb_rctLock);
1048 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1051 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1055 lock_ObtainWrite(&smb_rctLock);
1057 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1058 if (tidp->refCount == 0 && tidp->delete) {
1060 lock_ReleaseWrite(&smb_rctLock);
1061 smb_ReleaseTID(tidp);
1062 lock_ObtainWrite(&smb_rctLock);
1066 if (tid == tidp->tid) {
1071 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1072 tidp = malloc(sizeof(*tidp));
1073 memset(tidp, 0, sizeof(*tidp));
1074 tidp->nextp = vcp->tidsp;
1077 smb_HoldVCNoLock(vcp);
1079 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1082 lock_ReleaseWrite(&smb_rctLock);
1086 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1091 void smb_ReleaseTID(smb_tid_t *tidp)
1098 lock_ObtainWrite(&smb_rctLock);
1099 osi_assert(tidp->refCount-- > 0);
1100 if (tidp->refCount == 0 && (tidp->delete)) {
1101 ltpp = &tidp->vcp->tidsp;
1102 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1106 osi_assert(tp != NULL);
1108 lock_FinalizeMutex(&tidp->mx);
1109 userp = tidp->userp; /* remember to drop ref later */
1111 smb_ReleaseVCNoLock(tidp->vcp);
1114 lock_ReleaseWrite(&smb_rctLock);
1116 cm_ReleaseUser(userp);
1119 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1121 smb_user_t *uidp = NULL;
1123 lock_ObtainWrite(&smb_rctLock);
1124 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1125 if (uid == uidp->userID) {
1127 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1129 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1133 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1134 uidp = malloc(sizeof(*uidp));
1135 memset(uidp, 0, sizeof(*uidp));
1136 uidp->nextp = vcp->usersp;
1137 uidp->refCount = 2; /* one for the vcp and one for the caller */
1139 smb_HoldVCNoLock(vcp);
1141 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1143 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1145 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1147 lock_ReleaseWrite(&smb_rctLock);
1151 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1153 smb_username_t *unp= NULL;
1155 lock_ObtainWrite(&smb_rctLock);
1156 for(unp = usernamesp; unp; unp = unp->nextp) {
1157 if (stricmp(unp->name, usern) == 0 &&
1158 stricmp(unp->machine, machine) == 0) {
1163 if (!unp && (flags & SMB_FLAG_CREATE)) {
1164 unp = malloc(sizeof(*unp));
1165 memset(unp, 0, sizeof(*unp));
1167 unp->nextp = usernamesp;
1168 unp->name = strdup(usern);
1169 unp->machine = strdup(machine);
1171 lock_InitializeMutex(&unp->mx, "username_t mutex");
1172 if (flags & SMB_FLAG_AFSLOGON)
1173 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1176 lock_ReleaseWrite(&smb_rctLock);
1180 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1182 smb_user_t *uidp= NULL;
1184 lock_ObtainWrite(&smb_rctLock);
1185 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1188 if (stricmp(uidp->unp->name, usern) == 0) {
1190 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1191 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1196 lock_ReleaseWrite(&smb_rctLock);
1200 void smb_ReleaseUsername(smb_username_t *unp)
1203 smb_username_t **lupp;
1204 cm_user_t *userp = NULL;
1205 time_t now = osi_Time();
1207 lock_ObtainWrite(&smb_rctLock);
1208 osi_assert(unp->refCount-- > 0);
1209 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1210 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1212 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1216 osi_assert(up != NULL);
1218 up->nextp = NULL; /* do not remove this */
1219 lock_FinalizeMutex(&unp->mx);
1225 lock_ReleaseWrite(&smb_rctLock);
1228 cm_ReleaseUser(userp);
1232 void smb_HoldUIDNoLock(smb_user_t *uidp)
1237 void smb_ReleaseUID(smb_user_t *uidp)
1241 smb_username_t *unp = NULL;
1243 lock_ObtainWrite(&smb_rctLock);
1244 osi_assert(uidp->refCount-- > 0);
1245 if (uidp->refCount == 0) {
1246 lupp = &uidp->vcp->usersp;
1247 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1251 osi_assert(up != NULL);
1253 lock_FinalizeMutex(&uidp->mx);
1255 smb_ReleaseVCNoLock(uidp->vcp);
1259 lock_ReleaseWrite(&smb_rctLock);
1263 cm_ReleaseUserVCRef(unp->userp);
1264 smb_ReleaseUsername(unp);
1268 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1270 cm_user_t *up = NULL;
1275 lock_ObtainMutex(&uidp->mx);
1277 up = uidp->unp->userp;
1280 lock_ReleaseMutex(&uidp->mx);
1286 /* retrieve a held reference to a user structure corresponding to an incoming
1288 * corresponding release function is cm_ReleaseUser.
1290 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1293 cm_user_t *up = NULL;
1296 smbp = (smb_t *) inp;
1297 uidp = smb_FindUID(vcp, smbp->uid, 0);
1301 up = smb_GetUserFromUID(uidp);
1303 smb_ReleaseUID(uidp);
1308 * Return a pointer to a pathname extracted from a TID structure. The
1309 * TID structure is not held; assume it won't go away.
1311 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1316 tidp = smb_FindTID(vcp, tid, 0);
1320 if (tidp->flags & SMB_TIDFLAG_IPC) {
1321 code = CM_ERROR_TIDIPC;
1322 /* tidp->pathname would be NULL, but that's fine */
1324 *treepath = tidp->pathname;
1325 smb_ReleaseTID(tidp);
1330 /* check to see if we have a chained fid, that is, a fid that comes from an
1331 * OpenAndX message that ran earlier in this packet. In this case, the fid
1332 * field in a read, for example, request, isn't set, since the value is
1333 * supposed to be inherited from the openAndX call.
1335 int smb_ChainFID(int fid, smb_packet_t *inp)
1337 if (inp->fid == 0 || inp->inCount == 0)
1343 /* are we a priv'd user? What does this mean on NT? */
1344 int smb_SUser(cm_user_t *userp)
1349 /* find a file ID. If we pass in 0 we select an unused File ID.
1350 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1351 * smb_fid_t data structure if desired File ID cannot be found.
1353 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1358 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1361 lock_ObtainWrite(&smb_rctLock);
1362 /* figure out if we need to allocate a new file ID */
1365 fid = vcp->fidCounter;
1369 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1370 if (fidp->refCount == 0 && fidp->delete) {
1372 lock_ReleaseWrite(&smb_rctLock);
1373 smb_ReleaseFID(fidp);
1374 lock_ObtainWrite(&smb_rctLock);
1377 if (fid == fidp->fid) {
1380 if (fid == 0xFFFF) {
1382 "New FID number wraps on vcp 0x%x", vcp);
1392 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1393 char eventName[MAX_PATH];
1395 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1396 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1397 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1398 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1399 thrd_CloseHandle(event);
1401 if (fid == 0xFFFF) {
1402 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1408 fidp = malloc(sizeof(*fidp));
1409 memset(fidp, 0, sizeof(*fidp));
1410 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1413 smb_HoldVCNoLock(vcp);
1414 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1416 fidp->curr_chunk = fidp->prev_chunk = -2;
1417 fidp->raw_write_event = event;
1419 vcp->fidCounter = fid+1;
1420 if (vcp->fidCounter == 0xFFFF) {
1421 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1423 vcp->fidCounter = 1;
1428 lock_ReleaseWrite(&smb_rctLock);
1432 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1434 smb_fid_t *fidp = NULL;
1440 lock_ObtainWrite(&smb_rctLock);
1441 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1442 if (scp == fidp->scp) {
1447 lock_ReleaseWrite(&smb_rctLock);
1451 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1456 void smb_ReleaseFID(smb_fid_t *fidp)
1458 cm_scache_t *scp = NULL;
1459 cm_user_t *userp = NULL;
1460 smb_vc_t *vcp = NULL;
1461 smb_ioctl_t *ioctlp;
1463 lock_ObtainMutex(&fidp->mx);
1464 lock_ObtainWrite(&smb_rctLock);
1465 osi_assert(fidp->refCount-- > 0);
1466 if (fidp->refCount == 0 && (fidp->delete)) {
1469 scp = fidp->scp; /* release after lock is released */
1471 userp = fidp->userp;
1475 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1476 thrd_CloseHandle(fidp->raw_write_event);
1478 /* and see if there is ioctl stuff to free */
1479 ioctlp = fidp->ioctlp;
1482 cm_FreeSpace(ioctlp->prefix);
1483 if (ioctlp->inAllocp)
1484 free(ioctlp->inAllocp);
1485 if (ioctlp->outAllocp)
1486 free(ioctlp->outAllocp);
1489 lock_ReleaseMutex(&fidp->mx);
1490 lock_FinalizeMutex(&fidp->mx);
1494 smb_ReleaseVCNoLock(vcp);
1496 lock_ReleaseMutex(&fidp->mx);
1498 lock_ReleaseWrite(&smb_rctLock);
1500 /* now release the scache structure */
1502 cm_ReleaseSCache(scp);
1505 cm_ReleaseUser(userp);
1509 * Case-insensitive search for one string in another;
1510 * used to find variable names in submount pathnames.
1512 static char *smb_stristr(char *str1, char *str2)
1516 for (cursor = str1; *cursor; cursor++)
1517 if (stricmp(cursor, str2) == 0)
1524 * Substitute a variable value for its name in a submount pathname. Variable
1525 * name has been identified by smb_stristr() and is in substr. Variable name
1526 * length (plus one) is in substr_size. Variable value is in newstr.
1528 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1533 strcpy(temp, substr + substr_size - 1);
1534 strcpy(substr, newstr);
1538 char VNUserName[] = "%USERNAME%";
1539 char VNLCUserName[] = "%LCUSERNAME%";
1540 char VNComputerName[] = "%COMPUTERNAME%";
1541 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1544 typedef struct smb_findShare_rock {
1548 } smb_findShare_rock_t;
1550 #define SMB_FINDSHARE_EXACT_MATCH 1
1551 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1553 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1557 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1558 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1559 if(!stricmp(dep->name, vrock->shareName))
1560 matchType = SMB_FINDSHARE_EXACT_MATCH;
1562 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1563 if(vrock->match) free(vrock->match);
1564 vrock->match = strdup(dep->name);
1565 vrock->matchType = matchType;
1567 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1568 return CM_ERROR_STOPNOW;
1574 /* find a shareName in the table of submounts */
1575 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1579 char pathName[1024];
1586 DWORD allSubmount = 1;
1588 /* if allSubmounts == 0, only return the //mountRoot/all share
1589 * if in fact it has been been created in the subMounts table.
1590 * This is to allow sites that want to restrict access to the
1593 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1594 0, KEY_QUERY_VALUE, &parmKey);
1595 if (code == ERROR_SUCCESS) {
1596 len = sizeof(allSubmount);
1597 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1598 (BYTE *) &allSubmount, &len);
1599 if (code != ERROR_SUCCESS) {
1602 RegCloseKey (parmKey);
1605 if (allSubmount && _stricmp(shareName, "all") == 0) {
1610 /* In case, the all share is disabled we need to still be able
1611 * to handle ioctl requests
1613 if (_stricmp(shareName, "ioctl$") == 0) {
1614 *pathNamep = strdup("/.__ioctl__");
1618 if (_stricmp(shareName, "IPC$") == 0 ||
1619 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1620 _stricmp(shareName, "DESKTOP.INI") == 0
1626 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1627 0, KEY_QUERY_VALUE, &parmKey);
1628 if (code == ERROR_SUCCESS) {
1629 len = sizeof(pathName);
1630 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1631 (BYTE *) pathName, &len);
1632 if (code != ERROR_SUCCESS)
1634 RegCloseKey (parmKey);
1638 if (len != 0 && len != sizeof(pathName) - 1) {
1639 /* We can accept either unix or PC style AFS pathnames. Convert
1640 * Unix-style to PC style here for internal use.
1643 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1644 p += strlen(cm_mountRoot); /* skip mount path */
1647 if (*q == '/') *q = '\\'; /* change to \ */
1653 if (var = smb_stristr(p, VNUserName)) {
1654 if (uidp && uidp->unp)
1655 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1657 smb_subst(p, var, sizeof(VNUserName)," ");
1659 else if (var = smb_stristr(p, VNLCUserName))
1661 if (uidp && uidp->unp)
1662 strcpy(temp, uidp->unp->name);
1666 smb_subst(p, var, sizeof(VNLCUserName), temp);
1668 else if (var = smb_stristr(p, VNComputerName))
1670 sizeTemp = sizeof(temp);
1671 GetComputerName((LPTSTR)temp, &sizeTemp);
1672 smb_subst(p, var, sizeof(VNComputerName), temp);
1674 else if (var = smb_stristr(p, VNLCComputerName))
1676 sizeTemp = sizeof(temp);
1677 GetComputerName((LPTSTR)temp, &sizeTemp);
1679 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1684 *pathNamep = strdup(p);
1689 /* First lookup shareName in root.afs */
1691 smb_findShare_rock_t vrock;
1693 char * p = shareName;
1696 /* attempt to locate a partial match in root.afs. This is because
1697 when using the ANSI RAP calls, the share name is limited to 13 chars
1698 and hence is truncated. Of course we prefer exact matches. */
1700 thyper.HighPart = 0;
1703 vrock.shareName = shareName;
1705 vrock.matchType = 0;
1707 cm_HoldSCache(cm_data.rootSCachep);
1708 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1709 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1710 cm_ReleaseSCache(cm_data.rootSCachep);
1712 if (vrock.matchType) {
1713 sprintf(pathName,"/%s/",vrock.match);
1714 *pathNamep = strdup(strlwr(pathName));
1719 /* if we get here, there was no match for the share in root.afs */
1720 /* so try to create \\<netbiosName>\<cellname> */
1725 /* Get the full name for this cell */
1726 code = cm_SearchCellFile(p, temp, 0, 0);
1727 #ifdef AFS_AFSDB_ENV
1728 if (code && cm_dnsEnabled) {
1730 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1733 /* construct the path */
1735 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1736 *pathNamep = strdup(strlwr(pathName));
1745 /* Client-side offline caching policy types */
1746 #define CSC_POLICY_MANUAL 0
1747 #define CSC_POLICY_DOCUMENTS 1
1748 #define CSC_POLICY_PROGRAMS 2
1749 #define CSC_POLICY_DISABLE 3
1751 int smb_FindShareCSCPolicy(char *shareName)
1757 int retval = CSC_POLICY_MANUAL;
1759 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1760 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1763 REG_OPTION_NON_VOLATILE,
1769 len = sizeof(policy);
1770 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1772 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1774 else if (stricmp(policy, "documents") == 0)
1776 retval = CSC_POLICY_DOCUMENTS;
1778 else if (stricmp(policy, "programs") == 0)
1780 retval = CSC_POLICY_PROGRAMS;
1782 else if (stricmp(policy, "disable") == 0)
1784 retval = CSC_POLICY_DISABLE;
1787 RegCloseKey(hkCSCPolicy);
1791 /* find a dir search structure by cookie value, and return it held.
1792 * Must be called with smb_globalLock held.
1794 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1796 smb_dirSearch_t *dsp;
1798 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1799 if (dsp->cookie == cookie) {
1800 if (dsp != smb_firstDirSearchp) {
1801 /* move to head of LRU queue, too, if we're not already there */
1802 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1803 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1804 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1805 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1806 if (!smb_lastDirSearchp)
1807 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1809 lock_ObtainMutex(&dsp->mx);
1811 lock_ReleaseMutex(&dsp->mx);
1817 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1818 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1819 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1825 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1827 lock_ObtainWrite(&smb_globalLock);
1828 lock_ObtainMutex(&dsp->mx);
1829 dsp->flags |= SMB_DIRSEARCH_DELETE;
1830 if (dsp->scp != NULL) {
1831 lock_ObtainMutex(&dsp->scp->mx);
1832 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1833 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1834 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1835 dsp->scp->bulkStatProgress = hzero;
1837 lock_ReleaseMutex(&dsp->scp->mx);
1839 lock_ReleaseMutex(&dsp->mx);
1840 lock_ReleaseWrite(&smb_globalLock);
1843 /* Must be called with the smb_globalLock held */
1844 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1846 cm_scache_t *scp = NULL;
1848 lock_ObtainMutex(&dsp->mx);
1849 osi_assert(dsp->refCount-- > 0);
1850 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1851 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1852 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1853 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1854 lock_ReleaseMutex(&dsp->mx);
1855 lock_FinalizeMutex(&dsp->mx);
1859 lock_ReleaseMutex(&dsp->mx);
1861 /* do this now to avoid spurious locking hierarchy creation */
1863 cm_ReleaseSCache(scp);
1866 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1868 lock_ObtainWrite(&smb_globalLock);
1869 smb_ReleaseDirSearchNoLock(dsp);
1870 lock_ReleaseWrite(&smb_globalLock);
1873 /* find a dir search structure by cookie value, and return it held */
1874 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1876 smb_dirSearch_t *dsp;
1878 lock_ObtainWrite(&smb_globalLock);
1879 dsp = smb_FindDirSearchNoLock(cookie);
1880 lock_ReleaseWrite(&smb_globalLock);
1884 /* GC some dir search entries, in the address space expected by the specific protocol.
1885 * Must be called with smb_globalLock held; release the lock temporarily.
1887 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1888 void smb_GCDirSearches(int isV3)
1890 smb_dirSearch_t *prevp;
1891 smb_dirSearch_t *tp;
1892 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1896 victimCount = 0; /* how many have we got so far */
1897 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1898 /* we'll move tp from queue, so
1901 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1902 /* if no one is using this guy, and we're either in the new protocol,
1903 * or we're in the old one and this is a small enough ID to be useful
1904 * to the old protocol, GC this guy.
1906 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1907 /* hold and delete */
1908 lock_ObtainMutex(&tp->mx);
1909 tp->flags |= SMB_DIRSEARCH_DELETE;
1910 lock_ReleaseMutex(&tp->mx);
1911 victimsp[victimCount++] = tp;
1915 /* don't do more than this */
1916 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1920 /* now release them */
1921 for (i = 0; i < victimCount; i++) {
1922 smb_ReleaseDirSearchNoLock(victimsp[i]);
1926 /* function for allocating a dir search entry. We need these to remember enough context
1927 * since we don't get passed the path from call to call during a directory search.
1929 * Returns a held dir search structure, and bumps the reference count on the vnode,
1930 * since it saves a pointer to the vnode.
1932 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1934 smb_dirSearch_t *dsp;
1940 lock_ObtainWrite(&smb_globalLock);
1943 /* what's the biggest ID allowed in this version of the protocol */
1944 maxAllowed = isV3 ? 65535 : 255;
1945 if (smb_dirSearchCounter > maxAllowed)
1946 smb_dirSearchCounter = 1;
1948 start = smb_dirSearchCounter;
1951 /* twice so we have enough tries to find guys we GC after one pass;
1952 * 10 extra is just in case I mis-counted.
1954 if (++counter > 2*maxAllowed+10)
1955 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1957 if (smb_dirSearchCounter > maxAllowed) {
1958 smb_dirSearchCounter = 1;
1960 if (smb_dirSearchCounter == start) {
1962 smb_GCDirSearches(isV3);
1965 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1967 /* don't need to watch for refcount zero and deleted, since
1968 * we haven't dropped the global lock.
1970 lock_ObtainMutex(&dsp->mx);
1972 lock_ReleaseMutex(&dsp->mx);
1973 ++smb_dirSearchCounter;
1977 dsp = malloc(sizeof(*dsp));
1978 memset(dsp, 0, sizeof(*dsp));
1979 dsp->cookie = smb_dirSearchCounter;
1980 ++smb_dirSearchCounter;
1982 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1983 dsp->lastTime = osi_Time();
1984 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1985 if (!smb_lastDirSearchp)
1986 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1989 lock_ReleaseWrite(&smb_globalLock);
1993 static smb_packet_t *GetPacket(void)
1997 lock_ObtainWrite(&smb_globalLock);
1998 tbp = smb_packetFreeListp;
2000 smb_packetFreeListp = tbp->nextp;
2001 lock_ReleaseWrite(&smb_globalLock);
2003 tbp = calloc(65540,1);
2004 tbp->magic = SMB_PACKETMAGIC;
2007 tbp->resumeCode = 0;
2013 tbp->ncb_length = 0;
2018 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2023 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2027 memcpy(tbp, pkt, sizeof(smb_packet_t));
2028 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2030 smb_HoldVC(tbp->vcp);
2034 static NCB *GetNCB(void)
2039 lock_ObtainWrite(&smb_globalLock);
2040 tbp = smb_ncbFreeListp;
2042 smb_ncbFreeListp = tbp->nextp;
2043 lock_ReleaseWrite(&smb_globalLock);
2045 tbp = calloc(sizeof(*tbp),1);
2046 tbp->magic = SMB_NCBMAGIC;
2049 osi_assert(tbp->magic == SMB_NCBMAGIC);
2051 memset(&tbp->ncb, 0, sizeof(NCB));
2056 void smb_FreePacket(smb_packet_t *tbp)
2058 smb_vc_t * vcp = NULL;
2059 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2061 lock_ObtainWrite(&smb_globalLock);
2062 tbp->nextp = smb_packetFreeListp;
2063 smb_packetFreeListp = tbp;
2064 tbp->magic = SMB_PACKETMAGIC;
2068 tbp->resumeCode = 0;
2074 tbp->ncb_length = 0;
2076 lock_ReleaseWrite(&smb_globalLock);
2082 static void FreeNCB(NCB *bufferp)
2086 tbp = (smb_ncb_t *) bufferp;
2087 osi_assert(tbp->magic == SMB_NCBMAGIC);
2089 lock_ObtainWrite(&smb_globalLock);
2090 tbp->nextp = smb_ncbFreeListp;
2091 smb_ncbFreeListp = tbp;
2092 lock_ReleaseWrite(&smb_globalLock);
2095 /* get a ptr to the data part of a packet, and its count */
2096 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2100 unsigned char *afterParmsp;
2102 parmBytes = *smbp->wctp << 1;
2103 afterParmsp = smbp->wctp + parmBytes + 1;
2105 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2106 if (nbytesp) *nbytesp = dataBytes;
2108 /* don't forget to skip the data byte count, since it follows
2109 * the parameters; that's where the "2" comes from below.
2111 return (unsigned char *) (afterParmsp + 2);
2114 /* must set all the returned parameters before playing around with the
2115 * data region, since the data region is located past the end of the
2116 * variable number of parameters.
2118 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2120 unsigned char *afterParmsp;
2122 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2124 *afterParmsp++ = dsize & 0xff;
2125 *afterParmsp = (dsize>>8) & 0xff;
2128 /* return the parm'th parameter in the smbp packet */
2129 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2132 unsigned char *parmDatap;
2134 parmCount = *smbp->wctp;
2136 if (parm >= parmCount) {
2139 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2140 parm, parmCount, smbp->ncb_length);
2141 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2142 parm, parmCount, smbp->ncb_length);
2143 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2144 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2145 osi_panic(s, __FILE__, __LINE__);
2147 parmDatap = smbp->wctp + (2*parm) + 1;
2149 return parmDatap[0] + (parmDatap[1] << 8);
2152 /* return the parm'th parameter in the smbp packet */
2153 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2156 unsigned char *parmDatap;
2158 parmCount = *smbp->wctp;
2160 if (parm + 1 >= parmCount) {
2163 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2164 parm, parmCount, smbp->ncb_length);
2165 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2166 parm, parmCount, smbp->ncb_length);
2167 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2168 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2169 osi_panic(s, __FILE__, __LINE__);
2171 parmDatap = smbp->wctp + (2*parm) + 1;
2173 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2176 /* return the parm'th parameter in the smbp packet */
2177 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2180 unsigned char *parmDatap;
2182 parmCount = *smbp->wctp;
2184 if (parm * 2 + offset >= parmCount * 2) {
2187 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2188 parm, offset, parmCount, smbp->ncb_length);
2189 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2190 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2191 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2192 parm, offset, parmCount, smbp->ncb_length);
2193 osi_panic(s, __FILE__, __LINE__);
2195 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2197 return parmDatap[0] + (parmDatap[1] << 8);
2200 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2204 /* make sure we have enough slots */
2205 if (*smbp->wctp <= slot)
2206 *smbp->wctp = slot+1;
2208 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2209 *parmDatap++ = parmValue & 0xff;
2210 *parmDatap = (parmValue>>8) & 0xff;
2213 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2217 /* make sure we have enough slots */
2218 if (*smbp->wctp <= slot)
2219 *smbp->wctp = slot+2;
2221 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2222 *parmDatap++ = parmValue & 0xff;
2223 *parmDatap++ = (parmValue>>8) & 0xff;
2224 *parmDatap++ = (parmValue>>16) & 0xff;
2225 *parmDatap = (parmValue>>24) & 0xff;
2228 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2233 /* make sure we have enough slots */
2234 if (*smbp->wctp <= slot)
2235 *smbp->wctp = slot+4;
2237 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2239 *parmDatap++ = *parmValuep++;
2242 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2246 /* make sure we have enough slots */
2247 if (*smbp->wctp <= slot) {
2248 if (smbp->oddByte) {
2250 *smbp->wctp = slot+1;
2255 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2256 *parmDatap++ = parmValue & 0xff;
2259 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2263 lastSlashp = strrchr(inPathp, '\\');
2265 *lastComponentp = lastSlashp;
2268 if (inPathp == lastSlashp)
2270 *outPathp++ = *inPathp++;
2279 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2284 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2289 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2295 tlen = inp[0] + (inp[1]<<8);
2296 inp += 2; /* skip length field */
2299 *chainpp = inp + tlen;
2308 /* format a packet as a response */
2309 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2314 outp = (smb_t *) op;
2316 /* zero the basic structure through the smb_wct field, and zero the data
2317 * size field, assuming that wct stays zero; otherwise, you have to
2318 * explicitly set the data size field, too.
2320 inSmbp = (smb_t *) inp;
2321 memset(outp, 0, sizeof(smb_t)+2);
2327 outp->com = inSmbp->com;
2328 outp->tid = inSmbp->tid;
2329 outp->pid = inSmbp->pid;
2330 outp->uid = inSmbp->uid;
2331 outp->mid = inSmbp->mid;
2332 outp->res[0] = inSmbp->res[0];
2333 outp->res[1] = inSmbp->res[1];
2334 op->inCom = inSmbp->com;
2336 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2337 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2339 /* copy fields in generic packet area */
2340 op->wctp = &outp->wct;
2343 /* send a (probably response) packet; vcp tells us to whom to send it.
2344 * we compute the length by looking at wct and bcc fields.
2346 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2360 memset((char *)ncbp, 0, sizeof(NCB));
2362 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2363 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2364 extra += tp[0] + (tp[1]<<8);
2365 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2366 extra += 3; /* wct and length fields */
2368 ncbp->ncb_length = extra; /* bytes to send */
2369 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2370 ncbp->ncb_lana_num = vcp->lana;
2371 ncbp->ncb_command = NCBSEND; /* op means send data */
2372 ncbp->ncb_buffer = (char *) inp;/* packet */
2373 code = Netbios(ncbp);
2376 const char * s = ncb_error_string(code);
2377 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2378 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2380 lock_ObtainMutex(&vcp->mx);
2381 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2382 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2384 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2385 lock_ReleaseMutex(&vcp->mx);
2386 lock_ObtainWrite(&smb_globalLock);
2387 dead_sessions[vcp->session] = TRUE;
2388 lock_ReleaseWrite(&smb_globalLock);
2389 smb_CleanupDeadVC(vcp);
2391 lock_ReleaseMutex(&vcp->mx);
2399 void smb_MapNTError(long code, unsigned long *NTStatusp)
2401 unsigned long NTStatus;
2403 /* map CM_ERROR_* errors to NT 32-bit status codes */
2404 /* NT Status codes are listed in ntstatus.h not winerror.h */
2405 if (code == CM_ERROR_NOSUCHCELL) {
2406 NTStatus = 0xC000000FL; /* No such file */
2408 else if (code == CM_ERROR_NOSUCHVOLUME) {
2409 NTStatus = 0xC000000FL; /* No such file */
2411 else if (code == CM_ERROR_TIMEDOUT) {
2413 NTStatus = 0xC00000CFL; /* Sharing Paused */
2415 NTStatus = 0x00000102L; /* Timeout */
2418 else if (code == CM_ERROR_RETRY) {
2419 NTStatus = 0xC000022DL; /* Retry */
2421 else if (code == CM_ERROR_NOACCESS) {
2422 NTStatus = 0xC0000022L; /* Access denied */
2424 else if (code == CM_ERROR_READONLY) {
2425 NTStatus = 0xC00000A2L; /* Write protected */
2427 else if (code == CM_ERROR_NOSUCHFILE) {
2428 NTStatus = 0xC000000FL; /* No such file */
2430 else if (code == CM_ERROR_NOSUCHPATH) {
2431 NTStatus = 0xC000003AL; /* Object path not found */
2433 else if (code == CM_ERROR_TOOBIG) {
2434 NTStatus = 0xC000007BL; /* Invalid image format */
2436 else if (code == CM_ERROR_INVAL) {
2437 NTStatus = 0xC000000DL; /* Invalid parameter */
2439 else if (code == CM_ERROR_BADFD) {
2440 NTStatus = 0xC0000008L; /* Invalid handle */
2442 else if (code == CM_ERROR_BADFDOP) {
2443 NTStatus = 0xC0000022L; /* Access denied */
2445 else if (code == CM_ERROR_EXISTS) {
2446 NTStatus = 0xC0000035L; /* Object name collision */
2448 else if (code == CM_ERROR_NOTEMPTY) {
2449 NTStatus = 0xC0000101L; /* Directory not empty */
2451 else if (code == CM_ERROR_CROSSDEVLINK) {
2452 NTStatus = 0xC00000D4L; /* Not same device */
2454 else if (code == CM_ERROR_NOTDIR) {
2455 NTStatus = 0xC0000103L; /* Not a directory */
2457 else if (code == CM_ERROR_ISDIR) {
2458 NTStatus = 0xC00000BAL; /* File is a directory */
2460 else if (code == CM_ERROR_BADOP) {
2462 /* I have no idea where this comes from */
2463 NTStatus = 0xC09820FFL; /* SMB no support */
2465 NTStatus = 0xC00000BBL; /* Not supported */
2466 #endif /* COMMENT */
2468 else if (code == CM_ERROR_BADSHARENAME) {
2469 NTStatus = 0xC00000CCL; /* Bad network name */
2471 else if (code == CM_ERROR_NOIPC) {
2473 NTStatus = 0xC0000022L; /* Access Denied */
2475 NTStatus = 0xC000013DL; /* Remote Resources */
2478 else if (code == CM_ERROR_CLOCKSKEW) {
2479 NTStatus = 0xC0000133L; /* Time difference at DC */
2481 else if (code == CM_ERROR_BADTID) {
2482 NTStatus = 0xC0982005L; /* SMB bad TID */
2484 else if (code == CM_ERROR_USESTD) {
2485 NTStatus = 0xC09820FBL; /* SMB use standard */
2487 else if (code == CM_ERROR_QUOTA) {
2489 NTStatus = 0xC0000044L; /* Quota exceeded */
2491 NTStatus = 0xC000007FL; /* Disk full */
2494 else if (code == CM_ERROR_SPACE) {
2495 NTStatus = 0xC000007FL; /* Disk full */
2497 else if (code == CM_ERROR_ATSYS) {
2498 NTStatus = 0xC0000033L; /* Object name invalid */
2500 else if (code == CM_ERROR_BADNTFILENAME) {
2501 NTStatus = 0xC0000033L; /* Object name invalid */
2503 else if (code == CM_ERROR_WOULDBLOCK) {
2504 NTStatus = 0xC0000055L; /* Lock not granted */
2506 else if (code == CM_ERROR_SHARING_VIOLATION) {
2507 NTStatus = 0xC0000043L; /* Sharing violation */
2509 else if (code == CM_ERROR_LOCK_CONFLICT) {
2510 NTStatus = 0xC0000054L; /* Lock conflict */
2512 else if (code == CM_ERROR_PARTIALWRITE) {
2513 NTStatus = 0xC000007FL; /* Disk full */
2515 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2516 NTStatus = 0xC0000023L; /* Buffer too small */
2518 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2519 NTStatus = 0xC0000035L; /* Object name collision */
2521 else if (code == CM_ERROR_BADPASSWORD) {
2522 NTStatus = 0xC000006DL; /* unknown username or bad password */
2524 else if (code == CM_ERROR_BADLOGONTYPE) {
2525 NTStatus = 0xC000015BL; /* logon type not granted */
2527 else if (code == CM_ERROR_GSSCONTINUE) {
2528 NTStatus = 0xC0000016L; /* more processing required */
2530 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2532 NTStatus = 0xC0000280L; /* reparse point not resolved */
2534 NTStatus = 0xC0000022L; /* Access Denied */
2537 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2538 NTStatus = 0xC0000257L; /* Path Not Covered */
2541 else if (code == CM_ERROR_ALLBUSY) {
2542 NTStatus = 0xC00000BFL; /* Network Busy */
2544 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2545 NTStatus = 0xC0000350L; /* Remote Host Down */
2548 /* we do not want to be telling the SMB/CIFS client that
2549 * the AFS Client Service is busy or down.
2551 else if (code == CM_ERROR_ALLBUSY ||
2552 code == CM_ERROR_ALLOFFLINE ||
2553 code == CM_ERROR_ALLDOWN) {
2554 NTStatus = 0xC00000BEL; /* Bad Network Path */
2557 else if (code == RXKADUNKNOWNKEY) {
2558 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2560 NTStatus = 0xC0982001L; /* SMB non-specific error */
2563 *NTStatusp = NTStatus;
2564 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2567 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2568 unsigned char *classp)
2570 unsigned char class;
2571 unsigned short error;
2573 /* map CM_ERROR_* errors to SMB errors */
2574 if (code == CM_ERROR_NOSUCHCELL) {
2576 error = 3; /* bad path */
2578 else if (code == CM_ERROR_NOSUCHVOLUME) {
2580 error = 3; /* bad path */
2582 else if (code == CM_ERROR_TIMEDOUT) {
2584 error = 81; /* server is paused */
2586 else if (code == CM_ERROR_RETRY) {
2587 class = 2; /* shouldn't happen */
2590 else if (code == CM_ERROR_NOACCESS) {
2592 error = 4; /* bad access */
2594 else if (code == CM_ERROR_READONLY) {
2596 error = 19; /* read only */
2598 else if (code == CM_ERROR_NOSUCHFILE) {
2600 error = 2; /* ENOENT! */
2602 else if (code == CM_ERROR_NOSUCHPATH) {
2604 error = 3; /* Bad path */
2606 else if (code == CM_ERROR_TOOBIG) {
2608 error = 11; /* bad format */
2610 else if (code == CM_ERROR_INVAL) {
2611 class = 2; /* server non-specific error code */
2614 else if (code == CM_ERROR_BADFD) {
2616 error = 6; /* invalid file handle */
2618 else if (code == CM_ERROR_BADFDOP) {
2619 class = 1; /* invalid op on FD */
2622 else if (code == CM_ERROR_EXISTS) {
2624 error = 80; /* file already exists */
2626 else if (code == CM_ERROR_NOTEMPTY) {
2628 error = 5; /* delete directory not empty */
2630 else if (code == CM_ERROR_CROSSDEVLINK) {
2632 error = 17; /* EXDEV */
2634 else if (code == CM_ERROR_NOTDIR) {
2635 class = 1; /* bad path */
2638 else if (code == CM_ERROR_ISDIR) {
2639 class = 1; /* access denied; DOS doesn't have a good match */
2642 else if (code == CM_ERROR_BADOP) {
2646 else if (code == CM_ERROR_BADSHARENAME) {
2650 else if (code == CM_ERROR_NOIPC) {
2652 error = 4; /* bad access */
2654 else if (code == CM_ERROR_CLOCKSKEW) {
2655 class = 1; /* invalid function */
2658 else if (code == CM_ERROR_BADTID) {
2662 else if (code == CM_ERROR_USESTD) {
2666 else if (code == CM_ERROR_REMOTECONN) {
2670 else if (code == CM_ERROR_QUOTA) {
2671 if (vcp->flags & SMB_VCFLAG_USEV3) {
2673 error = 39; /* disk full */
2677 error = 5; /* access denied */
2680 else if (code == CM_ERROR_SPACE) {
2681 if (vcp->flags & SMB_VCFLAG_USEV3) {
2683 error = 39; /* disk full */
2687 error = 5; /* access denied */
2690 else if (code == CM_ERROR_PARTIALWRITE) {
2692 error = 39; /* disk full */
2694 else if (code == CM_ERROR_ATSYS) {
2696 error = 2; /* ENOENT */
2698 else if (code == CM_ERROR_WOULDBLOCK) {
2700 error = 33; /* lock conflict */
2702 else if (code == CM_ERROR_LOCK_CONFLICT) {
2704 error = 33; /* lock conflict */
2706 else if (code == CM_ERROR_SHARING_VIOLATION) {
2708 error = 33; /* lock conflict */
2710 else if (code == CM_ERROR_NOFILES) {
2712 error = 18; /* no files in search */
2714 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2716 error = 183; /* Samba uses this */
2718 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2719 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2721 error = 2; /* bad password */
2723 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2725 error = 3; /* bad path */
2734 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2737 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2739 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2740 return CM_ERROR_BADOP;
2743 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2745 unsigned short EchoCount, i;
2746 char *data, *outdata;
2749 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2751 for (i=1; i<=EchoCount; i++) {
2752 data = smb_GetSMBData(inp, &dataSize);
2753 smb_SetSMBParm(outp, 0, i);
2754 smb_SetSMBDataLength(outp, dataSize);
2755 outdata = smb_GetSMBData(outp, NULL);
2756 memcpy(outdata, data, dataSize);
2757 smb_SendPacket(vcp, outp);
2763 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2766 long count, minCount, finalCount;
2771 cm_user_t *userp = NULL;
2774 char *rawBuf = NULL;
2779 fd = smb_GetSMBParm(inp, 0);
2780 count = smb_GetSMBParm(inp, 3);
2781 minCount = smb_GetSMBParm(inp, 4);
2782 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2784 if (*inp->wctp == 10) {
2785 /* we were sent a request with 64-bit file offsets */
2786 #ifdef AFS_LARGEFILES
2787 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2789 if (LargeIntegerLessThanZero(offset)) {
2790 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2794 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2795 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2798 offset.HighPart = 0;
2802 /* we were sent a request with 32-bit file offsets */
2803 offset.HighPart = 0;
2806 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2807 fd, offset.HighPart, offset.LowPart, count);
2809 fidp = smb_FindFID(vcp, fd, 0);
2813 pid = ((smb_t *) inp)->pid;
2815 LARGE_INTEGER LOffset, LLength;
2818 key = cm_GenerateKey(vcp->vcID, pid, fd);
2820 LOffset.HighPart = offset.HighPart;
2821 LOffset.LowPart = offset.LowPart;
2822 LLength.HighPart = 0;
2823 LLength.LowPart = count;
2825 lock_ObtainMutex(&fidp->scp->mx);
2826 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2827 lock_ReleaseMutex(&fidp->scp->mx);
2833 lock_ObtainMutex(&smb_RawBufLock);
2835 /* Get a raw buf, from head of list */
2836 rawBuf = smb_RawBufs;
2837 smb_RawBufs = *(char **)smb_RawBufs;
2839 lock_ReleaseMutex(&smb_RawBufLock);
2843 lock_ObtainMutex(&fidp->mx);
2844 if (fidp->flags & SMB_FID_IOCTL)
2846 lock_ReleaseMutex(&fidp->mx);
2847 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2849 /* Give back raw buffer */
2850 lock_ObtainMutex(&smb_RawBufLock);
2851 *((char **) rawBuf) = smb_RawBufs;
2853 smb_RawBufs = rawBuf;
2854 lock_ReleaseMutex(&smb_RawBufLock);
2857 smb_ReleaseFID(fidp);
2860 lock_ReleaseMutex(&fidp->mx);
2862 userp = smb_GetUserFromVCP(vcp, inp);
2864 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2870 cm_ReleaseUser(userp);
2873 smb_ReleaseFID(fidp);
2877 memset((char *)ncbp, 0, sizeof(NCB));
2879 ncbp->ncb_length = (unsigned short) finalCount;
2880 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2881 ncbp->ncb_lana_num = vcp->lana;
2882 ncbp->ncb_command = NCBSEND;
2883 ncbp->ncb_buffer = rawBuf;
2885 code = Netbios(ncbp);
2887 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2890 /* Give back raw buffer */
2891 lock_ObtainMutex(&smb_RawBufLock);
2892 *((char **) rawBuf) = smb_RawBufs;
2894 smb_RawBufs = rawBuf;
2895 lock_ReleaseMutex(&smb_RawBufLock);
2901 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2903 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2908 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2910 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2915 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2922 int VistaProtoIndex;
2923 int protoIndex; /* index we're using */
2928 char protocol_array[10][1024]; /* protocol signature of the client */
2929 int caps; /* capabilities */
2932 TIME_ZONE_INFORMATION tzi;
2934 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2937 namep = smb_GetSMBData(inp, &dbytes);
2940 coreProtoIndex = -1; /* not found */
2943 VistaProtoIndex = -1;
2944 while(namex < dbytes) {
2945 osi_Log1(smb_logp, "Protocol %s",
2946 osi_LogSaveString(smb_logp, namep+1));
2947 strcpy(protocol_array[tcounter], namep+1);
2949 /* namep points at the first protocol, or really, a 0x02
2950 * byte preceding the null-terminated ASCII name.
2952 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2953 coreProtoIndex = tcounter;
2955 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2956 v3ProtoIndex = tcounter;
2958 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2959 NTProtoIndex = tcounter;
2961 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
2962 VistaProtoIndex = tcounter;
2965 /* compute size of protocol entry */
2966 entryLength = (int)strlen(namep+1);
2967 entryLength += 2; /* 0x02 bytes and null termination */
2969 /* advance over this protocol entry */
2970 namex += entryLength;
2971 namep += entryLength;
2972 tcounter++; /* which proto entry we're looking at */
2975 lock_ObtainMutex(&vcp->mx);
2977 if (VistaProtoIndex != -1) {
2978 protoIndex = VistaProtoIndex;
2979 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2982 if (NTProtoIndex != -1) {
2983 protoIndex = NTProtoIndex;
2984 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2986 else if (v3ProtoIndex != -1) {
2987 protoIndex = v3ProtoIndex;
2988 vcp->flags |= SMB_VCFLAG_USEV3;
2990 else if (coreProtoIndex != -1) {
2991 protoIndex = coreProtoIndex;
2992 vcp->flags |= SMB_VCFLAG_USECORE;
2994 else protoIndex = -1;
2995 lock_ReleaseMutex(&vcp->mx);
2997 if (protoIndex == -1)
2998 return CM_ERROR_INVAL;
2999 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3000 smb_SetSMBParm(outp, 0, protoIndex);
3001 if (smb_authType != SMB_AUTH_NONE) {
3002 smb_SetSMBParmByte(outp, 1,
3003 NEGOTIATE_SECURITY_USER_LEVEL |
3004 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3006 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3008 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3009 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3010 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3011 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3012 /* The session key is not a well documented field however most clients
3013 * will echo back the session key to the server. Currently we are using
3014 * the same value for all sessions. We should generate a random value
3015 * and store it into the vcp
3017 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3018 smb_SetSMBParm(outp, 8, 1);
3020 * Tried changing the capabilities to support for W2K - defect 117695
3021 * Maybe something else needs to be changed here?
3025 smb_SetSMBParmLong(outp, 9, 0x43fd);
3027 smb_SetSMBParmLong(outp, 9, 0x251);
3030 * 32-bit error codes *
3035 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3037 NTNEGOTIATE_CAPABILITY_DFS |
3039 #ifdef AFS_LARGEFILES
3040 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3042 NTNEGOTIATE_CAPABILITY_NTFIND |
3043 NTNEGOTIATE_CAPABILITY_RAWMODE |
3044 NTNEGOTIATE_CAPABILITY_NTSMB;
3046 if ( smb_authType == SMB_AUTH_EXTENDED )
3047 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3049 smb_SetSMBParmLong(outp, 9, caps);
3051 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3052 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3053 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3055 GetTimeZoneInformation(&tzi);
3056 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3058 if (smb_authType == SMB_AUTH_NTLM) {
3059 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3060 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3061 /* paste in encryption key */
3062 datap = smb_GetSMBData(outp, NULL);
3063 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3064 /* and the faux domain name */
3065 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3066 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3070 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3072 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3074 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3076 datap = smb_GetSMBData(outp, NULL);
3077 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3080 datap += sizeof(smb_ServerGUID);
3081 memcpy(datap, secBlob, secBlobLength);
3085 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3086 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3089 else if (v3ProtoIndex != -1) {
3090 smb_SetSMBParm(outp, 0, protoIndex);
3092 /* NOTE: Extended authentication cannot be negotiated with v3
3093 * therefore we fail over to NTLM
3095 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3096 smb_SetSMBParm(outp, 1,
3097 NEGOTIATE_SECURITY_USER_LEVEL |
3098 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3100 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3102 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3103 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3104 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3105 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3106 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3107 smb_SetSMBParm(outp, 7, 1);
3109 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3110 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3111 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3113 GetTimeZoneInformation(&tzi);
3114 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3116 /* NOTE: Extended authentication cannot be negotiated with v3
3117 * therefore we fail over to NTLM
3119 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3120 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3121 smb_SetSMBParm(outp, 12, 0); /* resvd */
3122 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3123 datap = smb_GetSMBData(outp, NULL);
3124 /* paste in a new encryption key */
3125 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3126 /* and the faux domain name */
3127 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3129 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3130 smb_SetSMBParm(outp, 12, 0); /* resvd */
3131 smb_SetSMBDataLength(outp, 0);
3134 else if (coreProtoIndex != -1) { /* not really supported anymore */
3135 smb_SetSMBParm(outp, 0, protoIndex);
3136 smb_SetSMBDataLength(outp, 0);
3141 void smb_CheckVCs(void)
3143 smb_vc_t * vcp, *nextp;
3144 smb_packet_t * outp = GetPacket();
3147 lock_ObtainWrite(&smb_rctLock);
3148 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3150 if (vcp->magic != SMB_VC_MAGIC)
3151 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3152 __FILE__, __LINE__);
3156 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3159 smb_HoldVCNoLock(vcp);
3161 smb_HoldVCNoLock(nextp);
3162 smb_FormatResponsePacket(vcp, NULL, outp);
3163 smbp = (smb_t *)outp;
3164 outp->inCom = smbp->com = 0x2b /* Echo */;
3172 smb_SetSMBParm(outp, 0, 0);
3173 smb_SetSMBDataLength(outp, 0);
3174 lock_ReleaseWrite(&smb_rctLock);
3176 smb_SendPacket(vcp, outp);
3178 lock_ObtainWrite(&smb_rctLock);
3179 smb_ReleaseVCNoLock(vcp);
3181 smb_ReleaseVCNoLock(nextp);
3183 lock_ReleaseWrite(&smb_rctLock);
3184 smb_FreePacket(outp);
3187 void smb_Daemon(void *parmp)
3189 afs_uint32 count = 0;
3190 smb_username_t **unpp;
3193 while(smbShutdownFlag == 0) {
3197 if (smbShutdownFlag == 1)
3200 if ((count % 72) == 0) { /* every five minutes */
3202 time_t old_localZero = smb_localZero;
3204 /* Initialize smb_localZero */
3205 myTime.tm_isdst = -1; /* compute whether on DST or not */
3206 myTime.tm_year = 70;
3212 smb_localZero = mktime(&myTime);
3214 #ifndef USE_NUMERIC_TIME_CONV
3215 smb_CalculateNowTZ();
3216 #endif /* USE_NUMERIC_TIME_CONV */
3217 #ifdef AFS_FREELANCE
3218 if ( smb_localZero != old_localZero )
3219 cm_noteLocalMountPointChange();
3225 /* GC smb_username_t objects that will no longer be used */
3227 lock_ObtainWrite(&smb_rctLock);
3228 for ( unpp=&usernamesp; *unpp; ) {
3230 smb_username_t *unp;
3232 lock_ObtainMutex(&(*unpp)->mx);
3233 if ( (*unpp)->refCount > 0 ||
3234 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3235 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3237 else if (!smb_LogoffTokenTransfer ||
3238 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3240 lock_ReleaseMutex(&(*unpp)->mx);
3248 lock_FinalizeMutex(&unp->mx);
3254 lock_ReleaseWrite(&smb_rctLock);
3255 cm_ReleaseUser(userp);
3256 lock_ObtainWrite(&smb_rctLock);
3259 unpp = &(*unpp)->nextp;
3262 lock_ReleaseWrite(&smb_rctLock);
3264 /* XXX GC dir search entries */
3268 void smb_WaitingLocksDaemon()
3270 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3271 smb_waitingLock_t *wl, *wlNext;
3274 smb_packet_t *inp, *outp;
3278 while (smbShutdownFlag == 0) {
3279 lock_ObtainWrite(&smb_globalLock);
3280 nwlRequest = smb_allWaitingLocks;
3281 if (nwlRequest == NULL) {
3282 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3287 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3294 lock_ObtainWrite(&smb_globalLock);
3296 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3298 wlRequest = nwlRequest;
3299 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3300 lock_ReleaseWrite(&smb_globalLock);
3304 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3305 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3308 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3310 /* wl->state is either _DONE or _WAITING. _ERROR
3311 would no longer be on the queue. */
3312 code = cm_RetryLock( wl->lockp,
3313 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3316 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3317 } else if (code != CM_ERROR_WOULDBLOCK) {
3318 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3323 if (code == CM_ERROR_WOULDBLOCK) {
3326 if (wlRequest->timeRemaining != 0xffffffff
3327 && (wlRequest->timeRemaining -= 1000) < 0)
3339 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3342 scp = wlRequest->scp;
3346 lock_ObtainMutex(&scp->mx);
3348 for (wl = wlRequest->locks; wl; wl = wlNext) {
3349 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3351 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3352 wl->LLength, wl->key, NULL, &req);
3354 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3359 lock_ReleaseMutex(&scp->mx);
3363 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3366 for (wl = wlRequest->locks; wl; wl = wlNext) {
3367 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3368 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3373 vcp = wlRequest->vcp;
3374 inp = wlRequest->inp;
3375 outp = wlRequest->outp;
3377 ncbp->ncb_length = inp->ncb_length;
3378 inp->spacep = cm_GetSpace();
3380 /* Remove waitingLock from list */
3381 lock_ObtainWrite(&smb_globalLock);
3382 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3384 lock_ReleaseWrite(&smb_globalLock);
3386 /* Resume packet processing */
3388 smb_SetSMBDataLength(outp, 0);
3389 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3390 outp->resumeCode = code;
3392 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3395 cm_FreeSpace(inp->spacep);
3396 smb_FreePacket(inp);
3397 smb_FreePacket(outp);
3399 cm_ReleaseSCache(wlRequest->scp);
3402 } while (nwlRequest && smbShutdownFlag == 0);
3407 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3409 osi_Log0(smb_logp, "SMB receive get disk attributes");
3411 smb_SetSMBParm(outp, 0, 32000);
3412 smb_SetSMBParm(outp, 1, 64);
3413 smb_SetSMBParm(outp, 2, 1024);
3414 smb_SetSMBParm(outp, 3, 30000);
3415 smb_SetSMBParm(outp, 4, 0);
3416 smb_SetSMBDataLength(outp, 0);
3420 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3424 unsigned short newTid;
3425 char shareName[256];
3433 osi_Log0(smb_logp, "SMB receive tree connect");
3435 /* parse input parameters */
3436 tp = smb_GetSMBData(inp, NULL);
3437 pathp = smb_ParseASCIIBlock(tp, &tp);
3438 if (smb_StoreAnsiFilenames)
3439 OemToChar(pathp,pathp);
3440 passwordp = smb_ParseASCIIBlock(tp, &tp);
3441 tp = strrchr(pathp, '\\');
3443 return CM_ERROR_BADSMB;
3444 strcpy(shareName, tp+1);
3446 lock_ObtainMutex(&vcp->mx);
3447 newTid = vcp->tidCounter++;
3448 lock_ReleaseMutex(&vcp->mx);
3450 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3451 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3452 userp = smb_GetUserFromUID(uidp);
3453 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3455 smb_ReleaseUID(uidp);
3457 smb_ReleaseTID(tidp);
3458 return CM_ERROR_BADSHARENAME;
3460 lock_ObtainMutex(&tidp->mx);
3461 tidp->userp = userp;
3462 tidp->pathname = sharePath;
3463 lock_ReleaseMutex(&tidp->mx);
3464 smb_ReleaseTID(tidp);
3466 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3467 smb_SetSMBParm(rsp, 1, newTid);
3468 smb_SetSMBDataLength(rsp, 0);
3470 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3474 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3478 if (*inp++ != 0x1) return NULL;
3479 tlen = inp[0] + (inp[1]<<8);
3480 inp += 2; /* skip length field */
3483 *chainpp = inp + tlen;
3486 if (lengthp) *lengthp = tlen;
3491 /* set maskp to the mask part of the incoming path.
3492 * Mask is 11 bytes long (8.3 with the dot elided).
3493 * Returns true if succeeds with a valid name, otherwise it does
3494 * its best, but returns false.
3496 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3504 /* starts off valid */
3507 /* mask starts out all blanks */
3508 memset(maskp, ' ', 11);
3510 /* find last backslash, or use whole thing if there is none */
3511 tp = strrchr(pathp, '\\');
3512 if (!tp) tp = pathp;
3513 else tp++; /* skip slash */
3517 /* names starting with a dot are illegal */
3518 if (*tp == '.') valid8Dot3 = 0;
3522 if (tc == 0) return valid8Dot3;
3523 if (tc == '.' || tc == '"') break;
3524 if (i < 8) *up++ = tc;
3525 else valid8Dot3 = 0;
3528 /* if we get here, tp point after the dot */
3529 up = maskp+8; /* ext goes here */
3536 if (tc == '.' || tc == '"')
3539 /* copy extension if not too long */
3549 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3559 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3561 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3565 /* otherwise, we have a valid 8.3 name; see if we have a match,
3566 * treating '?' as a wildcard in maskp (but not in the file name).
3568 tp1 = umask; /* real name, in mask format */
3569 tp2 = maskp; /* mask, in mask format */
3570 for(i=0; i<11; i++) {
3571 tc1 = *tp1++; /* char from real name */
3572 tc2 = *tp2++; /* char from mask */
3573 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3574 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3577 if (tc2 == '?' && tc1 != ' ')
3584 /* we got a match */
3588 char *smb_FindMask(char *pathp)
3592 tp = strrchr(pathp, '\\'); /* find last slash */
3595 return tp+1; /* skip the slash */
3597 return pathp; /* no slash, return the entire path */
3600 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3602 unsigned char *pathp;
3604 unsigned char mask[11];
3605 unsigned char *statBlockp;
3606 unsigned char initStatBlock[21];
3609 osi_Log0(smb_logp, "SMB receive search volume");
3611 /* pull pathname and stat block out of request */
3612 tp = smb_GetSMBData(inp, NULL);
3613 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3614 osi_assert(pathp != NULL);
3615 if (smb_StoreAnsiFilenames)
3616 OemToChar(pathp,pathp);
3617 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3618 osi_assert(statBlockp != NULL);
3620 statBlockp = initStatBlock;
3624 /* for returning to caller */
3625 smb_Get8Dot3MaskFromPath(mask, pathp);
3627 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3628 tp = smb_GetSMBData(outp, NULL);
3630 *tp++ = 43; /* bytes in a dir entry */
3631 *tp++ = 0; /* high byte in counter */
3633 /* now marshall the dir entry, starting with the search status */
3634 *tp++ = statBlockp[0]; /* Reserved */
3635 memcpy(tp, mask, 11); tp += 11; /* FileName */
3637 /* now pass back server use info, with 1st byte non-zero */
3639 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3641 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3643 *tp++ = 0x8; /* attribute: volume */
3653 /* 4 byte file size */
3659 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3660 memset(tp, ' ', 13);
3663 /* set the length of the data part of the packet to 43 + 3, for the dir
3664 * entry plus the 5 and the length fields.
3666 smb_SetSMBDataLength(outp, 46);
3670 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3671 cm_user_t *userp, cm_req_t *reqp)
3679 smb_dirListPatch_t *patchp;
3680 smb_dirListPatch_t *npatchp;
3682 for (patchp = *dirPatchespp; patchp; patchp =
3683 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3685 dptr = patchp->dptr;
3687 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3689 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3690 *dptr++ = SMB_ATTR_HIDDEN;
3693 lock_ObtainMutex(&scp->mx);
3694 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3695 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3697 lock_ReleaseMutex(&scp->mx);
3698 cm_ReleaseSCache(scp);
3699 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3700 *dptr++ = SMB_ATTR_HIDDEN;
3704 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3706 attr = smb_Attributes(scp);
3707 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3708 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3709 attr |= SMB_ATTR_HIDDEN;
3713 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3716 shortTemp = (unsigned short) (dosTime & 0xffff);
3717 *((u_short *)dptr) = shortTemp;
3720 /* and copy out date */
3721 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3722 *((u_short *)dptr) = shortTemp;
3725 /* copy out file length */
3726 *((u_long *)dptr) = scp->length.LowPart;
3728 lock_ReleaseMutex(&scp->mx);
3729 cm_ReleaseSCache(scp);
3732 /* now free the patches */
3733 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3734 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3738 /* and mark the list as empty */
3739 *dirPatchespp = NULL;
3744 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3753 smb_dirListPatch_t *dirListPatchesp;
3754 smb_dirListPatch_t *curPatchp;
3758 osi_hyper_t dirLength;
3759 osi_hyper_t bufferOffset;
3760 osi_hyper_t curOffset;
3762 unsigned char *inCookiep;
3763 smb_dirSearch_t *dsp;
3767 unsigned long clientCookie;
3768 cm_pageHeader_t *pageHeaderp;
3769 cm_user_t *userp = NULL;
3776 long nextEntryCookie;
3777 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3778 char resByte; /* reserved byte from the cookie */
3779 char *op; /* output data ptr */
3780 char *origOp; /* original value of op */
3781 cm_space_t *spacep; /* for pathname buffer */
3792 maxCount = smb_GetSMBParm(inp, 0);
3794 dirListPatchesp = NULL;
3796 caseFold = CM_FLAG_CASEFOLD;
3798 tp = smb_GetSMBData(inp, NULL);
3799 pathp = smb_ParseASCIIBlock(tp, &tp);
3800 if (smb_StoreAnsiFilenames)
3801 OemToChar(pathp,pathp);
3802 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3804 /* bail out if request looks bad */
3805 if (!tp || !pathp) {
3806 return CM_ERROR_BADSMB;
3809 /* We can handle long names */
3810 if (vcp->flags & SMB_VCFLAG_USENT)
3811 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3813 /* make sure we got a whole search status */
3814 if (dataLength < 21) {
3815 nextCookie = 0; /* start at the beginning of the dir */
3818 attribute = smb_GetSMBParm(inp, 1);
3820 /* handle volume info in another function */
3821 if (attribute & 0x8)
3822 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3824 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3825 maxCount, osi_LogSaveString(smb_logp, pathp));
3827 if (*pathp == 0) { /* null pathp, treat as root dir */
3828 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3829 return CM_ERROR_NOFILES;
3833 dsp = smb_NewDirSearch(0);
3834 dsp->attribute = attribute;
3835 smb_Get8Dot3MaskFromPath(mask, pathp);
3836 memcpy(dsp->mask, mask, 11);
3838 /* track if this is likely to match a lot of entries */
3839 if (smb_IsStarMask(mask))
3844 /* pull the next cookie value out of the search status block */
3845 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3846 + (inCookiep[16]<<24);
3847 dsp = smb_FindDirSearch(inCookiep[12]);
3849 /* can't find dir search status; fatal error */
3850 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3851 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3852 return CM_ERROR_BADFD;
3854 attribute = dsp->attribute;
3855 resByte = inCookiep[0];
3857 /* copy out client cookie, in host byte order. Don't bother
3858 * interpreting it, since we're just passing it through, anyway.
3860 memcpy(&clientCookie, &inCookiep[17], 4);
3862 memcpy(mask, dsp->mask, 11);
3864 /* assume we're doing a star match if it has continued for more
3870 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3871 nextCookie, dsp->cookie, attribute);
3873 userp = smb_GetUserFromVCP(vcp, inp);
3875 /* try to get the vnode for the path name next */
3876 lock_ObtainMutex(&dsp->mx);
3882 spacep = inp->spacep;
3883 smb_StripLastComponent(spacep->data, NULL, pathp);
3884 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3886 lock_ReleaseMutex(&dsp->mx);
3887 cm_ReleaseUser(userp);
3888 smb_DeleteDirSearch(dsp);
3889 smb_ReleaseDirSearch(dsp);
3890 return CM_ERROR_NOFILES;
3892 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3893 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3896 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3897 cm_ReleaseSCache(scp);
3898 lock_ReleaseMutex(&dsp->mx);
3899 cm_ReleaseUser(userp);
3900 smb_DeleteDirSearch(dsp);
3901 smb_ReleaseDirSearch(dsp);
3902 if ( WANTS_DFS_PATHNAMES(inp) )
3903 return CM_ERROR_PATH_NOT_COVERED;
3905 return CM_ERROR_BADSHARENAME;
3907 #endif /* DFS_SUPPORT */
3910 /* we need one hold for the entry we just stored into,
3911 * and one for our own processing. When we're done with this
3912 * function, we'll drop the one for our own processing.
3913 * We held it once from the namei call, and so we do another hold
3917 lock_ObtainMutex(&scp->mx);
3918 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3919 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3920 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3921 dsp->flags |= SMB_DIRSEARCH_BULKST;
3922 dsp->scp->bulkStatProgress = hzero;
3924 lock_ReleaseMutex(&scp->mx);
3927 lock_ReleaseMutex(&dsp->mx);
3929 cm_ReleaseUser(userp);
3930 smb_DeleteDirSearch(dsp);
3931 smb_ReleaseDirSearch(dsp);
3935 /* reserves space for parameter; we'll adjust it again later to the
3936 * real count of the # of entries we returned once we've actually
3937 * assembled the directory listing.
3939 smb_SetSMBParm(outp, 0, 0);
3941 /* get the directory size */
3942 lock_ObtainMutex(&scp->mx);
3943 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3944 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3946 lock_ReleaseMutex(&scp->mx);
3947 cm_ReleaseSCache(scp);
3948 cm_ReleaseUser(userp);
3949 smb_DeleteDirSearch(dsp);
3950 smb_ReleaseDirSearch(dsp);
3954 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3956 dirLength = scp->length;
3958 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3959 curOffset.HighPart = 0;
3960 curOffset.LowPart = nextCookie;
3961 origOp = op = smb_GetSMBData(outp, NULL);
3962 /* and write out the basic header */
3963 *op++ = 5; /* variable block */
3964 op += 2; /* skip vbl block length; we'll fill it in later */
3968 /* make sure that curOffset.LowPart doesn't point to the first
3969 * 32 bytes in the 2nd through last dir page, and that it doesn't
3970 * point at the first 13 32-byte chunks in the first dir page,
3971 * since those are dir and page headers, and don't contain useful
3974 temp = curOffset.LowPart & (2048-1);
3975 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3976 /* we're in the first page */
3977 if (temp < 13*32) temp = 13*32;
3980 /* we're in a later dir page */
3981 if (temp < 32) temp = 32;
3984 /* make sure the low order 5 bits are zero */
3987 /* now put temp bits back ito curOffset.LowPart */
3988 curOffset.LowPart &= ~(2048-1);
3989 curOffset.LowPart |= temp;
3991 /* check if we've returned all the names that will fit in the
3994 if (returnedNames >= maxCount) {
3995 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3996 returnedNames, maxCount);
4000 /* check if we've passed the dir's EOF */
4001 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4003 /* see if we can use the bufferp we have now; compute in which page
4004 * the current offset would be, and check whether that's the offset
4005 * of the buffer we have. If not, get the buffer.
4007 thyper.HighPart = curOffset.HighPart;
4008 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4009 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4012 buf_Release(bufferp);
4015 lock_ReleaseMutex(&scp->mx);
4016 lock_ObtainRead(&scp->bufCreateLock);
4017 code = buf_Get(scp, &thyper, &bufferp);
4018 lock_ReleaseRead(&scp->bufCreateLock);
4019 lock_ObtainMutex(&dsp->mx);
4021 /* now, if we're doing a star match, do bulk fetching of all of
4022 * the status info for files in the dir.
4025 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4026 lock_ObtainMutex(&scp->mx);
4027 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4028 LargeIntegerGreaterThanOrEqualTo(thyper,
4029 scp->bulkStatProgress)) {
4030 /* Don't bulk stat if risking timeout */
4031 int now = GetTickCount();
4032 if (now - req.startTime > RDRtimeout) {
4033 scp->bulkStatProgress = thyper;
4034 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4035 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4036 dsp->scp->bulkStatProgress = hzero;
4038 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4041 lock_ObtainMutex(&scp->mx);
4043 lock_ReleaseMutex(&dsp->mx);
4045 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4049 bufferOffset = thyper;
4051 /* now get the data in the cache */
4053 code = cm_SyncOp(scp, bufferp, userp, &req,
4055 CM_SCACHESYNC_NEEDCALLBACK |
4056 CM_SCACHESYNC_READ);
4058 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4062 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4064 if (cm_HaveBuffer(scp, bufferp, 0)) {
4065 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4069 /* otherwise, load the buffer and try again */
4070 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4072 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4073 scp, bufferp, code);
4078 buf_Release(bufferp);
4082 } /* if (wrong buffer) ... */
4084 /* now we have the buffer containing the entry we're interested in; copy
4085 * it out if it represents a non-deleted entry.
4087 entryInDir = curOffset.LowPart & (2048-1);
4088 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4090 /* page header will help tell us which entries are free. Page header
4091 * can change more often than once per buffer, since AFS 3 dir page size
4092 * may be less than (but not more than a buffer package buffer.
4094 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4095 temp &= ~(2048 - 1); /* turn off intra-page bits */
4096 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4098 /* now determine which entry we're looking at in the page. If it is
4099 * free (there's a free bitmap at the start of the dir), we should
4100 * skip these 32 bytes.
4102 slotInPage = (entryInDir & 0x7e0) >> 5;
4103 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4104 /* this entry is free */
4105 numDirChunks = 1; /* only skip this guy */
4109 tp = bufferp->datap + entryInBuffer;
4110 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4112 /* while we're here, compute the next entry's location, too,
4113 * since we'll need it when writing out the cookie into the dir
4116 * XXXX Probably should do more sanity checking.
4118 numDirChunks = cm_NameEntries(dep->name, NULL);
4120 /* compute the offset of the cookie representing the next entry */
4121 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4123 /* Compute 8.3 name if necessary */
4124 actualName = dep->name;
4125 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4126 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4127 actualName = shortName;
4130 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4131 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4132 osi_LogSaveString(smb_logp, actualName));
4134 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4135 /* this is one of the entries to use: it is not deleted
4136 * and it matches the star pattern we're looking for.
4139 /* Eliminate entries that don't match requested
4142 /* no hidden files */
4143 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4144 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4148 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4150 /* We have already done the cm_TryBulkStat above */
4151 fid.cell = scp->fid.cell;
4152 fid.volume = scp->fid.volume;
4153 fid.vnode = ntohl(dep->fid.vnode);
4154 fid.unique = ntohl(dep->fid.unique);
4155 fileType = cm_FindFileType(&fid);
4156 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4157 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4159 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4160 fileType == CM_SCACHETYPE_DFSLINK ||
4161 fileType == CM_SCACHETYPE_INVALID)
4162 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4167 memcpy(op, mask, 11); op += 11;
4168 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4169 *op++ = (char)(nextEntryCookie & 0xff);
4170 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4171 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4172 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4173 memcpy(op, &clientCookie, 4); op += 4;
4175 /* now we emit the attribute. This is sort of tricky,
4176 * since we need to really stat the file to find out
4177 * what type of entry we've got. Right now, we're
4178 * copying out data from a buffer, while holding the
4179 * scp locked, so it isn't really convenient to stat
4180 * something now. We'll put in a place holder now,
4181 * and make a second pass before returning this to get
4182 * the real attributes. So, we just skip the data for
4183 * now, and adjust it later. We allocate a patch
4184 * record to make it easy to find this point later.
4185 * The replay will happen at a time when it is safe to
4186 * unlock the directory.
4188 curPatchp = malloc(sizeof(*curPatchp));
4189 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4190 curPatchp->dptr = op;
4191 curPatchp->fid.cell = scp->fid.cell;
4192 curPatchp->fid.volume = scp->fid.volume;
4193 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4194 curPatchp->fid.unique = ntohl(dep->fid.unique);
4196 /* do hidden attribute here since name won't be around when applying
4200 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4201 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4203 curPatchp->flags = 0;
4205 op += 9; /* skip attr, time, date and size */
4207 /* zero out name area. The spec says to pad with
4208 * spaces, but Samba doesn't, and neither do we.
4212 /* finally, we get to copy out the name; we know that
4213 * it fits in 8.3 or the pattern wouldn't match, but it
4214 * never hurts to be sure.
4216 strncpy(op, actualName, 13);
4217 if (smb_StoreAnsiFilenames)
4220 /* Uppercase if requested by client */
4221 if (!KNOWS_LONG_NAMES(inp))
4226 /* now, adjust the # of entries copied */
4228 } /* if we're including this name */
4231 /* and adjust curOffset to be where the new cookie is */
4232 thyper.HighPart = 0;
4233 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4234 curOffset = LargeIntegerAdd(thyper, curOffset);
4235 } /* while copying data for dir listing */
4237 /* release the mutex */
4238 lock_ReleaseMutex(&scp->mx);
4240 buf_Release(bufferp);
4244 /* apply and free last set of patches; if not doing a star match, this
4245 * will be empty, but better safe (and freeing everything) than sorry.
4247 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4249 /* special return code for unsuccessful search */
4250 if (code == 0 && dataLength < 21 && returnedNames == 0)
4251 code = CM_ERROR_NOFILES;
4253 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4254 returnedNames, code);
4257 smb_DeleteDirSearch(dsp);
4258 smb_ReleaseDirSearch(dsp);
4259 cm_ReleaseSCache(scp);
4260 cm_ReleaseUser(userp);
4264 /* finalize the output buffer */
4265 smb_SetSMBParm(outp, 0, returnedNames);
4266 temp = (long) (op - origOp);
4267 smb_SetSMBDataLength(outp, temp);
4269 /* the data area is a variable block, which has a 5 (already there)
4270 * followed by the length of the # of data bytes. We now know this to
4271 * be "temp," although that includes the 3 bytes of vbl block header.
4272 * Deduct for them and fill in the length field.
4274 temp -= 3; /* deduct vbl block info */
4275 osi_assert(temp == (43 * returnedNames));
4276 origOp[1] = (char)(temp & 0xff);
4277 origOp[2] = (char)((temp>>8) & 0xff);
4278 if (returnedNames == 0)
4279 smb_DeleteDirSearch(dsp);
4280 smb_ReleaseDirSearch(dsp);
4281 cm_ReleaseSCache(scp);
4282 cm_ReleaseUser(userp);
4286 /* verify that this is a valid path to a directory. I don't know why they
4287 * don't use the get file attributes call.
4289 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4293 cm_scache_t *rootScp;
4294 cm_scache_t *newScp;
4303 pathp = smb_GetSMBData(inp, NULL);
4304 pathp = smb_ParseASCIIBlock(pathp, NULL);
4306 return CM_ERROR_BADFD;
4307 if (smb_StoreAnsiFilenames)
4308 OemToChar(pathp,pathp);
4309 osi_Log1(smb_logp, "SMB receive check path %s",
4310 osi_LogSaveString(smb_logp, pathp));
4312 rootScp = cm_data.rootSCachep;
4314 userp = smb_GetUserFromVCP(vcp, inp);
4316 caseFold = CM_FLAG_CASEFOLD;
4318 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4320 cm_ReleaseUser(userp);
4321 return CM_ERROR_NOSUCHPATH;
4323 code = cm_NameI(rootScp, pathp,
4324 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4325 userp, tidPathp, &req, &newScp);
4328 cm_ReleaseUser(userp);
4333 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4334 cm_ReleaseSCache(newScp);
4335 cm_ReleaseUser(userp);
4336 if ( WANTS_DFS_PATHNAMES(inp) )
4337 return CM_ERROR_PATH_NOT_COVERED;
4339 return CM_ERROR_BADSHARENAME;
4341 #endif /* DFS_SUPPORT */
4343 /* now lock the vnode with a callback; returns with newScp locked */
4344 lock_ObtainMutex(&newScp->mx);
4345 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4346 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4348 if (code != CM_ERROR_NOACCESS) {
4349 lock_ReleaseMutex(&newScp->mx);
4350 cm_ReleaseSCache(newScp);
4351 cm_ReleaseUser(userp);
4355 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4358 attrs = smb_Attributes(newScp);
4360 if (!(attrs & SMB_ATTR_DIRECTORY))
4361 code = CM_ERROR_NOTDIR;
4363 lock_ReleaseMutex(&newScp->mx);
4365 cm_ReleaseSCache(newScp);
4366 cm_ReleaseUser(userp);
4370 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4374 cm_scache_t *rootScp;
4375 unsigned short attribute;
4377 cm_scache_t *newScp;
4386 /* decode basic attributes we're passed */
4387 attribute = smb_GetSMBParm(inp, 0);
4388 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4390 pathp = smb_GetSMBData(inp, NULL);
4391 pathp = smb_ParseASCIIBlock(pathp, NULL);
4393 return CM_ERROR_BADSMB;
4394 if (smb_StoreAnsiFilenames)
4395 OemToChar(pathp,pathp);
4397 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4398 dosTime, attribute);
4400 rootScp = cm_data.rootSCachep;
4402 userp = smb_GetUserFromVCP(vcp, inp);
4404 caseFold = CM_FLAG_CASEFOLD;
4406 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4408 cm_ReleaseUser(userp);
4409 return CM_ERROR_NOSUCHFILE;
4411 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4412 tidPathp, &req, &newScp);
4415 cm_ReleaseUser(userp);
4420 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4421 cm_ReleaseSCache(newScp);
4422 cm_ReleaseUser(userp);
4423 if ( WANTS_DFS_PATHNAMES(inp) )
4424 return CM_ERROR_PATH_NOT_COVERED;
4426 return CM_ERROR_BADSHARENAME;
4428 #endif /* DFS_SUPPORT */
4430 /* now lock the vnode with a callback; returns with newScp locked; we
4431 * need the current status to determine what the new status is, in some
4434 lock_ObtainMutex(&newScp->mx);
4435 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4436 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4438 lock_ReleaseMutex(&newScp->mx);
4439 cm_ReleaseSCache(newScp);
4440 cm_ReleaseUser(userp);
4444 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4446 /* Check for RO volume */
4447 if (newScp->flags & CM_SCACHEFLAG_RO) {
4448 lock_ReleaseMutex(&newScp->mx);
4449 cm_ReleaseSCache(newScp);
4450 cm_ReleaseUser(userp);
4451 return CM_ERROR_READONLY;
4454 /* prepare for setattr call */
4457 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4458 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4460 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4461 /* we're told to make a writable file read-only */
4462 attr.unixModeBits = newScp->unixModeBits & ~0222;
4463 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4465 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4466 /* we're told to make a read-only file writable */
4467 attr.unixModeBits = newScp->unixModeBits | 0222;
4468 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4470 lock_ReleaseMutex(&newScp->mx);
4472 /* now call setattr */
4474 code = cm_SetAttr(newScp, &attr, userp, &req);
4478 cm_ReleaseSCache(newScp);
4479 cm_ReleaseUser(userp);
4484 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4488 cm_scache_t *rootScp;
4489 cm_scache_t *newScp, *dscp;
4501 pathp = smb_GetSMBData(inp, NULL);
4502 pathp = smb_ParseASCIIBlock(pathp, NULL);
4504 return CM_ERROR_BADSMB;
4506 if (*pathp == 0) /* null path */
4509 if (smb_StoreAnsiFilenames)
4510 OemToChar(pathp,pathp);
4512 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4513 osi_LogSaveString(smb_logp, pathp));
4515 rootScp = cm_data.rootSCachep;
4517 userp = smb_GetUserFromVCP(vcp, inp);
4519 /* we shouldn't need this for V3 requests, but we seem to */
4520 caseFold = CM_FLAG_CASEFOLD;
4522 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4524 cm_ReleaseUser(userp);
4525 return CM_ERROR_NOSUCHFILE;
4529 * XXX Strange hack XXX
4531 * As of Patch 5 (16 July 97), we are having the following problem:
4532 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4533 * requests to look up "desktop.ini" in all the subdirectories.
4534 * This can cause zillions of timeouts looking up non-existent cells
4535 * and volumes, especially in the top-level directory.
4537 * We have not found any way to avoid this or work around it except
4538 * to explicitly ignore the requests for mount points that haven't
4539 * yet been evaluated and for directories that haven't yet been
4542 * We should modify this hack to provide a fake desktop.ini file
4543 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4545 spacep = inp->spacep;
4546 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4547 #ifndef SPECIAL_FOLDERS
4548 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4549 code = cm_NameI(rootScp, spacep->data,
4550 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4551 userp, tidPathp, &req, &dscp);
4554 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4555 if ( WANTS_DFS_PATHNAMES(inp) )
4556 return CM_ERROR_PATH_NOT_COVERED;
4558 return CM_ERROR_BADSHARENAME;
4560 #endif /* DFS_SUPPORT */
4561 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4562 code = CM_ERROR_NOSUCHFILE;
4563 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4564 cm_buf_t *bp = buf_Find(dscp, &hzero);
4569 code = CM_ERROR_NOSUCHFILE;
4571 cm_ReleaseSCache(dscp);
4573 cm_ReleaseUser(userp);
4578 #endif /* SPECIAL_FOLDERS */
4580 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4581 tidPathp, &req, &newScp);
4583 cm_ReleaseUser(userp);
4588 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4589 cm_ReleaseSCache(newScp);
4590 cm_ReleaseUser(userp);
4591 if ( WANTS_DFS_PATHNAMES(inp) )
4592 return CM_ERROR_PATH_NOT_COVERED;
4594 return CM_ERROR_BADSHARENAME;
4596 #endif /* DFS_SUPPORT */
4598 /* now lock the vnode with a callback; returns with newScp locked */
4599 lock_ObtainMutex(&newScp->mx);
4600 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4601 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4603 lock_ReleaseMutex(&newScp->mx);
4604 cm_ReleaseSCache(newScp);
4605 cm_ReleaseUser(userp);
4609 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4612 /* use smb_Attributes instead. Also the fact that a file is
4613 * in a readonly volume doesn't mean it shojuld be marked as RO
4615 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4616 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4617 newScp->fileType == CM_SCACHETYPE_INVALID)
4618 attrs = SMB_ATTR_DIRECTORY;
4621 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4622 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4624 attrs = smb_Attributes(newScp);
4627 smb_SetSMBParm(outp, 0, attrs);
4629 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4630 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4631 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4632 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4633 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4634 smb_SetSMBParm(outp, 5, 0);
4635 smb_SetSMBParm(outp, 6, 0);
4636 smb_SetSMBParm(outp, 7, 0);
4637 smb_SetSMBParm(outp, 8, 0);
4638 smb_SetSMBParm(outp, 9, 0);
4639 smb_SetSMBDataLength(outp, 0);
4640 lock_ReleaseMutex(&newScp->mx);
4642 cm_ReleaseSCache(newScp);
4643 cm_ReleaseUser(userp);
4648 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4652 osi_Log0(smb_logp, "SMB receive tree disconnect");
4654 /* find the tree and free it */
4655 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4657 lock_ObtainWrite(&smb_rctLock);
4659 lock_ReleaseWrite(&smb_rctLock);
4660 smb_ReleaseTID(tidp);
4666 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4684 pathp = smb_GetSMBData(inp, NULL);
4685 pathp = smb_ParseASCIIBlock(pathp, NULL);
4686 if (smb_StoreAnsiFilenames)
4687 OemToChar(pathp,pathp);
4689 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4691 #ifdef DEBUG_VERBOSE
4695 hexpath = osi_HexifyString( pathp );
4696 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4701 share = smb_GetSMBParm(inp, 0);
4702 attribute = smb_GetSMBParm(inp, 1);
4704 spacep = inp->spacep;
4705 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4706 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4707 /* special case magic file name for receiving IOCTL requests
4708 * (since IOCTL calls themselves aren't getting through).
4710 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4711 smb_SetupIoctlFid(fidp, spacep);
4712 smb_SetSMBParm(outp, 0, fidp->fid);
4713 smb_SetSMBParm(outp, 1, 0); /* attrs */
4714 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4715 smb_SetSMBParm(outp, 3, 0);
4716 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4717 smb_SetSMBParm(outp, 5, 0x7fff);
4718 /* pass the open mode back */
4719 smb_SetSMBParm(outp, 6, (share & 0xf));
4720 smb_SetSMBDataLength(outp, 0);
4721 smb_ReleaseFID(fidp);
4725 userp = smb_GetUserFromVCP(vcp, inp);
4727 caseFold = CM_FLAG_CASEFOLD;
4729 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4731 cm_ReleaseUser(userp);
4732 return CM_ERROR_NOSUCHPATH;
4734 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4735 tidPathp, &req, &scp);
4738 cm_ReleaseUser(userp);
4743 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4744 cm_ReleaseSCache(scp);
4745 cm_ReleaseUser(userp);
4746 if ( WANTS_DFS_PATHNAMES(inp) )
4747 return CM_ERROR_PATH_NOT_COVERED;
4749 return CM_ERROR_BADSHARENAME;
4751 #endif /* DFS_SUPPORT */
4753 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4755 cm_ReleaseSCache(scp);
4756 cm_ReleaseUser(userp);
4760 /* don't need callback to check file type, since file types never
4761 * change, and namei and cm_Lookup all stat the object at least once on
4762 * a successful return.
4764 if (scp->fileType != CM_SCACHETYPE_FILE) {
4765 cm_ReleaseSCache(scp);
4766 cm_ReleaseUser(userp);
4767 return CM_ERROR_ISDIR;
4770 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4773 /* save a pointer to the vnode */
4777 fidp->userp = userp;
4779 lock_ObtainMutex(&fidp->mx);
4780 if ((share & 0xf) == 0)
4781 fidp->flags |= SMB_FID_OPENREAD;
4782 else if ((share & 0xf) == 1)
4783 fidp->flags |= SMB_FID_OPENWRITE;
4785 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4786 lock_ReleaseMutex(&fidp->mx);
4788 lock_ObtainMutex(&scp->mx);
4789 smb_SetSMBParm(outp, 0, fidp->fid);
4790 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4791 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4792 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4793 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4794 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4795 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4796 /* pass the open mode back; XXXX add access checks */
4797 smb_SetSMBParm(outp, 6, (share & 0xf));
4798 smb_SetSMBDataLength(outp, 0);
4799 lock_ReleaseMutex(&scp->mx);
4802 cm_Open(scp, 0, userp);
4804 /* send and free packet */
4805 smb_ReleaseFID(fidp);
4806 cm_ReleaseUser(userp);
4807 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4811 typedef struct smb_unlinkRock {
4816 char *maskp; /* pointer to the star pattern */
4821 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4824 smb_unlinkRock_t *rockp;
4832 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4833 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4834 caseFold |= CM_FLAG_8DOT3;
4836 matchName = dep->name;
4837 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4839 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4840 !cm_Is8Dot3(dep->name)) {
4841 cm_Gen8Dot3Name(dep, shortName, NULL);
4842 matchName = shortName;
4843 /* 8.3 matches are always case insensitive */
4844 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4847 osi_Log1(smb_logp, "Unlinking %s",
4848 osi_LogSaveString(smb_logp, matchName));
4849 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4850 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4851 smb_NotifyChange(FILE_ACTION_REMOVED,
4852 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
4853 dscp, dep->name, NULL, TRUE);
4857 /* If we made a case sensitive exact match, we might as well quit now. */
4858 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4859 code = CM_ERROR_STOPNOW;
4867 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4876 smb_unlinkRock_t rock;
4885 attribute = smb_GetSMBParm(inp, 0);
4887 tp = smb_GetSMBData(inp, NULL);
4888 pathp = smb_ParseASCIIBlock(tp, &tp);
4889 if (smb_StoreAnsiFilenames)
4890 OemToChar(pathp,pathp);
4892 osi_Log1(smb_logp, "SMB receive unlink %s",
4893 osi_LogSaveString(smb_logp, pathp));
4895 spacep = inp->spacep;
4896 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4898 userp = smb_GetUserFromVCP(vcp, inp);
4900 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4902 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4904 cm_ReleaseUser(userp);
4905 return CM_ERROR_NOSUCHPATH;
4907 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4910 cm_ReleaseUser(userp);
4915 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4916 cm_ReleaseSCache(dscp);
4917 cm_ReleaseUser(userp);
4918 if ( WANTS_DFS_PATHNAMES(inp) )
4919 return CM_ERROR_PATH_NOT_COVERED;
4921 return CM_ERROR_BADSHARENAME;
4923 #endif /* DFS_SUPPORT */
4925 /* otherwise, scp points to the parent directory. */
4932 rock.maskp = smb_FindMask(pathp);
4933 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4936 thyper.HighPart = 0;
4942 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4943 * match. If that fails, we do a case insensitve match.
4945 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4946 !smb_IsStarMask(rock.maskp)) {
4947 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4950 thyper.HighPart = 0;
4951 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4956 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4958 if (code == CM_ERROR_STOPNOW)
4961 cm_ReleaseUser(userp);
4963 cm_ReleaseSCache(dscp);
4965 if (code == 0 && !rock.any)
4966 code = CM_ERROR_NOSUCHFILE;
4970 typedef struct smb_renameRock {
4971 cm_scache_t *odscp; /* old dir */
4972 cm_scache_t *ndscp; /* new dir */
4973 cm_user_t *userp; /* user */
4974 cm_req_t *reqp; /* request struct */
4975 smb_vc_t *vcp; /* virtual circuit */
4976 char *maskp; /* pointer to star pattern of old file name */
4977 int flags; /* tilde, casefold, etc */
4978 char *newNamep; /* ptr to the new file's name */
4981 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4984 smb_renameRock_t *rockp;
4989 rockp = (smb_renameRock_t *) vrockp;
4991 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4992 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4993 caseFold |= CM_FLAG_8DOT3;
4995 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4997 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4998 !cm_Is8Dot3(dep->name)) {
4999 cm_Gen8Dot3Name(dep, shortName, NULL);
5000 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5003 code = cm_Rename(rockp->odscp, dep->name,
5004 rockp->ndscp, rockp->newNamep, rockp->userp,
5006 /* if the call worked, stop doing the search now, since we
5007 * really only want to rename one file.
5010 code = CM_ERROR_STOPNOW;
5019 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5022 cm_space_t *spacep = NULL;
5023 smb_renameRock_t rock;
5024 cm_scache_t *oldDscp = NULL;
5025 cm_scache_t *newDscp = NULL;
5026 cm_scache_t *tmpscp= NULL;
5027 cm_scache_t *tmpscp2 = NULL;
5037 userp = smb_GetUserFromVCP(vcp, inp);
5038 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5040 cm_ReleaseUser(userp);
5041 return CM_ERROR_NOSUCHPATH;
5045 spacep = inp->spacep;
5046 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5048 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5049 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5050 userp, tidPathp, &req, &oldDscp);
5052 cm_ReleaseUser(userp);
5057 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5058 cm_ReleaseSCache(oldDscp);
5059 cm_ReleaseUser(userp);
5060 if ( WANTS_DFS_PATHNAMES(inp) )
5061 return CM_ERROR_PATH_NOT_COVERED;
5063 return CM_ERROR_BADSHARENAME;
5065 #endif /* DFS_SUPPORT */
5067 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5068 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5069 userp, tidPathp, &req, &newDscp);
5072 cm_ReleaseSCache(oldDscp);
5073 cm_ReleaseUser(userp);
5078 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5079 cm_ReleaseSCache(oldDscp);
5080 cm_ReleaseSCache(newDscp);
5081 cm_ReleaseUser(userp);
5082 if ( WANTS_DFS_PATHNAMES(inp) )
5083 return CM_ERROR_PATH_NOT_COVERED;
5085 return CM_ERROR_BADSHARENAME;
5087 #endif /* DFS_SUPPORT */
5090 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5091 * next, get the component names, and lower case them.
5094 /* handle the old name first */
5096 oldLastNamep = oldPathp;
5100 /* and handle the new name, too */
5102 newLastNamep = newPathp;
5106 /* TODO: The old name could be a wildcard. The new name must not be */
5108 /* do the vnode call */
5109 rock.odscp = oldDscp;
5110 rock.ndscp = newDscp;
5114 rock.maskp = oldLastNamep;
5115 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5116 rock.newNamep = newLastNamep;
5118 /* Check if the file already exists; if so return error */
5119 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5120 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5121 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5122 osi_LogSaveString(afsd_logp, newLastNamep));
5124 /* Check if the old and the new names differ only in case. If so return
5125 * success, else return CM_ERROR_EXISTS
5127 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5129 /* This would be a success only if the old file is *as same as* the new file */
5130 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5132 if (tmpscp == tmpscp2)
5135 code = CM_ERROR_EXISTS;
5136 cm_ReleaseSCache(tmpscp2);
5139 code = CM_ERROR_NOSUCHFILE;
5142 /* file exist, do not rename, also fixes move */
5143 osi_Log0(smb_logp, "Can't rename. Target already exists");
5144 code = CM_ERROR_EXISTS;
5148 cm_ReleaseSCache(tmpscp);
5149 cm_ReleaseSCache(newDscp);
5150 cm_ReleaseSCache(oldDscp);
5151 cm_ReleaseUser(userp);
5155 /* Now search the directory for the pattern, and do the appropriate rename when found */
5156 thyper.LowPart = 0; /* search dir from here */
5157 thyper.HighPart = 0;
5159 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5160 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5162 if (code == CM_ERROR_STOPNOW)
5165 code = CM_ERROR_NOSUCHFILE;
5167 /* Handle Change Notification */
5169 * Being lazy, not distinguishing between files and dirs in this
5170 * filter, since we'd have to do a lookup.
5172 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5173 if (oldDscp == newDscp) {
5174 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5175 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5176 filter, oldDscp, oldLastNamep,
5177 newLastNamep, TRUE);
5179 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5180 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5181 filter, oldDscp, oldLastNamep,
5183 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5184 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5185 filter, newDscp, newLastNamep,
5190 cm_ReleaseSCache(tmpscp);
5191 cm_ReleaseUser(userp);
5192 cm_ReleaseSCache(oldDscp);
5193 cm_ReleaseSCache(newDscp);
5198 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5201 cm_space_t *spacep = NULL;
5202 cm_scache_t *oldDscp = NULL;
5203 cm_scache_t *newDscp = NULL;
5204 cm_scache_t *tmpscp= NULL;
5205 cm_scache_t *tmpscp2 = NULL;
5206 cm_scache_t *sscp = NULL;
5215 userp = smb_GetUserFromVCP(vcp, inp);
5217 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5219 cm_ReleaseUser(userp);
5220 return CM_ERROR_NOSUCHPATH;
5225 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5227 spacep = inp->spacep;
5228 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5230 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5231 userp, tidPathp, &req, &oldDscp);
5233 cm_ReleaseUser(userp);
5238 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5239 cm_ReleaseSCache(oldDscp);
5240 cm_ReleaseUser(userp);
5241 if ( WANTS_DFS_PATHNAMES(inp) )
5242 return CM_ERROR_PATH_NOT_COVERED;
5244 return CM_ERROR_BADSHARENAME;
5246 #endif /* DFS_SUPPORT */
5248 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5249 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5250 userp, tidPathp, &req, &newDscp);
5252 cm_ReleaseSCache(oldDscp);
5253 cm_ReleaseUser(userp);
5258 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5259 cm_ReleaseSCache(newDscp);
5260 cm_ReleaseSCache(oldDscp);
5261 cm_ReleaseUser(userp);
5262 if ( WANTS_DFS_PATHNAMES(inp) )
5263 return CM_ERROR_PATH_NOT_COVERED;
5265 return CM_ERROR_BADSHARENAME;
5267 #endif /* DFS_SUPPORT */
5269 /* Now, although we did two lookups for the two directories (because the same
5270 * directory can be referenced through different paths), we only allow hard links
5271 * within the same directory. */
5272 if (oldDscp != newDscp) {
5273 cm_ReleaseSCache(oldDscp);
5274 cm_ReleaseSCache(newDscp);
5275 cm_ReleaseUser(userp);
5276 return CM_ERROR_CROSSDEVLINK;
5279 /* handle the old name first */
5281 oldLastNamep = oldPathp;
5285 /* and handle the new name, too */
5287 newLastNamep = newPathp;
5291 /* now lookup the old name */
5292 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5293 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5295 cm_ReleaseSCache(oldDscp);
5296 cm_ReleaseSCache(newDscp);
5297 cm_ReleaseUser(userp);
5301 /* Check if the file already exists; if so return error */
5302 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5303 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5304 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5305 osi_LogSaveString(afsd_logp, newLastNamep));
5307 /* if the existing link is to the same file, then we return success */
5309 if(sscp == tmpscp) {
5312 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5313 code = CM_ERROR_EXISTS;
5318 cm_ReleaseSCache(tmpscp);
5319 cm_ReleaseSCache(sscp);
5320 cm_ReleaseSCache(newDscp);
5321 cm_ReleaseSCache(oldDscp);
5322 cm_ReleaseUser(userp);
5326 /* now create the hardlink */
5327 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5328 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5329 osi_Log1(smb_logp," Link returns 0x%x", code);
5331 /* Handle Change Notification */
5333 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5334 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5335 smb_NotifyChange(FILE_ACTION_ADDED,
5336 filter, newDscp, newLastNamep,
5341 cm_ReleaseSCache(tmpscp);
5342 cm_ReleaseUser(userp);
5343 cm_ReleaseSCache(sscp);
5344 cm_ReleaseSCache(oldDscp);
5345 cm_ReleaseSCache(newDscp);
5350 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5356 tp = smb_GetSMBData(inp, NULL);
5357 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5358 if (smb_StoreAnsiFilenames)
5359 OemToChar(oldPathp,oldPathp);
5360 newPathp = smb_ParseASCIIBlock(tp, &tp);
5361 if (smb_StoreAnsiFilenames)
5362 OemToChar(newPathp,newPathp);
5364 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5365 osi_LogSaveString(smb_logp, oldPathp),
5366 osi_LogSaveString(smb_logp, newPathp));
5368 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5373 typedef struct smb_rmdirRock {
5377 char *maskp; /* pointer to the star pattern */
5382 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5385 smb_rmdirRock_t *rockp;
5390 rockp = (smb_rmdirRock_t *) vrockp;
5392 matchName = dep->name;
5393 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5394 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5396 match = (strcmp(matchName, rockp->maskp) == 0);
5398 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5399 !cm_Is8Dot3(dep->name)) {
5400 cm_Gen8Dot3Name(dep, shortName, NULL);
5401 matchName = shortName;
5402 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5405 osi_Log1(smb_logp, "Removing directory %s",
5406 osi_LogSaveString(smb_logp, matchName));
5407 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5408 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5409 smb_NotifyChange(FILE_ACTION_REMOVED,
5410 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5411 dscp, dep->name, NULL, TRUE);
5420 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5428 smb_rmdirRock_t rock;
5437 tp = smb_GetSMBData(inp, NULL);
5438 pathp = smb_ParseASCIIBlock(tp, &tp);
5439 if (smb_StoreAnsiFilenames)
5440 OemToChar(pathp,pathp);
5442 spacep = inp->spacep;
5443 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5445 userp = smb_GetUserFromVCP(vcp, inp);
5447 caseFold = CM_FLAG_CASEFOLD;
5449 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5451 cm_ReleaseUser(userp);
5452 return CM_ERROR_NOSUCHPATH;
5454 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5455 userp, tidPathp, &req, &dscp);
5458 cm_ReleaseUser(userp);
5463 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5464 cm_ReleaseSCache(dscp);
5465 cm_ReleaseUser(userp);
5466 if ( WANTS_DFS_PATHNAMES(inp) )
5467 return CM_ERROR_PATH_NOT_COVERED;
5469 return CM_ERROR_BADSHARENAME;
5471 #endif /* DFS_SUPPORT */
5473 /* otherwise, scp points to the parent directory. */
5480 rock.maskp = lastNamep;
5481 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5484 thyper.HighPart = 0;
5488 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5489 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5490 if (code == 0 && !rock.any) {
5492 thyper.HighPart = 0;
5493 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5494 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5497 cm_ReleaseUser(userp);
5499 cm_ReleaseSCache(dscp);
5501 if (code == 0 && !rock.any)
5502 code = CM_ERROR_NOSUCHFILE;
5506 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5516 fid = smb_GetSMBParm(inp, 0);
5518 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5520 fid = smb_ChainFID(fid, inp);
5521 fidp = smb_FindFID(vcp, fid, 0);
5523 return CM_ERROR_BADFD;
5525 lock_ObtainMutex(&fidp->mx);
5526 if (fidp->flags & SMB_FID_IOCTL) {
5527 lock_ReleaseMutex(&fidp->mx);
5528 smb_ReleaseFID(fidp);
5529 return CM_ERROR_BADFD;
5531 lock_ReleaseMutex(&fidp->mx);
5533 userp = smb_GetUserFromVCP(vcp, inp);
5535 lock_ObtainMutex(&fidp->mx);
5536 if (fidp->flags & SMB_FID_OPENWRITE) {
5537 cm_scache_t * scp = fidp->scp;
5539 lock_ReleaseMutex(&fidp->mx);
5540 code = cm_FSync(scp, userp, &req);
5541 cm_ReleaseSCache(scp);
5544 lock_ReleaseMutex(&fidp->mx);
5547 smb_ReleaseFID(fidp);
5549 cm_ReleaseUser(userp);
5554 struct smb_FullNameRock {
5560 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5564 struct smb_FullNameRock *vrockp;
5566 vrockp = (struct smb_FullNameRock *)rockp;
5568 if (!cm_Is8Dot3(dep->name)) {
5569 cm_Gen8Dot3Name(dep, shortName, NULL);
5571 if (cm_stricmp(shortName, vrockp->name) == 0) {
5572 vrockp->fullName = strdup(dep->name);
5573 return CM_ERROR_STOPNOW;
5576 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5577 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5578 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5579 vrockp->fullName = strdup(dep->name);
5580 return CM_ERROR_STOPNOW;
5585 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5586 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5588 struct smb_FullNameRock rock;
5594 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5595 if (code == CM_ERROR_STOPNOW)
5596 *newPathp = rock.fullName;
5598 *newPathp = strdup(pathp);
5601 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5602 afs_uint32 dosTime) {
5605 cm_scache_t *dscp = fidp->NTopen_dscp;
5606 char *pathp = fidp->NTopen_pathp;
5609 osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
5610 fidp, fidp->fid, vcp);
5613 lock_ObtainMutex(&fidp->mx);
5614 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5615 lock_ReleaseMutex(&fidp->mx);
5616 osi_Log0(smb_logp, " No user specified. Not closing fid");
5617 return CM_ERROR_BADFD;
5620 userp = fidp->userp; /* no hold required since fidp is held
5621 throughout the function */
5622 lock_ReleaseMutex(&fidp->mx);
5627 lock_ObtainWrite(&smb_rctLock);
5629 osi_Log0(smb_logp, " Fid already closed.");
5630 lock_ReleaseWrite(&smb_rctLock);
5631 return CM_ERROR_BADFD;
5634 lock_ReleaseWrite(&smb_rctLock);
5636 lock_ObtainMutex(&fidp->mx);
5637 /* Don't jump the gun on an async raw write */
5638 while (fidp->raw_writers) {
5639 lock_ReleaseMutex(&fidp->mx);
5640 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5641 lock_ObtainMutex(&fidp->mx);
5648 /* watch for ioctl closes, and read-only opens */
5650 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5651 == SMB_FID_OPENWRITE) {
5652 if (dosTime != 0 && dosTime != -1) {
5653 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5654 /* This fixes defect 10958 */
5655 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5656 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5658 lock_ReleaseMutex(&fidp->mx);
5659 code = cm_FSync(scp, userp, &req);
5660 lock_ObtainMutex(&fidp->mx);
5665 /* unlock any pending locks */
5666 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5667 scp->fileType == CM_SCACHETYPE_FILE) {
5671 lock_ReleaseMutex(&fidp->mx);
5673 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5675 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5676 lock_ObtainMutex(&scp->mx);
5678 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5679 CM_SCACHESYNC_NEEDCALLBACK
5680 | CM_SCACHESYNC_GETSTATUS
5681 | CM_SCACHESYNC_LOCK);
5685 "smb CoreClose SyncOp failure code 0x%x", tcode);
5686 goto post_syncopdone;
5689 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5691 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5695 lock_ReleaseMutex(&scp->mx);
5696 lock_ObtainMutex(&fidp->mx);
5699 if (fidp->flags & SMB_FID_DELONCLOSE) {
5702 lock_ReleaseMutex(&fidp->mx);
5703 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5704 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5705 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5707 scp->flags |= CM_SCACHEFLAG_DELETED;
5708 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5709 smb_NotifyChange(FILE_ACTION_REMOVED,
5710 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5711 dscp, fullPathp, NULL, TRUE);
5714 code = cm_Unlink(dscp, fullPathp, userp, &req);
5716 scp->flags |= CM_SCACHEFLAG_DELETED;
5717 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5718 smb_NotifyChange(FILE_ACTION_REMOVED,
5719 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5720 dscp, fullPathp, NULL, TRUE);
5724 lock_ObtainMutex(&fidp->mx);
5725 fidp->flags &= ~SMB_FID_DELONCLOSE;
5728 /* if this was a newly created file, then clear the creator
5729 * in the stat cache entry. */
5730 if (fidp->flags & SMB_FID_CREATED) {
5731 lock_ObtainMutex(&scp->mx);
5732 if (scp->creator == userp)
5733 scp->creator = NULL;
5734 lock_ReleaseMutex(&scp->mx);
5735 fidp->flags &= ~SMB_FID_CREATED;
5738 if (fidp->flags & SMB_FID_NTOPEN) {
5739 fidp->NTopen_dscp = NULL;
5740 fidp->NTopen_pathp = NULL;
5741 fidp->flags &= ~SMB_FID_NTOPEN;
5743 if (fidp->NTopen_wholepathp) {
5744 free(fidp->NTopen_wholepathp);
5745 fidp->NTopen_wholepathp = NULL;
5747 lock_ReleaseMutex(&fidp->mx);
5750 cm_ReleaseSCache(dscp);
5753 cm_ReleaseSCache(scp);
5761 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5769 fid = smb_GetSMBParm(inp, 0);
5770 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5772 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5774 fid = smb_ChainFID(fid, inp);
5775 fidp = smb_FindFID(vcp, fid, 0);
5777 return CM_ERROR_BADFD;
5780 userp = smb_GetUserFromVCP(vcp, inp);
5782 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5784 smb_ReleaseFID(fidp);
5785 cm_ReleaseUser(userp);
5790 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5792 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5793 cm_user_t *userp, long *readp)
5799 osi_hyper_t fileLength;
5801 osi_hyper_t lastByte;
5802 osi_hyper_t bufferOffset;
5803 long bufIndex, nbytes;
5805 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
5813 lock_ObtainMutex(&fidp->mx);
5815 lock_ObtainMutex(&scp->mx);
5817 if (offset.HighPart == 0) {
5818 chunk = offset.LowPart >> cm_logChunkSize;
5819 if (chunk != fidp->curr_chunk) {
5820 fidp->prev_chunk = fidp->curr_chunk;
5821 fidp->curr_chunk = chunk;
5823 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
5826 lock_ReleaseMutex(&fidp->mx);
5828 /* start by looking up the file's end */
5829 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5830 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5834 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5836 /* now we have the entry locked, look up the length */
5837 fileLength = scp->length;
5839 /* adjust count down so that it won't go past EOF */
5840 thyper.LowPart = count;
5841 thyper.HighPart = 0;
5842 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5844 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5845 /* we'd read past EOF, so just stop at fileLength bytes.
5846 * Start by computing how many bytes remain in the file.
5848 thyper = LargeIntegerSubtract(fileLength, offset);
5850 /* if we are past EOF, read 0 bytes */
5851 if (LargeIntegerLessThanZero(thyper))
5854 count = thyper.LowPart;
5859 /* now, copy the data one buffer at a time,
5860 * until we've filled the request packet
5863 /* if we've copied all the data requested, we're done */
5864 if (count <= 0) break;
5866 /* otherwise, load up a buffer of data */
5867 thyper.HighPart = offset.HighPart;
5868 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5869 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5872 buf_Release(bufferp);
5875 lock_ReleaseMutex(&scp->mx);
5877 lock_ObtainRead(&scp->bufCreateLock);
5878 code = buf_Get(scp, &thyper, &bufferp);
5879 lock_ReleaseRead(&scp->bufCreateLock);
5881 lock_ObtainMutex(&scp->mx);
5882 if (code) goto done;
5883 bufferOffset = thyper;
5885 /* now get the data in the cache */
5887 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5888 CM_SCACHESYNC_NEEDCALLBACK |
5889 CM_SCACHESYNC_READ);
5893 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5895 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5897 /* otherwise, load the buffer and try again */
5898 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5902 buf_Release(bufferp);
5906 } /* if (wrong buffer) ... */
5908 /* now we have the right buffer loaded. Copy out the
5909 * data from here to the user's buffer.
5911 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5913 /* and figure out how many bytes we want from this buffer */
5914 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5915 if (nbytes > count) nbytes = count; /* don't go past EOF */
5917 /* now copy the data */
5918 memcpy(op, bufferp->datap + bufIndex, nbytes);
5920 /* adjust counters, pointers, etc. */
5923 thyper.LowPart = nbytes;
5924 thyper.HighPart = 0;
5925 offset = LargeIntegerAdd(thyper, offset);
5929 lock_ReleaseMutex(&scp->mx);
5931 buf_Release(bufferp);
5933 if (code == 0 && sequential)
5934 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5940 * smb_WriteData -- common code for Write and Raw Write
5942 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5943 cm_user_t *userp, long *writtenp)
5949 osi_hyper_t fileLength; /* file's length at start of write */
5950 osi_hyper_t minLength; /* don't read past this */
5951 long nbytes; /* # of bytes to transfer this iteration */
5953 osi_hyper_t thyper; /* hyper tmp variable */
5954 osi_hyper_t bufferOffset;
5955 long bufIndex; /* index in buffer where our data is */
5957 osi_hyper_t writeBackOffset;/* offset of region to write back when
5962 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5963 fidp->fid, offsetp->LowPart, count);
5973 lock_ObtainMutex(&fidp->mx);
5974 /* make sure we have a writable FD */
5975 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5976 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
5977 fidp->fid, fidp->flags);
5978 lock_ReleaseMutex(&fidp->mx);
5979 code = CM_ERROR_BADFDOP;
5985 lock_ReleaseMutex(&fidp->mx);
5987 lock_ObtainMutex(&scp->mx);
5988 /* start by looking up the file's end */
5989 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5990 CM_SCACHESYNC_NEEDCALLBACK
5991 | CM_SCACHESYNC_SETSTATUS
5992 | CM_SCACHESYNC_GETSTATUS);
5996 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
5998 /* now we have the entry locked, look up the length */
5999 fileLength = scp->length;
6000 minLength = fileLength;
6001 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6002 minLength = scp->serverLength;
6004 /* adjust file length if we extend past EOF */
6005 thyper.LowPart = count;
6006 thyper.HighPart = 0;
6007 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6008 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6009 /* we'd write past EOF, so extend the file */
6010 scp->mask |= CM_SCACHEMASK_LENGTH;
6011 scp->length = thyper;
6012 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6014 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6016 /* now, if the new position (thyper) and the old (offset) are in
6017 * different storeback windows, remember to store back the previous
6018 * storeback window when we're done with the write.
6020 if ((thyper.LowPart & (-cm_chunkSize)) !=
6021 (offset.LowPart & (-cm_chunkSize))) {
6022 /* they're different */
6024 writeBackOffset.HighPart = offset.HighPart;
6025 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6030 /* now, copy the data one buffer at a time, until we've filled the
6033 /* if we've copied all the data requested, we're done */
6037 /* handle over quota or out of space */
6038 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6039 *writtenp = written;
6040 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6044 /* otherwise, load up a buffer of data */
6045 thyper.HighPart = offset.HighPart;
6046 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6047 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6050 lock_ReleaseMutex(&bufferp->mx);
6051 buf_Release(bufferp);
6054 lock_ReleaseMutex(&scp->mx);
6056 lock_ObtainRead(&scp->bufCreateLock);
6057 code = buf_Get(scp, &thyper, &bufferp);
6058 lock_ReleaseRead(&scp->bufCreateLock);
6060 lock_ObtainMutex(&bufferp->mx);
6061 lock_ObtainMutex(&scp->mx);
6062 if (code) goto done;
6064 bufferOffset = thyper;
6066 /* now get the data in the cache */
6068 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6069 CM_SCACHESYNC_NEEDCALLBACK
6070 | CM_SCACHESYNC_WRITE
6071 | CM_SCACHESYNC_BUFLOCKED);
6075 cm_SyncOpDone(scp, bufferp,
6076 CM_SCACHESYNC_NEEDCALLBACK
6077 | CM_SCACHESYNC_WRITE
6078 | CM_SCACHESYNC_BUFLOCKED);
6080 /* If we're overwriting the entire buffer, or
6081 * if we're writing at or past EOF, mark the
6082 * buffer as current so we don't call
6083 * cm_GetBuffer. This skips the fetch from the
6084 * server in those cases where we're going to
6085 * obliterate all the data in the buffer anyway,
6086 * or in those cases where there is no useful
6087 * data at the server to start with.
6089 * Use minLength instead of scp->length, since
6090 * the latter has already been updated by this
6093 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6094 || LargeIntegerEqualTo(offset, bufferp->offset)
6095 && (count >= cm_data.buf_blockSize
6096 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6097 ConvertLongToLargeInteger(count)),
6099 if (count < cm_data.buf_blockSize
6100 && bufferp->dataVersion == -1)
6101 memset(bufferp->datap, 0,
6102 cm_data.buf_blockSize);
6103 bufferp->dataVersion = scp->dataVersion;
6106 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6108 /* otherwise, load the buffer and try again */
6109 lock_ReleaseMutex(&bufferp->mx);
6110 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6112 lock_ReleaseMutex(&scp->mx);
6113 lock_ObtainMutex(&bufferp->mx);
6114 lock_ObtainMutex(&scp->mx);
6118 lock_ReleaseMutex(&bufferp->mx);
6119 buf_Release(bufferp);
6123 } /* if (wrong buffer) ... */
6125 /* now we have the right buffer loaded. Copy out the
6126 * data from here to the user's buffer.
6128 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6130 /* and figure out how many bytes we want from this buffer */
6131 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6133 nbytes = count; /* don't go past end of request */
6135 /* now copy the data */
6136 memcpy(bufferp->datap + bufIndex, op, nbytes);
6137 buf_SetDirty(bufferp);
6139 /* and record the last writer */
6140 if (bufferp->userp != userp) {
6143 cm_ReleaseUser(bufferp->userp);
6144 bufferp->userp = userp;
6147 /* adjust counters, pointers, etc. */
6151 thyper.LowPart = nbytes;
6152 thyper.HighPart = 0;
6153 offset = LargeIntegerAdd(thyper, offset);
6157 lock_ReleaseMutex(&scp->mx);
6160 lock_ReleaseMutex(&bufferp->mx);
6161 buf_Release(bufferp);
6164 lock_ObtainMutex(&fidp->mx);
6165 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6166 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6167 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6168 fidp->NTopen_dscp, fidp->NTopen_pathp,
6171 lock_ReleaseMutex(&fidp->mx);
6173 if (code == 0 && doWriteBack) {
6175 lock_ObtainMutex(&scp->mx);
6176 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6178 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6179 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6181 lock_ReleaseMutex(&scp->mx);
6182 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6183 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6184 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6187 cm_ReleaseSCache(scp);
6189 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6190 fidp->fid, code, *writtenp);
6194 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6197 unsigned short count;
6199 unsigned short hint;
6200 long written = 0, total_written = 0;
6205 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6207 int inDataBlockCount;
6209 fd = smb_GetSMBParm(inp, 0);
6210 count = smb_GetSMBParm(inp, 1);
6211 offset.HighPart = 0; /* too bad */
6212 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6213 hint = smb_GetSMBParm(inp, 4);
6215 op = smb_GetSMBData(inp, NULL);
6216 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6218 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6219 fd, offset.LowPart, count);
6221 fd = smb_ChainFID(fd, inp);
6222 fidp = smb_FindFID(vcp, fd, 0);
6224 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6225 return CM_ERROR_BADFD;
6228 lock_ObtainMutex(&fidp->mx);
6229 if (fidp->flags & SMB_FID_IOCTL) {
6230 lock_ReleaseMutex(&fidp->mx);
6231 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6232 smb_ReleaseFID(fidp);
6233 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6236 lock_ReleaseMutex(&fidp->mx);
6237 userp = smb_GetUserFromVCP(vcp, inp);
6241 LARGE_INTEGER LOffset;
6242 LARGE_INTEGER LLength;
6244 pid = ((smb_t *) inp)->pid;
6245 key = cm_GenerateKey(vcp->vcID, pid, fd);
6247 LOffset.HighPart = offset.HighPart;
6248 LOffset.LowPart = offset.LowPart;
6249 LLength.HighPart = 0;
6250 LLength.LowPart = count;
6252 lock_ObtainMutex(&fidp->scp->mx);
6253 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6254 lock_ReleaseMutex(&fidp->scp->mx);
6257 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6262 /* special case: 0 bytes transferred means truncate to this position */
6266 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6270 truncAttr.mask = CM_ATTRMASK_LENGTH;
6271 truncAttr.length.LowPart = offset.LowPart;
6272 truncAttr.length.HighPart = 0;
6273 lock_ObtainMutex(&fidp->mx);
6274 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6275 fidp->flags |= SMB_FID_LENGTHSETDONE;
6276 lock_ReleaseMutex(&fidp->mx);
6277 smb_SetSMBParm(outp, 0, 0 /* count */);
6278 smb_SetSMBDataLength(outp, 0);
6283 * Work around bug in NT client
6285 * When copying a file, the NT client should first copy the data,
6286 * then copy the last write time. But sometimes the NT client does
6287 * these in the wrong order, so the data copies would inadvertently
6288 * cause the last write time to be overwritten. We try to detect this,
6289 * and don't set client mod time if we think that would go against the
6292 lock_ObtainMutex(&fidp->mx);
6293 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6294 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6295 fidp->scp->clientModTime = time(NULL);
6297 lock_ReleaseMutex(&fidp->mx);
6300 while ( code == 0 && count > 0 ) {
6301 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6302 if (code == 0 && written == 0)
6303 code = CM_ERROR_PARTIALWRITE;
6305 offset = LargeIntegerAdd(offset,
6306 ConvertLongToLargeInteger(written));
6308 total_written += written;
6312 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6313 total_written, code);
6315 /* set the packet data length to 3 bytes for the data block header,
6316 * plus the size of the data.
6318 smb_SetSMBParm(outp, 0, total_written);
6319 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6320 smb_SetSMBParm(outp, 3, hint);
6321 smb_SetSMBDataLength(outp, 0);
6324 smb_ReleaseFID(fidp);
6325 cm_ReleaseUser(userp);
6330 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6331 NCB *ncbp, raw_write_cont_t *rwcp)
6340 fd = smb_GetSMBParm(inp, 0);
6341 fidp = smb_FindFID(vcp, fd, 0);
6343 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6344 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6346 userp = smb_GetUserFromVCP(vcp, inp);
6349 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6351 if (rwcp->writeMode & 0x1) { /* synchronous */
6354 smb_FormatResponsePacket(vcp, inp, outp);
6355 op = (smb_t *) outp;
6356 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6357 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6358 smb_SetSMBDataLength(outp, 0);
6359 smb_SendPacket(vcp, outp);
6360 smb_FreePacket(outp);
6362 else { /* asynchronous */
6363 lock_ObtainMutex(&fidp->mx);
6364 fidp->raw_writers--;
6365 if (fidp->raw_writers == 0)
6366 thrd_SetEvent(fidp->raw_write_event);
6367 lock_ReleaseMutex(&fidp->mx);
6370 /* Give back raw buffer */
6371 lock_ObtainMutex(&smb_RawBufLock);
6372 *((char **)rawBuf) = smb_RawBufs;
6373 smb_RawBufs = rawBuf;
6374 lock_ReleaseMutex(&smb_RawBufLock);
6376 smb_ReleaseFID(fidp);
6377 cm_ReleaseUser(userp);
6380 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6385 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6388 long count, written = 0, total_written = 0;
6395 unsigned short writeMode;
6397 fd = smb_GetSMBParm(inp, 0);
6398 totalCount = smb_GetSMBParm(inp, 1);
6399 count = smb_GetSMBParm(inp, 10);
6400 writeMode = smb_GetSMBParm(inp, 7);
6402 op = (char *) inp->data;
6403 op += smb_GetSMBParm(inp, 11);
6405 offset.HighPart = 0;
6406 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6408 if (*inp->wctp == 14) {
6409 /* we received a 64-bit file offset */
6410 #ifdef AFS_LARGEFILES
6411 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6413 if (LargeIntegerLessThanZero(offset)) {
6415 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6416 offset.HighPart, offset.LowPart);
6417 return CM_ERROR_BADSMB;
6420 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6422 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6423 return CM_ERROR_BADSMB;
6426 offset.HighPart = 0;
6429 offset.HighPart = 0; /* 32-bit file offset */
6433 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6434 fd, offset.HighPart, offset.LowPart, count);
6436 " WriteRaw WriteMode 0x%x",
6439 fd = smb_ChainFID(fd, inp);
6440 fidp = smb_FindFID(vcp, fd, 0);
6442 return CM_ERROR_BADFD;
6448 LARGE_INTEGER LOffset;
6449 LARGE_INTEGER LLength;
6451 pid = ((smb_t *) inp)->pid;
6452 key = cm_GenerateKey(vcp->vcID, pid, fd);
6454 LOffset.HighPart = offset.HighPart;
6455 LOffset.LowPart = offset.LowPart;
6456 LLength.HighPart = 0;
6457 LLength.LowPart = count;
6459 lock_ObtainMutex(&fidp->scp->mx);
6460 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6461 lock_ReleaseMutex(&fidp->scp->mx);
6464 smb_ReleaseFID(fidp);
6469 userp = smb_GetUserFromVCP(vcp, inp);
6472 * Work around bug in NT client
6474 * When copying a file, the NT client should first copy the data,
6475 * then copy the last write time. But sometimes the NT client does
6476 * these in the wrong order, so the data copies would inadvertently
6477 * cause the last write time to be overwritten. We try to detect this,
6478 * and don't set client mod time if we think that would go against the
6481 lock_ObtainMutex(&fidp->mx);
6482 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6483 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6484 fidp->scp->clientModTime = time(NULL);
6486 lock_ReleaseMutex(&fidp->mx);
6489 while ( code == 0 && count > 0 ) {
6490 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6491 if (code == 0 && written == 0)
6492 code = CM_ERROR_PARTIALWRITE;
6494 offset = LargeIntegerAdd(offset,
6495 ConvertLongToLargeInteger(written));
6498 total_written += written;
6502 /* Get a raw buffer */
6505 lock_ObtainMutex(&smb_RawBufLock);
6507 /* Get a raw buf, from head of list */
6508 rawBuf = smb_RawBufs;
6509 smb_RawBufs = *(char **)smb_RawBufs;
6512 code = CM_ERROR_USESTD;
6514 lock_ReleaseMutex(&smb_RawBufLock);
6517 /* Don't allow a premature Close */
6518 if (code == 0 && (writeMode & 1) == 0) {
6519 lock_ObtainMutex(&fidp->mx);
6520 fidp->raw_writers++;
6521 thrd_ResetEvent(fidp->raw_write_event);
6522 lock_ReleaseMutex(&fidp->mx);
6525 smb_ReleaseFID(fidp);
6526 cm_ReleaseUser(userp);
6529 smb_SetSMBParm(outp, 0, total_written);
6530 smb_SetSMBDataLength(outp, 0);
6531 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6536 offset = LargeIntegerAdd(offset,
6537 ConvertLongToLargeInteger(count));
6541 rwcp->offset.HighPart = offset.HighPart;
6542 rwcp->offset.LowPart = offset.LowPart;
6543 rwcp->count = totalCount - count;
6544 rwcp->writeMode = writeMode;
6545 rwcp->alreadyWritten = total_written;
6547 /* set the packet data length to 3 bytes for the data block header,
6548 * plus the size of the data.
6550 smb_SetSMBParm(outp, 0, 0xffff);
6551 smb_SetSMBDataLength(outp, 0);
6556 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6559 long count, finalCount;
6567 fd = smb_GetSMBParm(inp, 0);
6568 count = smb_GetSMBParm(inp, 1);
6569 offset.HighPart = 0; /* too bad */
6570 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6572 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6573 fd, offset.LowPart, count);
6575 fd = smb_ChainFID(fd, inp);
6576 fidp = smb_FindFID(vcp, fd, 0);
6578 return CM_ERROR_BADFD;
6580 lock_ObtainMutex(&fidp->mx);
6581 if (fidp->flags & SMB_FID_IOCTL) {
6582 lock_ReleaseMutex(&fidp->mx);
6583 code = smb_IoctlRead(fidp, vcp, inp, outp);
6584 smb_ReleaseFID(fidp);
6587 lock_ReleaseMutex(&fidp->mx);
6590 LARGE_INTEGER LOffset, LLength;
6593 pid = ((smb_t *) inp)->pid;
6594 key = cm_GenerateKey(vcp->vcID, pid, fd);
6596 LOffset.HighPart = 0;
6597 LOffset.LowPart = offset.LowPart;
6598 LLength.HighPart = 0;
6599 LLength.LowPart = count;
6601 lock_ObtainMutex(&fidp->scp->mx);
6602 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6603 lock_ReleaseMutex(&fidp->scp->mx);
6606 smb_ReleaseFID(fidp);
6610 userp = smb_GetUserFromVCP(vcp, inp);
6612 /* remember this for final results */
6613 smb_SetSMBParm(outp, 0, count);
6614 smb_SetSMBParm(outp, 1, 0);
6615 smb_SetSMBParm(outp, 2, 0);
6616 smb_SetSMBParm(outp, 3, 0);
6617 smb_SetSMBParm(outp, 4, 0);
6619 /* set the packet data length to 3 bytes for the data block header,
6620 * plus the size of the data.
6622 smb_SetSMBDataLength(outp, count+3);
6624 /* get op ptr after putting in the parms, since otherwise we don't
6625 * know where the data really is.
6627 op = smb_GetSMBData(outp, NULL);
6629 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6630 *op++ = 1; /* data block marker */
6631 *op++ = (unsigned char) (count & 0xff);
6632 *op++ = (unsigned char) ((count >> 8) & 0xff);
6634 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6636 /* fix some things up */
6637 smb_SetSMBParm(outp, 0, finalCount);
6638 smb_SetSMBDataLength(outp, finalCount+3);
6640 smb_ReleaseFID(fidp);
6642 cm_ReleaseUser(userp);
6646 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6653 cm_scache_t *dscp; /* dir we're dealing with */
6654 cm_scache_t *scp; /* file we're creating */
6656 int initialModeBits;
6666 /* compute initial mode bits based on read-only flag in attributes */
6667 initialModeBits = 0777;
6669 tp = smb_GetSMBData(inp, NULL);
6670 pathp = smb_ParseASCIIBlock(tp, &tp);
6671 if (smb_StoreAnsiFilenames)
6672 OemToChar(pathp,pathp);
6674 if (strcmp(pathp, "\\") == 0)
6675 return CM_ERROR_EXISTS;
6677 spacep = inp->spacep;
6678 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6680 userp = smb_GetUserFromVCP(vcp, inp);
6682 caseFold = CM_FLAG_CASEFOLD;
6684 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6686 cm_ReleaseUser(userp);
6687 return CM_ERROR_NOSUCHPATH;
6690 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6691 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6692 userp, tidPathp, &req, &dscp);
6695 cm_ReleaseUser(userp);
6700 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6701 cm_ReleaseSCache(dscp);
6702 cm_ReleaseUser(userp);
6703 if ( WANTS_DFS_PATHNAMES(inp) )
6704 return CM_ERROR_PATH_NOT_COVERED;
6706 return CM_ERROR_BADSHARENAME;
6708 #endif /* DFS_SUPPORT */
6710 /* otherwise, scp points to the parent directory. Do a lookup, and
6711 * fail if we find it. Otherwise, we do the create.
6717 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6718 if (scp) cm_ReleaseSCache(scp);
6719 if (code != CM_ERROR_NOSUCHFILE) {
6720 if (code == 0) code = CM_ERROR_EXISTS;
6721 cm_ReleaseSCache(dscp);
6722 cm_ReleaseUser(userp);
6726 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6727 setAttr.clientModTime = time(NULL);
6728 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6729 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6730 smb_NotifyChange(FILE_ACTION_ADDED,
6731 FILE_NOTIFY_CHANGE_DIR_NAME,
6732 dscp, lastNamep, NULL, TRUE);
6734 /* we don't need this any longer */
6735 cm_ReleaseSCache(dscp);
6738 /* something went wrong creating or truncating the file */
6739 cm_ReleaseUser(userp);
6743 /* otherwise we succeeded */
6744 smb_SetSMBDataLength(outp, 0);
6745 cm_ReleaseUser(userp);
6750 BOOL smb_IsLegalFilename(char *filename)
6753 * Find the longest substring of filename that does not contain
6754 * any of the chars in illegalChars. If that substring is less
6755 * than the length of the whole string, then one or more of the
6756 * illegal chars is in filename.
6758 if (strcspn(filename, illegalChars) < strlen(filename))
6764 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6772 cm_scache_t *dscp; /* dir we're dealing with */
6773 cm_scache_t *scp; /* file we're creating */
6775 int initialModeBits;
6783 int created = 0; /* the file was new */
6788 excl = (inp->inCom == 0x03)? 0 : 1;
6790 attributes = smb_GetSMBParm(inp, 0);
6791 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6793 /* compute initial mode bits based on read-only flag in attributes */
6794 initialModeBits = 0666;
6795 if (attributes & SMB_ATTR_READONLY)
6796 initialModeBits &= ~0222;
6798 tp = smb_GetSMBData(inp, NULL);
6799 pathp = smb_ParseASCIIBlock(tp, &tp);
6800 if (smb_StoreAnsiFilenames)
6801 OemToChar(pathp,pathp);
6803 spacep = inp->spacep;
6804 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6806 userp = smb_GetUserFromVCP(vcp, inp);
6808 caseFold = CM_FLAG_CASEFOLD;
6810 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6812 cm_ReleaseUser(userp);
6813 return CM_ERROR_NOSUCHPATH;
6815 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6816 userp, tidPathp, &req, &dscp);
6819 cm_ReleaseUser(userp);
6824 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6825 cm_ReleaseSCache(dscp);
6826 cm_ReleaseUser(userp);
6827 if ( WANTS_DFS_PATHNAMES(inp) )
6828 return CM_ERROR_PATH_NOT_COVERED;
6830 return CM_ERROR_BADSHARENAME;
6832 #endif /* DFS_SUPPORT */
6834 /* otherwise, scp points to the parent directory. Do a lookup, and
6835 * truncate the file if we find it, otherwise we create the file.
6842 if (!smb_IsLegalFilename(lastNamep))
6843 return CM_ERROR_BADNTFILENAME;
6845 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6846 #ifdef DEBUG_VERBOSE
6849 hexp = osi_HexifyString( lastNamep );
6850 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6855 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6856 if (code && code != CM_ERROR_NOSUCHFILE) {
6857 cm_ReleaseSCache(dscp);
6858 cm_ReleaseUser(userp);
6862 /* if we get here, if code is 0, the file exists and is represented by
6863 * scp. Otherwise, we have to create it.
6867 /* oops, file shouldn't be there */
6868 cm_ReleaseSCache(dscp);
6869 cm_ReleaseSCache(scp);
6870 cm_ReleaseUser(userp);
6871 return CM_ERROR_EXISTS;
6874 setAttr.mask = CM_ATTRMASK_LENGTH;
6875 setAttr.length.LowPart = 0;
6876 setAttr.length.HighPart = 0;
6877 code = cm_SetAttr(scp, &setAttr, userp, &req);
6880 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6881 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6882 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6886 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6887 smb_NotifyChange(FILE_ACTION_ADDED,
6888 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6889 dscp, lastNamep, NULL, TRUE);
6890 } else if (!excl && code == CM_ERROR_EXISTS) {
6891 /* not an exclusive create, and someone else tried
6892 * creating it already, then we open it anyway. We
6893 * don't bother retrying after this, since if this next
6894 * fails, that means that the file was deleted after
6895 * we started this call.
6897 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6900 setAttr.mask = CM_ATTRMASK_LENGTH;
6901 setAttr.length.LowPart = 0;
6902 setAttr.length.HighPart = 0;
6903 code = cm_SetAttr(scp, &setAttr, userp, &req);
6908 /* we don't need this any longer */
6909 cm_ReleaseSCache(dscp);
6912 /* something went wrong creating or truncating the file */
6913 if (scp) cm_ReleaseSCache(scp);
6914 cm_ReleaseUser(userp);
6918 /* make sure we only open files */
6919 if (scp->fileType != CM_SCACHETYPE_FILE) {
6920 cm_ReleaseSCache(scp);
6921 cm_ReleaseUser(userp);
6922 return CM_ERROR_ISDIR;
6925 /* now all we have to do is open the file itself */
6926 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6931 lock_ObtainMutex(&fidp->mx);
6932 /* always create it open for read/write */
6933 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6935 /* remember that the file was newly created */
6937 fidp->flags |= SMB_FID_CREATED;
6939 /* save a pointer to the vnode */
6942 fidp->userp = userp;
6943 lock_ReleaseMutex(&fidp->mx);
6945 smb_SetSMBParm(outp, 0, fidp->fid);
6946 smb_SetSMBDataLength(outp, 0);
6948 cm_Open(scp, 0, userp);
6950 smb_ReleaseFID(fidp);
6951 cm_ReleaseUser(userp);
6952 /* leave scp held since we put it in fidp->scp */
6956 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6959 osi_hyper_t new_offset;
6970 fd = smb_GetSMBParm(inp, 0);
6971 whence = smb_GetSMBParm(inp, 1);
6972 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6974 /* try to find the file descriptor */
6975 fd = smb_ChainFID(fd, inp);
6976 fidp = smb_FindFID(vcp, fd, 0);
6979 return CM_ERROR_BADFD;
6981 lock_ObtainMutex(&fidp->mx);
6982 if (fidp->flags & SMB_FID_IOCTL) {
6983 lock_ReleaseMutex(&fidp->mx);
6984 smb_ReleaseFID(fidp);
6985 return CM_ERROR_BADFD;
6987 lock_ReleaseMutex(&fidp->mx);
6989 userp = smb_GetUserFromVCP(vcp, inp);
6991 lock_ObtainMutex(&fidp->mx);
6994 lock_ReleaseMutex(&fidp->mx);
6995 lock_ObtainMutex(&scp->mx);
6996 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6997 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6999 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7001 /* offset from current offset */
7002 new_offset = LargeIntegerAdd(fidp->offset,
7003 ConvertLongToLargeInteger(offset));
7005 else if (whence == 2) {
7006 /* offset from current EOF */
7007 new_offset = LargeIntegerAdd(scp->length,
7008 ConvertLongToLargeInteger(offset));
7010 new_offset = ConvertLongToLargeInteger(offset);
7013 fidp->offset = new_offset;
7014 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7015 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7016 smb_SetSMBDataLength(outp, 0);
7018 lock_ReleaseMutex(&scp->mx);
7019 smb_ReleaseFID(fidp);
7020 cm_ReleaseSCache(scp);
7021 cm_ReleaseUser(userp);
7025 /* dispatch all of the requests received in a packet. Due to chaining, this may
7026 * be more than one request.
7028 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7029 NCB *ncbp, raw_write_cont_t *rwcp)
7033 unsigned long code = 0;
7034 unsigned char *outWctp;
7035 int nparms; /* # of bytes of parameters */
7037 int nbytes; /* bytes of data, excluding count */
7040 unsigned short errCode;
7041 unsigned long NTStatus;
7043 unsigned char errClass;
7044 unsigned int oldGen;
7045 DWORD oldTime, newTime;
7047 /* get easy pointer to the data */
7048 smbp = (smb_t *) inp->data;
7050 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7051 /* setup the basic parms for the initial request in the packet */
7052 inp->inCom = smbp->com;
7053 inp->wctp = &smbp->wct;
7055 inp->ncb_length = ncbp->ncb_length;
7060 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7061 /* log it and discard it */
7062 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7063 __FILE__, __LINE__, ncbp->ncb_length);
7064 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7068 /* We are an ongoing op */
7069 thrd_Increment(&ongoingOps);
7071 /* set up response packet for receiving output */
7072 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7073 smb_FormatResponsePacket(vcp, inp, outp);
7074 outWctp = outp->wctp;
7076 /* Remember session generation number and time */
7077 oldGen = sessionGen;
7078 oldTime = GetTickCount();
7080 while (inp->inCom != 0xff) {
7081 dp = &smb_dispatchTable[inp->inCom];
7083 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7084 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7085 code = outp->resumeCode;
7089 /* process each request in the packet; inCom, wctp and inCount
7090 * are already set up.
7092 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7095 /* now do the dispatch */
7096 /* start by formatting the response record a little, as a default */
7097 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7099 outWctp[1] = 0xff; /* no operation */
7100 outWctp[2] = 0; /* padding */
7105 /* not a chained request, this is a more reasonable default */
7106 outWctp[0] = 0; /* wct of zero */
7107 outWctp[1] = 0; /* and bcc (word) of zero */
7111 /* once set, stays set. Doesn't matter, since we never chain
7112 * "no response" calls.
7114 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7118 /* we have a recognized operation */
7120 if (inp->inCom == 0x1d)
7122 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7124 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7125 code = (*(dp->procp)) (vcp, inp, outp);
7126 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7128 if ( code == CM_ERROR_BADSMB ||
7129 code == CM_ERROR_BADOP )
7131 #endif /* LOG_PACKET */
7134 if (oldGen != sessionGen) {
7135 newTime = GetTickCount();
7136 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7137 newTime - oldTime, ncbp->ncb_length);
7138 osi_Log2(smb_logp, "Pkt straddled session startup, "
7139 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7143 /* bad opcode, fail the request, after displaying it */
7144 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7147 #endif /* LOG_PACKET */
7150 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7151 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7152 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7153 if (code == IDCANCEL)
7156 code = CM_ERROR_BADOP;
7159 /* catastrophic failure: log as much as possible */
7160 if (code == CM_ERROR_BADSMB) {
7161 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7165 #endif /* LOG_PACKET */
7166 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7169 code = CM_ERROR_INVAL;
7172 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7173 thrd_Decrement(&ongoingOps);
7178 /* now, if we failed, turn the current response into an empty
7179 * one, and fill in the response packet's error code.
7182 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7183 smb_MapNTError(code, &NTStatus);
7184 outWctp = outp->wctp;
7185 smbp = (smb_t *) &outp->data;
7186 if (code != CM_ERROR_PARTIALWRITE
7187 && code != CM_ERROR_BUFFERTOOSMALL
7188 && code != CM_ERROR_GSSCONTINUE) {
7189 /* nuke wct and bcc. For a partial
7190 * write or an in-process authentication handshake,
7191 * assume they're OK.
7197 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7198 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7199 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7200 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7201 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7205 smb_MapCoreError(code, vcp, &errCode, &errClass);
7206 outWctp = outp->wctp;
7207 smbp = (smb_t *) &outp->data;
7208 if (code != CM_ERROR_PARTIALWRITE) {
7209 /* nuke wct and bcc. For a partial
7210 * write, assume they're OK.
7216 smbp->errLow = (unsigned char) (errCode & 0xff);
7217 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7218 smbp->rcls = errClass;
7221 } /* error occurred */
7223 /* if we're here, we've finished one request. Look to see if
7224 * this is a chained opcode. If it is, setup things to process
7225 * the chained request, and setup the output buffer to hold the
7226 * chained response. Start by finding the next input record.
7228 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7229 break; /* not a chained req */
7230 tp = inp->wctp; /* points to start of last request */
7231 /* in a chained request, the first two
7232 * parm fields are required, and are
7233 * AndXCommand/AndXReserved and
7235 if (tp[0] < 2) break;
7236 if (tp[1] == 0xff) break; /* no more chained opcodes */
7238 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7241 /* and now append the next output request to the end of this
7242 * last request. Begin by finding out where the last response
7243 * ends, since that's where we'll put our new response.
7245 outWctp = outp->wctp; /* ptr to out parameters */
7246 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7247 nparms = outWctp[0] << 1;
7248 tp = outWctp + nparms + 1; /* now points to bcc field */
7249 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7250 tp += 2 /* for the count itself */ + nbytes;
7251 /* tp now points to the new output record; go back and patch the
7252 * second parameter (off2) to point to the new record.
7254 temp = (unsigned int)(tp - outp->data);
7255 outWctp[3] = (unsigned char) (temp & 0xff);
7256 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7257 outWctp[2] = 0; /* padding */
7258 outWctp[1] = inp->inCom; /* next opcode */
7260 /* finally, setup for the next iteration */
7263 } /* while loop over all requests in the packet */
7265 /* now send the output packet, and return */
7267 smb_SendPacket(vcp, outp);
7268 thrd_Decrement(&ongoingOps);
7273 /* Wait for Netbios() calls to return, and make the results available to server
7274 * threads. Note that server threads can't wait on the NCBevents array
7275 * themselves, because NCB events are manual-reset, and the servers would race
7276 * each other to reset them.
7278 void smb_ClientWaiter(void *parmp)
7283 while (smbShutdownFlag == 0) {
7284 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7286 if (code == WAIT_OBJECT_0)
7289 /* error checking */
7290 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7292 int abandonIdx = code - WAIT_ABANDONED_0;
7293 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7296 if (code == WAIT_IO_COMPLETION)
7298 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7302 if (code == WAIT_TIMEOUT)
7304 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7307 if (code == WAIT_FAILED)
7309 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7312 idx = code - WAIT_OBJECT_0;
7314 /* check idx range! */
7315 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7317 /* this is fatal - log as much as possible */
7318 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7322 thrd_ResetEvent(NCBevents[idx]);
7323 thrd_SetEvent(NCBreturns[0][idx]);
7328 * Try to have one NCBRECV request waiting for every live session. Not more
7329 * than one, because if there is more than one, it's hard to handle Write Raw.
7331 void smb_ServerWaiter(void *parmp)
7334 int idx_session, idx_NCB;
7337 while (smbShutdownFlag == 0) {
7339 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7341 if (code == WAIT_OBJECT_0)
7344 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7346 int abandonIdx = code - WAIT_ABANDONED_0;
7347 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7350 if (code == WAIT_IO_COMPLETION)
7352 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7356 if (code == WAIT_TIMEOUT)
7358 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7361 if (code == WAIT_FAILED)
7363 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7366 idx_session = code - WAIT_OBJECT_0;
7368 /* check idx range! */
7369 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7371 /* this is fatal - log as much as possible */
7372 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7378 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7380 if (code == WAIT_OBJECT_0) {
7381 if (smbShutdownFlag == 1)
7387 /* error checking */
7388 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7390 int abandonIdx = code - WAIT_ABANDONED_0;
7391 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7394 if (code == WAIT_IO_COMPLETION)
7396 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7400 if (code == WAIT_TIMEOUT)
7402 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7405 if (code == WAIT_FAILED)
7407 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7410 idx_NCB = code - WAIT_OBJECT_0;
7412 /* check idx range! */
7413 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7415 /* this is fatal - log as much as possible */
7416 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7420 /* Link them together */
7421 NCBsessions[idx_NCB] = idx_session;
7424 ncbp = NCBs[idx_NCB];
7425 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7426 ncbp->ncb_command = NCBRECV | ASYNCH;
7427 ncbp->ncb_lana_num = lanas[idx_session];
7428 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7429 ncbp->ncb_event = NCBevents[idx_NCB];
7430 ncbp->ncb_length = SMB_PACKETSIZE;
7436 * The top level loop for handling SMB request messages. Each server thread
7437 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7438 * NCB and buffer for the incoming request are loaned to us.
7440 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7441 * to immediately send a request for the rest of the data. This must come
7442 * before any other traffic for that session, so we delay setting the session
7443 * event until that data has come in.
7445 void smb_Server(VOID *parmp)
7447 INT_PTR myIdx = (INT_PTR) parmp;
7451 smb_packet_t *outbufp;
7453 int idx_NCB, idx_session;
7455 smb_vc_t *vcp = NULL;
7458 rx_StartClientThread();
7461 outbufp = GetPacket();
7462 outbufp->ncbp = outncbp;
7470 smb_ResetServerPriority();
7472 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7475 /* terminate silently if shutdown flag is set */
7476 if (code == WAIT_OBJECT_0) {
7477 if (smbShutdownFlag == 1) {
7478 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7484 /* error checking */
7485 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7487 int abandonIdx = code - WAIT_ABANDONED_0;
7488 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7491 if (code == WAIT_IO_COMPLETION)
7493 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7497 if (code == WAIT_TIMEOUT)
7499 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7502 if (code == WAIT_FAILED)
7504 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7507 idx_NCB = code - WAIT_OBJECT_0;
7509 /* check idx range! */
7510 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7512 /* this is fatal - log as much as possible */
7513 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7517 ncbp = NCBs[idx_NCB];
7518 idx_session = NCBsessions[idx_NCB];
7519 rc = ncbp->ncb_retcode;
7521 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7522 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7526 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7530 /* Can this happen? Or is it just my UNIX paranoia? */
7531 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7536 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7539 /* Client closed session */
7540 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7542 lock_ObtainMutex(&vcp->mx);
7543 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7544 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7546 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7547 lock_ReleaseMutex(&vcp->mx);
7548 lock_ObtainWrite(&smb_globalLock);
7549 dead_sessions[vcp->session] = TRUE;
7550 lock_ReleaseWrite(&smb_globalLock);
7551 smb_CleanupDeadVC(vcp);
7555 lock_ReleaseMutex(&vcp->mx);
7561 /* Treat as transient error */
7562 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7565 "dispatch smb recv failed, message incomplete, ncb_length %d",
7568 "SMB message incomplete, "
7569 "length %d", ncbp->ncb_length);
7572 * We used to discard the packet.
7573 * Instead, try handling it normally.
7577 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7581 /* A weird error code. Log it, sleep, and continue. */
7582 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7584 lock_ObtainMutex(&vcp->mx);
7585 if (vcp && vcp->errorCount++ > 3) {
7586 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7587 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7588 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7590 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7591 lock_ReleaseMutex(&vcp->mx);
7592 lock_ObtainWrite(&smb_globalLock);
7593 dead_sessions[vcp->session] = TRUE;
7594 lock_ReleaseWrite(&smb_globalLock);
7595 smb_CleanupDeadVC(vcp);
7599 lock_ReleaseMutex(&vcp->mx);
7605 lock_ReleaseMutex(&vcp->mx);
7607 thrd_SetEvent(SessionEvents[idx_session]);
7612 /* Success, so now dispatch on all the data in the packet */
7614 smb_concurrentCalls++;
7615 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7616 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7619 * If at this point vcp is NULL (implies that packet was invalid)
7620 * then we are in big trouble. This means either :
7621 * a) we have the wrong NCB.
7622 * b) Netbios screwed up the call.
7623 * c) The VC was already marked dead before we were able to
7625 * Obviously this implies that
7626 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7627 * lanas[idx_session] != ncbp->ncb_lana_num )
7628 * Either way, we can't do anything with this packet.
7629 * Log, sleep and resume.
7632 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7636 ncbp->ncb_lana_num);
7638 /* Also log in the trace log. */
7639 osi_Log4(smb_logp, "Server: VCP does not exist!"
7640 "LSNs[idx_session]=[%d],"
7641 "lanas[idx_session]=[%d],"
7642 "ncbp->ncb_lsn=[%d],"
7643 "ncbp->ncb_lana_num=[%d]",
7647 ncbp->ncb_lana_num);
7649 /* thrd_Sleep(1000); Don't bother sleeping */
7650 thrd_SetEvent(SessionEvents[idx_session]);
7651 smb_concurrentCalls--;
7655 smb_SetRequestStartTime();
7657 vcp->errorCount = 0;
7658 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7659 smbp = (smb_t *)bufp->data;
7664 if (smbp->com == 0x1d) {
7665 /* Special handling for Write Raw */
7666 raw_write_cont_t rwc;
7667 EVENT_HANDLE rwevent;
7668 char eventName[MAX_PATH];
7670 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7671 if (rwc.code == 0) {
7672 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7673 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7674 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7675 ncbp->ncb_command = NCBRECV | ASYNCH;
7676 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7677 ncbp->ncb_lana_num = vcp->lana;
7678 ncbp->ncb_buffer = rwc.buf;
7679 ncbp->ncb_length = 65535;
7680 ncbp->ncb_event = rwevent;
7682 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7683 thrd_CloseHandle(rwevent);
7685 thrd_SetEvent(SessionEvents[idx_session]);
7687 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7689 else if (smbp->com == 0xa0) {
7691 * Serialize the handling for NT Transact
7694 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7695 thrd_SetEvent(SessionEvents[idx_session]);
7697 thrd_SetEvent(SessionEvents[idx_session]);
7698 /* TODO: what else needs to be serialized? */
7699 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7702 __except( smb_ServerExceptionFilter() ) {
7705 smb_concurrentCalls--;
7708 thrd_SetEvent(NCBavails[idx_NCB]);
7715 * Exception filter for the server threads. If an exception occurs in the
7716 * dispatch routines, which is where exceptions are most common, then do a
7717 * force trace and give control to upstream exception handlers. Useful for
7720 DWORD smb_ServerExceptionFilter(void) {
7721 /* While this is not the best time to do a trace, if it succeeds, then
7722 * we have a trace (assuming tracing was enabled). Otherwise, this should
7723 * throw a second exception.
7725 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7726 afsd_ForceTrace(TRUE);
7727 buf_ForceTrace(TRUE);
7728 return EXCEPTION_CONTINUE_SEARCH;
7732 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7733 * If the number of server threads is M, and the number of live sessions is
7734 * N, then the number of NCB's in use at any time either waiting for, or
7735 * holding, received messages is M + N, so that is how many NCB's get created.
7737 void InitNCBslot(int idx)
7739 struct smb_packet *bufp;
7740 EVENT_HANDLE retHandle;
7742 char eventName[MAX_PATH];
7744 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7746 NCBs[idx] = GetNCB();
7747 sprintf(eventName,"NCBavails[%d]", idx);
7748 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7749 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7750 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7751 sprintf(eventName,"NCBevents[%d]", idx);
7752 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7753 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7754 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7755 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7756 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7757 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7758 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7759 for (i=0; i<smb_NumServerThreads; i++)
7760 NCBreturns[i][idx] = retHandle;
7762 bufp->spacep = cm_GetSpace();
7766 /* listen for new connections */
7767 void smb_Listener(void *parmp)
7773 int session, thread;
7774 smb_vc_t *vcp = NULL;
7776 char rname[NCBNAMSZ+1];
7777 char cname[MAX_COMPUTERNAME_LENGTH+1];
7778 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7779 INT_PTR lana = (INT_PTR) parmp;
7783 /* retrieve computer name */
7784 GetComputerName(cname, &cnamelen);
7788 memset(ncbp, 0, sizeof(NCB));
7791 ncbp->ncb_command = NCBLISTEN;
7792 ncbp->ncb_rto = 0; /* No receive timeout */
7793 ncbp->ncb_sto = 0; /* No send timeout */
7795 /* pad out with spaces instead of null termination */
7796 len = (long)strlen(smb_localNamep);
7797 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7798 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7800 strcpy(ncbp->ncb_callname, "*");
7801 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7803 ncbp->ncb_lana_num = (UCHAR)lana;
7805 code = Netbios(ncbp);
7811 /* terminate silently if shutdown flag is set */
7812 if (smbShutdownFlag == 1) {
7817 "NCBLISTEN lana=%d failed with code %d",
7818 ncbp->ncb_lana_num, code);
7820 "Client exiting due to network failure. Please restart client.\n");
7823 "Client exiting due to network failure. Please restart client.\n"
7824 "NCBLISTEN lana=%d failed with code %d",
7825 ncbp->ncb_lana_num, code);
7827 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7828 MB_OK|MB_SERVICE_NOTIFICATION);
7829 osi_panic(tbuffer, __FILE__, __LINE__);
7832 /* check for remote conns */
7833 /* first get remote name and insert null terminator */
7834 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7835 for (i=NCBNAMSZ; i>0; i--) {
7836 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7842 /* compare with local name */
7844 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7845 flags |= SMB_VCFLAG_REMOTECONN;
7848 lock_ObtainMutex(&smb_ListenerLock);
7850 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7851 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
7853 /* now ncbp->ncb_lsn is the connection ID */
7854 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7855 if (vcp->session == 0) {
7856 /* New generation */
7857 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7860 /* Log session startup */
7862 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
7863 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7864 #endif /* NOTSERVICE */
7865 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7866 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7868 if (reportSessionStartups) {
7869 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7872 lock_ObtainMutex(&vcp->mx);
7873 strcpy(vcp->rname, rname);
7874 vcp->flags |= flags;
7875 lock_ReleaseMutex(&vcp->mx);
7877 /* Allocate slot in session arrays */
7878 /* Re-use dead session if possible, otherwise add one more */
7879 /* But don't look at session[0], it is reserved */
7880 lock_ObtainWrite(&smb_globalLock);
7881 for (session = 1; session < numSessions; session++) {
7882 if (dead_sessions[session]) {
7883 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
7884 dead_sessions[session] = FALSE;
7888 lock_ReleaseWrite(&smb_globalLock);
7890 /* We are re-using an existing VC because the lsn and lana
7892 session = vcp->session;
7894 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
7896 /* Log session startup */
7898 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
7899 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7900 #endif /* NOTSERVICE */
7901 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7902 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7904 if (reportSessionStartups) {
7905 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7909 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
7910 unsigned long code = CM_ERROR_ALLBUSY;
7911 smb_packet_t * outp = GetPacket();
7912 unsigned char *outWctp;
7915 smb_FormatResponsePacket(vcp, NULL, outp);
7918 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7919 unsigned long NTStatus;
7920 smb_MapNTError(code, &NTStatus);
7921 outWctp = outp->wctp;
7922 smbp = (smb_t *) &outp->data;
7926 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7927 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7928 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7929 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7930 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7932 unsigned short errCode;
7933 unsigned char errClass;
7934 smb_MapCoreError(code, vcp, &errCode, &errClass);
7935 outWctp = outp->wctp;
7936 smbp = (smb_t *) &outp->data;
7940 smbp->errLow = (unsigned char) (errCode & 0xff);
7941 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7942 smbp->rcls = errClass;
7944 smb_SendPacket(vcp, outp);
7945 smb_FreePacket(outp);
7947 lock_ObtainMutex(&vcp->mx);
7948 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7949 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7951 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7952 lock_ReleaseMutex(&vcp->mx);
7953 lock_ObtainWrite(&smb_globalLock);
7954 dead_sessions[vcp->session] = TRUE;
7955 lock_ReleaseWrite(&smb_globalLock);
7956 smb_CleanupDeadVC(vcp);
7958 lock_ReleaseMutex(&vcp->mx);
7961 /* assert that we do not exceed the maximum number of sessions or NCBs.
7962 * we should probably want to wait for a session to be freed in case
7965 osi_assert(session < SESSION_MAX - 1);
7966 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
7968 lock_ObtainMutex(&vcp->mx);
7969 vcp->session = session;
7970 lock_ReleaseMutex(&vcp->mx);
7971 lock_ObtainWrite(&smb_globalLock);
7972 LSNs[session] = ncbp->ncb_lsn;
7973 lanas[session] = ncbp->ncb_lana_num;
7974 lock_ReleaseWrite(&smb_globalLock);
7976 if (session == numSessions) {
7977 /* Add new NCB for new session */
7978 char eventName[MAX_PATH];
7980 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7982 InitNCBslot(numNCBs);
7983 lock_ObtainWrite(&smb_globalLock);
7985 lock_ReleaseWrite(&smb_globalLock);
7986 thrd_SetEvent(NCBavails[0]);
7987 thrd_SetEvent(NCBevents[0]);
7988 for (thread = 0; thread < smb_NumServerThreads; thread++)
7989 thrd_SetEvent(NCBreturns[thread][0]);
7990 /* Also add new session event */
7991 sprintf(eventName, "SessionEvents[%d]", session);
7992 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7993 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7994 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7995 lock_ObtainWrite(&smb_globalLock);
7997 lock_ReleaseWrite(&smb_globalLock);
7998 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7999 thrd_SetEvent(SessionEvents[0]);
8001 thrd_SetEvent(SessionEvents[session]);
8007 lock_ReleaseMutex(&smb_ListenerLock);
8008 } /* dispatch while loop */
8011 /* initialize Netbios */
8012 void smb_NetbiosInit()
8015 int i, lana, code, l;
8017 int delname_tried=0;
8020 OSVERSIONINFO Version;
8022 /* Get the version of Windows */
8023 memset(&Version, 0x00, sizeof(Version));
8024 Version.dwOSVersionInfoSize = sizeof(Version);
8025 GetVersionEx(&Version);
8027 /* setup the NCB system */
8030 if (smb_LANadapter == -1) {
8031 ncbp->ncb_command = NCBENUM;
8032 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8033 ncbp->ncb_length = sizeof(lana_list);
8034 code = Netbios(ncbp);
8036 afsi_log("Netbios NCBENUM error code %d", code);
8037 osi_panic(s, __FILE__, __LINE__);
8041 lana_list.length = 1;
8042 lana_list.lana[0] = smb_LANadapter;
8045 for (i = 0; i < lana_list.length; i++) {
8046 /* reset the adaptor: in Win32, this is required for every process, and
8047 * acts as an init call, not as a real hardware reset.
8049 ncbp->ncb_command = NCBRESET;
8050 ncbp->ncb_callname[0] = 100;
8051 ncbp->ncb_callname[2] = 100;
8052 ncbp->ncb_lana_num = lana_list.lana[i];
8053 code = Netbios(ncbp);
8055 code = ncbp->ncb_retcode;
8057 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8058 lana_list.lana[i] = 255; /* invalid lana */
8060 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8064 /* and declare our name so we can receive connections */
8065 memset(ncbp, 0, sizeof(*ncbp));
8066 len=lstrlen(smb_localNamep);
8067 memset(smb_sharename,' ',NCBNAMSZ);
8068 memcpy(smb_sharename,smb_localNamep,len);
8069 afsi_log("lana_list.length %d", lana_list.length);
8071 /* Keep the name so we can unregister it later */
8072 for (l = 0; l < lana_list.length; l++) {
8073 lana = lana_list.lana[l];
8075 ncbp->ncb_command = NCBADDNAME;
8076 ncbp->ncb_lana_num = lana;
8077 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8078 code = Netbios(ncbp);
8080 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8081 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8083 char name[NCBNAMSZ+1];
8085 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8086 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8089 if (code == 0) code = ncbp->ncb_retcode;
8091 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8094 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8095 if (code == NRC_BRIDGE) { /* invalid LANA num */
8096 lana_list.lana[l] = 255;
8099 else if (code == NRC_DUPNAME) {
8100 afsi_log("Name already exists; try to delete it");
8101 memset(ncbp, 0, sizeof(*ncbp));
8102 ncbp->ncb_command = NCBDELNAME;
8103 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8104 ncbp->ncb_lana_num = lana;
8105 code = Netbios(ncbp);
8107 code = ncbp->ncb_retcode;
8109 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8111 if (code != 0 || delname_tried) {
8112 lana_list.lana[l] = 255;
8114 else if (code == 0) {
8115 if (!delname_tried) {
8123 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8124 lana_list.lana[l] = 255; /* invalid lana */
8125 osi_panic(s, __FILE__, __LINE__);
8129 lana_found = 1; /* at least one worked */
8133 osi_assert(lana_list.length >= 0);
8135 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8138 /* we're done with the NCB now */
8142 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8153 EVENT_HANDLE retHandle;
8154 char eventName[MAX_PATH];
8156 smb_TlsRequestSlot = TlsAlloc();
8158 smb_MBfunc = aMBfunc;
8161 smb_LANadapter = LANadapt;
8163 /* Initialize smb_localZero */
8164 myTime.tm_isdst = -1; /* compute whether on DST or not */
8165 myTime.tm_year = 70;
8171 smb_localZero = mktime(&myTime);
8173 #ifndef USE_NUMERIC_TIME_CONV
8174 /* Initialize kludge-GMT */
8175 smb_CalculateNowTZ();
8176 #endif /* USE_NUMERIC_TIME_CONV */
8177 #ifdef AFS_FREELANCE_CLIENT
8178 /* Make sure the root.afs volume has the correct time */
8179 cm_noteLocalMountPointChange();
8182 /* initialize the remote debugging log */
8185 /* remember the name */
8186 len = (int)strlen(snamep);
8187 smb_localNamep = malloc(len+1);
8188 strcpy(smb_localNamep, snamep);
8189 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8191 /* and the global lock */
8192 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8193 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8195 /* Raw I/O data structures */
8196 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8198 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8200 /* 4 Raw I/O buffers */
8201 smb_RawBufs = calloc(65536,1);
8202 *((char **)smb_RawBufs) = NULL;
8203 for (i=0; i<3; i++) {
8204 char *rawBuf = calloc(65536,1);
8205 *((char **)rawBuf) = smb_RawBufs;
8206 smb_RawBufs = rawBuf;
8209 /* global free lists */
8210 smb_ncbFreeListp = NULL;
8211 smb_packetFreeListp = NULL;
8215 /* Initialize listener and server structures */
8217 memset(dead_sessions, 0, sizeof(dead_sessions));
8218 sprintf(eventName, "SessionEvents[0]");
8219 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8220 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8221 afsi_log("Event Object Already Exists: %s", eventName);
8223 smb_NumServerThreads = nThreads;
8224 sprintf(eventName, "NCBavails[0]");
8225 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8226 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8227 afsi_log("Event Object Already Exists: %s", eventName);
8228 sprintf(eventName, "NCBevents[0]");
8229 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8230 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8231 afsi_log("Event Object Already Exists: %s", eventName);
8232 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8233 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8234 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8235 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8236 afsi_log("Event Object Already Exists: %s", eventName);
8237 for (i = 0; i < smb_NumServerThreads; i++) {
8238 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8239 NCBreturns[i][0] = retHandle;
8242 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8243 for (i = 0; i < smb_NumServerThreads; i++) {
8244 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8245 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8246 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8247 afsi_log("Event Object Already Exists: %s", eventName);
8248 InitNCBslot((int)(i+1));
8250 numNCBs = smb_NumServerThreads + 1;
8252 /* Initialize dispatch table */
8253 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8254 /* Prepare the table for unknown operations */
8255 for(i=0; i<= SMB_NOPCODES; i++) {
8256 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8258 /* Fill in the ones we do know */
8259 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8260 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8261 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8262 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8263 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8264 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8265 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8266 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8267 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8268 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8269 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8270 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8271 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8272 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8273 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8274 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8275 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8276 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8277 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8278 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8279 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8280 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8281 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8282 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8283 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8284 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8285 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8286 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8287 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8288 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8289 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8290 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8291 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8292 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8293 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8294 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8295 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8296 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8297 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8298 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8299 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8300 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8301 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8302 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8303 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8304 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8305 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8306 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8307 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8308 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8309 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8310 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8311 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8312 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8313 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8314 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8315 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8316 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8317 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8318 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8319 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8320 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8321 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8322 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8323 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8324 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8325 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8326 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8327 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8328 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8329 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8330 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8331 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8332 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8334 /* setup tran 2 dispatch table */
8335 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8336 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8337 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8338 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8339 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8340 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8341 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8342 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8343 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8344 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8345 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8346 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8347 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8348 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8349 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8350 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8351 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8352 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8354 /* setup the rap dispatch table */
8355 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8356 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8357 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8358 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8359 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8363 /* if we are doing SMB authentication we have register outselves as a logon process */
8364 if (smb_authType != SMB_AUTH_NONE) {
8365 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8366 LSA_STRING afsProcessName;
8367 LSA_OPERATIONAL_MODE dummy; /*junk*/
8369 afsProcessName.Buffer = "OpenAFSClientDaemon";
8370 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8371 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8373 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8375 if (nts == STATUS_SUCCESS) {
8376 LSA_STRING packageName;
8377 /* we are registered. Find out the security package id */
8378 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8379 packageName.Length = (USHORT)strlen(packageName.Buffer);
8380 packageName.MaximumLength = packageName.Length + 1;
8381 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8382 if (nts == STATUS_SUCCESS) {
8384 * This code forces Windows to authenticate against the Logon Cache
8385 * first instead of attempting to authenticate against the Domain
8386 * Controller. When the Windows logon cache is enabled this improves
8387 * performance by removing the network access and works around a bug
8388 * seen at sites which are using a MIT Kerberos principal to login
8389 * to machines joined to a non-root domain in a multi-domain forest.
8391 PVOID pResponse = NULL;
8392 ULONG cbResponse = 0;
8393 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8395 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8396 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8397 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8398 OptionsRequest.DisableOptions = FALSE;
8400 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8403 sizeof(OptionsRequest),
8409 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8411 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8413 OutputDebugString(message);
8416 OutputDebugString("MsV1_0SetProcessOption success");
8417 afsi_log("MsV1_0SetProcessOption success");
8419 /* END - code from Larry */
8421 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8422 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8423 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8425 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8427 /* something went wrong. We report the error and revert back to no authentication
8428 because we can't perform any auth requests without a successful lsa handle
8429 or sec package id. */
8430 afsi_log("Reverting to NO SMB AUTH");
8431 smb_authType = SMB_AUTH_NONE;
8434 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8436 /* something went wrong. We report the error and revert back to no authentication
8437 because we can't perform any auth requests without a successful lsa handle
8438 or sec package id. */
8439 afsi_log("Reverting to NO SMB AUTH");
8440 smb_authType = SMB_AUTH_NONE;
8444 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8445 * time prevents the failure of authentication when logged into Windows with an
8446 * external Kerberos principal mapped to a local account.
8448 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8449 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8450 * then the only option is NTLMSSP anyway; so just fallback.
8455 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8456 if (secBlobLength == 0) {
8457 smb_authType = SMB_AUTH_NTLM;
8458 afsi_log("Reverting to SMB AUTH NTLM");
8467 /* Now get ourselves a domain name. */
8468 /* For now we are using the local computer name as the domain name.
8469 * It is actually the domain for local logins, and we are acting as
8470 * a local SMB server.
8472 bufsize = sizeof(smb_ServerDomainName) - 1;
8473 GetComputerName(smb_ServerDomainName, &bufsize);
8474 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8475 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8478 /* Start listeners, waiters, servers, and daemons */
8480 for (i = 0; i < lana_list.length; i++) {
8481 if (lana_list.lana[i] == 255)
8483 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8484 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8485 osi_assert(phandle != NULL);
8486 thrd_CloseHandle(phandle);
8489 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8490 NULL, 0, &lpid, "smb_ClientWaiter");
8491 osi_assert(phandle != NULL);
8492 thrd_CloseHandle(phandle);
8494 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8495 NULL, 0, &lpid, "smb_ServerWaiter");
8496 osi_assert(phandle != NULL);
8497 thrd_CloseHandle(phandle);
8499 for (i=0; i<smb_NumServerThreads; i++) {
8500 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8501 (void *) i, 0, &lpid, "smb_Server");
8502 osi_assert(phandle != NULL);
8503 thrd_CloseHandle(phandle);
8506 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8507 NULL, 0, &lpid, "smb_Daemon");
8508 osi_assert(phandle != NULL);
8509 thrd_CloseHandle(phandle);
8511 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8512 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8513 osi_assert(phandle != NULL);
8514 thrd_CloseHandle(phandle);
8519 void smb_Shutdown(void)
8526 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8528 /* setup the NCB system */
8531 /* Block new sessions by setting shutdown flag */
8532 smbShutdownFlag = 1;
8534 /* Hang up all sessions */
8535 memset((char *)ncbp, 0, sizeof(NCB));
8536 for (i = 1; i < numSessions; i++)
8538 if (dead_sessions[i])
8541 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8542 ncbp->ncb_command = NCBHANGUP;
8543 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8544 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8545 code = Netbios(ncbp);
8546 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8547 if (code == 0) code = ncbp->ncb_retcode;
8549 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8550 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8554 /* Trigger the shutdown of all SMB threads */
8555 for (i = 0; i < smb_NumServerThreads; i++)
8556 thrd_SetEvent(NCBreturns[i][0]);
8558 thrd_SetEvent(NCBevents[0]);
8559 thrd_SetEvent(SessionEvents[0]);
8560 thrd_SetEvent(NCBavails[0]);
8562 for (i = 0;i < smb_NumServerThreads; i++) {
8563 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8564 if (code == WAIT_OBJECT_0) {
8567 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8568 thrd_SetEvent(NCBreturns[i--][0]);
8572 /* Delete Netbios name */
8573 memset((char *)ncbp, 0, sizeof(NCB));
8574 for (i = 0; i < lana_list.length; i++) {
8575 if (lana_list.lana[i] == 255) continue;
8576 ncbp->ncb_command = NCBDELNAME;
8577 ncbp->ncb_lana_num = lana_list.lana[i];
8578 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8579 code = Netbios(ncbp);
8581 code = ncbp->ncb_retcode;
8583 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8584 ncbp->ncb_lana_num, code);
8589 /* Release the reference counts held by the VCs */
8590 lock_ObtainWrite(&smb_rctLock);
8591 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8596 if (vcp->magic != SMB_VC_MAGIC)
8597 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8598 __FILE__, __LINE__);
8600 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8602 if (fidp->scp != NULL) {
8605 lock_ObtainMutex(&fidp->mx);
8606 if (fidp->scp != NULL) {
8609 cm_ReleaseSCache(scp);
8611 lock_ReleaseMutex(&fidp->mx);
8615 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8617 smb_ReleaseVCNoLock(tidp->vcp);
8619 cm_user_t *userp = tidp->userp;
8621 lock_ReleaseWrite(&smb_rctLock);
8622 cm_ReleaseUser(userp);
8623 lock_ObtainWrite(&smb_rctLock);
8627 lock_ReleaseWrite(&smb_rctLock);
8629 TlsFree(smb_TlsRequestSlot);
8632 /* Get the UNC \\<servername>\<sharename> prefix. */
8633 char *smb_GetSharename()
8637 /* Make sure we have been properly initialized. */
8638 if (smb_localNamep == NULL)
8641 /* Allocate space for \\<servername>\<sharename>, plus the
8644 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8645 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8651 void smb_LogPacket(smb_packet_t *packet)
8654 unsigned length, paramlen, datalen, i, j;
8656 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8658 if (!packet) return;
8660 osi_Log0(smb_logp, "*** SMB packet dump ***");
8662 vp = (BYTE *) packet->data;
8664 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8665 length = paramlen + 2 + datalen;
8668 for (i=0;i < length; i+=16)
8670 memset( buf, ' ', 80 );
8675 buf[strlen(buf)] = ' ';
8677 cp = (BYTE*) buf + 7;
8679 for (j=0;j < 16 && (i+j)<length; j++)
8681 *(cp++) = hex[vp[i+j] >> 4];
8682 *(cp++) = hex[vp[i+j] & 0xf];
8692 for (j=0;j < 16 && (i+j)<length;j++)
8694 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8705 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
8708 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8710 #endif /* LOG_PACKET */
8713 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8721 lock_ObtainRead(&smb_rctLock);
8723 sprintf(output, "begin dumping smb_vc_t\n");
8724 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8726 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8730 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8731 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8732 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8734 sprintf(output, "begin dumping smb_fid_t\n");
8735 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8737 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8739 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
8740 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8741 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8742 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8743 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8746 sprintf(output, "done dumping smb_fid_t\n");
8747 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8750 sprintf(output, "done dumping smb_vc_t\n");
8751 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8753 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8754 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8756 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8760 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8761 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8762 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8764 sprintf(output, "begin dumping smb_fid_t\n");
8765 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8767 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8769 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
8770 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8771 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8772 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8773 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8776 sprintf(output, "done dumping smb_fid_t\n");
8777 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8780 sprintf(output, "done dumping DEAD smb_vc_t\n");
8781 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8783 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8784 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8786 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8790 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8791 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8792 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8794 sprintf(output, "begin dumping smb_fid_t\n");
8795 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8797 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8799 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
8800 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8801 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8802 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8803 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8806 sprintf(output, "done dumping smb_fid_t\n");
8807 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8810 sprintf(output, "done dumping DEAD smb_vc_t\n");
8811 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8814 lock_ReleaseRead(&smb_rctLock);