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>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 /* These characters are illegal in Windows filenames */
35 static char *illegalChars = "\\/:*?\"<>|";
37 static int smbShutdownFlag = 0;
38 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
40 int smb_LogoffTokenTransfer;
41 time_t smb_LogoffTransferTimeout;
43 int smb_StoreAnsiFilenames = 0;
45 DWORD last_msg_time = 0;
49 unsigned int sessionGen = 0;
51 extern void afsi_log(char *pattern, ...);
52 extern HANDLE afsi_file;
53 extern int powerStateSuspended;
55 osi_hyper_t hzero = {0, 0};
56 osi_hyper_t hones = {0xFFFFFFFF, -1};
59 osi_rwlock_t smb_globalLock;
60 osi_rwlock_t smb_rctLock;
61 osi_mutex_t smb_ListenerLock;
62 osi_mutex_t smb_StartedLock;
64 unsigned char smb_LANadapter = LANA_INVALID;
65 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
66 int smb_LanAdapterChangeDetected = 0;
67 afs_uint32 smb_AsyncStore = 1;
68 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
70 BOOL isGateway = FALSE;
73 long smb_maxObsConcurrentCalls=0;
74 long smb_concurrentCalls=0;
76 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
78 smb_packet_t *smb_packetFreeListp;
79 smb_ncb_t *smb_ncbFreeListp;
81 afs_uint32 smb_NumServerThreads;
83 afs_uint32 numNCBs, numSessions, numVCs;
85 int smb_maxVCPerServer;
86 int smb_maxMpxRequests;
88 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
90 ULONG smb_lsaSecPackage;
91 LSA_STRING smb_lsaLogonOrigin;
93 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
94 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
95 EVENT_HANDLE **NCBreturns;
96 EVENT_HANDLE **NCBShutdown;
97 EVENT_HANDLE *smb_ServerShutdown;
98 EVENT_HANDLE ListenerShutdown[256];
99 DWORD NCBsessions[NCB_MAX];
101 struct smb_packet *bufs[NCB_MAX];
103 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
104 EVENT_HANDLE SessionEvents[SESSION_MAX];
105 unsigned short LSNs[SESSION_MAX];
106 int lanas[SESSION_MAX];
107 BOOL dead_sessions[SESSION_MAX];
110 osi_mutex_t smb_RawBufLock;
113 #define SMB_MASKFLAG_TILDE 1
114 #define SMB_MASKFLAG_CASEFOLD 2
116 #define RAWTIMEOUT INFINITE
119 typedef struct raw_write_cont {
128 /* dir search stuff */
129 long smb_dirSearchCounter = 1;
130 smb_dirSearch_t *smb_firstDirSearchp;
131 smb_dirSearch_t *smb_lastDirSearchp;
133 /* hide dot files? */
134 int smb_hideDotFiles;
136 /* global state about V3 protocols */
137 int smb_useV3; /* try to negotiate V3 */
139 static showErrors = 0;
140 /* MessageBox or something like it */
141 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
144 * Time in Unix format of midnight, 1/1/1970 local time.
145 * When added to dosUTime, gives Unix (AFS) time.
147 time_t smb_localZero = 0;
149 #define USE_NUMERIC_TIME_CONV 1
151 #ifndef USE_NUMERIC_TIME_CONV
152 /* Time difference for converting to kludge-GMT */
153 afs_uint32 smb_NowTZ;
154 #endif /* USE_NUMERIC_TIME_CONV */
156 char *smb_localNamep = NULL;
158 smb_vc_t *smb_allVCsp;
159 smb_vc_t *smb_deadVCsp;
161 smb_username_t *usernamesp = NULL;
163 smb_waitingLockRequest_t *smb_allWaitingLocks;
165 DWORD smb_TlsRequestSlot = -1;
168 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
169 NCB *ncbp, raw_write_cont_t *rwcp);
170 int smb_NetbiosInit(int);
173 void smb_LogPacket(smb_packet_t *packet);
174 #endif /* LOG_PACKET */
176 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
177 int smb_ServerDomainNameLength = 0;
178 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
179 int smb_ServerOSLength = sizeof(smb_ServerOS);
180 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
181 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
183 /* Faux server GUID. This is never checked. */
184 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
186 void smb_ResetServerPriority()
188 void * p = TlsGetValue(smb_TlsRequestSlot);
191 TlsSetValue(smb_TlsRequestSlot, NULL);
192 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
196 void smb_SetRequestStartTime()
198 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
200 tp = malloc(sizeof(time_t));
204 if (!TlsSetValue(smb_TlsRequestSlot, tp))
209 void smb_UpdateServerPriority()
211 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
214 time_t now = osi_Time();
216 /* Give one priority boost for each 15 seconds */
217 SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
222 const char * ncb_error_string(int code)
226 case 0x01: s = "llegal buffer length"; break;
227 case 0x03: s = "illegal command"; break;
228 case 0x05: s = "command timed out"; break;
229 case 0x06: s = "message incomplete, issue another command"; break;
230 case 0x07: s = "illegal buffer address"; break;
231 case 0x08: s = "session number out of range"; break;
232 case 0x09: s = "no resource available"; break;
233 case 0x0a: s = "session closed"; break;
234 case 0x0b: s = "command cancelled"; break;
235 case 0x0d: s = "duplicate name"; break;
236 case 0x0e: s = "name table full"; break;
237 case 0x0f: s = "no deletions, name has active sessions"; break;
238 case 0x11: s = "local session table full"; break;
239 case 0x12: s = "remote session table full"; break;
240 case 0x13: s = "illegal name number"; break;
241 case 0x14: s = "no callname"; break;
242 case 0x15: s = "cannot put * in NCB_NAME"; break;
243 case 0x16: s = "name in use on remote adapter"; break;
244 case 0x17: s = "name deleted"; break;
245 case 0x18: s = "session ended abnormally"; break;
246 case 0x19: s = "name conflict detected"; break;
247 case 0x21: s = "interface busy, IRET before retrying"; break;
248 case 0x22: s = "too many commands outstanding, retry later";break;
249 case 0x23: s = "ncb_lana_num field invalid"; break;
250 case 0x24: s = "command completed while cancel occurring "; break;
251 case 0x26: s = "command not valid to cancel"; break;
252 case 0x30: s = "name defined by anther local process"; break;
253 case 0x34: s = "environment undefined. RESET required"; break;
254 case 0x35: s = "required OS resources exhausted"; break;
255 case 0x36: s = "max number of applications exceeded"; break;
256 case 0x37: s = "no saps available for netbios"; break;
257 case 0x38: s = "requested resources are not available"; break;
258 case 0x39: s = "invalid ncb address or length > segment"; break;
259 case 0x3B: s = "invalid NCB DDID"; break;
260 case 0x3C: s = "lock of user area failed"; break;
261 case 0x3f: s = "NETBIOS not loaded"; break;
262 case 0x40: s = "system error"; break;
263 default: s = "unknown error";
269 char * myCrt_Dispatch(int i)
274 return "(00)ReceiveCoreMakeDir";
276 return "(01)ReceiveCoreRemoveDir";
278 return "(02)ReceiveCoreOpen";
280 return "(03)ReceiveCoreCreate";
282 return "(04)ReceiveCoreClose";
284 return "(05)ReceiveCoreFlush";
286 return "(06)ReceiveCoreUnlink";
288 return "(07)ReceiveCoreRename";
290 return "(08)ReceiveCoreGetFileAttributes";
292 return "(09)ReceiveCoreSetFileAttributes";
294 return "(0a)ReceiveCoreRead";
296 return "(0b)ReceiveCoreWrite";
298 return "(0c)ReceiveCoreLockRecord";
300 return "(0d)ReceiveCoreUnlockRecord";
302 return "(0e)SendCoreBadOp";
304 return "(0f)ReceiveCoreCreate";
306 return "(10)ReceiveCoreCheckPath";
308 return "(11)SendCoreBadOp";
310 return "(12)ReceiveCoreSeek";
312 return "(1a)ReceiveCoreReadRaw";
314 return "(1d)ReceiveCoreWriteRawDummy";
316 return "(22)ReceiveV3SetAttributes";
318 return "(23)ReceiveV3GetAttributes";
320 return "(24)ReceiveV3LockingX";
322 return "(25)ReceiveV3Trans";
324 return "(26)ReceiveV3Trans[aux]";
326 return "(29)SendCoreBadOp";
328 return "(2b)ReceiveCoreEcho";
330 return "(2d)ReceiveV3OpenX";
332 return "(2e)ReceiveV3ReadX";
334 return "(2f)ReceiveV3WriteX";
336 return "(32)ReceiveV3Tran2A";
338 return "(33)ReceiveV3Tran2A[aux]";
340 return "(34)ReceiveV3FindClose";
342 return "(35)ReceiveV3FindNotifyClose";
344 return "(70)ReceiveCoreTreeConnect";
346 return "(71)ReceiveCoreTreeDisconnect";
348 return "(72)ReceiveNegotiate";
350 return "(73)ReceiveV3SessionSetupX";
352 return "(74)ReceiveV3UserLogoffX";
354 return "(75)ReceiveV3TreeConnectX";
356 return "(80)ReceiveCoreGetDiskAttributes";
358 return "(81)ReceiveCoreSearchDir";
362 return "(83)FindUnique";
364 return "(84)FindClose";
366 return "(A0)ReceiveNTTransact";
368 return "(A2)ReceiveNTCreateX";
370 return "(A4)ReceiveNTCancel";
372 return "(A5)ReceiveNTRename";
374 return "(C0)OpenPrintFile";
376 return "(C1)WritePrintFile";
378 return "(C2)ClosePrintFile";
380 return "(C3)GetPrintQueue";
382 return "(D8)ReadBulk";
384 return "(D9)WriteBulk";
386 return "(DA)WriteBulkData";
388 return "unknown SMB op";
392 char * myCrt_2Dispatch(int i)
397 return "unknown SMB op-2";
399 return "S(00)CreateFile_ReceiveTran2Open";
401 return "S(01)FindFirst_ReceiveTran2SearchDir";
403 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
405 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
407 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
409 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
411 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
413 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
415 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
417 return "S(09)_ReceiveTran2FSCTL";
419 return "S(0a)_ReceiveTran2IOCTL";
421 return "S(0b)_ReceiveTran2FindNotifyFirst";
423 return "S(0c)_ReceiveTran2FindNotifyNext";
425 return "S(0d)_ReceiveTran2CreateDirectory";
427 return "S(0e)_ReceiveTran2SessionSetup";
429 return "S(0f)_QueryFileSystemInformationFid";
431 return "S(10)_ReceiveTran2GetDfsReferral";
433 return "S(11)_ReceiveTran2ReportDfsInconsistency";
437 char * myCrt_RapDispatch(int i)
442 return "unknown RAP OP";
444 return "RAP(0)NetShareEnum";
446 return "RAP(1)NetShareGetInfo";
448 return "RAP(13)NetServerGetInfo";
450 return "RAP(63)NetWkStaGetInfo";
454 /* scache must be locked */
455 unsigned int smb_Attributes(cm_scache_t *scp)
459 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
460 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
461 scp->fileType == CM_SCACHETYPE_INVALID)
463 attrs = SMB_ATTR_DIRECTORY;
464 #ifdef SPECIAL_FOLDERS
465 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
466 #endif /* SPECIAL_FOLDERS */
467 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
468 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
473 * We used to mark a file RO if it was in an RO volume, but that
474 * turns out to be impolitic in NT. See defect 10007.
477 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
478 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
480 if ((scp->unixModeBits & 0222) == 0)
481 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
487 /* Check if the named file/dir is a dotfile/dotdir */
488 /* String pointed to by lastComp can have leading slashes, but otherwise should have
489 no other patch components */
490 unsigned int smb_IsDotFile(char *lastComp) {
493 /* skip over slashes */
494 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
499 /* nulls, curdir and parent dir doesn't count */
505 if(*(s+1) == '.' && !*(s + 2))
512 static int ExtractBits(WORD bits, short start, short len)
519 num = bits << (16 - end);
520 num = num >> ((16 - end) + start);
525 void ShowUnixTime(char *FuncName, time_t unixTime)
530 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
532 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
533 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
535 int day, month, year, sec, min, hour;
538 day = ExtractBits(wDate, 0, 5);
539 month = ExtractBits(wDate, 5, 4);
540 year = ExtractBits(wDate, 9, 7) + 1980;
542 sec = ExtractBits(wTime, 0, 5);
543 min = ExtractBits(wTime, 5, 6);
544 hour = ExtractBits(wTime, 11, 5);
546 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
547 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
551 /* Determine if we are observing daylight savings time */
552 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
554 TIME_ZONE_INFORMATION timeZoneInformation;
555 SYSTEMTIME utc, local, localDST;
557 /* Get the time zone info. NT uses this to calc if we are in DST. */
558 GetTimeZoneInformation(&timeZoneInformation);
560 /* Return the daylight bias */
561 *pDstBias = timeZoneInformation.DaylightBias;
563 /* Return the bias */
564 *pBias = timeZoneInformation.Bias;
566 /* Now determine if DST is being observed */
568 /* Get the UTC (GMT) time */
571 /* Convert UTC time to local time using the time zone info. If we are
572 observing DST, the calculated local time will include this.
574 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
576 /* Set the daylight bias to 0. The daylight bias is the amount of change
577 * in time that we use for daylight savings time. By setting this to 0
578 * we cause there to be no change in time during daylight savings time.
580 timeZoneInformation.DaylightBias = 0;
582 /* Convert the utc time to local time again, but this time without any
583 adjustment for daylight savings time.
585 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
587 /* If the two times are different, then it means that the localDST that
588 we calculated includes the daylight bias, and therefore we are
589 observing daylight savings time.
591 *pDST = localDST.wHour != local.wHour;
595 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
597 BOOL dst; /* Will be TRUE if observing DST */
598 LONG dstBias; /* Offset from local time if observing DST */
599 LONG bias; /* Offset from GMT for local time */
602 * This function will adjust the last write time to compensate
603 * for two bugs in the smb client:
605 * 1) During Daylight Savings Time, the LastWriteTime is ahead
606 * in time by the DaylightBias (ignoring the sign - the
607 * DaylightBias is always stored as a negative number). If
608 * the DaylightBias is -60, then the LastWriteTime will be
609 * ahead by 60 minutes.
611 * 2) If the local time zone is a positive offset from GMT, then
612 * the LastWriteTime will be the correct local time plus the
613 * Bias (ignoring the sign - a positive offset from GMT is
614 * always stored as a negative Bias). If the Bias is -120,
615 * then the LastWriteTime will be ahead by 120 minutes.
617 * These bugs can occur at the same time.
620 GetTimeZoneInfo(&dst, &dstBias, &bias);
622 /* First adjust for DST */
624 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
626 /* Now adjust for a positive offset from GMT (a negative bias). */
628 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
631 #ifndef USE_NUMERIC_TIME_CONV
633 * Calculate the difference (in seconds) between local time and GMT.
634 * This enables us to convert file times to kludge-GMT.
640 struct tm gmt_tm, local_tm;
641 int days, hours, minutes, seconds;
644 gmt_tm = *(gmtime(&t));
645 local_tm = *(localtime(&t));
647 days = local_tm.tm_yday - gmt_tm.tm_yday;
648 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
649 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
650 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
654 #endif /* USE_NUMERIC_TIME_CONV */
656 #ifdef USE_NUMERIC_TIME_CONV
657 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
659 // Note that LONGLONG is a 64-bit value
662 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
663 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
664 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
667 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
672 time_t ersatz_unixTime;
675 * Must use kludge-GMT instead of real GMT.
676 * kludge-GMT is computed by adding time zone difference to localtime.
679 * ltp = gmtime(&unixTime);
681 ersatz_unixTime = unixTime - smb_NowTZ;
682 ltp = localtime(&ersatz_unixTime);
684 /* if we fail, make up something */
687 localJunk.tm_year = 89 - 20;
688 localJunk.tm_mon = 4;
689 localJunk.tm_mday = 12;
690 localJunk.tm_hour = 0;
691 localJunk.tm_min = 0;
692 localJunk.tm_sec = 0;
695 stm.wYear = ltp->tm_year + 1900;
696 stm.wMonth = ltp->tm_mon + 1;
697 stm.wDayOfWeek = ltp->tm_wday;
698 stm.wDay = ltp->tm_mday;
699 stm.wHour = ltp->tm_hour;
700 stm.wMinute = ltp->tm_min;
701 stm.wSecond = ltp->tm_sec;
702 stm.wMilliseconds = 0;
704 SystemTimeToFileTime(&stm, largeTimep);
706 #endif /* USE_NUMERIC_TIME_CONV */
708 #ifdef USE_NUMERIC_TIME_CONV
709 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
711 // Note that LONGLONG is a 64-bit value
714 ll = largeTimep->dwHighDateTime;
716 ll += largeTimep->dwLowDateTime;
718 ll -= 116444736000000000;
721 *unixTimep = (DWORD)ll;
723 #else /* USE_NUMERIC_TIME_CONV */
724 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
730 FileTimeToSystemTime(largeTimep, &stm);
732 lt.tm_year = stm.wYear - 1900;
733 lt.tm_mon = stm.wMonth - 1;
734 lt.tm_wday = stm.wDayOfWeek;
735 lt.tm_mday = stm.wDay;
736 lt.tm_hour = stm.wHour;
737 lt.tm_min = stm.wMinute;
738 lt.tm_sec = stm.wSecond;
741 save_timezone = _timezone;
742 _timezone += smb_NowTZ;
743 *unixTimep = mktime(<);
744 _timezone = save_timezone;
746 #endif /* USE_NUMERIC_TIME_CONV */
748 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
758 /* if we fail, make up something */
761 localJunk.tm_year = 89 - 20;
762 localJunk.tm_mon = 4;
763 localJunk.tm_mday = 12;
764 localJunk.tm_hour = 0;
765 localJunk.tm_min = 0;
766 localJunk.tm_sec = 0;
769 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
770 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
771 *searchTimep = (dosDate<<16) | dosTime;
774 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
776 unsigned short dosDate;
777 unsigned short dosTime;
780 dosDate = (unsigned short) (searchTime & 0xffff);
781 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
783 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
784 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
785 localTm.tm_mday = (dosDate) & 0x1f;
786 localTm.tm_hour = (dosTime>>11) & 0x1f;
787 localTm.tm_min = (dosTime >> 5) & 0x3f;
788 localTm.tm_sec = (dosTime & 0x1f) * 2;
789 localTm.tm_isdst = -1; /* compute whether DST in effect */
791 *unixTimep = mktime(&localTm);
794 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
796 time_t diff_t = unixTime - smb_localZero;
797 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
798 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
800 *dosUTimep = (afs_uint32)diff_t;
803 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
805 *unixTimep = dosTime + smb_localZero;
808 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
812 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
813 lock_ObtainWrite(&smb_rctLock);
814 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
815 if (vcp->magic != SMB_VC_MAGIC)
816 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
819 if (lsn == vcp->lsn && lana == vcp->lana &&
820 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
821 smb_HoldVCNoLock(vcp);
825 if (!vcp && (flags & SMB_FLAG_CREATE)) {
826 vcp = malloc(sizeof(*vcp));
827 memset(vcp, 0, sizeof(*vcp));
828 vcp->vcID = ++numVCs;
829 vcp->magic = SMB_VC_MAGIC;
830 vcp->refCount = 2; /* smb_allVCsp and caller */
833 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
834 vcp->nextp = smb_allVCsp;
836 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
841 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
842 /* We must obtain a challenge for extended auth
843 * in case the client negotiates smb v3
845 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
846 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
847 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
848 ULONG lsaRespSize = 0;
850 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
852 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
859 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
860 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
861 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
862 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
863 nts, ntsEx, lsaRespSize);
865 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
867 if (ntsEx == STATUS_SUCCESS) {
868 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
869 LsaFreeReturnBuffer(lsaResp);
872 * This will cause the subsequent authentication to fail but
873 * that is better than us dereferencing a NULL pointer and
876 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
880 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
882 if (numVCs >= CM_SESSION_RESERVED) {
884 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
887 lock_ReleaseWrite(&smb_rctLock);
888 lock_ReleaseWrite(&smb_globalLock);
892 int smb_IsStarMask(char *maskp)
897 for(i=0; i<11; i++) {
899 if (tc == '?' || tc == '*' || tc == '>')
905 void smb_ReleaseVCInternal(smb_vc_t *vcp)
912 if (vcp->refCount == 0) {
913 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
914 /* remove VCP from smb_deadVCsp */
915 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
921 lock_FinalizeMutex(&vcp->mx);
922 memset(vcp,0,sizeof(smb_vc_t));
925 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
929 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
930 avcp?"not ":"",vcp, vcp->refCount);
932 GenerateMiniDump(NULL);
934 /* This is a wrong. However, I suspect that there is an undercount
935 * and I don't want to release 1.4.1 in a state that will allow
936 * smb_vc_t objects to be deallocated while still in the
937 * smb_allVCsp list. The list is supposed to keep a reference
938 * to the smb_vc_t. Put it back.
945 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
947 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
948 smb_ReleaseVCInternal(vcp);
951 void smb_ReleaseVC(smb_vc_t *vcp)
953 lock_ObtainWrite(&smb_rctLock);
954 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
955 smb_ReleaseVCInternal(vcp);
956 lock_ReleaseWrite(&smb_rctLock);
959 void smb_HoldVCNoLock(smb_vc_t *vcp)
962 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
965 void smb_HoldVC(smb_vc_t *vcp)
967 lock_ObtainWrite(&smb_rctLock);
969 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
970 lock_ReleaseWrite(&smb_rctLock);
973 void smb_CleanupDeadVC(smb_vc_t *vcp)
981 smb_user_t *uidpIter;
982 smb_user_t *uidpNext;
986 lock_ObtainMutex(&vcp->mx);
987 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
988 lock_ReleaseMutex(&vcp->mx);
989 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
992 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
993 lock_ReleaseMutex(&vcp->mx);
994 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
996 lock_ObtainWrite(&smb_rctLock);
997 /* remove VCP from smb_allVCsp */
998 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
999 if ((*vcpp)->magic != SMB_VC_MAGIC)
1000 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1001 __FILE__, __LINE__);
1004 vcp->nextp = smb_deadVCsp;
1006 /* Hold onto the reference until we are done with this function */
1011 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1012 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1014 if (fidpIter->delete)
1017 fid = fidpIter->fid;
1018 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1020 smb_HoldFIDNoLock(fidpIter);
1021 lock_ReleaseWrite(&smb_rctLock);
1023 smb_CloseFID(vcp, fidpIter, NULL, 0);
1024 smb_ReleaseFID(fidpIter);
1026 lock_ObtainWrite(&smb_rctLock);
1027 fidpNext = vcp->fidsp;
1030 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1031 tidpNext = tidpIter->nextp;
1032 if (tidpIter->delete)
1034 tidpIter->delete = 1;
1036 tid = tidpIter->tid;
1037 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1039 smb_HoldTIDNoLock(tidpIter);
1040 smb_ReleaseTID(tidpIter, TRUE);
1041 tidpNext = vcp->tidsp;
1044 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1045 uidpNext = uidpIter->nextp;
1046 if (uidpIter->delete)
1048 uidpIter->delete = 1;
1050 /* do not add an additional reference count for the smb_user_t
1051 * as the smb_vc_t already is holding a reference */
1052 lock_ReleaseWrite(&smb_rctLock);
1054 smb_ReleaseUID(uidpIter);
1056 lock_ObtainWrite(&smb_rctLock);
1057 uidpNext = vcp->usersp;
1060 /* The vcp is now on the deadVCsp list. We intentionally drop the
1061 * reference so that the refcount can reach 0 and we can delete it */
1062 smb_ReleaseVCNoLock(vcp);
1064 lock_ReleaseWrite(&smb_rctLock);
1065 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1068 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1072 lock_ObtainWrite(&smb_rctLock);
1074 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1075 if (tidp->refCount == 0 && tidp->delete) {
1077 smb_ReleaseTID(tidp, TRUE);
1081 if (tid == tidp->tid) {
1086 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1087 tidp = malloc(sizeof(*tidp));
1088 memset(tidp, 0, sizeof(*tidp));
1089 tidp->nextp = vcp->tidsp;
1092 smb_HoldVCNoLock(vcp);
1094 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1097 lock_ReleaseWrite(&smb_rctLock);
1101 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1106 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1114 lock_ObtainWrite(&smb_rctLock);
1115 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1116 if (tidp->refCount == 0 && (tidp->delete)) {
1117 ltpp = &tidp->vcp->tidsp;
1118 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1122 osi_assertx(tp != NULL, "null smb_tid_t");
1124 lock_FinalizeMutex(&tidp->mx);
1125 userp = tidp->userp; /* remember to drop ref later */
1127 smb_ReleaseVCNoLock(tidp->vcp);
1131 lock_ReleaseWrite(&smb_rctLock);
1133 cm_ReleaseUser(userp);
1136 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1138 smb_user_t *uidp = NULL;
1140 lock_ObtainWrite(&smb_rctLock);
1141 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1142 if (uid == uidp->userID) {
1144 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1146 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1150 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1151 uidp = malloc(sizeof(*uidp));
1152 memset(uidp, 0, sizeof(*uidp));
1153 uidp->nextp = vcp->usersp;
1154 uidp->refCount = 2; /* one for the vcp and one for the caller */
1156 smb_HoldVCNoLock(vcp);
1158 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1160 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1162 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1164 lock_ReleaseWrite(&smb_rctLock);
1168 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1170 smb_username_t *unp= NULL;
1172 lock_ObtainWrite(&smb_rctLock);
1173 for(unp = usernamesp; unp; unp = unp->nextp) {
1174 if (stricmp(unp->name, usern) == 0 &&
1175 stricmp(unp->machine, machine) == 0) {
1180 if (!unp && (flags & SMB_FLAG_CREATE)) {
1181 unp = malloc(sizeof(*unp));
1182 memset(unp, 0, sizeof(*unp));
1184 unp->nextp = usernamesp;
1185 unp->name = strdup(usern);
1186 unp->machine = strdup(machine);
1188 lock_InitializeMutex(&unp->mx, "username_t mutex");
1189 if (flags & SMB_FLAG_AFSLOGON)
1190 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1193 lock_ReleaseWrite(&smb_rctLock);
1197 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1199 smb_user_t *uidp= NULL;
1201 lock_ObtainWrite(&smb_rctLock);
1202 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1205 if (stricmp(uidp->unp->name, usern) == 0) {
1207 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1208 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1213 lock_ReleaseWrite(&smb_rctLock);
1217 void smb_ReleaseUsername(smb_username_t *unp)
1220 smb_username_t **lupp;
1221 cm_user_t *userp = NULL;
1222 time_t now = osi_Time();
1224 lock_ObtainWrite(&smb_rctLock);
1225 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1226 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1227 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1229 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1233 osi_assertx(up != NULL, "null smb_username_t");
1235 up->nextp = NULL; /* do not remove this */
1236 lock_FinalizeMutex(&unp->mx);
1242 lock_ReleaseWrite(&smb_rctLock);
1244 cm_ReleaseUser(userp);
1247 void smb_HoldUIDNoLock(smb_user_t *uidp)
1252 void smb_ReleaseUID(smb_user_t *uidp)
1256 smb_username_t *unp = NULL;
1258 lock_ObtainWrite(&smb_rctLock);
1259 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1260 if (uidp->refCount == 0) {
1261 lupp = &uidp->vcp->usersp;
1262 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1266 osi_assertx(up != NULL, "null smb_user_t");
1268 lock_FinalizeMutex(&uidp->mx);
1270 smb_ReleaseVCNoLock(uidp->vcp);
1274 lock_ReleaseWrite(&smb_rctLock);
1278 cm_ReleaseUserVCRef(unp->userp);
1279 smb_ReleaseUsername(unp);
1283 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1285 cm_user_t *up = NULL;
1290 lock_ObtainMutex(&uidp->mx);
1292 up = uidp->unp->userp;
1295 lock_ReleaseMutex(&uidp->mx);
1301 /* retrieve a held reference to a user structure corresponding to an incoming
1303 * corresponding release function is cm_ReleaseUser.
1305 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1308 cm_user_t *up = NULL;
1311 smbp = (smb_t *) inp;
1312 uidp = smb_FindUID(vcp, smbp->uid, 0);
1316 up = smb_GetUserFromUID(uidp);
1318 smb_ReleaseUID(uidp);
1323 * Return a pointer to a pathname extracted from a TID structure. The
1324 * TID structure is not held; assume it won't go away.
1326 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1331 tidp = smb_FindTID(vcp, tid, 0);
1335 if (tidp->flags & SMB_TIDFLAG_IPC) {
1336 code = CM_ERROR_TIDIPC;
1337 /* tidp->pathname would be NULL, but that's fine */
1339 *treepath = tidp->pathname;
1340 smb_ReleaseTID(tidp, FALSE);
1345 /* check to see if we have a chained fid, that is, a fid that comes from an
1346 * OpenAndX message that ran earlier in this packet. In this case, the fid
1347 * field in a read, for example, request, isn't set, since the value is
1348 * supposed to be inherited from the openAndX call.
1350 int smb_ChainFID(int fid, smb_packet_t *inp)
1352 if (inp->fid == 0 || inp->inCount == 0)
1358 /* are we a priv'd user? What does this mean on NT? */
1359 int smb_SUser(cm_user_t *userp)
1364 /* find a file ID. If we pass in 0 we select an unused File ID.
1365 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1366 * smb_fid_t data structure if desired File ID cannot be found.
1368 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1373 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1376 lock_ObtainWrite(&smb_rctLock);
1377 /* figure out if we need to allocate a new file ID */
1380 fid = vcp->fidCounter;
1384 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1385 if (fidp->refCount == 0 && fidp->delete) {
1387 lock_ReleaseWrite(&smb_rctLock);
1388 smb_ReleaseFID(fidp);
1389 lock_ObtainWrite(&smb_rctLock);
1392 if (fid == fidp->fid) {
1395 if (fid == 0xFFFF) {
1397 "New FID number wraps on vcp 0x%x", vcp);
1407 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1408 char eventName[MAX_PATH];
1410 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1411 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1412 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1413 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1414 thrd_CloseHandle(event);
1416 if (fid == 0xFFFF) {
1417 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1423 fidp = malloc(sizeof(*fidp));
1424 memset(fidp, 0, sizeof(*fidp));
1425 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1428 smb_HoldVCNoLock(vcp);
1429 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1431 fidp->curr_chunk = fidp->prev_chunk = -2;
1432 fidp->raw_write_event = event;
1434 vcp->fidCounter = fid+1;
1435 if (vcp->fidCounter == 0xFFFF) {
1436 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1438 vcp->fidCounter = 1;
1443 lock_ReleaseWrite(&smb_rctLock);
1447 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1449 smb_fid_t *fidp = NULL;
1455 lock_ObtainWrite(&smb_rctLock);
1456 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1457 if (scp == fidp->scp) {
1462 lock_ReleaseWrite(&smb_rctLock);
1466 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1472 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1473 /* the sm_fid_t->mx and smb_rctLock must not be held */
1474 void smb_ReleaseFID(smb_fid_t *fidp)
1476 cm_scache_t *scp = NULL;
1477 cm_user_t *userp = NULL;
1478 smb_vc_t *vcp = NULL;
1479 smb_ioctl_t *ioctlp;
1481 lock_ObtainMutex(&fidp->mx);
1482 lock_ObtainWrite(&smb_rctLock);
1483 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1484 if (fidp->refCount == 0 && (fidp->delete)) {
1487 scp = fidp->scp; /* release after lock is released */
1489 lock_ObtainWrite(&scp->rw);
1490 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1491 lock_ReleaseWrite(&scp->rw);
1492 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1495 userp = fidp->userp;
1499 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1500 thrd_CloseHandle(fidp->raw_write_event);
1502 /* and see if there is ioctl stuff to free */
1503 ioctlp = fidp->ioctlp;
1506 cm_FreeSpace(ioctlp->prefix);
1507 if (ioctlp->inAllocp)
1508 free(ioctlp->inAllocp);
1509 if (ioctlp->outAllocp)
1510 free(ioctlp->outAllocp);
1513 lock_ReleaseMutex(&fidp->mx);
1514 lock_FinalizeMutex(&fidp->mx);
1518 smb_ReleaseVCNoLock(vcp);
1520 lock_ReleaseMutex(&fidp->mx);
1522 lock_ReleaseWrite(&smb_rctLock);
1524 /* now release the scache structure */
1526 cm_ReleaseSCache(scp);
1529 cm_ReleaseUser(userp);
1533 * Case-insensitive search for one string in another;
1534 * used to find variable names in submount pathnames.
1536 static char *smb_stristr(char *str1, char *str2)
1540 for (cursor = str1; *cursor; cursor++)
1541 if (stricmp(cursor, str2) == 0)
1548 * Substitute a variable value for its name in a submount pathname. Variable
1549 * name has been identified by smb_stristr() and is in substr. Variable name
1550 * length (plus one) is in substr_size. Variable value is in newstr.
1552 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1557 strcpy(temp, substr + substr_size - 1);
1558 strcpy(substr, newstr);
1562 char VNUserName[] = "%USERNAME%";
1563 char VNLCUserName[] = "%LCUSERNAME%";
1564 char VNComputerName[] = "%COMPUTERNAME%";
1565 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1568 typedef struct smb_findShare_rock {
1572 } smb_findShare_rock_t;
1574 #define SMB_FINDSHARE_EXACT_MATCH 1
1575 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1577 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1581 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1582 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1583 if(!stricmp(dep->name, vrock->shareName))
1584 matchType = SMB_FINDSHARE_EXACT_MATCH;
1586 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1587 if(vrock->match) free(vrock->match);
1588 vrock->match = strdup(dep->name);
1589 vrock->matchType = matchType;
1591 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1592 return CM_ERROR_STOPNOW;
1598 /* find a shareName in the table of submounts */
1599 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1603 char pathName[1024];
1610 DWORD allSubmount = 1;
1612 /* if allSubmounts == 0, only return the //mountRoot/all share
1613 * if in fact it has been been created in the subMounts table.
1614 * This is to allow sites that want to restrict access to the
1617 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1618 0, KEY_QUERY_VALUE, &parmKey);
1619 if (code == ERROR_SUCCESS) {
1620 len = sizeof(allSubmount);
1621 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1622 (BYTE *) &allSubmount, &len);
1623 if (code != ERROR_SUCCESS) {
1626 RegCloseKey (parmKey);
1629 if (allSubmount && _stricmp(shareName, "all") == 0) {
1634 /* In case, the all share is disabled we need to still be able
1635 * to handle ioctl requests
1637 if (_stricmp(shareName, "ioctl$") == 0) {
1638 *pathNamep = strdup("/.__ioctl__");
1642 if (_stricmp(shareName, "IPC$") == 0 ||
1643 _stricmp(shareName, "srvsvc") == 0 ||
1644 _stricmp(shareName, "wkssvc") == 0 ||
1645 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1646 _stricmp(shareName, "DESKTOP.INI") == 0
1652 /* Check for volume references
1654 * They look like <cell>{%,#}<volume>
1656 if (strchr(shareName, '%') != NULL ||
1657 strchr(shareName, '#') != NULL) {
1658 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1659 /* make room for '/@vol:' + mountchar + NULL terminator*/
1661 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1662 osi_LogSaveString(smb_logp, shareName));
1664 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1665 "/" CM_PREFIX_VOL "%s", shareName);
1666 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1667 len = (DWORD)(strlen(pathstr) + 1);
1669 *pathNamep = malloc(len);
1671 strcpy(*pathNamep, pathstr);
1673 osi_Log1(smb_logp, " returning pathname [%s]",
1674 osi_LogSaveString(smb_logp, *pathNamep));
1682 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1683 0, KEY_QUERY_VALUE, &parmKey);
1684 if (code == ERROR_SUCCESS) {
1685 len = sizeof(pathName);
1686 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1687 (BYTE *) pathName, &len);
1688 if (code != ERROR_SUCCESS)
1690 RegCloseKey (parmKey);
1694 if (len != 0 && len != sizeof(pathName) - 1) {
1695 /* We can accept either unix or PC style AFS pathnames. Convert
1696 * Unix-style to PC style here for internal use.
1699 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1700 p += strlen(cm_mountRoot); /* skip mount path */
1703 if (*q == '/') *q = '\\'; /* change to \ */
1709 if (var = smb_stristr(p, VNUserName)) {
1710 if (uidp && uidp->unp)
1711 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1713 smb_subst(p, var, sizeof(VNUserName)," ");
1715 else if (var = smb_stristr(p, VNLCUserName))
1717 if (uidp && uidp->unp)
1718 strcpy(temp, uidp->unp->name);
1722 smb_subst(p, var, sizeof(VNLCUserName), temp);
1724 else if (var = smb_stristr(p, VNComputerName))
1726 sizeTemp = sizeof(temp);
1727 GetComputerName((LPTSTR)temp, &sizeTemp);
1728 smb_subst(p, var, sizeof(VNComputerName), temp);
1730 else if (var = smb_stristr(p, VNLCComputerName))
1732 sizeTemp = sizeof(temp);
1733 GetComputerName((LPTSTR)temp, &sizeTemp);
1735 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1740 *pathNamep = strdup(p);
1745 /* First lookup shareName in root.afs */
1747 smb_findShare_rock_t vrock;
1749 char * p = shareName;
1752 /* attempt to locate a partial match in root.afs. This is because
1753 when using the ANSI RAP calls, the share name is limited to 13 chars
1754 and hence is truncated. Of course we prefer exact matches. */
1756 thyper.HighPart = 0;
1759 vrock.shareName = shareName;
1761 vrock.matchType = 0;
1763 cm_HoldSCache(cm_data.rootSCachep);
1764 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1765 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1766 cm_ReleaseSCache(cm_data.rootSCachep);
1768 if (vrock.matchType) {
1769 sprintf(pathName,"/%s/",vrock.match);
1770 *pathNamep = strdup(strlwr(pathName));
1775 /* if we get here, there was no match for the share in root.afs */
1776 /* so try to create \\<netbiosName>\<cellname> */
1781 /* Get the full name for this cell */
1782 code = cm_SearchCellFile(p, temp, 0, 0);
1783 #ifdef AFS_AFSDB_ENV
1784 if (code && cm_dnsEnabled) {
1786 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1789 /* construct the path */
1791 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1792 *pathNamep = strdup(strlwr(pathName));
1801 /* Client-side offline caching policy types */
1802 #define CSC_POLICY_MANUAL 0
1803 #define CSC_POLICY_DOCUMENTS 1
1804 #define CSC_POLICY_PROGRAMS 2
1805 #define CSC_POLICY_DISABLE 3
1807 int smb_FindShareCSCPolicy(char *shareName)
1813 int retval = CSC_POLICY_MANUAL;
1815 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1816 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1819 REG_OPTION_NON_VOLATILE,
1825 len = sizeof(policy);
1826 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1828 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1830 else if (stricmp(policy, "documents") == 0)
1832 retval = CSC_POLICY_DOCUMENTS;
1834 else if (stricmp(policy, "programs") == 0)
1836 retval = CSC_POLICY_PROGRAMS;
1838 else if (stricmp(policy, "disable") == 0)
1840 retval = CSC_POLICY_DISABLE;
1843 RegCloseKey(hkCSCPolicy);
1847 /* find a dir search structure by cookie value, and return it held.
1848 * Must be called with smb_globalLock held.
1850 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1852 smb_dirSearch_t *dsp;
1854 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1855 if (dsp->cookie == cookie) {
1856 if (dsp != smb_firstDirSearchp) {
1857 /* move to head of LRU queue, too, if we're not already there */
1858 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1859 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1860 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1861 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1862 if (!smb_lastDirSearchp)
1863 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1865 lock_ObtainMutex(&dsp->mx);
1867 lock_ReleaseMutex(&dsp->mx);
1873 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1874 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1875 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1881 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1883 lock_ObtainWrite(&smb_globalLock);
1884 lock_ObtainMutex(&dsp->mx);
1885 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1886 dsp->cookie, dsp, dsp->scp);
1887 dsp->flags |= SMB_DIRSEARCH_DELETE;
1888 if (dsp->scp != NULL) {
1889 lock_ObtainWrite(&dsp->scp->rw);
1890 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1891 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1892 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1893 dsp->scp->bulkStatProgress = hzero;
1895 lock_ReleaseWrite(&dsp->scp->rw);
1897 lock_ReleaseMutex(&dsp->mx);
1898 lock_ReleaseWrite(&smb_globalLock);
1901 /* Must be called with the smb_globalLock held */
1902 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1904 cm_scache_t *scp = NULL;
1906 lock_ObtainMutex(&dsp->mx);
1907 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1908 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1909 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1910 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1911 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1912 lock_ReleaseMutex(&dsp->mx);
1913 lock_FinalizeMutex(&dsp->mx);
1915 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1916 dsp->cookie, dsp, scp);
1919 lock_ReleaseMutex(&dsp->mx);
1921 /* do this now to avoid spurious locking hierarchy creation */
1923 cm_ReleaseSCache(scp);
1926 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1928 lock_ObtainWrite(&smb_globalLock);
1929 smb_ReleaseDirSearchNoLock(dsp);
1930 lock_ReleaseWrite(&smb_globalLock);
1933 /* find a dir search structure by cookie value, and return it held */
1934 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1936 smb_dirSearch_t *dsp;
1938 lock_ObtainWrite(&smb_globalLock);
1939 dsp = smb_FindDirSearchNoLock(cookie);
1940 lock_ReleaseWrite(&smb_globalLock);
1944 /* GC some dir search entries, in the address space expected by the specific protocol.
1945 * Must be called with smb_globalLock held; release the lock temporarily.
1947 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1948 void smb_GCDirSearches(int isV3)
1950 smb_dirSearch_t *prevp;
1951 smb_dirSearch_t *tp;
1952 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1956 victimCount = 0; /* how many have we got so far */
1957 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1958 /* we'll move tp from queue, so
1961 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1962 /* if no one is using this guy, and we're either in the new protocol,
1963 * or we're in the old one and this is a small enough ID to be useful
1964 * to the old protocol, GC this guy.
1966 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1967 /* hold and delete */
1968 lock_ObtainMutex(&tp->mx);
1969 tp->flags |= SMB_DIRSEARCH_DELETE;
1970 lock_ReleaseMutex(&tp->mx);
1971 victimsp[victimCount++] = tp;
1975 /* don't do more than this */
1976 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1980 /* now release them */
1981 for (i = 0; i < victimCount; i++) {
1982 smb_ReleaseDirSearchNoLock(victimsp[i]);
1986 /* function for allocating a dir search entry. We need these to remember enough context
1987 * since we don't get passed the path from call to call during a directory search.
1989 * Returns a held dir search structure, and bumps the reference count on the vnode,
1990 * since it saves a pointer to the vnode.
1992 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1994 smb_dirSearch_t *dsp;
2000 lock_ObtainWrite(&smb_globalLock);
2003 /* what's the biggest ID allowed in this version of the protocol */
2004 /* TODO: do we really want a non v3 dir search request to wrap
2005 smb_dirSearchCounter? */
2006 maxAllowed = isV3 ? 65535 : 255;
2007 if (smb_dirSearchCounter > maxAllowed)
2008 smb_dirSearchCounter = 1;
2010 start = smb_dirSearchCounter;
2013 /* twice so we have enough tries to find guys we GC after one pass;
2014 * 10 extra is just in case I mis-counted.
2016 if (++counter > 2*maxAllowed+10)
2017 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2019 if (smb_dirSearchCounter > maxAllowed) {
2020 smb_dirSearchCounter = 1;
2022 if (smb_dirSearchCounter == start) {
2024 smb_GCDirSearches(isV3);
2027 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2029 /* don't need to watch for refcount zero and deleted, since
2030 * we haven't dropped the global lock.
2032 lock_ObtainMutex(&dsp->mx);
2034 lock_ReleaseMutex(&dsp->mx);
2035 ++smb_dirSearchCounter;
2039 dsp = malloc(sizeof(*dsp));
2040 memset(dsp, 0, sizeof(*dsp));
2041 dsp->cookie = smb_dirSearchCounter;
2042 ++smb_dirSearchCounter;
2044 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2045 dsp->lastTime = osi_Time();
2046 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2047 if (!smb_lastDirSearchp)
2048 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2050 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2054 lock_ReleaseWrite(&smb_globalLock);
2058 static smb_packet_t *GetPacket(void)
2062 lock_ObtainWrite(&smb_globalLock);
2063 tbp = smb_packetFreeListp;
2065 smb_packetFreeListp = tbp->nextp;
2066 lock_ReleaseWrite(&smb_globalLock);
2068 tbp = calloc(65540,1);
2069 tbp->magic = SMB_PACKETMAGIC;
2072 tbp->resumeCode = 0;
2078 tbp->ncb_length = 0;
2083 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2088 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2092 memcpy(tbp, pkt, sizeof(smb_packet_t));
2093 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2095 smb_HoldVC(tbp->vcp);
2099 static NCB *GetNCB(void)
2104 lock_ObtainWrite(&smb_globalLock);
2105 tbp = smb_ncbFreeListp;
2107 smb_ncbFreeListp = tbp->nextp;
2108 lock_ReleaseWrite(&smb_globalLock);
2110 tbp = calloc(sizeof(*tbp),1);
2111 tbp->magic = SMB_NCBMAGIC;
2114 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2116 memset(&tbp->ncb, 0, sizeof(NCB));
2121 void smb_FreePacket(smb_packet_t *tbp)
2123 smb_vc_t * vcp = NULL;
2124 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2126 lock_ObtainWrite(&smb_globalLock);
2127 tbp->nextp = smb_packetFreeListp;
2128 smb_packetFreeListp = tbp;
2129 tbp->magic = SMB_PACKETMAGIC;
2133 tbp->resumeCode = 0;
2139 tbp->ncb_length = 0;
2141 lock_ReleaseWrite(&smb_globalLock);
2147 static void FreeNCB(NCB *bufferp)
2151 tbp = (smb_ncb_t *) bufferp;
2152 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2154 lock_ObtainWrite(&smb_globalLock);
2155 tbp->nextp = smb_ncbFreeListp;
2156 smb_ncbFreeListp = tbp;
2157 lock_ReleaseWrite(&smb_globalLock);
2160 /* get a ptr to the data part of a packet, and its count */
2161 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2165 unsigned char *afterParmsp;
2167 parmBytes = *smbp->wctp << 1;
2168 afterParmsp = smbp->wctp + parmBytes + 1;
2170 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2171 if (nbytesp) *nbytesp = dataBytes;
2173 /* don't forget to skip the data byte count, since it follows
2174 * the parameters; that's where the "2" comes from below.
2176 return (unsigned char *) (afterParmsp + 2);
2179 /* must set all the returned parameters before playing around with the
2180 * data region, since the data region is located past the end of the
2181 * variable number of parameters.
2183 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2185 unsigned char *afterParmsp;
2187 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2189 *afterParmsp++ = dsize & 0xff;
2190 *afterParmsp = (dsize>>8) & 0xff;
2193 /* return the parm'th parameter in the smbp packet */
2194 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2197 unsigned char *parmDatap;
2199 parmCount = *smbp->wctp;
2201 if (parm >= parmCount) {
2204 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2205 parm, parmCount, smbp->ncb_length);
2206 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2207 parm, parmCount, smbp->ncb_length);
2208 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2209 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2210 osi_panic(s, __FILE__, __LINE__);
2212 parmDatap = smbp->wctp + (2*parm) + 1;
2214 return parmDatap[0] + (parmDatap[1] << 8);
2217 /* return the parm'th parameter in the smbp packet */
2218 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2221 unsigned char *parmDatap;
2223 parmCount = *smbp->wctp;
2225 if (parm >= parmCount) {
2228 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2229 parm, parmCount, smbp->ncb_length);
2230 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2231 parm, parmCount, smbp->ncb_length);
2232 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2233 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2234 osi_panic(s, __FILE__, __LINE__);
2236 parmDatap = smbp->wctp + (2*parm) + 1;
2238 return parmDatap[0];
2241 /* return the parm'th parameter in the smbp packet */
2242 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2245 unsigned char *parmDatap;
2247 parmCount = *smbp->wctp;
2249 if (parm + 1 >= parmCount) {
2252 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2253 parm, parmCount, smbp->ncb_length);
2254 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2255 parm, parmCount, smbp->ncb_length);
2256 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2257 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2258 osi_panic(s, __FILE__, __LINE__);
2260 parmDatap = smbp->wctp + (2*parm) + 1;
2262 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2265 /* return the parm'th parameter in the smbp packet */
2266 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2269 unsigned char *parmDatap;
2271 parmCount = *smbp->wctp;
2273 if (parm * 2 + offset >= parmCount * 2) {
2276 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2277 parm, offset, parmCount, smbp->ncb_length);
2278 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2279 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2280 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2281 parm, offset, parmCount, smbp->ncb_length);
2282 osi_panic(s, __FILE__, __LINE__);
2284 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2286 return parmDatap[0] + (parmDatap[1] << 8);
2289 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2293 /* make sure we have enough slots */
2294 if (*smbp->wctp <= slot)
2295 *smbp->wctp = slot+1;
2297 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2298 *parmDatap++ = parmValue & 0xff;
2299 *parmDatap = (parmValue>>8) & 0xff;
2302 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2306 /* make sure we have enough slots */
2307 if (*smbp->wctp <= slot)
2308 *smbp->wctp = slot+2;
2310 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2311 *parmDatap++ = parmValue & 0xff;
2312 *parmDatap++ = (parmValue>>8) & 0xff;
2313 *parmDatap++ = (parmValue>>16) & 0xff;
2314 *parmDatap = (parmValue>>24) & 0xff;
2317 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2322 /* make sure we have enough slots */
2323 if (*smbp->wctp <= slot)
2324 *smbp->wctp = slot+4;
2326 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2328 *parmDatap++ = *parmValuep++;
2331 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2335 /* make sure we have enough slots */
2336 if (*smbp->wctp <= slot) {
2337 if (smbp->oddByte) {
2339 *smbp->wctp = slot+1;
2344 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2345 *parmDatap++ = parmValue & 0xff;
2348 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2352 lastSlashp = strrchr(inPathp, '\\');
2354 *lastComponentp = lastSlashp;
2357 if (inPathp == lastSlashp)
2359 *outPathp++ = *inPathp++;
2368 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2373 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2378 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2384 tlen = inp[0] + (inp[1]<<8);
2385 inp += 2; /* skip length field */
2388 *chainpp = inp + tlen;
2397 /* format a packet as a response */
2398 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2403 outp = (smb_t *) op;
2405 /* zero the basic structure through the smb_wct field, and zero the data
2406 * size field, assuming that wct stays zero; otherwise, you have to
2407 * explicitly set the data size field, too.
2409 inSmbp = (smb_t *) inp;
2410 memset(outp, 0, sizeof(smb_t)+2);
2416 outp->com = inSmbp->com;
2417 outp->tid = inSmbp->tid;
2418 outp->pid = inSmbp->pid;
2419 outp->uid = inSmbp->uid;
2420 outp->mid = inSmbp->mid;
2421 outp->res[0] = inSmbp->res[0];
2422 outp->res[1] = inSmbp->res[1];
2423 op->inCom = inSmbp->com;
2425 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2426 #ifdef SEND_CANONICAL_PATHNAMES
2427 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2429 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2431 /* copy fields in generic packet area */
2432 op->wctp = &outp->wct;
2435 /* send a (probably response) packet; vcp tells us to whom to send it.
2436 * we compute the length by looking at wct and bcc fields.
2438 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2452 memset((char *)ncbp, 0, sizeof(NCB));
2454 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2455 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2456 extra += tp[0] + (tp[1]<<8);
2457 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2458 extra += 3; /* wct and length fields */
2460 ncbp->ncb_length = extra; /* bytes to send */
2461 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2462 ncbp->ncb_lana_num = vcp->lana;
2463 ncbp->ncb_command = NCBSEND; /* op means send data */
2464 ncbp->ncb_buffer = (char *) inp;/* packet */
2465 code = Netbios(ncbp);
2468 const char * s = ncb_error_string(code);
2469 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2470 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2472 lock_ObtainMutex(&vcp->mx);
2473 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2474 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2476 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2477 lock_ReleaseMutex(&vcp->mx);
2478 lock_ObtainWrite(&smb_globalLock);
2479 dead_sessions[vcp->session] = TRUE;
2480 lock_ReleaseWrite(&smb_globalLock);
2481 smb_CleanupDeadVC(vcp);
2483 lock_ReleaseMutex(&vcp->mx);
2491 void smb_MapNTError(long code, unsigned long *NTStatusp)
2493 unsigned long NTStatus;
2495 /* map CM_ERROR_* errors to NT 32-bit status codes */
2496 /* NT Status codes are listed in ntstatus.h not winerror.h */
2497 if (code == CM_ERROR_NOSUCHCELL) {
2498 NTStatus = 0xC000000FL; /* No such file */
2500 else if (code == CM_ERROR_NOSUCHVOLUME) {
2501 NTStatus = 0xC000000FL; /* No such file */
2503 else if (code == CM_ERROR_TIMEDOUT) {
2505 NTStatus = 0xC00000CFL; /* Sharing Paused */
2507 NTStatus = 0x00000102L; /* Timeout */
2510 else if (code == CM_ERROR_RETRY) {
2511 NTStatus = 0xC000022DL; /* Retry */
2513 else if (code == CM_ERROR_NOACCESS) {
2514 NTStatus = 0xC0000022L; /* Access denied */
2516 else if (code == CM_ERROR_READONLY) {
2517 NTStatus = 0xC00000A2L; /* Write protected */
2519 else if (code == CM_ERROR_NOSUCHFILE ||
2520 code == CM_ERROR_BPLUS_NOMATCH) {
2521 NTStatus = 0xC000000FL; /* No such file */
2523 else if (code == CM_ERROR_NOSUCHPATH) {
2524 NTStatus = 0xC000003AL; /* Object path not found */
2526 else if (code == CM_ERROR_TOOBIG) {
2527 NTStatus = 0xC000007BL; /* Invalid image format */
2529 else if (code == CM_ERROR_INVAL) {
2530 NTStatus = 0xC000000DL; /* Invalid parameter */
2532 else if (code == CM_ERROR_BADFD) {
2533 NTStatus = 0xC0000008L; /* Invalid handle */
2535 else if (code == CM_ERROR_BADFDOP) {
2536 NTStatus = 0xC0000022L; /* Access denied */
2538 else if (code == CM_ERROR_EXISTS) {
2539 NTStatus = 0xC0000035L; /* Object name collision */
2541 else if (code == CM_ERROR_NOTEMPTY) {
2542 NTStatus = 0xC0000101L; /* Directory not empty */
2544 else if (code == CM_ERROR_CROSSDEVLINK) {
2545 NTStatus = 0xC00000D4L; /* Not same device */
2547 else if (code == CM_ERROR_NOTDIR) {
2548 NTStatus = 0xC0000103L; /* Not a directory */
2550 else if (code == CM_ERROR_ISDIR) {
2551 NTStatus = 0xC00000BAL; /* File is a directory */
2553 else if (code == CM_ERROR_BADOP) {
2555 /* I have no idea where this comes from */
2556 NTStatus = 0xC09820FFL; /* SMB no support */
2558 NTStatus = 0xC00000BBL; /* Not supported */
2559 #endif /* COMMENT */
2561 else if (code == CM_ERROR_BADSHARENAME) {
2562 NTStatus = 0xC00000CCL; /* Bad network name */
2564 else if (code == CM_ERROR_NOIPC) {
2566 NTStatus = 0xC0000022L; /* Access Denied */
2568 NTStatus = 0xC000013DL; /* Remote Resources */
2571 else if (code == CM_ERROR_CLOCKSKEW) {
2572 NTStatus = 0xC0000133L; /* Time difference at DC */
2574 else if (code == CM_ERROR_BADTID) {
2575 NTStatus = 0xC0982005L; /* SMB bad TID */
2577 else if (code == CM_ERROR_USESTD) {
2578 NTStatus = 0xC09820FBL; /* SMB use standard */
2580 else if (code == CM_ERROR_QUOTA) {
2581 NTStatus = 0xC0000044L; /* Quota exceeded */
2583 else if (code == CM_ERROR_SPACE) {
2584 NTStatus = 0xC000007FL; /* Disk full */
2586 else if (code == CM_ERROR_ATSYS) {
2587 NTStatus = 0xC0000033L; /* Object name invalid */
2589 else if (code == CM_ERROR_BADNTFILENAME) {
2590 NTStatus = 0xC0000033L; /* Object name invalid */
2592 else if (code == CM_ERROR_WOULDBLOCK) {
2593 NTStatus = 0xC0000055L; /* Lock not granted */
2595 else if (code == CM_ERROR_SHARING_VIOLATION) {
2596 NTStatus = 0xC0000043L; /* Sharing violation */
2598 else if (code == CM_ERROR_LOCK_CONFLICT) {
2599 NTStatus = 0xC0000054L; /* Lock conflict */
2601 else if (code == CM_ERROR_PARTIALWRITE) {
2602 NTStatus = 0xC000007FL; /* Disk full */
2604 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2605 NTStatus = 0xC0000023L; /* Buffer too small */
2607 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2608 NTStatus = 0xC0000035L; /* Object name collision */
2610 else if (code == CM_ERROR_BADPASSWORD) {
2611 NTStatus = 0xC000006DL; /* unknown username or bad password */
2613 else if (code == CM_ERROR_BADLOGONTYPE) {
2614 NTStatus = 0xC000015BL; /* logon type not granted */
2616 else if (code == CM_ERROR_GSSCONTINUE) {
2617 NTStatus = 0xC0000016L; /* more processing required */
2619 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2621 NTStatus = 0xC0000280L; /* reparse point not resolved */
2623 NTStatus = 0xC0000022L; /* Access Denied */
2626 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2627 NTStatus = 0xC0000257L; /* Path Not Covered */
2629 else if (code == CM_ERROR_ALLBUSY) {
2630 NTStatus = 0xC000022DL; /* Retry */
2632 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2633 NTStatus = 0xC00000BEL; /* Bad Network Path */
2635 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
2636 NTStatus = 0xC0000322L; /* No Kerberos key */
2638 else if (code == CM_ERROR_BAD_LEVEL) {
2639 NTStatus = 0xC0000148L; /* Invalid Level */
2641 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
2642 NTStatus = 0xC000007EL; /* Range Not Locked */
2644 else if (code == CM_ERROR_NOSUCHDEVICE) {
2645 NTStatus = 0xC000000EL; /* No Such Device */
2647 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
2648 NTStatus = 0xC0000055L; /* Lock Not Granted */
2650 NTStatus = 0xC0982001L; /* SMB non-specific error */
2653 *NTStatusp = NTStatus;
2654 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2657 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2658 unsigned char *classp)
2660 unsigned char class;
2661 unsigned short error;
2663 /* map CM_ERROR_* errors to SMB errors */
2664 if (code == CM_ERROR_NOSUCHCELL) {
2666 error = 3; /* bad path */
2668 else if (code == CM_ERROR_NOSUCHVOLUME) {
2670 error = 3; /* bad path */
2672 else if (code == CM_ERROR_TIMEDOUT) {
2674 error = 81; /* server is paused */
2676 else if (code == CM_ERROR_RETRY) {
2677 class = 2; /* shouldn't happen */
2680 else if (code == CM_ERROR_NOACCESS) {
2682 error = 4; /* bad access */
2684 else if (code == CM_ERROR_READONLY) {
2686 error = 19; /* read only */
2688 else if (code == CM_ERROR_NOSUCHFILE ||
2689 code == CM_ERROR_BPLUS_NOMATCH) {
2691 error = 2; /* ENOENT! */
2693 else if (code == CM_ERROR_NOSUCHPATH) {
2695 error = 3; /* Bad path */
2697 else if (code == CM_ERROR_TOOBIG) {
2699 error = 11; /* bad format */
2701 else if (code == CM_ERROR_INVAL) {
2702 class = 2; /* server non-specific error code */
2705 else if (code == CM_ERROR_BADFD) {
2707 error = 6; /* invalid file handle */
2709 else if (code == CM_ERROR_BADFDOP) {
2710 class = 1; /* invalid op on FD */
2713 else if (code == CM_ERROR_EXISTS) {
2715 error = 80; /* file already exists */
2717 else if (code == CM_ERROR_NOTEMPTY) {
2719 error = 5; /* delete directory not empty */
2721 else if (code == CM_ERROR_CROSSDEVLINK) {
2723 error = 17; /* EXDEV */
2725 else if (code == CM_ERROR_NOTDIR) {
2726 class = 1; /* bad path */
2729 else if (code == CM_ERROR_ISDIR) {
2730 class = 1; /* access denied; DOS doesn't have a good match */
2733 else if (code == CM_ERROR_BADOP) {
2737 else if (code == CM_ERROR_BADSHARENAME) {
2741 else if (code == CM_ERROR_NOIPC) {
2743 error = 4; /* bad access */
2745 else if (code == CM_ERROR_CLOCKSKEW) {
2746 class = 1; /* invalid function */
2749 else if (code == CM_ERROR_BADTID) {
2753 else if (code == CM_ERROR_USESTD) {
2757 else if (code == CM_ERROR_REMOTECONN) {
2761 else if (code == CM_ERROR_QUOTA) {
2762 if (vcp->flags & SMB_VCFLAG_USEV3) {
2764 error = 39; /* disk full */
2768 error = 5; /* access denied */
2771 else if (code == CM_ERROR_SPACE) {
2772 if (vcp->flags & SMB_VCFLAG_USEV3) {
2774 error = 39; /* disk full */
2778 error = 5; /* access denied */
2781 else if (code == CM_ERROR_PARTIALWRITE) {
2783 error = 39; /* disk full */
2785 else if (code == CM_ERROR_ATSYS) {
2787 error = 2; /* ENOENT */
2789 else if (code == CM_ERROR_WOULDBLOCK) {
2791 error = 33; /* lock conflict */
2793 else if (code == CM_ERROR_LOCK_CONFLICT) {
2795 error = 33; /* lock conflict */
2797 else if (code == CM_ERROR_SHARING_VIOLATION) {
2799 error = 33; /* lock conflict */
2801 else if (code == CM_ERROR_NOFILES) {
2803 error = 18; /* no files in search */
2805 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2807 error = 183; /* Samba uses this */
2809 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2810 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2812 error = 2; /* bad password */
2814 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2816 error = 3; /* bad path */
2825 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2828 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2830 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2831 return CM_ERROR_BADOP;
2834 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2836 unsigned short EchoCount, i;
2837 char *data, *outdata;
2840 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2842 for (i=1; i<=EchoCount; i++) {
2843 data = smb_GetSMBData(inp, &dataSize);
2844 smb_SetSMBParm(outp, 0, i);
2845 smb_SetSMBDataLength(outp, dataSize);
2846 outdata = smb_GetSMBData(outp, NULL);
2847 memcpy(outdata, data, dataSize);
2848 smb_SendPacket(vcp, outp);
2854 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2857 long count, minCount, finalCount;
2861 smb_t *smbp = (smb_t*) inp;
2863 cm_user_t *userp = NULL;
2866 char *rawBuf = NULL;
2871 fd = smb_GetSMBParm(inp, 0);
2872 count = smb_GetSMBParm(inp, 3);
2873 minCount = smb_GetSMBParm(inp, 4);
2874 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2876 if (*inp->wctp == 10) {
2877 /* we were sent a request with 64-bit file offsets */
2878 #ifdef AFS_LARGEFILES
2879 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2881 if (LargeIntegerLessThanZero(offset)) {
2882 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2886 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2887 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2890 offset.HighPart = 0;
2894 /* we were sent a request with 32-bit file offsets */
2895 offset.HighPart = 0;
2898 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2899 fd, offset.HighPart, offset.LowPart, count);
2901 fidp = smb_FindFID(vcp, fd, 0);
2905 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2906 smb_CloseFID(vcp, fidp, NULL, 0);
2907 code = CM_ERROR_NOSUCHFILE;
2914 LARGE_INTEGER LOffset, LLength;
2917 key = cm_GenerateKey(vcp->vcID, pid, fd);
2919 LOffset.HighPart = offset.HighPart;
2920 LOffset.LowPart = offset.LowPart;
2921 LLength.HighPart = 0;
2922 LLength.LowPart = count;
2924 lock_ObtainWrite(&fidp->scp->rw);
2925 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2926 lock_ReleaseWrite(&fidp->scp->rw);
2932 lock_ObtainMutex(&smb_RawBufLock);
2934 /* Get a raw buf, from head of list */
2935 rawBuf = smb_RawBufs;
2936 smb_RawBufs = *(char **)smb_RawBufs;
2938 lock_ReleaseMutex(&smb_RawBufLock);
2942 lock_ObtainMutex(&fidp->mx);
2943 if (fidp->flags & SMB_FID_IOCTL)
2945 lock_ReleaseMutex(&fidp->mx);
2946 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2948 /* Give back raw buffer */
2949 lock_ObtainMutex(&smb_RawBufLock);
2950 *((char **) rawBuf) = smb_RawBufs;
2952 smb_RawBufs = rawBuf;
2953 lock_ReleaseMutex(&smb_RawBufLock);
2956 lock_ReleaseMutex(&fidp->mx);
2957 smb_ReleaseFID(fidp);
2960 lock_ReleaseMutex(&fidp->mx);
2962 userp = smb_GetUserFromVCP(vcp, inp);
2964 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2970 cm_ReleaseUser(userp);
2973 smb_ReleaseFID(fidp);
2977 memset((char *)ncbp, 0, sizeof(NCB));
2979 ncbp->ncb_length = (unsigned short) finalCount;
2980 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2981 ncbp->ncb_lana_num = vcp->lana;
2982 ncbp->ncb_command = NCBSEND;
2983 ncbp->ncb_buffer = rawBuf;
2985 code = Netbios(ncbp);
2987 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2990 /* Give back raw buffer */
2991 lock_ObtainMutex(&smb_RawBufLock);
2992 *((char **) rawBuf) = smb_RawBufs;
2994 smb_RawBufs = rawBuf;
2995 lock_ReleaseMutex(&smb_RawBufLock);
3001 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3003 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3008 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3010 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3015 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3022 int VistaProtoIndex;
3023 int protoIndex; /* index we're using */
3028 char protocol_array[10][1024]; /* protocol signature of the client */
3029 int caps; /* capabilities */
3032 TIME_ZONE_INFORMATION tzi;
3034 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3037 namep = smb_GetSMBData(inp, &dbytes);
3040 coreProtoIndex = -1; /* not found */
3043 VistaProtoIndex = -1;
3044 while(namex < dbytes) {
3045 osi_Log1(smb_logp, "Protocol %s",
3046 osi_LogSaveString(smb_logp, namep+1));
3047 strcpy(protocol_array[tcounter], namep+1);
3049 /* namep points at the first protocol, or really, a 0x02
3050 * byte preceding the null-terminated ASCII name.
3052 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3053 coreProtoIndex = tcounter;
3055 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3056 v3ProtoIndex = tcounter;
3058 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3059 NTProtoIndex = tcounter;
3061 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3062 VistaProtoIndex = tcounter;
3065 /* compute size of protocol entry */
3066 entryLength = (int)strlen(namep+1);
3067 entryLength += 2; /* 0x02 bytes and null termination */
3069 /* advance over this protocol entry */
3070 namex += entryLength;
3071 namep += entryLength;
3072 tcounter++; /* which proto entry we're looking at */
3075 lock_ObtainMutex(&vcp->mx);
3077 if (VistaProtoIndex != -1) {
3078 protoIndex = VistaProtoIndex;
3079 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3082 if (NTProtoIndex != -1) {
3083 protoIndex = NTProtoIndex;
3084 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3086 else if (v3ProtoIndex != -1) {
3087 protoIndex = v3ProtoIndex;
3088 vcp->flags |= SMB_VCFLAG_USEV3;
3090 else if (coreProtoIndex != -1) {
3091 protoIndex = coreProtoIndex;
3092 vcp->flags |= SMB_VCFLAG_USECORE;
3094 else protoIndex = -1;
3095 lock_ReleaseMutex(&vcp->mx);
3097 if (protoIndex == -1)
3098 return CM_ERROR_INVAL;
3099 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3100 smb_SetSMBParm(outp, 0, protoIndex);
3101 if (smb_authType != SMB_AUTH_NONE) {
3102 smb_SetSMBParmByte(outp, 1,
3103 NEGOTIATE_SECURITY_USER_LEVEL |
3104 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3106 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3108 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3109 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3110 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3111 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3112 /* The session key is not a well documented field however most clients
3113 * will echo back the session key to the server. Currently we are using
3114 * the same value for all sessions. We should generate a random value
3115 * and store it into the vcp
3117 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3118 smb_SetSMBParm(outp, 8, 1);
3120 * Tried changing the capabilities to support for W2K - defect 117695
3121 * Maybe something else needs to be changed here?
3125 smb_SetSMBParmLong(outp, 9, 0x43fd);
3127 smb_SetSMBParmLong(outp, 9, 0x251);
3130 * 32-bit error codes *
3135 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3137 NTNEGOTIATE_CAPABILITY_DFS |
3139 #ifdef AFS_LARGEFILES
3140 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3142 NTNEGOTIATE_CAPABILITY_NTFIND |
3143 NTNEGOTIATE_CAPABILITY_RAWMODE |
3144 NTNEGOTIATE_CAPABILITY_NTSMB;
3146 if ( smb_authType == SMB_AUTH_EXTENDED )
3147 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3149 smb_SetSMBParmLong(outp, 9, caps);
3151 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3152 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3153 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3155 GetTimeZoneInformation(&tzi);
3156 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3158 if (smb_authType == SMB_AUTH_NTLM) {
3159 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3160 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3161 /* paste in encryption key */
3162 datap = smb_GetSMBData(outp, NULL);
3163 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3164 /* and the faux domain name */
3165 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3166 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3170 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3172 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3174 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3176 datap = smb_GetSMBData(outp, NULL);
3177 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3180 datap += sizeof(smb_ServerGUID);
3181 memcpy(datap, secBlob, secBlobLength);
3185 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3186 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3189 else if (v3ProtoIndex != -1) {
3190 smb_SetSMBParm(outp, 0, protoIndex);
3192 /* NOTE: Extended authentication cannot be negotiated with v3
3193 * therefore we fail over to NTLM
3195 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3196 smb_SetSMBParm(outp, 1,
3197 NEGOTIATE_SECURITY_USER_LEVEL |
3198 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3200 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3202 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3203 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3204 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3205 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3206 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3207 smb_SetSMBParm(outp, 7, 1);
3209 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3210 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3211 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3213 GetTimeZoneInformation(&tzi);
3214 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3216 /* NOTE: Extended authentication cannot be negotiated with v3
3217 * therefore we fail over to NTLM
3219 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3220 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3221 smb_SetSMBParm(outp, 12, 0); /* resvd */
3222 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3223 datap = smb_GetSMBData(outp, NULL);
3224 /* paste in a new encryption key */
3225 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3226 /* and the faux domain name */
3227 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3229 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3230 smb_SetSMBParm(outp, 12, 0); /* resvd */
3231 smb_SetSMBDataLength(outp, 0);
3234 else if (coreProtoIndex != -1) { /* not really supported anymore */
3235 smb_SetSMBParm(outp, 0, protoIndex);
3236 smb_SetSMBDataLength(outp, 0);
3241 void smb_CheckVCs(void)
3243 smb_vc_t * vcp, *nextp;
3244 smb_packet_t * outp = GetPacket();
3247 lock_ObtainWrite(&smb_rctLock);
3248 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3250 if (vcp->magic != SMB_VC_MAGIC)
3251 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3252 __FILE__, __LINE__);
3256 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3259 smb_HoldVCNoLock(vcp);
3261 smb_HoldVCNoLock(nextp);
3262 smb_FormatResponsePacket(vcp, NULL, outp);
3263 smbp = (smb_t *)outp;
3264 outp->inCom = smbp->com = 0x2b /* Echo */;
3272 smb_SetSMBParm(outp, 0, 0);
3273 smb_SetSMBDataLength(outp, 0);
3274 lock_ReleaseWrite(&smb_rctLock);
3276 smb_SendPacket(vcp, outp);
3278 lock_ObtainWrite(&smb_rctLock);
3279 smb_ReleaseVCNoLock(vcp);
3281 smb_ReleaseVCNoLock(nextp);
3283 lock_ReleaseWrite(&smb_rctLock);
3284 smb_FreePacket(outp);
3287 void smb_Daemon(void *parmp)
3289 afs_uint32 count = 0;
3290 smb_username_t **unpp;
3293 while(smbShutdownFlag == 0) {
3297 if (smbShutdownFlag == 1)
3300 if ((count % 72) == 0) { /* every five minutes */
3302 time_t old_localZero = smb_localZero;
3304 /* Initialize smb_localZero */
3305 myTime.tm_isdst = -1; /* compute whether on DST or not */
3306 myTime.tm_year = 70;
3312 smb_localZero = mktime(&myTime);
3314 #ifndef USE_NUMERIC_TIME_CONV
3315 smb_CalculateNowTZ();
3316 #endif /* USE_NUMERIC_TIME_CONV */
3317 #ifdef AFS_FREELANCE
3318 if ( smb_localZero != old_localZero )
3319 cm_noteLocalMountPointChange();
3325 /* GC smb_username_t objects that will no longer be used */
3327 lock_ObtainWrite(&smb_rctLock);
3328 for ( unpp=&usernamesp; *unpp; ) {
3330 smb_username_t *unp;
3332 lock_ObtainMutex(&(*unpp)->mx);
3333 if ( (*unpp)->refCount > 0 ||
3334 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3335 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3337 else if (!smb_LogoffTokenTransfer ||
3338 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3340 lock_ReleaseMutex(&(*unpp)->mx);
3348 lock_FinalizeMutex(&unp->mx);
3354 cm_ReleaseUser(userp);
3356 unpp = &(*unpp)->nextp;
3359 lock_ReleaseWrite(&smb_rctLock);
3361 /* XXX GC dir search entries */
3365 void smb_WaitingLocksDaemon()
3367 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3368 smb_waitingLock_t *wl, *wlNext;
3371 smb_packet_t *inp, *outp;
3375 while (smbShutdownFlag == 0) {
3376 lock_ObtainWrite(&smb_globalLock);
3377 nwlRequest = smb_allWaitingLocks;
3378 if (nwlRequest == NULL) {
3379 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3384 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3391 lock_ObtainWrite(&smb_globalLock);
3393 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3395 wlRequest = nwlRequest;
3396 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3397 lock_ReleaseWrite(&smb_globalLock);
3401 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3402 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3405 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3406 code = CM_ERROR_LOCK_NOT_GRANTED;
3410 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3412 /* wl->state is either _DONE or _WAITING. _ERROR
3413 would no longer be on the queue. */
3414 code = cm_RetryLock( wl->lockp,
3415 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3418 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3419 } else if (code != CM_ERROR_WOULDBLOCK) {
3420 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3425 if (code == CM_ERROR_WOULDBLOCK) {
3428 if (wlRequest->msTimeout != 0xffffffff
3429 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3441 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3444 scp = wlRequest->scp;
3445 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3449 lock_ObtainWrite(&scp->rw);
3451 for (wl = wlRequest->locks; wl; wl = wlNext) {
3452 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3454 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3455 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3456 wl->LLength, wl->key, NULL, &req);
3458 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3463 lock_ReleaseWrite(&scp->rw);
3467 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3470 for (wl = wlRequest->locks; wl; wl = wlNext) {
3471 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3472 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3477 vcp = wlRequest->vcp;
3478 inp = wlRequest->inp;
3479 outp = wlRequest->outp;
3481 ncbp->ncb_length = inp->ncb_length;
3482 inp->spacep = cm_GetSpace();
3484 /* Remove waitingLock from list */
3485 lock_ObtainWrite(&smb_globalLock);
3486 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3488 lock_ReleaseWrite(&smb_globalLock);
3490 /* Resume packet processing */
3492 smb_SetSMBDataLength(outp, 0);
3493 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3494 outp->resumeCode = code;
3496 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3499 cm_FreeSpace(inp->spacep);
3500 smb_FreePacket(inp);
3501 smb_FreePacket(outp);
3503 cm_ReleaseSCache(wlRequest->scp);
3506 } while (nwlRequest && smbShutdownFlag == 0);
3511 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3513 osi_Log0(smb_logp, "SMB receive get disk attributes");
3515 smb_SetSMBParm(outp, 0, 32000);
3516 smb_SetSMBParm(outp, 1, 64);
3517 smb_SetSMBParm(outp, 2, 1024);
3518 smb_SetSMBParm(outp, 3, 30000);
3519 smb_SetSMBParm(outp, 4, 0);
3520 smb_SetSMBDataLength(outp, 0);
3524 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3528 unsigned short newTid;
3529 char shareName[AFSPATHMAX];
3537 osi_Log0(smb_logp, "SMB receive tree connect");
3539 /* parse input parameters */
3540 tp = smb_GetSMBData(inp, NULL);
3541 pathp = smb_ParseASCIIBlock(tp, &tp);
3542 if (smb_StoreAnsiFilenames)
3543 OemToChar(pathp,pathp);
3544 passwordp = smb_ParseASCIIBlock(tp, &tp);
3545 tp = strrchr(pathp, '\\');
3547 return CM_ERROR_BADSMB;
3548 strcpy(shareName, tp+1);
3550 lock_ObtainMutex(&vcp->mx);
3551 newTid = vcp->tidCounter++;
3552 lock_ReleaseMutex(&vcp->mx);
3554 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3555 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3556 userp = smb_GetUserFromUID(uidp);
3557 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3559 smb_ReleaseUID(uidp);
3561 smb_ReleaseTID(tidp, FALSE);
3562 return CM_ERROR_BADSHARENAME;
3564 lock_ObtainMutex(&tidp->mx);
3565 tidp->userp = userp;
3566 tidp->pathname = sharePath;
3567 lock_ReleaseMutex(&tidp->mx);
3568 smb_ReleaseTID(tidp, FALSE);
3570 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3571 smb_SetSMBParm(rsp, 1, newTid);
3572 smb_SetSMBDataLength(rsp, 0);
3574 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3578 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3582 if (*inp++ != 0x1) return NULL;
3583 tlen = inp[0] + (inp[1]<<8);
3584 inp += 2; /* skip length field */
3587 *chainpp = inp + tlen;
3590 if (lengthp) *lengthp = tlen;
3595 /* set maskp to the mask part of the incoming path.
3596 * Mask is 11 bytes long (8.3 with the dot elided).
3597 * Returns true if succeeds with a valid name, otherwise it does
3598 * its best, but returns false.
3600 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3608 /* starts off valid */
3611 /* mask starts out all blanks */
3612 memset(maskp, ' ', 11);
3615 /* find last backslash, or use whole thing if there is none */
3616 tp = strrchr(pathp, '\\');
3620 tp++; /* skip slash */
3624 /* names starting with a dot are illegal */
3632 if (tc == '.' || tc == '"')
3640 /* if we get here, tp point after the dot */
3641 up = maskp+8; /* ext goes here */
3648 if (tc == '.' || tc == '"')
3651 /* copy extension if not too long */
3661 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3671 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3673 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3677 /* otherwise, we have a valid 8.3 name; see if we have a match,
3678 * treating '?' as a wildcard in maskp (but not in the file name).
3680 tp1 = umask; /* real name, in mask format */
3681 tp2 = maskp; /* mask, in mask format */
3682 for(i=0; i<11; i++) {
3683 tc1 = *tp1++; /* char from real name */
3684 tc2 = *tp2++; /* char from mask */
3685 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3686 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3689 if (tc2 == '?' && tc1 != ' ')
3696 /* we got a match */
3700 char *smb_FindMask(char *pathp)
3704 tp = strrchr(pathp, '\\'); /* find last slash */
3707 return tp+1; /* skip the slash */
3709 return pathp; /* no slash, return the entire path */
3712 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3714 unsigned char *pathp;
3716 unsigned char mask[12];
3717 unsigned char *statBlockp;
3718 unsigned char initStatBlock[21];
3721 osi_Log0(smb_logp, "SMB receive search volume");
3723 /* pull pathname and stat block out of request */
3724 tp = smb_GetSMBData(inp, NULL);
3725 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3726 osi_assertx(pathp != NULL, "null path");
3727 if (smb_StoreAnsiFilenames)
3728 OemToChar(pathp,pathp);
3729 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3730 osi_assertx(statBlockp != NULL, "null statBlock");
3732 statBlockp = initStatBlock;
3736 /* for returning to caller */
3737 smb_Get8Dot3MaskFromPath(mask, pathp);
3739 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3740 tp = smb_GetSMBData(outp, NULL);
3742 *tp++ = 43; /* bytes in a dir entry */
3743 *tp++ = 0; /* high byte in counter */
3745 /* now marshall the dir entry, starting with the search status */
3746 *tp++ = statBlockp[0]; /* Reserved */
3747 memcpy(tp, mask, 11); tp += 11; /* FileName */
3749 /* now pass back server use info, with 1st byte non-zero */
3751 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3753 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3755 *tp++ = 0x8; /* attribute: volume */
3765 /* 4 byte file size */
3771 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3772 memset(tp, ' ', 13);
3775 /* set the length of the data part of the packet to 43 + 3, for the dir
3776 * entry plus the 5 and the length fields.
3778 smb_SetSMBDataLength(outp, 46);
3783 smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3784 char * tidPathp, char * relPathp,
3785 cm_user_t *userp, cm_req_t *reqp)
3793 smb_dirListPatch_t *patchp;
3794 smb_dirListPatch_t *npatchp;
3795 char path[AFSPATHMAX];
3797 for (patchp = *dirPatchespp; patchp; patchp =
3798 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3800 dptr = patchp->dptr;
3802 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
3803 reqp->relPathp = path;
3804 reqp->tidPathp = tidPathp;
3806 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3807 reqp->relPathp = reqp->tidPathp = NULL;
3810 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3811 *dptr++ = SMB_ATTR_HIDDEN;
3814 lock_ObtainWrite(&scp->rw);
3815 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3816 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3818 lock_ReleaseWrite(&scp->rw);
3819 cm_ReleaseSCache(scp);
3820 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3821 *dptr++ = SMB_ATTR_HIDDEN;
3825 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3827 lock_ConvertWToR(&scp->rw);
3828 attr = smb_Attributes(scp);
3829 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3830 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3831 attr |= SMB_ATTR_HIDDEN;
3835 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3838 shortTemp = (unsigned short) (dosTime & 0xffff);
3839 *((u_short *)dptr) = shortTemp;
3842 /* and copy out date */
3843 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3844 *((u_short *)dptr) = shortTemp;
3847 /* copy out file length */
3848 *((u_long *)dptr) = scp->length.LowPart;
3850 lock_ReleaseRead(&scp->rw);
3851 cm_ReleaseSCache(scp);
3854 /* now free the patches */
3855 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3856 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3860 /* and mark the list as empty */
3861 *dirPatchespp = NULL;
3866 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3873 cm_dirEntry_t *dep = 0;
3875 smb_dirListPatch_t *dirListPatchesp;
3876 smb_dirListPatch_t *curPatchp;
3880 osi_hyper_t dirLength;
3881 osi_hyper_t bufferOffset;
3882 osi_hyper_t curOffset;
3884 unsigned char *inCookiep;
3885 smb_dirSearch_t *dsp;
3889 unsigned long clientCookie;
3890 cm_pageHeader_t *pageHeaderp;
3891 cm_user_t *userp = NULL;
3898 long nextEntryCookie;
3899 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3900 char resByte; /* reserved byte from the cookie */
3901 char *op; /* output data ptr */
3902 char *origOp; /* original value of op */
3903 cm_space_t *spacep; /* for pathname buffer */
3914 maxCount = smb_GetSMBParm(inp, 0);
3916 dirListPatchesp = NULL;
3918 caseFold = CM_FLAG_CASEFOLD;
3920 tp = smb_GetSMBData(inp, NULL);
3921 pathp = smb_ParseASCIIBlock(tp, &tp);
3922 if (smb_StoreAnsiFilenames)
3923 OemToChar(pathp,pathp);
3924 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3926 /* bail out if request looks bad */
3927 if (!tp || !pathp) {
3928 return CM_ERROR_BADSMB;
3931 /* We can handle long names */
3932 if (vcp->flags & SMB_VCFLAG_USENT)
3933 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3935 /* make sure we got a whole search status */
3936 if (dataLength < 21) {
3937 nextCookie = 0; /* start at the beginning of the dir */
3940 attribute = smb_GetSMBParm(inp, 1);
3942 /* handle volume info in another function */
3943 if (attribute & 0x8)
3944 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3946 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3947 maxCount, osi_LogSaveString(smb_logp, pathp));
3949 if (*pathp == 0) { /* null pathp, treat as root dir */
3950 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3951 return CM_ERROR_NOFILES;
3955 dsp = smb_NewDirSearch(0);
3956 dsp->attribute = attribute;
3957 smb_Get8Dot3MaskFromPath(mask, pathp);
3958 memcpy(dsp->mask, mask, 12);
3960 /* track if this is likely to match a lot of entries */
3961 if (smb_IsStarMask(mask))
3966 /* pull the next cookie value out of the search status block */
3967 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3968 + (inCookiep[16]<<24);
3969 dsp = smb_FindDirSearch(inCookiep[12]);
3971 /* can't find dir search status; fatal error */
3972 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3973 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3974 return CM_ERROR_BADFD;
3976 attribute = dsp->attribute;
3977 resByte = inCookiep[0];
3979 /* copy out client cookie, in host byte order. Don't bother
3980 * interpreting it, since we're just passing it through, anyway.
3982 memcpy(&clientCookie, &inCookiep[17], 4);
3984 memcpy(mask, dsp->mask, 12);
3986 /* assume we're doing a star match if it has continued for more
3992 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3993 nextCookie, dsp->cookie, attribute);
3995 userp = smb_GetUserFromVCP(vcp, inp);
3997 /* try to get the vnode for the path name next */
3998 lock_ObtainMutex(&dsp->mx);
4001 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4005 spacep = inp->spacep;
4006 smb_StripLastComponent(spacep->data, NULL, pathp);
4007 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4009 lock_ReleaseMutex(&dsp->mx);
4010 cm_ReleaseUser(userp);
4011 smb_DeleteDirSearch(dsp);
4012 smb_ReleaseDirSearch(dsp);
4013 return CM_ERROR_NOFILES;
4015 strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
4016 strcpy(dsp->relPath, spacep->data);
4018 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4019 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4022 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4023 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4024 cm_ReleaseSCache(scp);
4025 lock_ReleaseMutex(&dsp->mx);
4026 cm_ReleaseUser(userp);
4027 smb_DeleteDirSearch(dsp);
4028 smb_ReleaseDirSearch(dsp);
4029 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4030 return CM_ERROR_PATH_NOT_COVERED;
4032 return CM_ERROR_BADSHARENAME;
4034 #endif /* DFS_SUPPORT */
4037 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4038 /* we need one hold for the entry we just stored into,
4039 * and one for our own processing. When we're done with this
4040 * function, we'll drop the one for our own processing.
4041 * We held it once from the namei call, and so we do another hold
4045 lock_ObtainWrite(&scp->rw);
4046 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4047 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4048 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4049 dsp->flags |= SMB_DIRSEARCH_BULKST;
4050 dsp->scp->bulkStatProgress = hzero;
4052 lock_ReleaseWrite(&scp->rw);
4055 lock_ReleaseMutex(&dsp->mx);
4057 cm_ReleaseUser(userp);
4058 smb_DeleteDirSearch(dsp);
4059 smb_ReleaseDirSearch(dsp);
4063 /* reserves space for parameter; we'll adjust it again later to the
4064 * real count of the # of entries we returned once we've actually
4065 * assembled the directory listing.
4067 smb_SetSMBParm(outp, 0, 0);
4069 /* get the directory size */
4070 lock_ObtainWrite(&scp->rw);
4071 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4072 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4074 lock_ReleaseWrite(&scp->rw);
4075 cm_ReleaseSCache(scp);
4076 cm_ReleaseUser(userp);
4077 smb_DeleteDirSearch(dsp);
4078 smb_ReleaseDirSearch(dsp);
4082 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4084 dirLength = scp->length;
4086 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4087 curOffset.HighPart = 0;
4088 curOffset.LowPart = nextCookie;
4089 origOp = op = smb_GetSMBData(outp, NULL);
4090 /* and write out the basic header */
4091 *op++ = 5; /* variable block */
4092 op += 2; /* skip vbl block length; we'll fill it in later */
4096 /* make sure that curOffset.LowPart doesn't point to the first
4097 * 32 bytes in the 2nd through last dir page, and that it doesn't
4098 * point at the first 13 32-byte chunks in the first dir page,
4099 * since those are dir and page headers, and don't contain useful
4102 temp = curOffset.LowPart & (2048-1);
4103 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4104 /* we're in the first page */
4105 if (temp < 13*32) temp = 13*32;
4108 /* we're in a later dir page */
4109 if (temp < 32) temp = 32;
4112 /* make sure the low order 5 bits are zero */
4115 /* now put temp bits back ito curOffset.LowPart */
4116 curOffset.LowPart &= ~(2048-1);
4117 curOffset.LowPart |= temp;
4119 /* check if we've returned all the names that will fit in the
4122 if (returnedNames >= maxCount) {
4123 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4124 returnedNames, maxCount);
4128 /* check if we've passed the dir's EOF */
4129 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4131 /* see if we can use the bufferp we have now; compute in which page
4132 * the current offset would be, and check whether that's the offset
4133 * of the buffer we have. If not, get the buffer.
4135 thyper.HighPart = curOffset.HighPart;
4136 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4137 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4140 buf_Release(bufferp);
4143 lock_ReleaseWrite(&scp->rw);
4144 code = buf_Get(scp, &thyper, &bufferp);
4145 lock_ObtainMutex(&dsp->mx);
4147 /* now, if we're doing a star match, do bulk fetching of all of
4148 * the status info for files in the dir.
4151 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4152 lock_ObtainWrite(&scp->rw);
4153 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4154 LargeIntegerGreaterThanOrEqualTo(thyper,
4155 scp->bulkStatProgress)) {
4156 /* Don't bulk stat if risking timeout */
4157 int now = GetTickCount();
4158 if (now - req.startTime > RDRtimeout * 1000) {
4159 scp->bulkStatProgress = thyper;
4160 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4161 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4162 dsp->scp->bulkStatProgress = hzero;
4164 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4167 lock_ObtainWrite(&scp->rw);
4169 lock_ReleaseMutex(&dsp->mx);
4171 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4175 bufferOffset = thyper;
4177 /* now get the data in the cache */
4179 code = cm_SyncOp(scp, bufferp, userp, &req,
4181 CM_SCACHESYNC_NEEDCALLBACK |
4182 CM_SCACHESYNC_READ);
4184 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4188 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4190 if (cm_HaveBuffer(scp, bufferp, 0)) {
4191 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4195 /* otherwise, load the buffer and try again */
4196 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4198 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4199 scp, bufferp, code);
4204 buf_Release(bufferp);
4208 } /* if (wrong buffer) ... */
4210 /* now we have the buffer containing the entry we're interested in; copy
4211 * it out if it represents a non-deleted entry.
4213 entryInDir = curOffset.LowPart & (2048-1);
4214 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4216 /* page header will help tell us which entries are free. Page header
4217 * can change more often than once per buffer, since AFS 3 dir page size
4218 * may be less than (but not more than a buffer package buffer.
4220 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4221 temp &= ~(2048 - 1); /* turn off intra-page bits */
4222 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4224 /* now determine which entry we're looking at in the page. If it is
4225 * free (there's a free bitmap at the start of the dir), we should
4226 * skip these 32 bytes.
4228 slotInPage = (entryInDir & 0x7e0) >> 5;
4229 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4230 /* this entry is free */
4231 numDirChunks = 1; /* only skip this guy */
4235 tp = bufferp->datap + entryInBuffer;
4236 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4238 /* while we're here, compute the next entry's location, too,
4239 * since we'll need it when writing out the cookie into the dir
4242 * XXXX Probably should do more sanity checking.
4244 numDirChunks = cm_NameEntries(dep->name, NULL);
4246 /* compute the offset of the cookie representing the next entry */
4247 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4249 /* Compute 8.3 name if necessary */
4250 actualName = dep->name;
4251 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4252 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4253 actualName = shortName;
4256 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4257 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4258 osi_LogSaveString(smb_logp, actualName));
4260 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4261 /* this is one of the entries to use: it is not deleted
4262 * and it matches the star pattern we're looking for.
4265 /* Eliminate entries that don't match requested
4268 /* no hidden files */
4269 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4270 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4274 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4276 /* We have already done the cm_TryBulkStat above */
4277 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4278 fileType = cm_FindFileType(&fid);
4279 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4280 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4282 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4283 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4284 fileType == CM_SCACHETYPE_DFSLINK ||
4285 fileType == CM_SCACHETYPE_INVALID)
4286 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4291 memcpy(op, mask, 11); op += 11;
4292 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4293 *op++ = (char)(nextEntryCookie & 0xff);
4294 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4295 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4296 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4297 memcpy(op, &clientCookie, 4); op += 4;
4299 /* now we emit the attribute. This is sort of tricky,
4300 * since we need to really stat the file to find out
4301 * what type of entry we've got. Right now, we're
4302 * copying out data from a buffer, while holding the
4303 * scp locked, so it isn't really convenient to stat
4304 * something now. We'll put in a place holder now,
4305 * and make a second pass before returning this to get
4306 * the real attributes. So, we just skip the data for
4307 * now, and adjust it later. We allocate a patch
4308 * record to make it easy to find this point later.
4309 * The replay will happen at a time when it is safe to
4310 * unlock the directory.
4312 curPatchp = malloc(sizeof(*curPatchp));
4313 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4314 curPatchp->dptr = op;
4315 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4317 /* do hidden attribute here since name won't be around when applying
4321 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4322 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4324 curPatchp->flags = 0;
4326 op += 9; /* skip attr, time, date and size */
4328 /* zero out name area. The spec says to pad with
4329 * spaces, but Samba doesn't, and neither do we.
4333 /* finally, we get to copy out the name; we know that
4334 * it fits in 8.3 or the pattern wouldn't match, but it
4335 * never hurts to be sure.
4337 strncpy(op, actualName, 13);
4338 if (smb_StoreAnsiFilenames)
4341 /* Uppercase if requested by client */
4342 if (!KNOWS_LONG_NAMES(inp))
4347 /* now, adjust the # of entries copied */
4349 } /* if we're including this name */
4352 /* and adjust curOffset to be where the new cookie is */
4353 thyper.HighPart = 0;
4354 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4355 curOffset = LargeIntegerAdd(thyper, curOffset);
4356 } /* while copying data for dir listing */
4358 /* release the mutex */
4359 lock_ReleaseWrite(&scp->rw);
4361 buf_Release(bufferp);
4365 /* apply and free last set of patches; if not doing a star match, this
4366 * will be empty, but better safe (and freeing everything) than sorry.
4368 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4370 /* special return code for unsuccessful search */
4371 if (code == 0 && dataLength < 21 && returnedNames == 0)
4372 code = CM_ERROR_NOFILES;
4374 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4375 returnedNames, code);
4378 smb_DeleteDirSearch(dsp);
4379 smb_ReleaseDirSearch(dsp);
4380 cm_ReleaseSCache(scp);
4381 cm_ReleaseUser(userp);
4385 /* finalize the output buffer */
4386 smb_SetSMBParm(outp, 0, returnedNames);
4387 temp = (long) (op - origOp);
4388 smb_SetSMBDataLength(outp, temp);
4390 /* the data area is a variable block, which has a 5 (already there)
4391 * followed by the length of the # of data bytes. We now know this to
4392 * be "temp," although that includes the 3 bytes of vbl block header.
4393 * Deduct for them and fill in the length field.
4395 temp -= 3; /* deduct vbl block info */
4396 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4397 origOp[1] = (char)(temp & 0xff);
4398 origOp[2] = (char)((temp>>8) & 0xff);
4399 if (returnedNames == 0)
4400 smb_DeleteDirSearch(dsp);
4401 smb_ReleaseDirSearch(dsp);
4402 cm_ReleaseSCache(scp);
4403 cm_ReleaseUser(userp);
4407 /* verify that this is a valid path to a directory. I don't know why they
4408 * don't use the get file attributes call.
4410 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4414 cm_scache_t *rootScp;
4415 cm_scache_t *newScp;
4424 pathp = smb_GetSMBData(inp, NULL);
4425 pathp = smb_ParseASCIIBlock(pathp, NULL);
4427 return CM_ERROR_BADFD;
4428 if (smb_StoreAnsiFilenames)
4429 OemToChar(pathp,pathp);
4430 osi_Log1(smb_logp, "SMB receive check path %s",
4431 osi_LogSaveString(smb_logp, pathp));
4433 rootScp = cm_data.rootSCachep;
4435 userp = smb_GetUserFromVCP(vcp, inp);
4437 caseFold = CM_FLAG_CASEFOLD;
4439 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4441 cm_ReleaseUser(userp);
4442 return CM_ERROR_NOSUCHPATH;
4444 code = cm_NameI(rootScp, pathp,
4445 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4446 userp, tidPathp, &req, &newScp);
4449 cm_ReleaseUser(userp);
4454 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4455 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4456 cm_ReleaseSCache(newScp);
4457 cm_ReleaseUser(userp);
4458 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4459 return CM_ERROR_PATH_NOT_COVERED;
4461 return CM_ERROR_BADSHARENAME;
4463 #endif /* DFS_SUPPORT */
4465 /* now lock the vnode with a callback; returns with newScp locked */
4466 lock_ObtainWrite(&newScp->rw);
4467 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4468 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4470 if (code != CM_ERROR_NOACCESS) {
4471 lock_ReleaseWrite(&newScp->rw);
4472 cm_ReleaseSCache(newScp);
4473 cm_ReleaseUser(userp);
4477 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4480 attrs = smb_Attributes(newScp);
4482 if (!(attrs & SMB_ATTR_DIRECTORY))
4483 code = CM_ERROR_NOTDIR;
4485 lock_ReleaseWrite(&newScp->rw);
4487 cm_ReleaseSCache(newScp);
4488 cm_ReleaseUser(userp);
4492 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4496 cm_scache_t *rootScp;
4497 unsigned short attribute;
4499 cm_scache_t *newScp;
4508 /* decode basic attributes we're passed */
4509 attribute = smb_GetSMBParm(inp, 0);
4510 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4512 pathp = smb_GetSMBData(inp, NULL);
4513 pathp = smb_ParseASCIIBlock(pathp, NULL);
4515 return CM_ERROR_BADSMB;
4516 if (smb_StoreAnsiFilenames)
4517 OemToChar(pathp,pathp);
4519 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4520 dosTime, attribute);
4522 rootScp = cm_data.rootSCachep;
4524 userp = smb_GetUserFromVCP(vcp, inp);
4526 caseFold = CM_FLAG_CASEFOLD;
4528 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4530 cm_ReleaseUser(userp);
4531 return CM_ERROR_NOSUCHFILE;
4533 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4534 tidPathp, &req, &newScp);
4537 cm_ReleaseUser(userp);
4542 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4543 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4544 cm_ReleaseSCache(newScp);
4545 cm_ReleaseUser(userp);
4546 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4547 return CM_ERROR_PATH_NOT_COVERED;
4549 return CM_ERROR_BADSHARENAME;
4551 #endif /* DFS_SUPPORT */
4553 /* now lock the vnode with a callback; returns with newScp locked; we
4554 * need the current status to determine what the new status is, in some
4557 lock_ObtainWrite(&newScp->rw);
4558 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4559 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4561 lock_ReleaseWrite(&newScp->rw);
4562 cm_ReleaseSCache(newScp);
4563 cm_ReleaseUser(userp);
4567 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4569 /* Check for RO volume */
4570 if (newScp->flags & CM_SCACHEFLAG_RO) {
4571 lock_ReleaseWrite(&newScp->rw);
4572 cm_ReleaseSCache(newScp);
4573 cm_ReleaseUser(userp);
4574 return CM_ERROR_READONLY;
4577 /* prepare for setattr call */
4580 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4581 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4583 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4584 /* we're told to make a writable file read-only */
4585 attr.unixModeBits = newScp->unixModeBits & ~0222;
4586 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4588 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4589 /* we're told to make a read-only file writable */
4590 attr.unixModeBits = newScp->unixModeBits | 0222;
4591 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4593 lock_ReleaseWrite(&newScp->rw);
4595 /* now call setattr */
4597 code = cm_SetAttr(newScp, &attr, userp, &req);
4601 cm_ReleaseSCache(newScp);
4602 cm_ReleaseUser(userp);
4607 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4611 cm_scache_t *rootScp;
4612 cm_scache_t *newScp, *dscp;
4624 pathp = smb_GetSMBData(inp, NULL);
4625 pathp = smb_ParseASCIIBlock(pathp, NULL);
4627 return CM_ERROR_BADSMB;
4629 if (*pathp == 0) /* null path */
4632 if (smb_StoreAnsiFilenames)
4633 OemToChar(pathp,pathp);
4635 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4636 osi_LogSaveString(smb_logp, pathp));
4638 rootScp = cm_data.rootSCachep;
4640 userp = smb_GetUserFromVCP(vcp, inp);
4642 /* we shouldn't need this for V3 requests, but we seem to */
4643 caseFold = CM_FLAG_CASEFOLD;
4645 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4647 cm_ReleaseUser(userp);
4648 return CM_ERROR_NOSUCHFILE;
4652 * XXX Strange hack XXX
4654 * As of Patch 5 (16 July 97), we are having the following problem:
4655 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4656 * requests to look up "desktop.ini" in all the subdirectories.
4657 * This can cause zillions of timeouts looking up non-existent cells
4658 * and volumes, especially in the top-level directory.
4660 * We have not found any way to avoid this or work around it except
4661 * to explicitly ignore the requests for mount points that haven't
4662 * yet been evaluated and for directories that haven't yet been
4665 * We should modify this hack to provide a fake desktop.ini file
4666 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4668 spacep = inp->spacep;
4669 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4670 #ifndef SPECIAL_FOLDERS
4671 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4672 code = cm_NameI(rootScp, spacep->data,
4673 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4674 userp, tidPathp, &req, &dscp);
4677 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4678 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
4679 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4680 return CM_ERROR_PATH_NOT_COVERED;
4682 return CM_ERROR_BADSHARENAME;
4684 #endif /* DFS_SUPPORT */
4685 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4686 code = CM_ERROR_NOSUCHFILE;
4687 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4688 cm_buf_t *bp = buf_Find(dscp, &hzero);
4693 code = CM_ERROR_NOSUCHFILE;
4695 cm_ReleaseSCache(dscp);
4697 cm_ReleaseUser(userp);
4702 #endif /* SPECIAL_FOLDERS */
4704 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4705 tidPathp, &req, &newScp);
4707 cm_ReleaseUser(userp);
4712 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4713 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4714 cm_ReleaseSCache(newScp);
4715 cm_ReleaseUser(userp);
4716 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4717 return CM_ERROR_PATH_NOT_COVERED;
4719 return CM_ERROR_BADSHARENAME;
4721 #endif /* DFS_SUPPORT */
4723 /* now lock the vnode with a callback; returns with newScp locked */
4724 lock_ObtainWrite(&newScp->rw);
4725 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4726 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4728 lock_ReleaseWrite(&newScp->rw);
4729 cm_ReleaseSCache(newScp);
4730 cm_ReleaseUser(userp);
4734 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4737 /* use smb_Attributes instead. Also the fact that a file is
4738 * in a readonly volume doesn't mean it shojuld be marked as RO
4740 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4741 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4742 newScp->fileType == CM_SCACHETYPE_INVALID)
4743 attrs = SMB_ATTR_DIRECTORY;
4746 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4747 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4749 attrs = smb_Attributes(newScp);
4752 smb_SetSMBParm(outp, 0, attrs);
4754 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4755 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4756 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4757 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4758 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4759 smb_SetSMBParm(outp, 5, 0);
4760 smb_SetSMBParm(outp, 6, 0);
4761 smb_SetSMBParm(outp, 7, 0);
4762 smb_SetSMBParm(outp, 8, 0);
4763 smb_SetSMBParm(outp, 9, 0);
4764 smb_SetSMBDataLength(outp, 0);
4765 lock_ReleaseWrite(&newScp->rw);
4767 cm_ReleaseSCache(newScp);
4768 cm_ReleaseUser(userp);
4773 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4777 osi_Log0(smb_logp, "SMB receive tree disconnect");
4779 /* find the tree and free it */
4780 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4782 lock_ObtainWrite(&smb_rctLock);
4784 smb_ReleaseTID(tidp, TRUE);
4785 lock_ReleaseWrite(&smb_rctLock);
4791 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4809 pathp = smb_GetSMBData(inp, NULL);
4810 pathp = smb_ParseASCIIBlock(pathp, NULL);
4811 if (smb_StoreAnsiFilenames)
4812 OemToChar(pathp,pathp);
4814 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4816 #ifdef DEBUG_VERBOSE
4820 hexpath = osi_HexifyString( pathp );
4821 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4826 share = smb_GetSMBParm(inp, 0);
4827 attribute = smb_GetSMBParm(inp, 1);
4829 spacep = inp->spacep;
4830 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4831 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4832 /* special case magic file name for receiving IOCTL requests
4833 * (since IOCTL calls themselves aren't getting through).
4835 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4836 smb_SetupIoctlFid(fidp, spacep);
4837 smb_SetSMBParm(outp, 0, fidp->fid);
4838 smb_SetSMBParm(outp, 1, 0); /* attrs */
4839 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4840 smb_SetSMBParm(outp, 3, 0);
4841 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4842 smb_SetSMBParm(outp, 5, 0x7fff);
4843 /* pass the open mode back */
4844 smb_SetSMBParm(outp, 6, (share & 0xf));
4845 smb_SetSMBDataLength(outp, 0);
4846 smb_ReleaseFID(fidp);
4850 userp = smb_GetUserFromVCP(vcp, inp);
4852 caseFold = CM_FLAG_CASEFOLD;
4854 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4856 cm_ReleaseUser(userp);
4857 return CM_ERROR_NOSUCHPATH;
4859 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4860 tidPathp, &req, &scp);
4863 cm_ReleaseUser(userp);
4868 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4869 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
4870 cm_ReleaseSCache(scp);
4871 cm_ReleaseUser(userp);
4872 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4873 return CM_ERROR_PATH_NOT_COVERED;
4875 return CM_ERROR_BADSHARENAME;
4877 #endif /* DFS_SUPPORT */
4879 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4881 cm_ReleaseSCache(scp);
4882 cm_ReleaseUser(userp);
4886 /* don't need callback to check file type, since file types never
4887 * change, and namei and cm_Lookup all stat the object at least once on
4888 * a successful return.
4890 if (scp->fileType != CM_SCACHETYPE_FILE) {
4891 cm_ReleaseSCache(scp);
4892 cm_ReleaseUser(userp);
4893 return CM_ERROR_ISDIR;
4896 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4897 osi_assertx(fidp, "null smb_fid_t");
4899 /* save a pointer to the vnode */
4901 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4902 lock_ObtainWrite(&scp->rw);
4903 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4904 lock_ReleaseWrite(&scp->rw);
4908 fidp->userp = userp;
4910 lock_ObtainMutex(&fidp->mx);
4911 if ((share & 0xf) == 0)
4912 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4913 else if ((share & 0xf) == 1)
4914 fidp->flags |= SMB_FID_OPENWRITE;
4916 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4917 lock_ReleaseMutex(&fidp->mx);
4919 lock_ObtainRead(&scp->rw);
4920 smb_SetSMBParm(outp, 0, fidp->fid);
4921 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4922 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4923 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4924 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4925 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4926 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4927 /* pass the open mode back; XXXX add access checks */
4928 smb_SetSMBParm(outp, 6, (share & 0xf));
4929 smb_SetSMBDataLength(outp, 0);
4930 lock_ReleaseRead(&scp->rw);
4933 cm_Open(scp, 0, userp);
4935 /* send and free packet */
4936 smb_ReleaseFID(fidp);
4937 cm_ReleaseUser(userp);
4938 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4942 typedef struct smb_unlinkRock {
4947 char *maskp; /* pointer to the star pattern */
4950 cm_dirEntryList_t * matches;
4953 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4956 smb_unlinkRock_t *rockp;
4964 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4965 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4966 caseFold |= CM_FLAG_8DOT3;
4968 matchName = dep->name;
4969 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4971 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4972 !cm_Is8Dot3(dep->name)) {
4973 cm_Gen8Dot3Name(dep, shortName, NULL);
4974 matchName = shortName;
4975 /* 8.3 matches are always case insensitive */
4976 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4979 osi_Log1(smb_logp, "Found match %s",
4980 osi_LogSaveString(smb_logp, matchName));
4982 cm_DirEntryListAdd(dep->name, &rockp->matches);
4986 /* If we made a case sensitive exact match, we might as well quit now. */
4987 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4988 code = CM_ERROR_STOPNOW;
4997 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5006 smb_unlinkRock_t rock;
5015 attribute = smb_GetSMBParm(inp, 0);
5017 tp = smb_GetSMBData(inp, NULL);
5018 pathp = smb_ParseASCIIBlock(tp, &tp);
5019 if (smb_StoreAnsiFilenames)
5020 OemToChar(pathp,pathp);
5022 osi_Log1(smb_logp, "SMB receive unlink %s",
5023 osi_LogSaveString(smb_logp, pathp));
5025 spacep = inp->spacep;
5026 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5028 userp = smb_GetUserFromVCP(vcp, inp);
5030 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5032 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5034 cm_ReleaseUser(userp);
5035 return CM_ERROR_NOSUCHPATH;
5037 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5040 cm_ReleaseUser(userp);
5045 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5046 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,spacep->data);
5047 cm_ReleaseSCache(dscp);
5048 cm_ReleaseUser(userp);
5049 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5050 return CM_ERROR_PATH_NOT_COVERED;
5052 return CM_ERROR_BADSHARENAME;
5054 #endif /* DFS_SUPPORT */
5056 /* otherwise, scp points to the parent directory. */
5063 rock.maskp = smb_FindMask(pathp);
5064 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5067 thyper.HighPart = 0;
5072 rock.matches = NULL;
5074 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5075 * match. If that fails, we do a case insensitve match.
5077 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5078 !smb_IsStarMask(rock.maskp)) {
5079 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5082 thyper.HighPart = 0;
5083 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5088 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5090 if (code == CM_ERROR_STOPNOW)
5093 if (code == 0 && rock.matches) {
5094 cm_dirEntryList_t * entry;
5096 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5098 osi_Log1(smb_logp, "Unlinking %s",
5099 osi_LogSaveString(smb_logp, entry->name));
5100 code = cm_Unlink(dscp, entry->name, userp, &req);
5102 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5103 smb_NotifyChange(FILE_ACTION_REMOVED,
5104 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5105 dscp, entry->name, NULL, TRUE);
5109 cm_DirEntryListFree(&rock.matches);
5111 cm_ReleaseUser(userp);
5113 cm_ReleaseSCache(dscp);
5115 if (code == 0 && !rock.any)
5116 code = CM_ERROR_NOSUCHFILE;
5120 typedef struct smb_renameRock {
5121 cm_scache_t *odscp; /* old dir */
5122 cm_scache_t *ndscp; /* new dir */
5123 cm_user_t *userp; /* user */
5124 cm_req_t *reqp; /* request struct */
5125 smb_vc_t *vcp; /* virtual circuit */
5126 char *maskp; /* pointer to star pattern of old file name */
5127 int flags; /* tilde, casefold, etc */
5128 char *newNamep; /* ptr to the new file's name */
5129 char oldName[MAX_PATH];
5133 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5136 smb_renameRock_t *rockp;
5139 char shortName[13]="";
5141 rockp = (smb_renameRock_t *) vrockp;
5143 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5144 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5145 caseFold |= CM_FLAG_8DOT3;
5147 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5149 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5150 !cm_Is8Dot3(dep->name)) {
5151 cm_Gen8Dot3Name(dep, shortName, NULL);
5152 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5157 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5158 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5159 code = CM_ERROR_STOPNOW;
5169 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5172 cm_space_t *spacep = NULL;
5173 smb_renameRock_t rock;
5174 cm_scache_t *oldDscp = NULL;
5175 cm_scache_t *newDscp = NULL;
5176 cm_scache_t *tmpscp= NULL;
5177 cm_scache_t *tmpscp2 = NULL;
5187 userp = smb_GetUserFromVCP(vcp, inp);
5188 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5190 cm_ReleaseUser(userp);
5191 return CM_ERROR_NOSUCHPATH;
5195 spacep = inp->spacep;
5196 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5198 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5199 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5200 userp, tidPathp, &req, &oldDscp);
5202 cm_ReleaseUser(userp);
5207 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5208 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5209 cm_ReleaseSCache(oldDscp);
5210 cm_ReleaseUser(userp);
5211 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5212 return CM_ERROR_PATH_NOT_COVERED;
5214 return CM_ERROR_BADSHARENAME;
5216 #endif /* DFS_SUPPORT */
5218 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5219 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5220 userp, tidPathp, &req, &newDscp);
5223 cm_ReleaseSCache(oldDscp);
5224 cm_ReleaseUser(userp);
5229 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5230 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5231 cm_ReleaseSCache(oldDscp);
5232 cm_ReleaseSCache(newDscp);
5233 cm_ReleaseUser(userp);
5234 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5235 return CM_ERROR_PATH_NOT_COVERED;
5237 return CM_ERROR_BADSHARENAME;
5239 #endif /* DFS_SUPPORT */
5242 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5243 * next, get the component names, and lower case them.
5246 /* handle the old name first */
5248 oldLastNamep = oldPathp;
5252 /* and handle the new name, too */
5254 newLastNamep = newPathp;
5258 /* TODO: The old name could be a wildcard. The new name must not be */
5260 /* do the vnode call */
5261 rock.odscp = oldDscp;
5262 rock.ndscp = newDscp;
5266 rock.maskp = oldLastNamep;
5267 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5268 rock.newNamep = newLastNamep;
5269 rock.oldName[0] = '\0';
5272 /* Check if the file already exists; if so return error */
5273 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5274 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5275 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5277 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5278 osi_LogSaveString(smb_logp, newLastNamep));
5280 /* Check if the old and the new names differ only in case. If so return
5281 * success, else return CM_ERROR_EXISTS
5283 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5285 /* This would be a success only if the old file is *as same as* the new file */
5286 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5288 if (tmpscp == tmpscp2)
5291 code = CM_ERROR_EXISTS;
5292 cm_ReleaseSCache(tmpscp2);
5295 code = CM_ERROR_NOSUCHFILE;
5298 /* file exist, do not rename, also fixes move */
5299 osi_Log0(smb_logp, "Can't rename. Target already exists");
5300 code = CM_ERROR_EXISTS;
5304 cm_ReleaseSCache(tmpscp);
5305 cm_ReleaseSCache(newDscp);
5306 cm_ReleaseSCache(oldDscp);
5307 cm_ReleaseUser(userp);
5311 /* Now search the directory for the pattern, and do the appropriate rename when found */
5312 thyper.LowPart = 0; /* search dir from here */
5313 thyper.HighPart = 0;
5315 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5316 if (code == 0 && !rock.any) {
5318 thyper.HighPart = 0;
5319 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5320 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5322 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5324 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5325 code = cm_Rename(rock.odscp, rock.oldName,
5326 rock.ndscp, rock.newNamep, rock.userp,
5328 /* if the call worked, stop doing the search now, since we
5329 * really only want to rename one file.
5331 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5332 } else if (code == 0) {
5333 code = CM_ERROR_NOSUCHFILE;
5336 /* Handle Change Notification */
5338 * Being lazy, not distinguishing between files and dirs in this
5339 * filter, since we'd have to do a lookup.
5342 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5343 if (oldDscp == newDscp) {
5344 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5345 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5346 filter, oldDscp, oldLastNamep,
5347 newLastNamep, TRUE);
5349 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5350 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5351 filter, oldDscp, oldLastNamep,
5353 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5354 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5355 filter, newDscp, newLastNamep,
5361 cm_ReleaseSCache(tmpscp);
5362 cm_ReleaseUser(userp);
5363 cm_ReleaseSCache(oldDscp);
5364 cm_ReleaseSCache(newDscp);
5369 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5372 cm_space_t *spacep = NULL;
5373 cm_scache_t *oldDscp = NULL;
5374 cm_scache_t *newDscp = NULL;
5375 cm_scache_t *tmpscp= NULL;
5376 cm_scache_t *tmpscp2 = NULL;
5377 cm_scache_t *sscp = NULL;
5386 userp = smb_GetUserFromVCP(vcp, inp);
5388 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5390 cm_ReleaseUser(userp);
5391 return CM_ERROR_NOSUCHPATH;
5396 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5398 spacep = inp->spacep;
5399 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5401 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5402 userp, tidPathp, &req, &oldDscp);
5404 cm_ReleaseUser(userp);
5409 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5410 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5411 cm_ReleaseSCache(oldDscp);
5412 cm_ReleaseUser(userp);
5413 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5414 return CM_ERROR_PATH_NOT_COVERED;
5416 return CM_ERROR_BADSHARENAME;
5418 #endif /* DFS_SUPPORT */
5420 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5421 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5422 userp, tidPathp, &req, &newDscp);
5424 cm_ReleaseSCache(oldDscp);
5425 cm_ReleaseUser(userp);
5430 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5431 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5432 cm_ReleaseSCache(newDscp);
5433 cm_ReleaseSCache(oldDscp);
5434 cm_ReleaseUser(userp);
5435 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5436 return CM_ERROR_PATH_NOT_COVERED;
5438 return CM_ERROR_BADSHARENAME;
5440 #endif /* DFS_SUPPORT */
5442 /* Now, although we did two lookups for the two directories (because the same
5443 * directory can be referenced through different paths), we only allow hard links
5444 * within the same directory. */
5445 if (oldDscp != newDscp) {
5446 cm_ReleaseSCache(oldDscp);
5447 cm_ReleaseSCache(newDscp);
5448 cm_ReleaseUser(userp);
5449 return CM_ERROR_CROSSDEVLINK;
5452 /* handle the old name first */
5454 oldLastNamep = oldPathp;
5458 /* and handle the new name, too */
5460 newLastNamep = newPathp;
5464 /* now lookup the old name */
5465 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5466 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5468 cm_ReleaseSCache(oldDscp);
5469 cm_ReleaseSCache(newDscp);
5470 cm_ReleaseUser(userp);
5474 /* Check if the file already exists; if so return error */
5475 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5476 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5477 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5479 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5480 osi_LogSaveString(smb_logp, newLastNamep));
5482 /* if the existing link is to the same file, then we return success */
5484 if(sscp == tmpscp) {
5487 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5488 code = CM_ERROR_EXISTS;
5493 cm_ReleaseSCache(tmpscp);
5494 cm_ReleaseSCache(sscp);
5495 cm_ReleaseSCache(newDscp);
5496 cm_ReleaseSCache(oldDscp);
5497 cm_ReleaseUser(userp);
5501 /* now create the hardlink */
5502 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5503 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5504 osi_Log1(smb_logp," Link returns 0x%x", code);
5506 /* Handle Change Notification */
5508 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5509 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5510 smb_NotifyChange(FILE_ACTION_ADDED,
5511 filter, newDscp, newLastNamep,
5516 cm_ReleaseSCache(tmpscp);
5517 cm_ReleaseUser(userp);
5518 cm_ReleaseSCache(sscp);
5519 cm_ReleaseSCache(oldDscp);
5520 cm_ReleaseSCache(newDscp);
5525 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5532 tp = smb_GetSMBData(inp, NULL);
5533 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5534 if (smb_StoreAnsiFilenames)
5535 OemToChar(oldPathp,oldPathp);
5536 newPathp = smb_ParseASCIIBlock(tp, &tp);
5537 if (smb_StoreAnsiFilenames)
5538 OemToChar(newPathp,newPathp);
5540 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5541 osi_LogSaveString(smb_logp, oldPathp),
5542 osi_LogSaveString(smb_logp, newPathp));
5544 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5546 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5552 typedef struct smb_rmdirRock {
5556 char *maskp; /* pointer to the star pattern */
5559 cm_dirEntryList_t * matches;
5562 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5565 smb_rmdirRock_t *rockp;
5570 rockp = (smb_rmdirRock_t *) vrockp;
5572 matchName = dep->name;
5573 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5574 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5576 match = (strcmp(matchName, rockp->maskp) == 0);
5578 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5579 !cm_Is8Dot3(dep->name)) {
5580 cm_Gen8Dot3Name(dep, shortName, NULL);
5581 matchName = shortName;
5582 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5587 cm_DirEntryListAdd(dep->name, &rockp->matches);
5593 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5601 smb_rmdirRock_t rock;
5610 tp = smb_GetSMBData(inp, NULL);
5611 pathp = smb_ParseASCIIBlock(tp, &tp);
5612 if (smb_StoreAnsiFilenames)
5613 OemToChar(pathp,pathp);
5615 spacep = inp->spacep;
5616 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5618 userp = smb_GetUserFromVCP(vcp, inp);
5620 caseFold = CM_FLAG_CASEFOLD;
5622 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5624 cm_ReleaseUser(userp);
5625 return CM_ERROR_NOSUCHPATH;
5627 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5628 userp, tidPathp, &req, &dscp);
5631 cm_ReleaseUser(userp);
5636 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5637 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
5638 cm_ReleaseSCache(dscp);
5639 cm_ReleaseUser(userp);
5640 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5641 return CM_ERROR_PATH_NOT_COVERED;
5643 return CM_ERROR_BADSHARENAME;
5645 #endif /* DFS_SUPPORT */
5647 /* otherwise, scp points to the parent directory. */
5654 rock.maskp = lastNamep;
5655 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5658 thyper.HighPart = 0;
5662 rock.matches = NULL;
5664 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5665 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5666 if (code == 0 && !rock.any) {
5668 thyper.HighPart = 0;
5669 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5670 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5673 if (code == 0 && rock.matches) {
5674 cm_dirEntryList_t * entry;
5676 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5677 osi_Log1(smb_logp, "Removing directory %s",
5678 osi_LogSaveString(smb_logp, entry->name));
5680 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5682 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5683 smb_NotifyChange(FILE_ACTION_REMOVED,
5684 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5685 dscp, entry->name, NULL, TRUE);
5689 cm_DirEntryListFree(&rock.matches);
5691 cm_ReleaseUser(userp);
5693 cm_ReleaseSCache(dscp);
5695 if (code == 0 && !rock.any)
5696 code = CM_ERROR_NOSUCHFILE;
5700 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5710 fid = smb_GetSMBParm(inp, 0);
5712 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5714 fid = smb_ChainFID(fid, inp);
5715 fidp = smb_FindFID(vcp, fid, 0);
5717 return CM_ERROR_BADFD;
5719 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5720 smb_CloseFID(vcp, fidp, NULL, 0);
5721 smb_ReleaseFID(fidp);
5722 return CM_ERROR_NOSUCHFILE;
5725 lock_ObtainMutex(&fidp->mx);
5726 if (fidp->flags & SMB_FID_IOCTL) {
5727 lock_ReleaseMutex(&fidp->mx);
5728 smb_ReleaseFID(fidp);
5729 return CM_ERROR_BADFD;
5731 lock_ReleaseMutex(&fidp->mx);
5733 userp = smb_GetUserFromVCP(vcp, inp);
5735 lock_ObtainMutex(&fidp->mx);
5736 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
5737 cm_scache_t * scp = fidp->scp;
5739 lock_ReleaseMutex(&fidp->mx);
5740 code = cm_FSync(scp, userp, &req);
5741 cm_ReleaseSCache(scp);
5744 lock_ReleaseMutex(&fidp->mx);
5747 smb_ReleaseFID(fidp);
5749 cm_ReleaseUser(userp);
5754 struct smb_FullNameRock {
5760 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5764 struct smb_FullNameRock *vrockp;
5766 vrockp = (struct smb_FullNameRock *)rockp;
5768 if (!cm_Is8Dot3(dep->name)) {
5769 cm_Gen8Dot3Name(dep, shortName, NULL);
5771 if (cm_stricmp(shortName, vrockp->name) == 0) {
5772 vrockp->fullName = strdup(dep->name);
5773 return CM_ERROR_STOPNOW;
5776 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5777 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5778 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5779 vrockp->fullName = strdup(dep->name);
5780 return CM_ERROR_STOPNOW;
5785 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5786 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5788 struct smb_FullNameRock rock;
5794 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5795 if (code == CM_ERROR_STOPNOW)
5796 *newPathp = rock.fullName;
5798 *newPathp = strdup(pathp);
5801 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5802 afs_uint32 dosTime) {
5805 cm_scache_t *dscp = NULL;
5807 cm_scache_t * scp = NULL;
5808 cm_scache_t *delscp = NULL;
5810 int nullcreator = 0;
5812 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5813 fidp, fidp->fid, scp, vcp);
5816 lock_ObtainMutex(&fidp->mx);
5817 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5818 lock_ReleaseMutex(&fidp->mx);
5819 osi_Log0(smb_logp, " No user specified. Not closing fid");
5820 return CM_ERROR_BADFD;
5823 userp = fidp->userp; /* no hold required since fidp is held
5824 throughout the function */
5825 lock_ReleaseMutex(&fidp->mx);
5830 lock_ObtainWrite(&smb_rctLock);
5832 osi_Log0(smb_logp, " Fid already closed.");
5833 lock_ReleaseWrite(&smb_rctLock);
5834 return CM_ERROR_BADFD;
5837 lock_ReleaseWrite(&smb_rctLock);
5839 lock_ObtainMutex(&fidp->mx);
5840 if (fidp->NTopen_dscp) {
5841 dscp = fidp->NTopen_dscp;
5842 cm_HoldSCache(dscp);
5845 if (fidp->NTopen_pathp) {
5846 pathp = strdup(fidp->NTopen_pathp);
5854 /* Don't jump the gun on an async raw write */
5855 while (fidp->raw_writers) {
5856 lock_ReleaseMutex(&fidp->mx);
5857 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5858 lock_ObtainMutex(&fidp->mx);
5861 /* watch for ioctl closes, and read-only opens */
5863 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5864 == SMB_FID_OPENWRITE) {
5865 if (dosTime != 0 && dosTime != -1) {
5866 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5867 /* This fixes defect 10958 */
5868 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5869 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5871 if (smb_AsyncStore != 2) {
5872 lock_ReleaseMutex(&fidp->mx);
5873 code = cm_FSync(scp, userp, &req);
5874 lock_ObtainMutex(&fidp->mx);
5880 /* unlock any pending locks */
5881 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5882 scp->fileType == CM_SCACHETYPE_FILE) {
5886 lock_ReleaseMutex(&fidp->mx);
5888 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5890 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5891 lock_ObtainWrite(&scp->rw);
5893 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5894 CM_SCACHESYNC_NEEDCALLBACK
5895 | CM_SCACHESYNC_GETSTATUS
5896 | CM_SCACHESYNC_LOCK);
5900 "smb CoreClose SyncOp failure code 0x%x", tcode);
5901 goto post_syncopdone;
5904 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5906 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5910 lock_ReleaseWrite(&scp->rw);
5911 lock_ObtainMutex(&fidp->mx);
5914 if (fidp->flags & SMB_FID_DELONCLOSE) {
5917 lock_ReleaseMutex(&fidp->mx);
5919 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
5924 smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
5925 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5926 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5929 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5930 smb_NotifyChange(FILE_ACTION_REMOVED,
5931 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5932 dscp, fullPathp, NULL, TRUE);
5935 code = cm_Unlink(dscp, fullPathp, userp, &req);
5938 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5939 smb_NotifyChange(FILE_ACTION_REMOVED,
5940 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5941 dscp, fullPathp, NULL, TRUE);
5945 lock_ObtainMutex(&fidp->mx);
5946 fidp->flags &= ~SMB_FID_DELONCLOSE;
5949 /* if this was a newly created file, then clear the creator
5950 * in the stat cache entry. */
5951 if (fidp->flags & SMB_FID_CREATED) {
5953 fidp->flags &= ~SMB_FID_CREATED;
5956 if (fidp->flags & SMB_FID_NTOPEN) {
5957 cm_ReleaseSCache(fidp->NTopen_dscp);
5958 fidp->NTopen_dscp = NULL;
5959 free(fidp->NTopen_pathp);
5960 fidp->NTopen_pathp = NULL;
5961 fidp->flags &= ~SMB_FID_NTOPEN;
5963 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
5964 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
5967 if (fidp->NTopen_wholepathp) {
5968 free(fidp->NTopen_wholepathp);
5969 fidp->NTopen_wholepathp = NULL;
5973 cm_ReleaseSCache(fidp->scp);
5976 lock_ReleaseMutex(&fidp->mx);
5979 cm_ReleaseSCache(dscp);
5983 lock_ObtainWrite(&delscp->rw);
5985 delscp->flags |= CM_SCACHEFLAG_DELETED;
5986 lock_ReleaseWrite(&delscp->rw);
5988 cm_ReleaseSCache(delscp);
5992 lock_ObtainWrite(&scp->rw);
5993 if (nullcreator && scp->creator == userp)
5994 scp->creator = NULL;
5995 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5996 lock_ReleaseWrite(&scp->rw);
5997 cm_ReleaseSCache(scp);
6006 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6014 fid = smb_GetSMBParm(inp, 0);
6015 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6017 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6019 fid = smb_ChainFID(fid, inp);
6020 fidp = smb_FindFID(vcp, fid, 0);
6022 return CM_ERROR_BADFD;
6025 userp = smb_GetUserFromVCP(vcp, inp);
6027 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6029 smb_ReleaseFID(fidp);
6030 cm_ReleaseUser(userp);
6035 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6037 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6038 cm_user_t *userp, long *readp)
6044 osi_hyper_t fileLength;
6046 osi_hyper_t lastByte;
6047 osi_hyper_t bufferOffset;
6051 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6054 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6055 fidp->fid, offsetp->LowPart, count);
6059 lock_ObtainMutex(&fidp->mx);
6060 /* make sure we have a readable FD */
6061 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6062 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6063 fidp->fid, fidp->flags);
6064 lock_ReleaseMutex(&fidp->mx);
6065 code = CM_ERROR_BADFDOP;
6076 lock_ObtainWrite(&scp->rw);
6078 if (offset.HighPart == 0) {
6079 chunk = offset.LowPart >> cm_logChunkSize;
6080 if (chunk != fidp->curr_chunk) {
6081 fidp->prev_chunk = fidp->curr_chunk;
6082 fidp->curr_chunk = chunk;
6084 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6087 lock_ReleaseMutex(&fidp->mx);
6089 /* start by looking up the file's end */
6090 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6091 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6095 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6097 /* now we have the entry locked, look up the length */
6098 fileLength = scp->length;
6100 /* adjust count down so that it won't go past EOF */
6101 thyper.LowPart = count;
6102 thyper.HighPart = 0;
6103 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6105 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6106 /* we'd read past EOF, so just stop at fileLength bytes.
6107 * Start by computing how many bytes remain in the file.
6109 thyper = LargeIntegerSubtract(fileLength, offset);
6111 /* if we are past EOF, read 0 bytes */
6112 if (LargeIntegerLessThanZero(thyper))
6115 count = thyper.LowPart;
6120 /* now, copy the data one buffer at a time,
6121 * until we've filled the request packet
6124 /* if we've copied all the data requested, we're done */
6125 if (count <= 0) break;
6127 /* otherwise, load up a buffer of data */
6128 thyper.HighPart = offset.HighPart;
6129 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6130 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6133 buf_Release(bufferp);
6136 lock_ReleaseWrite(&scp->rw);
6138 code = buf_Get(scp, &thyper, &bufferp);
6140 lock_ObtainWrite(&scp->rw);
6141 if (code) goto done;
6142 bufferOffset = thyper;
6144 /* now get the data in the cache */
6146 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6147 CM_SCACHESYNC_NEEDCALLBACK |
6148 CM_SCACHESYNC_READ);
6152 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6154 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6156 /* otherwise, load the buffer and try again */
6157 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6161 buf_Release(bufferp);
6165 } /* if (wrong buffer) ... */
6167 /* now we have the right buffer loaded. Copy out the
6168 * data from here to the user's buffer.
6170 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6172 /* and figure out how many bytes we want from this buffer */
6173 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6174 if (nbytes > count) nbytes = count; /* don't go past EOF */
6176 /* now copy the data */
6177 memcpy(op, bufferp->datap + bufIndex, nbytes);
6179 /* adjust counters, pointers, etc. */
6182 thyper.LowPart = nbytes;
6183 thyper.HighPart = 0;
6184 offset = LargeIntegerAdd(thyper, offset);
6188 lock_ReleaseWrite(&scp->rw);
6190 buf_Release(bufferp);
6192 if (code == 0 && sequential)
6193 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6195 cm_ReleaseSCache(scp);
6198 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6199 fidp->fid, code, *readp);
6204 * smb_WriteData -- common code for Write and Raw Write
6206 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6207 cm_user_t *userp, long *writtenp)
6209 osi_hyper_t offset = *offsetp;
6212 cm_scache_t *scp = NULL;
6213 osi_hyper_t fileLength; /* file's length at start of write */
6214 osi_hyper_t minLength; /* don't read past this */
6215 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6216 cm_buf_t *bufferp = NULL;
6217 osi_hyper_t thyper; /* hyper tmp variable */
6218 osi_hyper_t bufferOffset;
6219 afs_uint32 bufIndex; /* index in buffer where our data is */
6220 int doWriteBack = 0;
6221 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6225 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6226 fidp->fid, offsetp->LowPart, count);
6230 lock_ObtainMutex(&fidp->mx);
6231 /* make sure we have a writable FD */
6232 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6233 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6234 fidp->fid, fidp->flags);
6235 lock_ReleaseMutex(&fidp->mx);
6236 code = CM_ERROR_BADFDOP;
6244 lock_ReleaseMutex(&fidp->mx);
6246 lock_ObtainWrite(&scp->rw);
6247 /* start by looking up the file's end */
6248 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6249 CM_SCACHESYNC_NEEDCALLBACK
6250 | CM_SCACHESYNC_SETSTATUS
6251 | CM_SCACHESYNC_GETSTATUS);
6255 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6257 /* now we have the entry locked, look up the length */
6258 fileLength = scp->length;
6259 minLength = fileLength;
6260 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6261 minLength = scp->serverLength;
6263 /* adjust file length if we extend past EOF */
6264 thyper.LowPart = count;
6265 thyper.HighPart = 0;
6266 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6267 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6268 /* we'd write past EOF, so extend the file */
6269 scp->mask |= CM_SCACHEMASK_LENGTH;
6270 scp->length = thyper;
6271 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6273 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6275 /* now, if the new position (thyper) and the old (offset) are in
6276 * different storeback windows, remember to store back the previous
6277 * storeback window when we're done with the write.
6279 * the purpose of this logic is to slow down the CIFS client
6280 * in order to avoid the client disconnecting during the CLOSE
6281 * operation if there are too many dirty buffers left to write
6282 * than can be accomplished during 45 seconds. This used to be
6283 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6284 * so that we can read larger amounts of data at a time.
6286 if (smb_AsyncStore == 1 &&
6287 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
6288 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
6289 /* they're different */
6291 writeBackOffset.HighPart = offset.HighPart;
6292 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
6297 /* now, copy the data one buffer at a time, until we've filled the
6300 /* if we've copied all the data requested, we're done */
6304 /* handle over quota or out of space */
6305 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6306 *writtenp = written;
6307 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6311 /* otherwise, load up a buffer of data */
6312 thyper.HighPart = offset.HighPart;
6313 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6314 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6317 lock_ReleaseMutex(&bufferp->mx);
6318 buf_Release(bufferp);
6321 lock_ReleaseWrite(&scp->rw);
6323 code = buf_Get(scp, &thyper, &bufferp);
6325 lock_ObtainMutex(&bufferp->mx);
6326 lock_ObtainWrite(&scp->rw);
6327 if (code) goto done;
6329 bufferOffset = thyper;
6331 /* now get the data in the cache */
6333 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6334 CM_SCACHESYNC_NEEDCALLBACK
6335 | CM_SCACHESYNC_WRITE
6336 | CM_SCACHESYNC_BUFLOCKED);
6340 cm_SyncOpDone(scp, bufferp,
6341 CM_SCACHESYNC_NEEDCALLBACK
6342 | CM_SCACHESYNC_WRITE
6343 | CM_SCACHESYNC_BUFLOCKED);
6345 /* If we're overwriting the entire buffer, or
6346 * if we're writing at or past EOF, mark the
6347 * buffer as current so we don't call
6348 * cm_GetBuffer. This skips the fetch from the
6349 * server in those cases where we're going to
6350 * obliterate all the data in the buffer anyway,
6351 * or in those cases where there is no useful
6352 * data at the server to start with.
6354 * Use minLength instead of scp->length, since
6355 * the latter has already been updated by this
6358 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6359 || LargeIntegerEqualTo(offset, bufferp->offset)
6360 && (count >= cm_data.buf_blockSize
6361 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6362 ConvertLongToLargeInteger(count)),
6364 if (count < cm_data.buf_blockSize
6365 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
6366 memset(bufferp->datap, 0,
6367 cm_data.buf_blockSize);
6368 bufferp->dataVersion = scp->dataVersion;
6371 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6373 /* otherwise, load the buffer and try again */
6374 lock_ReleaseMutex(&bufferp->mx);
6375 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6377 lock_ReleaseWrite(&scp->rw);
6378 lock_ObtainMutex(&bufferp->mx);
6379 lock_ObtainWrite(&scp->rw);
6383 lock_ReleaseMutex(&bufferp->mx);
6384 buf_Release(bufferp);
6388 } /* if (wrong buffer) ... */
6390 /* now we have the right buffer loaded. Copy out the
6391 * data from here to the user's buffer.
6393 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6395 /* and figure out how many bytes we want from this buffer */
6396 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6398 nbytes = count; /* don't go past end of request */
6400 /* now copy the data */
6401 memcpy(bufferp->datap + bufIndex, op, nbytes);
6402 buf_SetDirty(bufferp, bufIndex, nbytes);
6404 /* and record the last writer */
6405 if (bufferp->userp != userp) {
6408 cm_ReleaseUser(bufferp->userp);
6409 bufferp->userp = userp;
6412 /* adjust counters, pointers, etc. */
6416 thyper.LowPart = nbytes;
6417 thyper.HighPart = 0;
6418 offset = LargeIntegerAdd(thyper, offset);
6422 lock_ReleaseWrite(&scp->rw);
6425 lock_ReleaseMutex(&bufferp->mx);
6426 buf_Release(bufferp);
6429 lock_ObtainMutex(&fidp->mx);
6430 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6431 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6432 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6433 fidp->NTopen_dscp, fidp->NTopen_pathp,
6436 lock_ReleaseMutex(&fidp->mx);
6439 if (smb_AsyncStore > 0) {
6443 lock_ObtainWrite(&scp->rw);
6444 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6446 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6447 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6449 lock_ReleaseWrite(&scp->rw);
6450 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6451 writeBackOffset.HighPart,
6452 smb_AsyncStoreSize, 0, userp);
6453 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6456 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
6460 cm_ReleaseSCache(scp);
6463 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6464 fidp->fid, code, *writtenp);
6468 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6471 unsigned short count;
6473 unsigned short hint;
6474 long written = 0, total_written = 0;
6477 smb_t* smbp = (smb_t*) inp;
6480 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6482 int inDataBlockCount;
6484 fd = smb_GetSMBParm(inp, 0);
6485 count = smb_GetSMBParm(inp, 1);
6486 offset.HighPart = 0; /* too bad */
6487 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6488 hint = smb_GetSMBParm(inp, 4);
6490 op = smb_GetSMBData(inp, NULL);
6491 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6493 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6494 fd, offset.LowPart, count);
6496 fd = smb_ChainFID(fd, inp);
6497 fidp = smb_FindFID(vcp, fd, 0);
6499 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6500 return CM_ERROR_BADFD;
6503 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6504 smb_CloseFID(vcp, fidp, NULL, 0);
6505 smb_ReleaseFID(fidp);
6506 return CM_ERROR_NOSUCHFILE;
6509 lock_ObtainMutex(&fidp->mx);
6510 if (fidp->flags & SMB_FID_IOCTL) {
6511 lock_ReleaseMutex(&fidp->mx);
6512 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6513 smb_ReleaseFID(fidp);
6514 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6517 lock_ReleaseMutex(&fidp->mx);
6518 userp = smb_GetUserFromVCP(vcp, inp);
6522 LARGE_INTEGER LOffset;
6523 LARGE_INTEGER LLength;
6526 key = cm_GenerateKey(vcp->vcID, pid, fd);
6528 LOffset.HighPart = offset.HighPart;
6529 LOffset.LowPart = offset.LowPart;
6530 LLength.HighPart = 0;
6531 LLength.LowPart = count;
6533 lock_ObtainWrite(&fidp->scp->rw);
6534 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6535 lock_ReleaseWrite(&fidp->scp->rw);
6538 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6543 /* special case: 0 bytes transferred means truncate to this position */
6547 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6551 truncAttr.mask = CM_ATTRMASK_LENGTH;
6552 truncAttr.length.LowPart = offset.LowPart;
6553 truncAttr.length.HighPart = 0;
6554 lock_ObtainMutex(&fidp->mx);
6555 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6556 fidp->flags |= SMB_FID_LENGTHSETDONE;
6557 lock_ReleaseMutex(&fidp->mx);
6558 smb_SetSMBParm(outp, 0, 0 /* count */);
6559 smb_SetSMBDataLength(outp, 0);
6564 * Work around bug in NT client
6566 * When copying a file, the NT client should first copy the data,
6567 * then copy the last write time. But sometimes the NT client does
6568 * these in the wrong order, so the data copies would inadvertently
6569 * cause the last write time to be overwritten. We try to detect this,
6570 * and don't set client mod time if we think that would go against the
6573 lock_ObtainMutex(&fidp->mx);
6574 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6575 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6576 fidp->scp->clientModTime = time(NULL);
6578 lock_ReleaseMutex(&fidp->mx);
6581 while ( code == 0 && count > 0 ) {
6582 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6583 if (code == 0 && written == 0)
6584 code = CM_ERROR_PARTIALWRITE;
6586 offset = LargeIntegerAdd(offset,
6587 ConvertLongToLargeInteger(written));
6588 count -= (unsigned short)written;
6589 total_written += written;
6593 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6594 total_written, code);
6596 /* set the packet data length to 3 bytes for the data block header,
6597 * plus the size of the data.
6599 smb_SetSMBParm(outp, 0, total_written);
6600 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6601 smb_SetSMBParm(outp, 3, hint);
6602 smb_SetSMBDataLength(outp, 0);
6605 smb_ReleaseFID(fidp);
6606 cm_ReleaseUser(userp);
6611 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6612 NCB *ncbp, raw_write_cont_t *rwcp)
6621 fd = smb_GetSMBParm(inp, 0);
6622 fidp = smb_FindFID(vcp, fd, 0);
6624 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6625 smb_CloseFID(vcp, fidp, NULL, 0);
6626 smb_ReleaseFID(fidp);
6630 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6631 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6633 userp = smb_GetUserFromVCP(vcp, inp);
6636 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6638 if (rwcp->writeMode & 0x1) { /* synchronous */
6641 smb_FormatResponsePacket(vcp, inp, outp);
6642 op = (smb_t *) outp;
6643 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6644 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6645 smb_SetSMBDataLength(outp, 0);
6646 smb_SendPacket(vcp, outp);
6647 smb_FreePacket(outp);
6649 else { /* asynchronous */
6650 lock_ObtainMutex(&fidp->mx);
6651 fidp->raw_writers--;
6652 if (fidp->raw_writers == 0)
6653 thrd_SetEvent(fidp->raw_write_event);
6654 lock_ReleaseMutex(&fidp->mx);
6657 /* Give back raw buffer */
6658 lock_ObtainMutex(&smb_RawBufLock);
6659 *((char **)rawBuf) = smb_RawBufs;
6660 smb_RawBufs = rawBuf;
6661 lock_ReleaseMutex(&smb_RawBufLock);
6663 smb_ReleaseFID(fidp);
6664 cm_ReleaseUser(userp);
6667 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6672 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6675 long count, written = 0, total_written = 0;
6679 smb_t *smbp = (smb_t*) inp;
6683 unsigned short writeMode;
6685 fd = smb_GetSMBParm(inp, 0);
6686 totalCount = smb_GetSMBParm(inp, 1);
6687 count = smb_GetSMBParm(inp, 10);
6688 writeMode = smb_GetSMBParm(inp, 7);
6690 op = (char *) inp->data;
6691 op += smb_GetSMBParm(inp, 11);
6693 offset.HighPart = 0;
6694 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6696 if (*inp->wctp == 14) {
6697 /* we received a 64-bit file offset */
6698 #ifdef AFS_LARGEFILES
6699 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6701 if (LargeIntegerLessThanZero(offset)) {
6703 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6704 offset.HighPart, offset.LowPart);
6705 return CM_ERROR_BADSMB;
6708 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6710 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6711 return CM_ERROR_BADSMB;
6714 offset.HighPart = 0;
6717 offset.HighPart = 0; /* 32-bit file offset */
6721 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6722 fd, offset.HighPart, offset.LowPart, count);
6724 " WriteRaw WriteMode 0x%x",
6727 fd = smb_ChainFID(fd, inp);
6728 fidp = smb_FindFID(vcp, fd, 0);
6730 return CM_ERROR_BADFD;
6733 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6734 smb_CloseFID(vcp, fidp, NULL, 0);
6735 smb_ReleaseFID(fidp);
6736 return CM_ERROR_NOSUCHFILE;
6742 LARGE_INTEGER LOffset;
6743 LARGE_INTEGER LLength;
6746 key = cm_GenerateKey(vcp->vcID, pid, fd);
6748 LOffset.HighPart = offset.HighPart;
6749 LOffset.LowPart = offset.LowPart;
6750 LLength.HighPart = 0;
6751 LLength.LowPart = count;
6753 lock_ObtainWrite(&fidp->scp->rw);
6754 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6755 lock_ReleaseWrite(&fidp->scp->rw);
6758 smb_ReleaseFID(fidp);
6763 userp = smb_GetUserFromVCP(vcp, inp);
6766 * Work around bug in NT client
6768 * When copying a file, the NT client should first copy the data,
6769 * then copy the last write time. But sometimes the NT client does
6770 * these in the wrong order, so the data copies would inadvertently
6771 * cause the last write time to be overwritten. We try to detect this,
6772 * and don't set client mod time if we think that would go against the
6775 lock_ObtainMutex(&fidp->mx);
6776 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6777 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6778 fidp->scp->clientModTime = time(NULL);
6780 lock_ReleaseMutex(&fidp->mx);
6783 while ( code == 0 && count > 0 ) {
6784 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6785 if (code == 0 && written == 0)
6786 code = CM_ERROR_PARTIALWRITE;
6788 offset = LargeIntegerAdd(offset,
6789 ConvertLongToLargeInteger(written));
6792 total_written += written;
6796 /* Get a raw buffer */
6799 lock_ObtainMutex(&smb_RawBufLock);
6801 /* Get a raw buf, from head of list */
6802 rawBuf = smb_RawBufs;
6803 smb_RawBufs = *(char **)smb_RawBufs;
6806 code = CM_ERROR_USESTD;
6808 lock_ReleaseMutex(&smb_RawBufLock);
6811 /* Don't allow a premature Close */
6812 if (code == 0 && (writeMode & 1) == 0) {
6813 lock_ObtainMutex(&fidp->mx);
6814 fidp->raw_writers++;
6815 thrd_ResetEvent(fidp->raw_write_event);
6816 lock_ReleaseMutex(&fidp->mx);
6819 smb_ReleaseFID(fidp);
6820 cm_ReleaseUser(userp);
6823 smb_SetSMBParm(outp, 0, total_written);
6824 smb_SetSMBDataLength(outp, 0);
6825 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6830 offset = LargeIntegerAdd(offset,
6831 ConvertLongToLargeInteger(count));
6835 rwcp->offset.HighPart = offset.HighPart;
6836 rwcp->offset.LowPart = offset.LowPart;
6837 rwcp->count = totalCount - count;
6838 rwcp->writeMode = writeMode;
6839 rwcp->alreadyWritten = total_written;
6841 /* set the packet data length to 3 bytes for the data block header,
6842 * plus the size of the data.
6844 smb_SetSMBParm(outp, 0, 0xffff);
6845 smb_SetSMBDataLength(outp, 0);
6850 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6853 long count, finalCount;
6857 smb_t *smbp = (smb_t*) inp;
6862 fd = smb_GetSMBParm(inp, 0);
6863 count = smb_GetSMBParm(inp, 1);
6864 offset.HighPart = 0; /* too bad */
6865 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6867 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6868 fd, offset.LowPart, count);
6870 fd = smb_ChainFID(fd, inp);
6871 fidp = smb_FindFID(vcp, fd, 0);
6873 return CM_ERROR_BADFD;
6875 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6876 smb_CloseFID(vcp, fidp, NULL, 0);
6877 smb_ReleaseFID(fidp);
6878 return CM_ERROR_NOSUCHFILE;
6881 lock_ObtainMutex(&fidp->mx);
6882 if (fidp->flags & SMB_FID_IOCTL) {
6883 lock_ReleaseMutex(&fidp->mx);
6884 code = smb_IoctlRead(fidp, vcp, inp, outp);
6885 smb_ReleaseFID(fidp);
6888 lock_ReleaseMutex(&fidp->mx);
6891 LARGE_INTEGER LOffset, LLength;
6895 key = cm_GenerateKey(vcp->vcID, pid, fd);
6897 LOffset.HighPart = 0;
6898 LOffset.LowPart = offset.LowPart;
6899 LLength.HighPart = 0;
6900 LLength.LowPart = count;
6902 lock_ObtainWrite(&fidp->scp->rw);
6903 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6904 lock_ReleaseWrite(&fidp->scp->rw);
6907 smb_ReleaseFID(fidp);
6911 userp = smb_GetUserFromVCP(vcp, inp);
6913 /* remember this for final results */
6914 smb_SetSMBParm(outp, 0, count);
6915 smb_SetSMBParm(outp, 1, 0);
6916 smb_SetSMBParm(outp, 2, 0);
6917 smb_SetSMBParm(outp, 3, 0);
6918 smb_SetSMBParm(outp, 4, 0);
6920 /* set the packet data length to 3 bytes for the data block header,
6921 * plus the size of the data.
6923 smb_SetSMBDataLength(outp, count+3);
6925 /* get op ptr after putting in the parms, since otherwise we don't
6926 * know where the data really is.
6928 op = smb_GetSMBData(outp, NULL);
6930 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6931 *op++ = 1; /* data block marker */
6932 *op++ = (unsigned char) (count & 0xff);
6933 *op++ = (unsigned char) ((count >> 8) & 0xff);
6935 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6937 /* fix some things up */
6938 smb_SetSMBParm(outp, 0, finalCount);
6939 smb_SetSMBDataLength(outp, finalCount+3);
6941 smb_ReleaseFID(fidp);
6943 cm_ReleaseUser(userp);
6947 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6954 cm_scache_t *dscp; /* dir we're dealing with */
6955 cm_scache_t *scp; /* file we're creating */
6957 int initialModeBits;
6967 /* compute initial mode bits based on read-only flag in attributes */
6968 initialModeBits = 0777;
6970 tp = smb_GetSMBData(inp, NULL);
6971 pathp = smb_ParseASCIIBlock(tp, &tp);
6972 if (smb_StoreAnsiFilenames)
6973 OemToChar(pathp,pathp);
6975 if (strcmp(pathp, "\\") == 0)
6976 return CM_ERROR_EXISTS;
6978 spacep = inp->spacep;
6979 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6981 userp = smb_GetUserFromVCP(vcp, inp);
6983 caseFold = CM_FLAG_CASEFOLD;
6985 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6987 cm_ReleaseUser(userp);
6988 return CM_ERROR_NOSUCHPATH;
6991 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6992 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6993 userp, tidPathp, &req, &dscp);
6996 cm_ReleaseUser(userp);
7001 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7002 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7003 cm_ReleaseSCache(dscp);
7004 cm_ReleaseUser(userp);
7005 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7006 return CM_ERROR_PATH_NOT_COVERED;
7008 return CM_ERROR_BADSHARENAME;
7010 #endif /* DFS_SUPPORT */
7012 /* otherwise, scp points to the parent directory. Do a lookup, and
7013 * fail if we find it. Otherwise, we do the create.
7019 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7020 if (scp) cm_ReleaseSCache(scp);
7021 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7022 if (code == 0) code = CM_ERROR_EXISTS;
7023 cm_ReleaseSCache(dscp);
7024 cm_ReleaseUser(userp);
7028 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7029 setAttr.clientModTime = time(NULL);
7030 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7031 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7032 smb_NotifyChange(FILE_ACTION_ADDED,
7033 FILE_NOTIFY_CHANGE_DIR_NAME,
7034 dscp, lastNamep, NULL, TRUE);
7036 /* we don't need this any longer */
7037 cm_ReleaseSCache(dscp);
7040 /* something went wrong creating or truncating the file */
7041 cm_ReleaseUser(userp);
7045 /* otherwise we succeeded */
7046 smb_SetSMBDataLength(outp, 0);
7047 cm_ReleaseUser(userp);
7052 BOOL smb_IsLegalFilename(char *filename)
7055 * Find the longest substring of filename that does not contain
7056 * any of the chars in illegalChars. If that substring is less
7057 * than the length of the whole string, then one or more of the
7058 * illegal chars is in filename.
7060 if (strcspn(filename, illegalChars) < strlen(filename))
7066 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7074 cm_scache_t *dscp; /* dir we're dealing with */
7075 cm_scache_t *scp; /* file we're creating */
7077 int initialModeBits;
7085 int created = 0; /* the file was new */
7090 excl = (inp->inCom == 0x03)? 0 : 1;
7092 attributes = smb_GetSMBParm(inp, 0);
7093 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7095 /* compute initial mode bits based on read-only flag in attributes */
7096 initialModeBits = 0666;
7097 if (attributes & SMB_ATTR_READONLY)
7098 initialModeBits &= ~0222;
7100 tp = smb_GetSMBData(inp, NULL);
7101 pathp = smb_ParseASCIIBlock(tp, &tp);
7102 if (smb_StoreAnsiFilenames)
7103 OemToChar(pathp,pathp);
7105 spacep = inp->spacep;
7106 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7108 userp = smb_GetUserFromVCP(vcp, inp);
7110 caseFold = CM_FLAG_CASEFOLD;
7112 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7114 cm_ReleaseUser(userp);
7115 return CM_ERROR_NOSUCHPATH;
7117 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7118 userp, tidPathp, &req, &dscp);
7121 cm_ReleaseUser(userp);
7126 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7127 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7128 cm_ReleaseSCache(dscp);
7129 cm_ReleaseUser(userp);
7130 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7131 return CM_ERROR_PATH_NOT_COVERED;
7133 return CM_ERROR_BADSHARENAME;
7135 #endif /* DFS_SUPPORT */
7137 /* otherwise, scp points to the parent directory. Do a lookup, and
7138 * truncate the file if we find it, otherwise we create the file.
7145 if (!smb_IsLegalFilename(lastNamep))
7146 return CM_ERROR_BADNTFILENAME;
7148 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7149 #ifdef DEBUG_VERBOSE
7152 hexp = osi_HexifyString( lastNamep );
7153 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7158 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7159 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7160 cm_ReleaseSCache(dscp);
7161 cm_ReleaseUser(userp);
7165 /* if we get here, if code is 0, the file exists and is represented by
7166 * scp. Otherwise, we have to create it.
7170 /* oops, file shouldn't be there */
7171 cm_ReleaseSCache(dscp);
7172 cm_ReleaseSCache(scp);
7173 cm_ReleaseUser(userp);
7174 return CM_ERROR_EXISTS;
7177 setAttr.mask = CM_ATTRMASK_LENGTH;
7178 setAttr.length.LowPart = 0;
7179 setAttr.length.HighPart = 0;
7180 code = cm_SetAttr(scp, &setAttr, userp, &req);
7183 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7184 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7185 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7189 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7190 smb_NotifyChange(FILE_ACTION_ADDED,
7191 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7192 dscp, lastNamep, NULL, TRUE);
7193 } else if (!excl && code == CM_ERROR_EXISTS) {
7194 /* not an exclusive create, and someone else tried
7195 * creating it already, then we open it anyway. We
7196 * don't bother retrying after this, since if this next
7197 * fails, that means that the file was deleted after
7198 * we started this call.
7200 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7203 setAttr.mask = CM_ATTRMASK_LENGTH;
7204 setAttr.length.LowPart = 0;
7205 setAttr.length.HighPart = 0;
7206 code = cm_SetAttr(scp, &setAttr, userp, &req);
7211 /* we don't need this any longer */
7212 cm_ReleaseSCache(dscp);
7215 /* something went wrong creating or truncating the file */
7216 if (scp) cm_ReleaseSCache(scp);
7217 cm_ReleaseUser(userp);
7221 /* make sure we only open files */
7222 if (scp->fileType != CM_SCACHETYPE_FILE) {
7223 cm_ReleaseSCache(scp);
7224 cm_ReleaseUser(userp);
7225 return CM_ERROR_ISDIR;
7228 /* now all we have to do is open the file itself */
7229 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7230 osi_assertx(fidp, "null smb_fid_t");
7234 lock_ObtainMutex(&fidp->mx);
7235 /* always create it open for read/write */
7236 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7238 /* remember that the file was newly created */
7240 fidp->flags |= SMB_FID_CREATED;
7242 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7244 /* save a pointer to the vnode */
7246 lock_ObtainWrite(&scp->rw);
7247 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7248 lock_ReleaseWrite(&scp->rw);
7251 fidp->userp = userp;
7252 lock_ReleaseMutex(&fidp->mx);
7254 smb_SetSMBParm(outp, 0, fidp->fid);
7255 smb_SetSMBDataLength(outp, 0);
7257 cm_Open(scp, 0, userp);
7259 smb_ReleaseFID(fidp);
7260 cm_ReleaseUser(userp);
7261 /* leave scp held since we put it in fidp->scp */
7265 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7268 osi_hyper_t new_offset;
7279 fd = smb_GetSMBParm(inp, 0);
7280 whence = smb_GetSMBParm(inp, 1);
7281 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7283 /* try to find the file descriptor */
7284 fd = smb_ChainFID(fd, inp);
7285 fidp = smb_FindFID(vcp, fd, 0);
7287 return CM_ERROR_BADFD;
7289 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7290 smb_CloseFID(vcp, fidp, NULL, 0);
7291 smb_ReleaseFID(fidp);
7292 return CM_ERROR_NOSUCHFILE;
7295 lock_ObtainMutex(&fidp->mx);
7296 if (fidp->flags & SMB_FID_IOCTL) {
7297 lock_ReleaseMutex(&fidp->mx);
7298 smb_ReleaseFID(fidp);
7299 return CM_ERROR_BADFD;
7301 lock_ReleaseMutex(&fidp->mx);
7303 userp = smb_GetUserFromVCP(vcp, inp);
7305 lock_ObtainMutex(&fidp->mx);
7308 lock_ReleaseMutex(&fidp->mx);
7309 lock_ObtainWrite(&scp->rw);
7310 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7311 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7313 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7315 /* offset from current offset */
7316 new_offset = LargeIntegerAdd(fidp->offset,
7317 ConvertLongToLargeInteger(offset));
7319 else if (whence == 2) {
7320 /* offset from current EOF */
7321 new_offset = LargeIntegerAdd(scp->length,
7322 ConvertLongToLargeInteger(offset));
7324 new_offset = ConvertLongToLargeInteger(offset);
7327 fidp->offset = new_offset;
7328 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7329 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7330 smb_SetSMBDataLength(outp, 0);
7332 lock_ReleaseWrite(&scp->rw);
7333 smb_ReleaseFID(fidp);
7334 cm_ReleaseSCache(scp);
7335 cm_ReleaseUser(userp);
7339 /* dispatch all of the requests received in a packet. Due to chaining, this may
7340 * be more than one request.
7342 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7343 NCB *ncbp, raw_write_cont_t *rwcp)
7347 unsigned long code = 0;
7348 unsigned char *outWctp;
7349 int nparms; /* # of bytes of parameters */
7351 int nbytes; /* bytes of data, excluding count */
7354 unsigned short errCode;
7355 unsigned long NTStatus;
7357 unsigned char errClass;
7358 unsigned int oldGen;
7359 DWORD oldTime, newTime;
7361 /* get easy pointer to the data */
7362 smbp = (smb_t *) inp->data;
7364 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7365 /* setup the basic parms for the initial request in the packet */
7366 inp->inCom = smbp->com;
7367 inp->wctp = &smbp->wct;
7369 inp->ncb_length = ncbp->ncb_length;
7374 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7375 /* log it and discard it */
7376 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7377 __FILE__, __LINE__, ncbp->ncb_length);
7378 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7382 /* We are an ongoing op */
7383 thrd_Increment(&ongoingOps);
7385 /* set up response packet for receiving output */
7386 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7387 smb_FormatResponsePacket(vcp, inp, outp);
7388 outWctp = outp->wctp;
7390 /* Remember session generation number and time */
7391 oldGen = sessionGen;
7392 oldTime = GetTickCount();
7394 while (inp->inCom != 0xff) {
7395 dp = &smb_dispatchTable[inp->inCom];
7397 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7398 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7399 code = outp->resumeCode;
7403 /* process each request in the packet; inCom, wctp and inCount
7404 * are already set up.
7406 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7409 /* now do the dispatch */
7410 /* start by formatting the response record a little, as a default */
7411 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7413 outWctp[1] = 0xff; /* no operation */
7414 outWctp[2] = 0; /* padding */
7419 /* not a chained request, this is a more reasonable default */
7420 outWctp[0] = 0; /* wct of zero */
7421 outWctp[1] = 0; /* and bcc (word) of zero */
7425 /* once set, stays set. Doesn't matter, since we never chain
7426 * "no response" calls.
7428 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7432 /* we have a recognized operation */
7433 char * opName = myCrt_Dispatch(inp->inCom);
7435 if (inp->inCom == 0x1d)
7437 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7439 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",opName,vcp,vcp->lana,vcp->lsn);
7440 code = (*(dp->procp)) (vcp, inp, outp);
7441 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7443 if ( code == CM_ERROR_BADSMB ||
7444 code == CM_ERROR_BADOP )
7446 #endif /* LOG_PACKET */
7449 newTime = GetTickCount();
7450 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
7452 if (oldGen != sessionGen) {
7453 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7454 newTime - oldTime, ncbp->ncb_length);
7455 osi_Log3(smb_logp, "Request %s straddled session startup, "
7456 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
7460 /* bad opcode, fail the request, after displaying it */
7461 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7464 #endif /* LOG_PACKET */
7467 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7468 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7469 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7470 if (code == IDCANCEL)
7473 code = CM_ERROR_BADOP;
7476 /* catastrophic failure: log as much as possible */
7477 if (code == CM_ERROR_BADSMB) {
7478 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7482 #endif /* LOG_PACKET */
7483 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7486 code = CM_ERROR_INVAL;
7489 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7490 thrd_Decrement(&ongoingOps);
7495 /* now, if we failed, turn the current response into an empty
7496 * one, and fill in the response packet's error code.
7499 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7500 smb_MapNTError(code, &NTStatus);
7501 outWctp = outp->wctp;
7502 smbp = (smb_t *) &outp->data;
7503 if (code != CM_ERROR_PARTIALWRITE
7504 && code != CM_ERROR_BUFFERTOOSMALL
7505 && code != CM_ERROR_GSSCONTINUE) {
7506 /* nuke wct and bcc. For a partial
7507 * write or an in-process authentication handshake,
7508 * assume they're OK.
7514 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7515 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7516 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7517 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7518 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7522 smb_MapCoreError(code, vcp, &errCode, &errClass);
7523 outWctp = outp->wctp;
7524 smbp = (smb_t *) &outp->data;
7525 if (code != CM_ERROR_PARTIALWRITE) {
7526 /* nuke wct and bcc. For a partial
7527 * write, assume they're OK.
7533 smbp->errLow = (unsigned char) (errCode & 0xff);
7534 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7535 smbp->rcls = errClass;
7538 } /* error occurred */
7540 /* if we're here, we've finished one request. Look to see if
7541 * this is a chained opcode. If it is, setup things to process
7542 * the chained request, and setup the output buffer to hold the
7543 * chained response. Start by finding the next input record.
7545 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7546 break; /* not a chained req */
7547 tp = inp->wctp; /* points to start of last request */
7548 /* in a chained request, the first two
7549 * parm fields are required, and are
7550 * AndXCommand/AndXReserved and
7552 if (tp[0] < 2) break;
7553 if (tp[1] == 0xff) break; /* no more chained opcodes */
7555 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7558 /* and now append the next output request to the end of this
7559 * last request. Begin by finding out where the last response
7560 * ends, since that's where we'll put our new response.
7562 outWctp = outp->wctp; /* ptr to out parameters */
7563 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7564 nparms = outWctp[0] << 1;
7565 tp = outWctp + nparms + 1; /* now points to bcc field */
7566 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7567 tp += 2 /* for the count itself */ + nbytes;
7568 /* tp now points to the new output record; go back and patch the
7569 * second parameter (off2) to point to the new record.
7571 temp = (unsigned int)(tp - outp->data);
7572 outWctp[3] = (unsigned char) (temp & 0xff);
7573 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7574 outWctp[2] = 0; /* padding */
7575 outWctp[1] = inp->inCom; /* next opcode */
7577 /* finally, setup for the next iteration */
7580 } /* while loop over all requests in the packet */
7582 /* now send the output packet, and return */
7584 smb_SendPacket(vcp, outp);
7585 thrd_Decrement(&ongoingOps);
7590 /* Wait for Netbios() calls to return, and make the results available to server
7591 * threads. Note that server threads can't wait on the NCBevents array
7592 * themselves, because NCB events are manual-reset, and the servers would race
7593 * each other to reset them.
7595 void smb_ClientWaiter(void *parmp)
7600 while (smbShutdownFlag == 0) {
7601 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7603 if (code == WAIT_OBJECT_0)
7606 /* error checking */
7607 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7609 int abandonIdx = code - WAIT_ABANDONED_0;
7610 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7613 if (code == WAIT_IO_COMPLETION)
7615 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7619 if (code == WAIT_TIMEOUT)
7621 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7624 if (code == WAIT_FAILED)
7626 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7629 idx = code - WAIT_OBJECT_0;
7631 /* check idx range! */
7632 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7634 /* this is fatal - log as much as possible */
7635 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7636 osi_assertx(0, "invalid index");
7639 thrd_ResetEvent(NCBevents[idx]);
7640 thrd_SetEvent(NCBreturns[0][idx]);
7645 * Try to have one NCBRECV request waiting for every live session. Not more
7646 * than one, because if there is more than one, it's hard to handle Write Raw.
7648 void smb_ServerWaiter(void *parmp)
7651 int idx_session, idx_NCB;
7654 while (smbShutdownFlag == 0) {
7656 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7658 if (code == WAIT_OBJECT_0)
7661 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7663 int abandonIdx = code - WAIT_ABANDONED_0;
7664 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7667 if (code == WAIT_IO_COMPLETION)
7669 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7673 if (code == WAIT_TIMEOUT)
7675 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7678 if (code == WAIT_FAILED)
7680 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7683 idx_session = code - WAIT_OBJECT_0;
7685 /* check idx range! */
7686 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7688 /* this is fatal - log as much as possible */
7689 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7690 osi_assertx(0, "invalid index");
7695 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7697 if (code == WAIT_OBJECT_0) {
7698 if (smbShutdownFlag == 1)
7704 /* error checking */
7705 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7707 int abandonIdx = code - WAIT_ABANDONED_0;
7708 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7711 if (code == WAIT_IO_COMPLETION)
7713 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7717 if (code == WAIT_TIMEOUT)
7719 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7722 if (code == WAIT_FAILED)
7724 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7727 idx_NCB = code - WAIT_OBJECT_0;
7729 /* check idx range! */
7730 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7732 /* this is fatal - log as much as possible */
7733 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7734 osi_assertx(0, "invalid index");
7737 /* Link them together */
7738 NCBsessions[idx_NCB] = idx_session;
7741 ncbp = NCBs[idx_NCB];
7742 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7743 ncbp->ncb_command = NCBRECV | ASYNCH;
7744 ncbp->ncb_lana_num = lanas[idx_session];
7745 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7746 ncbp->ncb_event = NCBevents[idx_NCB];
7747 ncbp->ncb_length = SMB_PACKETSIZE;
7753 * The top level loop for handling SMB request messages. Each server thread
7754 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7755 * NCB and buffer for the incoming request are loaned to us.
7757 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7758 * to immediately send a request for the rest of the data. This must come
7759 * before any other traffic for that session, so we delay setting the session
7760 * event until that data has come in.
7762 void smb_Server(VOID *parmp)
7764 INT_PTR myIdx = (INT_PTR) parmp;
7768 smb_packet_t *outbufp;
7770 int idx_NCB, idx_session;
7772 smb_vc_t *vcp = NULL;
7775 rx_StartClientThread();
7778 outbufp = GetPacket();
7779 outbufp->ncbp = outncbp;
7787 smb_ResetServerPriority();
7789 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7792 /* terminate silently if shutdown flag is set */
7793 if (code == WAIT_OBJECT_0) {
7794 if (smbShutdownFlag == 1) {
7795 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7801 /* error checking */
7802 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7804 int abandonIdx = code - WAIT_ABANDONED_0;
7805 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7808 if (code == WAIT_IO_COMPLETION)
7810 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7814 if (code == WAIT_TIMEOUT)
7816 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7819 if (code == WAIT_FAILED)
7821 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7824 idx_NCB = code - WAIT_OBJECT_0;
7826 /* check idx range! */
7827 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7829 /* this is fatal - log as much as possible */
7830 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7831 osi_assertx(0, "invalid index");
7834 ncbp = NCBs[idx_NCB];
7835 idx_session = NCBsessions[idx_NCB];
7836 rc = ncbp->ncb_retcode;
7838 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7839 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7843 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7847 /* Can this happen? Or is it just my UNIX paranoia? */
7848 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7853 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7856 /* Client closed session */
7857 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7859 lock_ObtainMutex(&vcp->mx);
7860 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7861 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7863 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7864 lock_ReleaseMutex(&vcp->mx);
7865 lock_ObtainWrite(&smb_globalLock);
7866 dead_sessions[vcp->session] = TRUE;
7867 lock_ReleaseWrite(&smb_globalLock);
7868 smb_CleanupDeadVC(vcp);
7872 lock_ReleaseMutex(&vcp->mx);
7878 /* Treat as transient error */
7879 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7882 "dispatch smb recv failed, message incomplete, ncb_length %d",
7885 "SMB message incomplete, "
7886 "length %d", ncbp->ncb_length);
7889 * We used to discard the packet.
7890 * Instead, try handling it normally.
7894 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7898 /* A weird error code. Log it, sleep, and continue. */
7899 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7901 lock_ObtainMutex(&vcp->mx);
7902 if (vcp && vcp->errorCount++ > 3) {
7903 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7904 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7905 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7907 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7908 lock_ReleaseMutex(&vcp->mx);
7909 lock_ObtainWrite(&smb_globalLock);
7910 dead_sessions[vcp->session] = TRUE;
7911 lock_ReleaseWrite(&smb_globalLock);
7912 smb_CleanupDeadVC(vcp);
7916 lock_ReleaseMutex(&vcp->mx);
7922 lock_ReleaseMutex(&vcp->mx);
7924 thrd_SetEvent(SessionEvents[idx_session]);
7929 /* Success, so now dispatch on all the data in the packet */
7931 smb_concurrentCalls++;
7932 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7933 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7936 * If at this point vcp is NULL (implies that packet was invalid)
7937 * then we are in big trouble. This means either :
7938 * a) we have the wrong NCB.
7939 * b) Netbios screwed up the call.
7940 * c) The VC was already marked dead before we were able to
7942 * Obviously this implies that
7943 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7944 * lanas[idx_session] != ncbp->ncb_lana_num )
7945 * Either way, we can't do anything with this packet.
7946 * Log, sleep and resume.
7949 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7953 ncbp->ncb_lana_num);
7955 /* Also log in the trace log. */
7956 osi_Log4(smb_logp, "Server: VCP does not exist!"
7957 "LSNs[idx_session]=[%d],"
7958 "lanas[idx_session]=[%d],"
7959 "ncbp->ncb_lsn=[%d],"
7960 "ncbp->ncb_lana_num=[%d]",
7964 ncbp->ncb_lana_num);
7966 /* thrd_Sleep(1000); Don't bother sleeping */
7967 thrd_SetEvent(SessionEvents[idx_session]);
7968 smb_concurrentCalls--;
7972 smb_SetRequestStartTime();
7974 vcp->errorCount = 0;
7975 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7976 smbp = (smb_t *)bufp->data;
7981 if (smbp->com == 0x1d) {
7982 /* Special handling for Write Raw */
7983 raw_write_cont_t rwc;
7984 EVENT_HANDLE rwevent;
7985 char eventName[MAX_PATH];
7987 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7988 if (rwc.code == 0) {
7989 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7990 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7991 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7992 ncbp->ncb_command = NCBRECV | ASYNCH;
7993 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7994 ncbp->ncb_lana_num = vcp->lana;
7995 ncbp->ncb_buffer = rwc.buf;
7996 ncbp->ncb_length = 65535;
7997 ncbp->ncb_event = rwevent;
7999 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8000 thrd_CloseHandle(rwevent);
8002 thrd_SetEvent(SessionEvents[idx_session]);
8004 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8006 else if (smbp->com == 0xa0) {
8008 * Serialize the handling for NT Transact
8011 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8012 thrd_SetEvent(SessionEvents[idx_session]);
8014 thrd_SetEvent(SessionEvents[idx_session]);
8015 /* TODO: what else needs to be serialized? */
8016 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8019 __except( smb_ServerExceptionFilter() ) {
8022 smb_concurrentCalls--;
8025 thrd_SetEvent(NCBavails[idx_NCB]);
8032 * Exception filter for the server threads. If an exception occurs in the
8033 * dispatch routines, which is where exceptions are most common, then do a
8034 * force trace and give control to upstream exception handlers. Useful for
8037 DWORD smb_ServerExceptionFilter(void) {
8038 /* While this is not the best time to do a trace, if it succeeds, then
8039 * we have a trace (assuming tracing was enabled). Otherwise, this should
8040 * throw a second exception.
8042 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8043 afsd_ForceTrace(TRUE);
8044 buf_ForceTrace(TRUE);
8045 return EXCEPTION_CONTINUE_SEARCH;
8049 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8050 * If the number of server threads is M, and the number of live sessions is
8051 * N, then the number of NCB's in use at any time either waiting for, or
8052 * holding, received messages is M + N, so that is how many NCB's get created.
8054 void InitNCBslot(int idx)
8056 struct smb_packet *bufp;
8057 EVENT_HANDLE retHandle;
8059 char eventName[MAX_PATH];
8061 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8063 NCBs[idx] = GetNCB();
8064 sprintf(eventName,"NCBavails[%d]", idx);
8065 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8066 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8067 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8068 sprintf(eventName,"NCBevents[%d]", idx);
8069 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8070 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8071 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8072 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8073 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8074 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8075 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8076 for (i=0; i<smb_NumServerThreads; i++)
8077 NCBreturns[i][idx] = retHandle;
8079 bufp->spacep = cm_GetSpace();
8083 /* listen for new connections */
8084 void smb_Listener(void *parmp)
8090 afs_uint32 session, thread;
8091 smb_vc_t *vcp = NULL;
8093 char rname[NCBNAMSZ+1];
8094 char cname[MAX_COMPUTERNAME_LENGTH+1];
8095 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8096 INT_PTR lana = (INT_PTR) parmp;
8097 char eventName[MAX_PATH];
8099 sprintf(eventName,"smb_Listener_lana_%d", (char)lana);
8100 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8101 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8102 thrd_ResetEvent(ListenerShutdown[lana]);
8106 /* retrieve computer name */
8107 GetComputerName(cname, &cnamelen);
8110 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8111 memset(ncbp, 0, sizeof(NCB));
8114 ncbp->ncb_command = NCBLISTEN;
8115 ncbp->ncb_rto = 0; /* No receive timeout */
8116 ncbp->ncb_sto = 0; /* No send timeout */
8118 /* pad out with spaces instead of null termination */
8119 len = (long)strlen(smb_localNamep);
8120 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8121 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8123 strcpy(ncbp->ncb_callname, "*");
8124 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8126 ncbp->ncb_lana_num = (UCHAR)lana;
8128 code = Netbios(ncbp);
8130 if (code == NRC_NAMERR) {
8131 /* An smb shutdown or Vista resume must have taken place */
8133 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8134 ncbp->ncb_lana_num, code);
8136 if (lock_TryMutex(&smb_StartedLock)) {
8137 lana_list.lana[i] = LANA_INVALID;
8138 lock_ReleaseMutex(&smb_StartedLock);
8141 } else if (code == NRC_BRIDGE || code != 0) {
8142 int lanaRemaining = 0;
8144 while (!lock_TryMutex(&smb_StartedLock)) {
8145 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8151 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8152 ncbp->ncb_lana_num, ncb_error_string(code));
8154 for (i = 0; i < lana_list.length; i++) {
8155 if (lana_list.lana[i] == lana) {
8156 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8157 lana_list.lana[i] = LANA_INVALID;
8159 if (lana_list.lana[i] != LANA_INVALID)
8163 if (lanaRemaining == 0) {
8164 cm_VolStatus_Network_Stopped(cm_NetbiosName
8169 smb_ListenerState = SMB_LISTENER_STOPPED;
8170 smb_LANadapter = LANA_INVALID;
8171 lana_list.length = 0;
8173 lock_ReleaseMutex(&smb_StartedLock);
8177 else if (code != 0) {
8178 char tbuffer[AFSPATHMAX];
8180 /* terminate silently if shutdown flag is set */
8181 while (!lock_TryMutex(&smb_StartedLock)) {
8182 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8188 "NCBLISTEN lana=%d failed with code %d [%s]",
8189 ncbp->ncb_lana_num, code, ncb_error_string(code));
8191 "Client exiting due to network failure. Please restart client.\n");
8194 "Client exiting due to network failure. Please restart client.\n"
8195 "NCBLISTEN lana=%d failed with code %d [%s]",
8196 ncbp->ncb_lana_num, code, ncb_error_string(code));
8198 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8199 MB_OK|MB_SERVICE_NOTIFICATION);
8200 osi_panic(tbuffer, __FILE__, __LINE__);
8202 lock_ReleaseMutex(&smb_StartedLock);
8207 /* check for remote conns */
8208 /* first get remote name and insert null terminator */
8209 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8210 for (i=NCBNAMSZ; i>0; i--) {
8211 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8217 /* compare with local name */
8219 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8220 flags |= SMB_VCFLAG_REMOTECONN;
8223 lock_ObtainMutex(&smb_ListenerLock);
8225 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8226 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8228 /* now ncbp->ncb_lsn is the connection ID */
8229 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8230 if (vcp->session == 0) {
8231 /* New generation */
8232 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8235 /* Log session startup */
8237 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8238 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8239 #endif /* NOTSERVICE */
8240 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8241 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8243 if (reportSessionStartups) {
8244 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8247 lock_ObtainMutex(&vcp->mx);
8248 strcpy(vcp->rname, rname);
8249 vcp->flags |= flags;
8250 lock_ReleaseMutex(&vcp->mx);
8252 /* Allocate slot in session arrays */
8253 /* Re-use dead session if possible, otherwise add one more */
8254 /* But don't look at session[0], it is reserved */
8255 lock_ObtainWrite(&smb_globalLock);
8256 for (session = 1; session < numSessions; session++) {
8257 if (dead_sessions[session]) {
8258 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8259 dead_sessions[session] = FALSE;
8263 lock_ReleaseWrite(&smb_globalLock);
8265 /* We are re-using an existing VC because the lsn and lana
8267 session = vcp->session;
8269 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8271 /* Log session startup */
8273 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8274 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8275 #endif /* NOTSERVICE */
8276 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8277 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8279 if (reportSessionStartups) {
8280 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8284 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8285 unsigned long code = CM_ERROR_ALLBUSY;
8286 smb_packet_t * outp = GetPacket();
8287 unsigned char *outWctp;
8290 smb_FormatResponsePacket(vcp, NULL, outp);
8293 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8294 unsigned long NTStatus;
8295 smb_MapNTError(code, &NTStatus);
8296 outWctp = outp->wctp;
8297 smbp = (smb_t *) &outp->data;
8301 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8302 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8303 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8304 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8305 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8307 unsigned short errCode;
8308 unsigned char errClass;
8309 smb_MapCoreError(code, vcp, &errCode, &errClass);
8310 outWctp = outp->wctp;
8311 smbp = (smb_t *) &outp->data;
8315 smbp->errLow = (unsigned char) (errCode & 0xff);
8316 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8317 smbp->rcls = errClass;
8319 smb_SendPacket(vcp, outp);
8320 smb_FreePacket(outp);
8322 lock_ObtainMutex(&vcp->mx);
8323 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8324 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8326 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8327 lock_ReleaseMutex(&vcp->mx);
8328 lock_ObtainWrite(&smb_globalLock);
8329 dead_sessions[vcp->session] = TRUE;
8330 lock_ReleaseWrite(&smb_globalLock);
8331 smb_CleanupDeadVC(vcp);
8333 lock_ReleaseMutex(&vcp->mx);
8336 /* assert that we do not exceed the maximum number of sessions or NCBs.
8337 * we should probably want to wait for a session to be freed in case
8340 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8341 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8343 lock_ObtainMutex(&vcp->mx);
8344 vcp->session = session;
8345 lock_ReleaseMutex(&vcp->mx);
8346 lock_ObtainWrite(&smb_globalLock);
8347 LSNs[session] = ncbp->ncb_lsn;
8348 lanas[session] = ncbp->ncb_lana_num;
8349 lock_ReleaseWrite(&smb_globalLock);
8351 if (session == numSessions) {
8352 /* Add new NCB for new session */
8353 char eventName[MAX_PATH];
8355 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8357 InitNCBslot(numNCBs);
8358 lock_ObtainWrite(&smb_globalLock);
8360 lock_ReleaseWrite(&smb_globalLock);
8361 thrd_SetEvent(NCBavails[0]);
8362 thrd_SetEvent(NCBevents[0]);
8363 for (thread = 0; thread < smb_NumServerThreads; thread++)
8364 thrd_SetEvent(NCBreturns[thread][0]);
8365 /* Also add new session event */
8366 sprintf(eventName, "SessionEvents[%d]", session);
8367 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8368 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8369 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8370 lock_ObtainWrite(&smb_globalLock);
8372 lock_ReleaseWrite(&smb_globalLock);
8373 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8374 thrd_SetEvent(SessionEvents[0]);
8376 thrd_SetEvent(SessionEvents[session]);
8382 lock_ReleaseMutex(&smb_ListenerLock);
8383 } /* dispatch while loop */
8387 thrd_SetEvent(ListenerShutdown[lana]);
8392 smb_LanAdapterChangeThread(void *param)
8395 * Give the IPAddrDaemon thread a chance
8396 * to block before we trigger.
8399 smb_LanAdapterChange(0);
8402 void smb_SetLanAdapterChangeDetected(void)
8407 lock_ObtainMutex(&smb_StartedLock);
8409 if (!powerStateSuspended) {
8410 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
8411 NULL, 0, &lpid, "smb_LanAdapterChange");
8412 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
8413 thrd_CloseHandle(phandle);
8416 smb_LanAdapterChangeDetected = 1;
8417 lock_ReleaseMutex(&smb_StartedLock);
8420 void smb_LanAdapterChange(int locked) {
8421 lana_number_t lanaNum;
8423 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
8425 LANA_ENUM temp_list;
8430 afsi_log("smb_LanAdapterChange");
8433 lock_ObtainMutex(&smb_StartedLock);
8435 smb_LanAdapterChangeDetected = 0;
8437 if (!powerStateSuspended &&
8438 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
8439 LANA_NETBIOS_NAME_FULL)) &&
8440 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
8441 if ( isGateway != bGateway ||
8442 strcmp(cm_NetbiosName, NetbiosName) ) {
8445 NCB *ncbp = GetNCB();
8446 ncbp->ncb_command = NCBENUM;
8447 ncbp->ncb_buffer = (PUCHAR)&temp_list;
8448 ncbp->ncb_length = sizeof(temp_list);
8449 code = Netbios(ncbp);
8451 if (temp_list.length != lana_list.length)
8454 for (i=0; i<lana_list.length; i++) {
8455 if ( temp_list.lana[i] != lana_list.lana[i] ) {
8467 afsi_log("Lan Adapter Change detected");
8468 smb_StopListeners(1);
8469 smb_RestartListeners(1);
8472 lock_ReleaseMutex(&smb_StartedLock);
8475 /* initialize Netbios */
8476 int smb_NetbiosInit(int locked)
8479 int i, lana, code, l;
8481 int delname_tried=0;
8484 lana_number_t lanaNum;
8487 lock_ObtainMutex(&smb_StartedLock);
8489 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
8490 smb_ListenerState != SMB_LISTENER_STOPPED) {
8493 lock_ReleaseMutex(&smb_StartedLock);
8496 /* setup the NCB system */
8499 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8500 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8501 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8503 if (smb_LANadapter != LANA_INVALID)
8504 afsi_log("LAN adapter number %d", smb_LANadapter);
8506 afsi_log("LAN adapter number not determined");
8509 afsi_log("Set for gateway service");
8511 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8513 /* something went horribly wrong. We can't proceed without a netbios name */
8515 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8516 osi_panic(buf, __FILE__, __LINE__);
8519 /* remember the name */
8520 len = (int)strlen(cm_NetbiosName);
8522 free(smb_localNamep);
8523 smb_localNamep = malloc(len+1);
8524 strcpy(smb_localNamep, cm_NetbiosName);
8525 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8528 if (smb_LANadapter == LANA_INVALID) {
8529 ncbp->ncb_command = NCBENUM;
8530 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8531 ncbp->ncb_length = sizeof(lana_list);
8532 code = Netbios(ncbp);
8534 afsi_log("Netbios NCBENUM error code %d", code);
8535 osi_panic(s, __FILE__, __LINE__);
8539 lana_list.length = 1;
8540 lana_list.lana[0] = smb_LANadapter;
8543 for (i = 0; i < lana_list.length; i++) {
8544 /* reset the adaptor: in Win32, this is required for every process, and
8545 * acts as an init call, not as a real hardware reset.
8547 ncbp->ncb_command = NCBRESET;
8548 ncbp->ncb_callname[0] = 100;
8549 ncbp->ncb_callname[2] = 100;
8550 ncbp->ncb_lana_num = lana_list.lana[i];
8551 code = Netbios(ncbp);
8553 code = ncbp->ncb_retcode;
8555 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8556 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
8558 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8562 /* and declare our name so we can receive connections */
8563 memset(ncbp, 0, sizeof(*ncbp));
8564 len=lstrlen(smb_localNamep);
8565 memset(smb_sharename,' ',NCBNAMSZ);
8566 memcpy(smb_sharename,smb_localNamep,len);
8567 afsi_log("lana_list.length %d", lana_list.length);
8569 /* Keep the name so we can unregister it later */
8570 for (l = 0; l < lana_list.length; l++) {
8571 lana = lana_list.lana[l];
8573 ncbp->ncb_command = NCBADDNAME;
8574 ncbp->ncb_lana_num = lana;
8575 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8576 code = Netbios(ncbp);
8578 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8579 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8581 char name[NCBNAMSZ+1];
8583 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8584 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8588 code = ncbp->ncb_retcode;
8591 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8594 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8595 if (code == NRC_BRIDGE) { /* invalid LANA num */
8596 lana_list.lana[l] = LANA_INVALID;
8599 else if (code == NRC_DUPNAME) {
8600 afsi_log("Name already exists; try to delete it");
8601 memset(ncbp, 0, sizeof(*ncbp));
8602 ncbp->ncb_command = NCBDELNAME;
8603 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8604 ncbp->ncb_lana_num = lana;
8605 code = Netbios(ncbp);
8607 code = ncbp->ncb_retcode;
8609 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8611 if (code != 0 || delname_tried) {
8612 lana_list.lana[l] = LANA_INVALID;
8614 else if (code == 0) {
8615 if (!delname_tried) {
8623 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8624 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8628 smb_LANadapter = lana;
8629 lana_found = 1; /* at least one worked */
8633 osi_assertx(lana_list.length >= 0, "empty lana list");
8635 afsi_log("No valid LANA numbers found!");
8636 lana_list.length = 0;
8637 smb_LANadapter = LANA_INVALID;
8638 smb_ListenerState = SMB_LISTENER_STOPPED;
8639 cm_VolStatus_Network_Stopped(cm_NetbiosName
8646 /* we're done with the NCB now */
8649 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
8650 if (lana_list.length > 0)
8651 osi_assert(smb_LANadapter != LANA_INVALID);
8654 lock_ReleaseMutex(&smb_StartedLock);
8656 return (lana_list.length > 0 ? 1 : 0);
8659 void smb_StartListeners(int locked)
8666 lock_ObtainMutex(&smb_StartedLock);
8668 if (smb_ListenerState == SMB_LISTENER_STARTED) {
8670 lock_ReleaseMutex(&smb_StartedLock);
8674 afsi_log("smb_StartListeners");
8675 smb_ListenerState = SMB_LISTENER_STARTED;
8676 cm_VolStatus_Network_Started(cm_NetbiosName
8682 for (i = 0; i < lana_list.length; i++) {
8683 if (lana_list.lana[i] == LANA_INVALID)
8685 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8686 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8687 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
8688 thrd_CloseHandle(phandle);
8691 lock_ReleaseMutex(&smb_StartedLock);
8694 void smb_RestartListeners(int locked)
8697 lock_ObtainMutex(&smb_StartedLock);
8699 if (powerStateSuspended)
8700 afsi_log("smb_RestartListeners called while suspended");
8702 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
8703 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8704 if (smb_NetbiosInit(1))
8705 smb_StartListeners(1);
8706 } else if (smb_LanAdapterChangeDetected) {
8707 smb_LanAdapterChange(1);
8711 lock_ReleaseMutex(&smb_StartedLock);
8714 void smb_StopListener(NCB *ncbp, int lana, int wait)
8718 memset(ncbp, 0, sizeof(*ncbp));
8719 ncbp->ncb_command = NCBDELNAME;
8720 ncbp->ncb_lana_num = lana;
8721 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8722 code = Netbios(ncbp);
8724 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8725 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8727 /* and then reset the LANA; this will cause the listener threads to exit */
8728 ncbp->ncb_command = NCBRESET;
8729 ncbp->ncb_callname[0] = 100;
8730 ncbp->ncb_callname[2] = 100;
8731 ncbp->ncb_lana_num = lana;
8732 code = Netbios(ncbp);
8734 code = ncbp->ncb_retcode;
8736 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8738 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8742 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
8745 void smb_StopListeners(int locked)
8751 lock_ObtainMutex(&smb_StartedLock);
8753 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8755 lock_ReleaseMutex(&smb_StartedLock);
8759 afsi_log("smb_StopListeners");
8760 smb_ListenerState = SMB_LISTENER_STOPPED;
8761 cm_VolStatus_Network_Stopped(cm_NetbiosName
8769 /* Unregister the SMB name */
8770 for (l = 0; l < lana_list.length; l++) {
8771 lana = lana_list.lana[l];
8773 if (lana != LANA_INVALID) {
8774 smb_StopListener(ncbp, lana, TRUE);
8776 /* mark the adapter invalid */
8777 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8781 /* force a re-evaluation of the network adapters */
8782 lana_list.length = 0;
8783 smb_LANadapter = LANA_INVALID;
8786 lock_ReleaseMutex(&smb_StartedLock);
8789 void smb_Init(osi_log_t *logp, int useV3,
8799 EVENT_HANDLE retHandle;
8800 char eventName[MAX_PATH];
8801 int startListeners = 0;
8803 smb_TlsRequestSlot = TlsAlloc();
8805 smb_MBfunc = aMBfunc;
8809 /* Initialize smb_localZero */
8810 myTime.tm_isdst = -1; /* compute whether on DST or not */
8811 myTime.tm_year = 70;
8817 smb_localZero = mktime(&myTime);
8819 #ifndef USE_NUMERIC_TIME_CONV
8820 /* Initialize kludge-GMT */
8821 smb_CalculateNowTZ();
8822 #endif /* USE_NUMERIC_TIME_CONV */
8823 #ifdef AFS_FREELANCE_CLIENT
8824 /* Make sure the root.afs volume has the correct time */
8825 cm_noteLocalMountPointChange();
8828 /* initialize the remote debugging log */
8831 /* and the global lock */
8832 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8833 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8835 /* Raw I/O data structures */
8836 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8838 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8839 lock_InitializeMutex(&smb_StartedLock, "smb started lock");
8841 /* 4 Raw I/O buffers */
8842 smb_RawBufs = calloc(65536,1);
8843 *((char **)smb_RawBufs) = NULL;
8844 for (i=0; i<3; i++) {
8845 char *rawBuf = calloc(65536,1);
8846 *((char **)rawBuf) = smb_RawBufs;
8847 smb_RawBufs = rawBuf;
8850 /* global free lists */
8851 smb_ncbFreeListp = NULL;
8852 smb_packetFreeListp = NULL;
8854 lock_ObtainMutex(&smb_StartedLock);
8855 startListeners = smb_NetbiosInit(1);
8857 /* Initialize listener and server structures */
8859 memset(dead_sessions, 0, sizeof(dead_sessions));
8860 sprintf(eventName, "SessionEvents[0]");
8861 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8862 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8863 afsi_log("Event Object Already Exists: %s", eventName);
8865 smb_NumServerThreads = nThreads;
8866 sprintf(eventName, "NCBavails[0]");
8867 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8868 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8869 afsi_log("Event Object Already Exists: %s", eventName);
8870 sprintf(eventName, "NCBevents[0]");
8871 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8872 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8873 afsi_log("Event Object Already Exists: %s", eventName);
8874 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8875 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8876 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8877 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8878 afsi_log("Event Object Already Exists: %s", eventName);
8879 for (i = 0; i < smb_NumServerThreads; i++) {
8880 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8881 NCBreturns[i][0] = retHandle;
8884 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8885 for (i = 0; i < smb_NumServerThreads; i++) {
8886 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8887 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8888 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8889 afsi_log("Event Object Already Exists: %s", eventName);
8890 InitNCBslot((int)(i+1));
8892 numNCBs = smb_NumServerThreads + 1;
8894 /* Initialize dispatch table */
8895 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8896 /* Prepare the table for unknown operations */
8897 for(i=0; i<= SMB_NOPCODES; i++) {
8898 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8900 /* Fill in the ones we do know */
8901 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8902 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8903 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8904 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8905 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8906 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8907 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8908 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8909 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8910 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8911 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8912 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8913 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8914 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8915 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8916 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8917 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8918 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8919 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8920 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8921 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8922 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8923 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8924 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8925 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8926 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8927 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8928 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8929 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8930 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8931 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8932 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8933 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8934 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8935 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8936 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8937 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8938 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8939 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8940 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8941 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8942 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8943 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8944 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8945 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8946 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8947 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8948 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8949 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8950 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8951 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8952 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8953 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8954 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8955 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8956 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8957 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8958 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8959 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8960 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8961 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8962 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8963 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8964 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8965 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8966 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8967 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8968 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8969 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8970 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8971 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8972 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8973 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8974 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8976 /* setup tran 2 dispatch table */
8977 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8978 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8979 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8980 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8981 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8982 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8983 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8984 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8985 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8986 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8987 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8988 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8989 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8990 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8991 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8992 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8993 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8994 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8996 /* setup the rap dispatch table */
8997 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8998 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8999 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9000 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9001 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9005 /* if we are doing SMB authentication we have register outselves as a logon process */
9006 if (smb_authType != SMB_AUTH_NONE) {
9007 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9008 LSA_STRING afsProcessName;
9009 LSA_OPERATIONAL_MODE dummy; /*junk*/
9011 afsProcessName.Buffer = "OpenAFSClientDaemon";
9012 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9013 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9015 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9017 if (nts == STATUS_SUCCESS) {
9018 LSA_STRING packageName;
9019 /* we are registered. Find out the security package id */
9020 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9021 packageName.Length = (USHORT)strlen(packageName.Buffer);
9022 packageName.MaximumLength = packageName.Length + 1;
9023 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9024 if (nts == STATUS_SUCCESS) {
9026 * This code forces Windows to authenticate against the Logon Cache
9027 * first instead of attempting to authenticate against the Domain
9028 * Controller. When the Windows logon cache is enabled this improves
9029 * performance by removing the network access and works around a bug
9030 * seen at sites which are using a MIT Kerberos principal to login
9031 * to machines joined to a non-root domain in a multi-domain forest.
9032 * MsV1_0SetProcessOption was added in Windows XP.
9034 PVOID pResponse = NULL;
9035 ULONG cbResponse = 0;
9036 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9038 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9039 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9040 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9041 OptionsRequest.DisableOptions = FALSE;
9043 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9046 sizeof(OptionsRequest),
9052 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9053 char message[AFSPATHMAX];
9054 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9056 OutputDebugString(message);
9059 OutputDebugString("MsV1_0SetProcessOption success");
9060 afsi_log("MsV1_0SetProcessOption success");
9062 /* END - code from Larry */
9064 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9065 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9066 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9068 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9070 /* something went wrong. We report the error and revert back to no authentication
9071 because we can't perform any auth requests without a successful lsa handle
9072 or sec package id. */
9073 afsi_log("Reverting to NO SMB AUTH");
9074 smb_authType = SMB_AUTH_NONE;
9077 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9079 /* something went wrong. We report the error and revert back to no authentication
9080 because we can't perform any auth requests without a successful lsa handle
9081 or sec package id. */
9082 afsi_log("Reverting to NO SMB AUTH");
9083 smb_authType = SMB_AUTH_NONE;
9087 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9088 * time prevents the failure of authentication when logged into Windows with an
9089 * external Kerberos principal mapped to a local account.
9091 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9092 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9093 * then the only option is NTLMSSP anyway; so just fallback.
9098 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9099 if (secBlobLength == 0) {
9100 smb_authType = SMB_AUTH_NTLM;
9101 afsi_log("Reverting to SMB AUTH NTLM");
9110 /* Now get ourselves a domain name. */
9111 /* For now we are using the local computer name as the domain name.
9112 * It is actually the domain for local logins, and we are acting as
9113 * a local SMB server.
9115 bufsize = sizeof(smb_ServerDomainName) - 1;
9116 GetComputerName(smb_ServerDomainName, &bufsize);
9117 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9118 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
9121 /* Start listeners, waiters, servers, and daemons */
9123 smb_StartListeners(1);
9125 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9126 NULL, 0, &lpid, "smb_ClientWaiter");
9127 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9128 thrd_CloseHandle(phandle);
9130 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9131 NULL, 0, &lpid, "smb_ServerWaiter");
9132 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9133 thrd_CloseHandle(phandle);
9135 for (i=0; i<smb_NumServerThreads; i++) {
9136 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9137 (void *) i, 0, &lpid, "smb_Server");
9138 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9139 thrd_CloseHandle(phandle);
9142 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9143 NULL, 0, &lpid, "smb_Daemon");
9144 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9145 thrd_CloseHandle(phandle);
9147 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9148 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9149 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9150 thrd_CloseHandle(phandle);
9152 lock_ReleaseMutex(&smb_StartedLock);
9156 void smb_Shutdown(void)
9163 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9165 /* setup the NCB system */
9168 /* Block new sessions by setting shutdown flag */
9169 smbShutdownFlag = 1;
9171 /* Hang up all sessions */
9172 memset((char *)ncbp, 0, sizeof(NCB));
9173 for (i = 1; i < numSessions; i++)
9175 if (dead_sessions[i])
9178 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9179 ncbp->ncb_command = NCBHANGUP;
9180 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9181 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9182 code = Netbios(ncbp);
9183 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9184 if (code == 0) code = ncbp->ncb_retcode;
9186 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9187 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9191 /* Trigger the shutdown of all SMB threads */
9192 for (i = 0; i < smb_NumServerThreads; i++)
9193 thrd_SetEvent(NCBreturns[i][0]);
9195 thrd_SetEvent(NCBevents[0]);
9196 thrd_SetEvent(SessionEvents[0]);
9197 thrd_SetEvent(NCBavails[0]);
9199 for (i = 0;i < smb_NumServerThreads; i++) {
9200 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9201 if (code == WAIT_OBJECT_0) {
9204 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9205 thrd_SetEvent(NCBreturns[i--][0]);
9209 /* Delete Netbios name */
9210 memset((char *)ncbp, 0, sizeof(NCB));
9211 for (i = 0; i < lana_list.length; i++) {
9212 if (lana_list.lana[i] == LANA_INVALID) continue;
9213 ncbp->ncb_command = NCBDELNAME;
9214 ncbp->ncb_lana_num = lana_list.lana[i];
9215 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9216 code = Netbios(ncbp);
9218 code = ncbp->ncb_retcode;
9220 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9221 ncbp->ncb_lana_num, code);
9226 /* Release the reference counts held by the VCs */
9227 lock_ObtainWrite(&smb_rctLock);
9228 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9233 if (vcp->magic != SMB_VC_MAGIC)
9234 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9235 __FILE__, __LINE__);
9237 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9239 if (fidp->scp != NULL) {
9242 lock_ObtainMutex(&fidp->mx);
9243 if (fidp->scp != NULL) {
9246 lock_ObtainWrite(&scp->rw);
9247 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9248 lock_ReleaseWrite(&scp->rw);
9249 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9250 cm_ReleaseSCache(scp);
9252 lock_ReleaseMutex(&fidp->mx);
9256 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9258 smb_ReleaseVCNoLock(tidp->vcp);
9260 cm_user_t *userp = tidp->userp;
9262 cm_ReleaseUser(userp);
9266 lock_ReleaseWrite(&smb_rctLock);
9268 TlsFree(smb_TlsRequestSlot);
9271 /* Get the UNC \\<servername>\<sharename> prefix. */
9272 char *smb_GetSharename()
9276 /* Make sure we have been properly initialized. */
9277 if (smb_localNamep == NULL)
9280 /* Allocate space for \\<servername>\<sharename>, plus the
9283 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9284 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9290 void smb_LogPacket(smb_packet_t *packet)
9293 unsigned length, paramlen, datalen, i, j;
9295 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9297 if (!packet) return;
9299 osi_Log0(smb_logp, "*** SMB packet dump ***");
9301 vp = (BYTE *) packet->data;
9303 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9304 length = paramlen + 2 + datalen;
9307 for (i=0;i < length; i+=16)
9309 memset( buf, ' ', 80 );
9314 buf[strlen(buf)] = ' ';
9316 cp = (BYTE*) buf + 7;
9318 for (j=0;j < 16 && (i+j)<length; j++)
9320 *(cp++) = hex[vp[i+j] >> 4];
9321 *(cp++) = hex[vp[i+j] & 0xf];
9331 for (j=0;j < 16 && (i+j)<length;j++)
9333 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9344 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9347 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9349 #endif /* LOG_PACKET */
9352 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9360 lock_ObtainRead(&smb_rctLock);
9362 sprintf(output, "begin dumping smb_vc_t\r\n");
9363 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9365 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9369 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9370 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9371 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9373 sprintf(output, "begin dumping smb_fid_t\r\n");
9374 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9376 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9378 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\r\n",
9379 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9380 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9381 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9382 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9385 sprintf(output, "done dumping smb_fid_t\r\n");
9386 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9389 sprintf(output, "done dumping smb_vc_t\r\n");
9390 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9392 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9393 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9395 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9399 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9400 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9401 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9403 sprintf(output, "begin dumping smb_fid_t\r\n");
9404 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9406 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9408 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\r\n",
9409 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9410 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9411 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9412 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9415 sprintf(output, "done dumping smb_fid_t\r\n");
9416 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9419 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9420 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9423 lock_ReleaseRead(&smb_rctLock);
9427 long smb_IsNetworkStarted(void)
9430 lock_ObtainWrite(&smb_globalLock);
9431 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
9432 lock_ReleaseWrite(&smb_globalLock);