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;
2862 cm_user_t *userp = NULL;
2865 char *rawBuf = NULL;
2870 fd = smb_GetSMBParm(inp, 0);
2871 count = smb_GetSMBParm(inp, 3);
2872 minCount = smb_GetSMBParm(inp, 4);
2873 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2875 if (*inp->wctp == 10) {
2876 /* we were sent a request with 64-bit file offsets */
2877 #ifdef AFS_LARGEFILES
2878 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2880 if (LargeIntegerLessThanZero(offset)) {
2881 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2885 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2886 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2889 offset.HighPart = 0;
2893 /* we were sent a request with 32-bit file offsets */
2894 offset.HighPart = 0;
2897 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2898 fd, offset.HighPart, offset.LowPart, count);
2900 fidp = smb_FindFID(vcp, fd, 0);
2904 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2905 smb_CloseFID(vcp, fidp, NULL, 0);
2906 code = CM_ERROR_NOSUCHFILE;
2911 pid = ((smb_t *) inp)->pid;
2913 LARGE_INTEGER LOffset, LLength;
2916 key = cm_GenerateKey(vcp->vcID, pid, fd);
2918 LOffset.HighPart = offset.HighPart;
2919 LOffset.LowPart = offset.LowPart;
2920 LLength.HighPart = 0;
2921 LLength.LowPart = count;
2923 lock_ObtainWrite(&fidp->scp->rw);
2924 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2925 lock_ReleaseWrite(&fidp->scp->rw);
2931 lock_ObtainMutex(&smb_RawBufLock);
2933 /* Get a raw buf, from head of list */
2934 rawBuf = smb_RawBufs;
2935 smb_RawBufs = *(char **)smb_RawBufs;
2937 lock_ReleaseMutex(&smb_RawBufLock);
2941 lock_ObtainMutex(&fidp->mx);
2942 if (fidp->flags & SMB_FID_IOCTL)
2944 lock_ReleaseMutex(&fidp->mx);
2945 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2947 /* Give back raw buffer */
2948 lock_ObtainMutex(&smb_RawBufLock);
2949 *((char **) rawBuf) = smb_RawBufs;
2951 smb_RawBufs = rawBuf;
2952 lock_ReleaseMutex(&smb_RawBufLock);
2955 lock_ReleaseMutex(&fidp->mx);
2956 smb_ReleaseFID(fidp);
2959 lock_ReleaseMutex(&fidp->mx);
2961 userp = smb_GetUserFromVCP(vcp, inp);
2963 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2969 cm_ReleaseUser(userp);
2972 smb_ReleaseFID(fidp);
2976 memset((char *)ncbp, 0, sizeof(NCB));
2978 ncbp->ncb_length = (unsigned short) finalCount;
2979 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2980 ncbp->ncb_lana_num = vcp->lana;
2981 ncbp->ncb_command = NCBSEND;
2982 ncbp->ncb_buffer = rawBuf;
2984 code = Netbios(ncbp);
2986 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2989 /* Give back raw buffer */
2990 lock_ObtainMutex(&smb_RawBufLock);
2991 *((char **) rawBuf) = smb_RawBufs;
2993 smb_RawBufs = rawBuf;
2994 lock_ReleaseMutex(&smb_RawBufLock);
3000 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3002 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3007 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3009 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3014 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3021 int VistaProtoIndex;
3022 int protoIndex; /* index we're using */
3027 char protocol_array[10][1024]; /* protocol signature of the client */
3028 int caps; /* capabilities */
3031 TIME_ZONE_INFORMATION tzi;
3033 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3036 namep = smb_GetSMBData(inp, &dbytes);
3039 coreProtoIndex = -1; /* not found */
3042 VistaProtoIndex = -1;
3043 while(namex < dbytes) {
3044 osi_Log1(smb_logp, "Protocol %s",
3045 osi_LogSaveString(smb_logp, namep+1));
3046 strcpy(protocol_array[tcounter], namep+1);
3048 /* namep points at the first protocol, or really, a 0x02
3049 * byte preceding the null-terminated ASCII name.
3051 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3052 coreProtoIndex = tcounter;
3054 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3055 v3ProtoIndex = tcounter;
3057 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3058 NTProtoIndex = tcounter;
3060 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3061 VistaProtoIndex = tcounter;
3064 /* compute size of protocol entry */
3065 entryLength = (int)strlen(namep+1);
3066 entryLength += 2; /* 0x02 bytes and null termination */
3068 /* advance over this protocol entry */
3069 namex += entryLength;
3070 namep += entryLength;
3071 tcounter++; /* which proto entry we're looking at */
3074 lock_ObtainMutex(&vcp->mx);
3076 if (VistaProtoIndex != -1) {
3077 protoIndex = VistaProtoIndex;
3078 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3081 if (NTProtoIndex != -1) {
3082 protoIndex = NTProtoIndex;
3083 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3085 else if (v3ProtoIndex != -1) {
3086 protoIndex = v3ProtoIndex;
3087 vcp->flags |= SMB_VCFLAG_USEV3;
3089 else if (coreProtoIndex != -1) {
3090 protoIndex = coreProtoIndex;
3091 vcp->flags |= SMB_VCFLAG_USECORE;
3093 else protoIndex = -1;
3094 lock_ReleaseMutex(&vcp->mx);
3096 if (protoIndex == -1)
3097 return CM_ERROR_INVAL;
3098 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3099 smb_SetSMBParm(outp, 0, protoIndex);
3100 if (smb_authType != SMB_AUTH_NONE) {
3101 smb_SetSMBParmByte(outp, 1,
3102 NEGOTIATE_SECURITY_USER_LEVEL |
3103 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3105 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3107 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3108 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3109 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3110 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3111 /* The session key is not a well documented field however most clients
3112 * will echo back the session key to the server. Currently we are using
3113 * the same value for all sessions. We should generate a random value
3114 * and store it into the vcp
3116 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3117 smb_SetSMBParm(outp, 8, 1);
3119 * Tried changing the capabilities to support for W2K - defect 117695
3120 * Maybe something else needs to be changed here?
3124 smb_SetSMBParmLong(outp, 9, 0x43fd);
3126 smb_SetSMBParmLong(outp, 9, 0x251);
3129 * 32-bit error codes *
3134 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3136 NTNEGOTIATE_CAPABILITY_DFS |
3138 #ifdef AFS_LARGEFILES
3139 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3141 NTNEGOTIATE_CAPABILITY_NTFIND |
3142 NTNEGOTIATE_CAPABILITY_RAWMODE |
3143 NTNEGOTIATE_CAPABILITY_NTSMB;
3145 if ( smb_authType == SMB_AUTH_EXTENDED )
3146 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3148 smb_SetSMBParmLong(outp, 9, caps);
3150 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3151 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3152 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3154 GetTimeZoneInformation(&tzi);
3155 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3157 if (smb_authType == SMB_AUTH_NTLM) {
3158 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3159 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3160 /* paste in encryption key */
3161 datap = smb_GetSMBData(outp, NULL);
3162 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3163 /* and the faux domain name */
3164 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3165 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3169 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3171 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3173 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3175 datap = smb_GetSMBData(outp, NULL);
3176 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3179 datap += sizeof(smb_ServerGUID);
3180 memcpy(datap, secBlob, secBlobLength);
3184 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3185 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3188 else if (v3ProtoIndex != -1) {
3189 smb_SetSMBParm(outp, 0, protoIndex);
3191 /* NOTE: Extended authentication cannot be negotiated with v3
3192 * therefore we fail over to NTLM
3194 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3195 smb_SetSMBParm(outp, 1,
3196 NEGOTIATE_SECURITY_USER_LEVEL |
3197 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3199 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3201 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3202 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3203 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3204 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3205 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3206 smb_SetSMBParm(outp, 7, 1);
3208 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3209 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3210 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3212 GetTimeZoneInformation(&tzi);
3213 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3215 /* NOTE: Extended authentication cannot be negotiated with v3
3216 * therefore we fail over to NTLM
3218 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3219 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3220 smb_SetSMBParm(outp, 12, 0); /* resvd */
3221 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3222 datap = smb_GetSMBData(outp, NULL);
3223 /* paste in a new encryption key */
3224 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3225 /* and the faux domain name */
3226 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3228 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3229 smb_SetSMBParm(outp, 12, 0); /* resvd */
3230 smb_SetSMBDataLength(outp, 0);
3233 else if (coreProtoIndex != -1) { /* not really supported anymore */
3234 smb_SetSMBParm(outp, 0, protoIndex);
3235 smb_SetSMBDataLength(outp, 0);
3240 void smb_CheckVCs(void)
3242 smb_vc_t * vcp, *nextp;
3243 smb_packet_t * outp = GetPacket();
3246 lock_ObtainWrite(&smb_rctLock);
3247 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3249 if (vcp->magic != SMB_VC_MAGIC)
3250 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3251 __FILE__, __LINE__);
3255 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3258 smb_HoldVCNoLock(vcp);
3260 smb_HoldVCNoLock(nextp);
3261 smb_FormatResponsePacket(vcp, NULL, outp);
3262 smbp = (smb_t *)outp;
3263 outp->inCom = smbp->com = 0x2b /* Echo */;
3271 smb_SetSMBParm(outp, 0, 0);
3272 smb_SetSMBDataLength(outp, 0);
3273 lock_ReleaseWrite(&smb_rctLock);
3275 smb_SendPacket(vcp, outp);
3277 lock_ObtainWrite(&smb_rctLock);
3278 smb_ReleaseVCNoLock(vcp);
3280 smb_ReleaseVCNoLock(nextp);
3282 lock_ReleaseWrite(&smb_rctLock);
3283 smb_FreePacket(outp);
3286 void smb_Daemon(void *parmp)
3288 afs_uint32 count = 0;
3289 smb_username_t **unpp;
3292 while(smbShutdownFlag == 0) {
3296 if (smbShutdownFlag == 1)
3299 if ((count % 72) == 0) { /* every five minutes */
3301 time_t old_localZero = smb_localZero;
3303 /* Initialize smb_localZero */
3304 myTime.tm_isdst = -1; /* compute whether on DST or not */
3305 myTime.tm_year = 70;
3311 smb_localZero = mktime(&myTime);
3313 #ifndef USE_NUMERIC_TIME_CONV
3314 smb_CalculateNowTZ();
3315 #endif /* USE_NUMERIC_TIME_CONV */
3316 #ifdef AFS_FREELANCE
3317 if ( smb_localZero != old_localZero )
3318 cm_noteLocalMountPointChange();
3324 /* GC smb_username_t objects that will no longer be used */
3326 lock_ObtainWrite(&smb_rctLock);
3327 for ( unpp=&usernamesp; *unpp; ) {
3329 smb_username_t *unp;
3331 lock_ObtainMutex(&(*unpp)->mx);
3332 if ( (*unpp)->refCount > 0 ||
3333 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3334 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3336 else if (!smb_LogoffTokenTransfer ||
3337 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3339 lock_ReleaseMutex(&(*unpp)->mx);
3347 lock_FinalizeMutex(&unp->mx);
3353 cm_ReleaseUser(userp);
3355 unpp = &(*unpp)->nextp;
3358 lock_ReleaseWrite(&smb_rctLock);
3360 /* XXX GC dir search entries */
3364 void smb_WaitingLocksDaemon()
3366 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3367 smb_waitingLock_t *wl, *wlNext;
3370 smb_packet_t *inp, *outp;
3374 while (smbShutdownFlag == 0) {
3375 lock_ObtainWrite(&smb_globalLock);
3376 nwlRequest = smb_allWaitingLocks;
3377 if (nwlRequest == NULL) {
3378 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3383 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3390 lock_ObtainWrite(&smb_globalLock);
3392 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3394 wlRequest = nwlRequest;
3395 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3396 lock_ReleaseWrite(&smb_globalLock);
3400 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3401 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3404 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3405 code = CM_ERROR_LOCK_NOT_GRANTED;
3409 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3411 /* wl->state is either _DONE or _WAITING. _ERROR
3412 would no longer be on the queue. */
3413 code = cm_RetryLock( wl->lockp,
3414 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3417 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3418 } else if (code != CM_ERROR_WOULDBLOCK) {
3419 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3424 if (code == CM_ERROR_WOULDBLOCK) {
3427 if (wlRequest->msTimeout != 0xffffffff
3428 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3440 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3443 scp = wlRequest->scp;
3444 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3448 lock_ObtainWrite(&scp->rw);
3450 for (wl = wlRequest->locks; wl; wl = wlNext) {
3451 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3453 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3454 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3455 wl->LLength, wl->key, NULL, &req);
3457 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3462 lock_ReleaseWrite(&scp->rw);
3466 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3469 for (wl = wlRequest->locks; wl; wl = wlNext) {
3470 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3471 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3476 vcp = wlRequest->vcp;
3477 inp = wlRequest->inp;
3478 outp = wlRequest->outp;
3480 ncbp->ncb_length = inp->ncb_length;
3481 inp->spacep = cm_GetSpace();
3483 /* Remove waitingLock from list */
3484 lock_ObtainWrite(&smb_globalLock);
3485 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3487 lock_ReleaseWrite(&smb_globalLock);
3489 /* Resume packet processing */
3491 smb_SetSMBDataLength(outp, 0);
3492 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3493 outp->resumeCode = code;
3495 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3498 cm_FreeSpace(inp->spacep);
3499 smb_FreePacket(inp);
3500 smb_FreePacket(outp);
3502 cm_ReleaseSCache(wlRequest->scp);
3505 } while (nwlRequest && smbShutdownFlag == 0);
3510 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3512 osi_Log0(smb_logp, "SMB receive get disk attributes");
3514 smb_SetSMBParm(outp, 0, 32000);
3515 smb_SetSMBParm(outp, 1, 64);
3516 smb_SetSMBParm(outp, 2, 1024);
3517 smb_SetSMBParm(outp, 3, 30000);
3518 smb_SetSMBParm(outp, 4, 0);
3519 smb_SetSMBDataLength(outp, 0);
3523 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3527 unsigned short newTid;
3528 char shareName[AFSPATHMAX];
3536 osi_Log0(smb_logp, "SMB receive tree connect");
3538 /* parse input parameters */
3539 tp = smb_GetSMBData(inp, NULL);
3540 pathp = smb_ParseASCIIBlock(tp, &tp);
3541 if (smb_StoreAnsiFilenames)
3542 OemToChar(pathp,pathp);
3543 passwordp = smb_ParseASCIIBlock(tp, &tp);
3544 tp = strrchr(pathp, '\\');
3546 return CM_ERROR_BADSMB;
3547 strcpy(shareName, tp+1);
3549 lock_ObtainMutex(&vcp->mx);
3550 newTid = vcp->tidCounter++;
3551 lock_ReleaseMutex(&vcp->mx);
3553 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3554 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3555 userp = smb_GetUserFromUID(uidp);
3556 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3558 smb_ReleaseUID(uidp);
3560 smb_ReleaseTID(tidp, FALSE);
3561 return CM_ERROR_BADSHARENAME;
3563 lock_ObtainMutex(&tidp->mx);
3564 tidp->userp = userp;
3565 tidp->pathname = sharePath;
3566 lock_ReleaseMutex(&tidp->mx);
3567 smb_ReleaseTID(tidp, FALSE);
3569 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3570 smb_SetSMBParm(rsp, 1, newTid);
3571 smb_SetSMBDataLength(rsp, 0);
3573 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3577 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3581 if (*inp++ != 0x1) return NULL;
3582 tlen = inp[0] + (inp[1]<<8);
3583 inp += 2; /* skip length field */
3586 *chainpp = inp + tlen;
3589 if (lengthp) *lengthp = tlen;
3594 /* set maskp to the mask part of the incoming path.
3595 * Mask is 11 bytes long (8.3 with the dot elided).
3596 * Returns true if succeeds with a valid name, otherwise it does
3597 * its best, but returns false.
3599 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3607 /* starts off valid */
3610 /* mask starts out all blanks */
3611 memset(maskp, ' ', 11);
3614 /* find last backslash, or use whole thing if there is none */
3615 tp = strrchr(pathp, '\\');
3619 tp++; /* skip slash */
3623 /* names starting with a dot are illegal */
3631 if (tc == '.' || tc == '"')
3639 /* if we get here, tp point after the dot */
3640 up = maskp+8; /* ext goes here */
3647 if (tc == '.' || tc == '"')
3650 /* copy extension if not too long */
3660 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3670 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3672 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3676 /* otherwise, we have a valid 8.3 name; see if we have a match,
3677 * treating '?' as a wildcard in maskp (but not in the file name).
3679 tp1 = umask; /* real name, in mask format */
3680 tp2 = maskp; /* mask, in mask format */
3681 for(i=0; i<11; i++) {
3682 tc1 = *tp1++; /* char from real name */
3683 tc2 = *tp2++; /* char from mask */
3684 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3685 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3688 if (tc2 == '?' && tc1 != ' ')
3695 /* we got a match */
3699 char *smb_FindMask(char *pathp)
3703 tp = strrchr(pathp, '\\'); /* find last slash */
3706 return tp+1; /* skip the slash */
3708 return pathp; /* no slash, return the entire path */
3711 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3713 unsigned char *pathp;
3715 unsigned char mask[12];
3716 unsigned char *statBlockp;
3717 unsigned char initStatBlock[21];
3720 osi_Log0(smb_logp, "SMB receive search volume");
3722 /* pull pathname and stat block out of request */
3723 tp = smb_GetSMBData(inp, NULL);
3724 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3725 osi_assertx(pathp != NULL, "null path");
3726 if (smb_StoreAnsiFilenames)
3727 OemToChar(pathp,pathp);
3728 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3729 osi_assertx(statBlockp != NULL, "null statBlock");
3731 statBlockp = initStatBlock;
3735 /* for returning to caller */
3736 smb_Get8Dot3MaskFromPath(mask, pathp);
3738 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3739 tp = smb_GetSMBData(outp, NULL);
3741 *tp++ = 43; /* bytes in a dir entry */
3742 *tp++ = 0; /* high byte in counter */
3744 /* now marshall the dir entry, starting with the search status */
3745 *tp++ = statBlockp[0]; /* Reserved */
3746 memcpy(tp, mask, 11); tp += 11; /* FileName */
3748 /* now pass back server use info, with 1st byte non-zero */
3750 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3752 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3754 *tp++ = 0x8; /* attribute: volume */
3764 /* 4 byte file size */
3770 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3771 memset(tp, ' ', 13);
3774 /* set the length of the data part of the packet to 43 + 3, for the dir
3775 * entry plus the 5 and the length fields.
3777 smb_SetSMBDataLength(outp, 46);
3782 smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3783 char * tidPathp, char * relPathp,
3784 cm_user_t *userp, cm_req_t *reqp)
3792 smb_dirListPatch_t *patchp;
3793 smb_dirListPatch_t *npatchp;
3794 char path[AFSPATHMAX];
3796 for (patchp = *dirPatchespp; patchp; patchp =
3797 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3799 dptr = patchp->dptr;
3801 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
3802 reqp->relPathp = path;
3803 reqp->tidPathp = tidPathp;
3805 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3806 reqp->relPathp = reqp->tidPathp = NULL;
3809 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3810 *dptr++ = SMB_ATTR_HIDDEN;
3813 lock_ObtainWrite(&scp->rw);
3814 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3815 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3817 lock_ReleaseWrite(&scp->rw);
3818 cm_ReleaseSCache(scp);
3819 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3820 *dptr++ = SMB_ATTR_HIDDEN;
3824 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3826 lock_ConvertWToR(&scp->rw);
3827 attr = smb_Attributes(scp);
3828 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3829 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3830 attr |= SMB_ATTR_HIDDEN;
3834 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3837 shortTemp = (unsigned short) (dosTime & 0xffff);
3838 *((u_short *)dptr) = shortTemp;
3841 /* and copy out date */
3842 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3843 *((u_short *)dptr) = shortTemp;
3846 /* copy out file length */
3847 *((u_long *)dptr) = scp->length.LowPart;
3849 lock_ReleaseRead(&scp->rw);
3850 cm_ReleaseSCache(scp);
3853 /* now free the patches */
3854 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3855 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3859 /* and mark the list as empty */
3860 *dirPatchespp = NULL;
3865 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3872 cm_dirEntry_t *dep = 0;
3874 smb_dirListPatch_t *dirListPatchesp;
3875 smb_dirListPatch_t *curPatchp;
3879 osi_hyper_t dirLength;
3880 osi_hyper_t bufferOffset;
3881 osi_hyper_t curOffset;
3883 unsigned char *inCookiep;
3884 smb_dirSearch_t *dsp;
3888 unsigned long clientCookie;
3889 cm_pageHeader_t *pageHeaderp;
3890 cm_user_t *userp = NULL;
3897 long nextEntryCookie;
3898 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3899 char resByte; /* reserved byte from the cookie */
3900 char *op; /* output data ptr */
3901 char *origOp; /* original value of op */
3902 cm_space_t *spacep; /* for pathname buffer */
3913 maxCount = smb_GetSMBParm(inp, 0);
3915 dirListPatchesp = NULL;
3917 caseFold = CM_FLAG_CASEFOLD;
3919 tp = smb_GetSMBData(inp, NULL);
3920 pathp = smb_ParseASCIIBlock(tp, &tp);
3921 if (smb_StoreAnsiFilenames)
3922 OemToChar(pathp,pathp);
3923 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3925 /* bail out if request looks bad */
3926 if (!tp || !pathp) {
3927 return CM_ERROR_BADSMB;
3930 /* We can handle long names */
3931 if (vcp->flags & SMB_VCFLAG_USENT)
3932 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3934 /* make sure we got a whole search status */
3935 if (dataLength < 21) {
3936 nextCookie = 0; /* start at the beginning of the dir */
3939 attribute = smb_GetSMBParm(inp, 1);
3941 /* handle volume info in another function */
3942 if (attribute & 0x8)
3943 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3945 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3946 maxCount, osi_LogSaveString(smb_logp, pathp));
3948 if (*pathp == 0) { /* null pathp, treat as root dir */
3949 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3950 return CM_ERROR_NOFILES;
3954 dsp = smb_NewDirSearch(0);
3955 dsp->attribute = attribute;
3956 smb_Get8Dot3MaskFromPath(mask, pathp);
3957 memcpy(dsp->mask, mask, 12);
3959 /* track if this is likely to match a lot of entries */
3960 if (smb_IsStarMask(mask))
3965 /* pull the next cookie value out of the search status block */
3966 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3967 + (inCookiep[16]<<24);
3968 dsp = smb_FindDirSearch(inCookiep[12]);
3970 /* can't find dir search status; fatal error */
3971 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3972 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3973 return CM_ERROR_BADFD;
3975 attribute = dsp->attribute;
3976 resByte = inCookiep[0];
3978 /* copy out client cookie, in host byte order. Don't bother
3979 * interpreting it, since we're just passing it through, anyway.
3981 memcpy(&clientCookie, &inCookiep[17], 4);
3983 memcpy(mask, dsp->mask, 12);
3985 /* assume we're doing a star match if it has continued for more
3991 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3992 nextCookie, dsp->cookie, attribute);
3994 userp = smb_GetUserFromVCP(vcp, inp);
3996 /* try to get the vnode for the path name next */
3997 lock_ObtainMutex(&dsp->mx);
4000 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4004 spacep = inp->spacep;
4005 smb_StripLastComponent(spacep->data, NULL, pathp);
4006 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4008 lock_ReleaseMutex(&dsp->mx);
4009 cm_ReleaseUser(userp);
4010 smb_DeleteDirSearch(dsp);
4011 smb_ReleaseDirSearch(dsp);
4012 return CM_ERROR_NOFILES;
4014 strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
4015 strcpy(dsp->relPath, spacep->data);
4017 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4018 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4021 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4022 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4023 cm_ReleaseSCache(scp);
4024 lock_ReleaseMutex(&dsp->mx);
4025 cm_ReleaseUser(userp);
4026 smb_DeleteDirSearch(dsp);
4027 smb_ReleaseDirSearch(dsp);
4028 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4029 return CM_ERROR_PATH_NOT_COVERED;
4031 return CM_ERROR_BADSHARENAME;
4033 #endif /* DFS_SUPPORT */
4036 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4037 /* we need one hold for the entry we just stored into,
4038 * and one for our own processing. When we're done with this
4039 * function, we'll drop the one for our own processing.
4040 * We held it once from the namei call, and so we do another hold
4044 lock_ObtainWrite(&scp->rw);
4045 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4046 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4047 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4048 dsp->flags |= SMB_DIRSEARCH_BULKST;
4049 dsp->scp->bulkStatProgress = hzero;
4051 lock_ReleaseWrite(&scp->rw);
4054 lock_ReleaseMutex(&dsp->mx);
4056 cm_ReleaseUser(userp);
4057 smb_DeleteDirSearch(dsp);
4058 smb_ReleaseDirSearch(dsp);
4062 /* reserves space for parameter; we'll adjust it again later to the
4063 * real count of the # of entries we returned once we've actually
4064 * assembled the directory listing.
4066 smb_SetSMBParm(outp, 0, 0);
4068 /* get the directory size */
4069 lock_ObtainWrite(&scp->rw);
4070 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4071 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4073 lock_ReleaseWrite(&scp->rw);
4074 cm_ReleaseSCache(scp);
4075 cm_ReleaseUser(userp);
4076 smb_DeleteDirSearch(dsp);
4077 smb_ReleaseDirSearch(dsp);
4081 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4083 dirLength = scp->length;
4085 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4086 curOffset.HighPart = 0;
4087 curOffset.LowPart = nextCookie;
4088 origOp = op = smb_GetSMBData(outp, NULL);
4089 /* and write out the basic header */
4090 *op++ = 5; /* variable block */
4091 op += 2; /* skip vbl block length; we'll fill it in later */
4095 /* make sure that curOffset.LowPart doesn't point to the first
4096 * 32 bytes in the 2nd through last dir page, and that it doesn't
4097 * point at the first 13 32-byte chunks in the first dir page,
4098 * since those are dir and page headers, and don't contain useful
4101 temp = curOffset.LowPart & (2048-1);
4102 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4103 /* we're in the first page */
4104 if (temp < 13*32) temp = 13*32;
4107 /* we're in a later dir page */
4108 if (temp < 32) temp = 32;
4111 /* make sure the low order 5 bits are zero */
4114 /* now put temp bits back ito curOffset.LowPart */
4115 curOffset.LowPart &= ~(2048-1);
4116 curOffset.LowPart |= temp;
4118 /* check if we've returned all the names that will fit in the
4121 if (returnedNames >= maxCount) {
4122 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4123 returnedNames, maxCount);
4127 /* check if we've passed the dir's EOF */
4128 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4130 /* see if we can use the bufferp we have now; compute in which page
4131 * the current offset would be, and check whether that's the offset
4132 * of the buffer we have. If not, get the buffer.
4134 thyper.HighPart = curOffset.HighPart;
4135 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4136 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4139 buf_Release(bufferp);
4142 lock_ReleaseWrite(&scp->rw);
4143 code = buf_Get(scp, &thyper, &bufferp);
4144 lock_ObtainMutex(&dsp->mx);
4146 /* now, if we're doing a star match, do bulk fetching of all of
4147 * the status info for files in the dir.
4150 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4151 lock_ObtainWrite(&scp->rw);
4152 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4153 LargeIntegerGreaterThanOrEqualTo(thyper,
4154 scp->bulkStatProgress)) {
4155 /* Don't bulk stat if risking timeout */
4156 int now = GetTickCount();
4157 if (now - req.startTime > RDRtimeout * 1000) {
4158 scp->bulkStatProgress = thyper;
4159 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4160 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4161 dsp->scp->bulkStatProgress = hzero;
4163 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4166 lock_ObtainWrite(&scp->rw);
4168 lock_ReleaseMutex(&dsp->mx);
4170 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4174 bufferOffset = thyper;
4176 /* now get the data in the cache */
4178 code = cm_SyncOp(scp, bufferp, userp, &req,
4180 CM_SCACHESYNC_NEEDCALLBACK |
4181 CM_SCACHESYNC_READ);
4183 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4187 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4189 if (cm_HaveBuffer(scp, bufferp, 0)) {
4190 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4194 /* otherwise, load the buffer and try again */
4195 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4197 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4198 scp, bufferp, code);
4203 buf_Release(bufferp);
4207 } /* if (wrong buffer) ... */
4209 /* now we have the buffer containing the entry we're interested in; copy
4210 * it out if it represents a non-deleted entry.
4212 entryInDir = curOffset.LowPart & (2048-1);
4213 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4215 /* page header will help tell us which entries are free. Page header
4216 * can change more often than once per buffer, since AFS 3 dir page size
4217 * may be less than (but not more than a buffer package buffer.
4219 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4220 temp &= ~(2048 - 1); /* turn off intra-page bits */
4221 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4223 /* now determine which entry we're looking at in the page. If it is
4224 * free (there's a free bitmap at the start of the dir), we should
4225 * skip these 32 bytes.
4227 slotInPage = (entryInDir & 0x7e0) >> 5;
4228 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4229 /* this entry is free */
4230 numDirChunks = 1; /* only skip this guy */
4234 tp = bufferp->datap + entryInBuffer;
4235 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4237 /* while we're here, compute the next entry's location, too,
4238 * since we'll need it when writing out the cookie into the dir
4241 * XXXX Probably should do more sanity checking.
4243 numDirChunks = cm_NameEntries(dep->name, NULL);
4245 /* compute the offset of the cookie representing the next entry */
4246 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4248 /* Compute 8.3 name if necessary */
4249 actualName = dep->name;
4250 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4251 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4252 actualName = shortName;
4255 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4256 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4257 osi_LogSaveString(smb_logp, actualName));
4259 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4260 /* this is one of the entries to use: it is not deleted
4261 * and it matches the star pattern we're looking for.
4264 /* Eliminate entries that don't match requested
4267 /* no hidden files */
4268 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4269 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4273 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4275 /* We have already done the cm_TryBulkStat above */
4276 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4277 fileType = cm_FindFileType(&fid);
4278 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4279 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4281 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4282 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4283 fileType == CM_SCACHETYPE_DFSLINK ||
4284 fileType == CM_SCACHETYPE_INVALID)
4285 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4290 memcpy(op, mask, 11); op += 11;
4291 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4292 *op++ = (char)(nextEntryCookie & 0xff);
4293 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4294 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4295 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4296 memcpy(op, &clientCookie, 4); op += 4;
4298 /* now we emit the attribute. This is sort of tricky,
4299 * since we need to really stat the file to find out
4300 * what type of entry we've got. Right now, we're
4301 * copying out data from a buffer, while holding the
4302 * scp locked, so it isn't really convenient to stat
4303 * something now. We'll put in a place holder now,
4304 * and make a second pass before returning this to get
4305 * the real attributes. So, we just skip the data for
4306 * now, and adjust it later. We allocate a patch
4307 * record to make it easy to find this point later.
4308 * The replay will happen at a time when it is safe to
4309 * unlock the directory.
4311 curPatchp = malloc(sizeof(*curPatchp));
4312 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4313 curPatchp->dptr = op;
4314 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4316 /* do hidden attribute here since name won't be around when applying
4320 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4321 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4323 curPatchp->flags = 0;
4325 op += 9; /* skip attr, time, date and size */
4327 /* zero out name area. The spec says to pad with
4328 * spaces, but Samba doesn't, and neither do we.
4332 /* finally, we get to copy out the name; we know that
4333 * it fits in 8.3 or the pattern wouldn't match, but it
4334 * never hurts to be sure.
4336 strncpy(op, actualName, 13);
4337 if (smb_StoreAnsiFilenames)
4340 /* Uppercase if requested by client */
4341 if (!KNOWS_LONG_NAMES(inp))
4346 /* now, adjust the # of entries copied */
4348 } /* if we're including this name */
4351 /* and adjust curOffset to be where the new cookie is */
4352 thyper.HighPart = 0;
4353 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4354 curOffset = LargeIntegerAdd(thyper, curOffset);
4355 } /* while copying data for dir listing */
4357 /* release the mutex */
4358 lock_ReleaseWrite(&scp->rw);
4360 buf_Release(bufferp);
4364 /* apply and free last set of patches; if not doing a star match, this
4365 * will be empty, but better safe (and freeing everything) than sorry.
4367 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4369 /* special return code for unsuccessful search */
4370 if (code == 0 && dataLength < 21 && returnedNames == 0)
4371 code = CM_ERROR_NOFILES;
4373 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4374 returnedNames, code);
4377 smb_DeleteDirSearch(dsp);
4378 smb_ReleaseDirSearch(dsp);
4379 cm_ReleaseSCache(scp);
4380 cm_ReleaseUser(userp);
4384 /* finalize the output buffer */
4385 smb_SetSMBParm(outp, 0, returnedNames);
4386 temp = (long) (op - origOp);
4387 smb_SetSMBDataLength(outp, temp);
4389 /* the data area is a variable block, which has a 5 (already there)
4390 * followed by the length of the # of data bytes. We now know this to
4391 * be "temp," although that includes the 3 bytes of vbl block header.
4392 * Deduct for them and fill in the length field.
4394 temp -= 3; /* deduct vbl block info */
4395 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4396 origOp[1] = (char)(temp & 0xff);
4397 origOp[2] = (char)((temp>>8) & 0xff);
4398 if (returnedNames == 0)
4399 smb_DeleteDirSearch(dsp);
4400 smb_ReleaseDirSearch(dsp);
4401 cm_ReleaseSCache(scp);
4402 cm_ReleaseUser(userp);
4406 /* verify that this is a valid path to a directory. I don't know why they
4407 * don't use the get file attributes call.
4409 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4413 cm_scache_t *rootScp;
4414 cm_scache_t *newScp;
4423 pathp = smb_GetSMBData(inp, NULL);
4424 pathp = smb_ParseASCIIBlock(pathp, NULL);
4426 return CM_ERROR_BADFD;
4427 if (smb_StoreAnsiFilenames)
4428 OemToChar(pathp,pathp);
4429 osi_Log1(smb_logp, "SMB receive check path %s",
4430 osi_LogSaveString(smb_logp, pathp));
4432 rootScp = cm_data.rootSCachep;
4434 userp = smb_GetUserFromVCP(vcp, inp);
4436 caseFold = CM_FLAG_CASEFOLD;
4438 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4440 cm_ReleaseUser(userp);
4441 return CM_ERROR_NOSUCHPATH;
4443 code = cm_NameI(rootScp, pathp,
4444 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4445 userp, tidPathp, &req, &newScp);
4448 cm_ReleaseUser(userp);
4453 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4454 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4455 cm_ReleaseSCache(newScp);
4456 cm_ReleaseUser(userp);
4457 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4458 return CM_ERROR_PATH_NOT_COVERED;
4460 return CM_ERROR_BADSHARENAME;
4462 #endif /* DFS_SUPPORT */
4464 /* now lock the vnode with a callback; returns with newScp locked */
4465 lock_ObtainWrite(&newScp->rw);
4466 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4467 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4469 if (code != CM_ERROR_NOACCESS) {
4470 lock_ReleaseWrite(&newScp->rw);
4471 cm_ReleaseSCache(newScp);
4472 cm_ReleaseUser(userp);
4476 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4479 attrs = smb_Attributes(newScp);
4481 if (!(attrs & SMB_ATTR_DIRECTORY))
4482 code = CM_ERROR_NOTDIR;
4484 lock_ReleaseWrite(&newScp->rw);
4486 cm_ReleaseSCache(newScp);
4487 cm_ReleaseUser(userp);
4491 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4495 cm_scache_t *rootScp;
4496 unsigned short attribute;
4498 cm_scache_t *newScp;
4507 /* decode basic attributes we're passed */
4508 attribute = smb_GetSMBParm(inp, 0);
4509 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4511 pathp = smb_GetSMBData(inp, NULL);
4512 pathp = smb_ParseASCIIBlock(pathp, NULL);
4514 return CM_ERROR_BADSMB;
4515 if (smb_StoreAnsiFilenames)
4516 OemToChar(pathp,pathp);
4518 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4519 dosTime, attribute);
4521 rootScp = cm_data.rootSCachep;
4523 userp = smb_GetUserFromVCP(vcp, inp);
4525 caseFold = CM_FLAG_CASEFOLD;
4527 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4529 cm_ReleaseUser(userp);
4530 return CM_ERROR_NOSUCHFILE;
4532 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4533 tidPathp, &req, &newScp);
4536 cm_ReleaseUser(userp);
4541 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4542 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4543 cm_ReleaseSCache(newScp);
4544 cm_ReleaseUser(userp);
4545 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4546 return CM_ERROR_PATH_NOT_COVERED;
4548 return CM_ERROR_BADSHARENAME;
4550 #endif /* DFS_SUPPORT */
4552 /* now lock the vnode with a callback; returns with newScp locked; we
4553 * need the current status to determine what the new status is, in some
4556 lock_ObtainWrite(&newScp->rw);
4557 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4558 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4560 lock_ReleaseWrite(&newScp->rw);
4561 cm_ReleaseSCache(newScp);
4562 cm_ReleaseUser(userp);
4566 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4568 /* Check for RO volume */
4569 if (newScp->flags & CM_SCACHEFLAG_RO) {
4570 lock_ReleaseWrite(&newScp->rw);
4571 cm_ReleaseSCache(newScp);
4572 cm_ReleaseUser(userp);
4573 return CM_ERROR_READONLY;
4576 /* prepare for setattr call */
4579 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4580 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4582 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4583 /* we're told to make a writable file read-only */
4584 attr.unixModeBits = newScp->unixModeBits & ~0222;
4585 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4587 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4588 /* we're told to make a read-only file writable */
4589 attr.unixModeBits = newScp->unixModeBits | 0222;
4590 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4592 lock_ReleaseWrite(&newScp->rw);
4594 /* now call setattr */
4596 code = cm_SetAttr(newScp, &attr, userp, &req);
4600 cm_ReleaseSCache(newScp);
4601 cm_ReleaseUser(userp);
4606 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4610 cm_scache_t *rootScp;
4611 cm_scache_t *newScp, *dscp;
4623 pathp = smb_GetSMBData(inp, NULL);
4624 pathp = smb_ParseASCIIBlock(pathp, NULL);
4626 return CM_ERROR_BADSMB;
4628 if (*pathp == 0) /* null path */
4631 if (smb_StoreAnsiFilenames)
4632 OemToChar(pathp,pathp);
4634 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4635 osi_LogSaveString(smb_logp, pathp));
4637 rootScp = cm_data.rootSCachep;
4639 userp = smb_GetUserFromVCP(vcp, inp);
4641 /* we shouldn't need this for V3 requests, but we seem to */
4642 caseFold = CM_FLAG_CASEFOLD;
4644 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4646 cm_ReleaseUser(userp);
4647 return CM_ERROR_NOSUCHFILE;
4651 * XXX Strange hack XXX
4653 * As of Patch 5 (16 July 97), we are having the following problem:
4654 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4655 * requests to look up "desktop.ini" in all the subdirectories.
4656 * This can cause zillions of timeouts looking up non-existent cells
4657 * and volumes, especially in the top-level directory.
4659 * We have not found any way to avoid this or work around it except
4660 * to explicitly ignore the requests for mount points that haven't
4661 * yet been evaluated and for directories that haven't yet been
4664 * We should modify this hack to provide a fake desktop.ini file
4665 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4667 spacep = inp->spacep;
4668 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4669 #ifndef SPECIAL_FOLDERS
4670 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4671 code = cm_NameI(rootScp, spacep->data,
4672 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4673 userp, tidPathp, &req, &dscp);
4676 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4677 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
4678 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4679 return CM_ERROR_PATH_NOT_COVERED;
4681 return CM_ERROR_BADSHARENAME;
4683 #endif /* DFS_SUPPORT */
4684 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4685 code = CM_ERROR_NOSUCHFILE;
4686 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4687 cm_buf_t *bp = buf_Find(dscp, &hzero);
4692 code = CM_ERROR_NOSUCHFILE;
4694 cm_ReleaseSCache(dscp);
4696 cm_ReleaseUser(userp);
4701 #endif /* SPECIAL_FOLDERS */
4703 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4704 tidPathp, &req, &newScp);
4706 cm_ReleaseUser(userp);
4711 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4712 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4713 cm_ReleaseSCache(newScp);
4714 cm_ReleaseUser(userp);
4715 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4716 return CM_ERROR_PATH_NOT_COVERED;
4718 return CM_ERROR_BADSHARENAME;
4720 #endif /* DFS_SUPPORT */
4722 /* now lock the vnode with a callback; returns with newScp locked */
4723 lock_ObtainWrite(&newScp->rw);
4724 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4725 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4727 lock_ReleaseWrite(&newScp->rw);
4728 cm_ReleaseSCache(newScp);
4729 cm_ReleaseUser(userp);
4733 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4736 /* use smb_Attributes instead. Also the fact that a file is
4737 * in a readonly volume doesn't mean it shojuld be marked as RO
4739 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4740 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4741 newScp->fileType == CM_SCACHETYPE_INVALID)
4742 attrs = SMB_ATTR_DIRECTORY;
4745 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4746 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4748 attrs = smb_Attributes(newScp);
4751 smb_SetSMBParm(outp, 0, attrs);
4753 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4754 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4755 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4756 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4757 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4758 smb_SetSMBParm(outp, 5, 0);
4759 smb_SetSMBParm(outp, 6, 0);
4760 smb_SetSMBParm(outp, 7, 0);
4761 smb_SetSMBParm(outp, 8, 0);
4762 smb_SetSMBParm(outp, 9, 0);
4763 smb_SetSMBDataLength(outp, 0);
4764 lock_ReleaseWrite(&newScp->rw);
4766 cm_ReleaseSCache(newScp);
4767 cm_ReleaseUser(userp);
4772 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4776 osi_Log0(smb_logp, "SMB receive tree disconnect");
4778 /* find the tree and free it */
4779 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4781 lock_ObtainWrite(&smb_rctLock);
4783 smb_ReleaseTID(tidp, TRUE);
4784 lock_ReleaseWrite(&smb_rctLock);
4790 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4808 pathp = smb_GetSMBData(inp, NULL);
4809 pathp = smb_ParseASCIIBlock(pathp, NULL);
4810 if (smb_StoreAnsiFilenames)
4811 OemToChar(pathp,pathp);
4813 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4815 #ifdef DEBUG_VERBOSE
4819 hexpath = osi_HexifyString( pathp );
4820 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4825 share = smb_GetSMBParm(inp, 0);
4826 attribute = smb_GetSMBParm(inp, 1);
4828 spacep = inp->spacep;
4829 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4830 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4831 /* special case magic file name for receiving IOCTL requests
4832 * (since IOCTL calls themselves aren't getting through).
4834 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4835 smb_SetupIoctlFid(fidp, spacep);
4836 smb_SetSMBParm(outp, 0, fidp->fid);
4837 smb_SetSMBParm(outp, 1, 0); /* attrs */
4838 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4839 smb_SetSMBParm(outp, 3, 0);
4840 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4841 smb_SetSMBParm(outp, 5, 0x7fff);
4842 /* pass the open mode back */
4843 smb_SetSMBParm(outp, 6, (share & 0xf));
4844 smb_SetSMBDataLength(outp, 0);
4845 smb_ReleaseFID(fidp);
4849 userp = smb_GetUserFromVCP(vcp, inp);
4851 caseFold = CM_FLAG_CASEFOLD;
4853 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4855 cm_ReleaseUser(userp);
4856 return CM_ERROR_NOSUCHPATH;
4858 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4859 tidPathp, &req, &scp);
4862 cm_ReleaseUser(userp);
4867 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4868 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
4869 cm_ReleaseSCache(scp);
4870 cm_ReleaseUser(userp);
4871 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4872 return CM_ERROR_PATH_NOT_COVERED;
4874 return CM_ERROR_BADSHARENAME;
4876 #endif /* DFS_SUPPORT */
4878 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4880 cm_ReleaseSCache(scp);
4881 cm_ReleaseUser(userp);
4885 /* don't need callback to check file type, since file types never
4886 * change, and namei and cm_Lookup all stat the object at least once on
4887 * a successful return.
4889 if (scp->fileType != CM_SCACHETYPE_FILE) {
4890 cm_ReleaseSCache(scp);
4891 cm_ReleaseUser(userp);
4892 return CM_ERROR_ISDIR;
4895 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4896 osi_assertx(fidp, "null smb_fid_t");
4898 /* save a pointer to the vnode */
4900 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4901 lock_ObtainWrite(&scp->rw);
4902 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4903 lock_ReleaseWrite(&scp->rw);
4907 fidp->userp = userp;
4909 lock_ObtainMutex(&fidp->mx);
4910 if ((share & 0xf) == 0)
4911 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4912 else if ((share & 0xf) == 1)
4913 fidp->flags |= SMB_FID_OPENWRITE;
4915 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4916 lock_ReleaseMutex(&fidp->mx);
4918 lock_ObtainRead(&scp->rw);
4919 smb_SetSMBParm(outp, 0, fidp->fid);
4920 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4921 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4922 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4923 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4924 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4925 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4926 /* pass the open mode back; XXXX add access checks */
4927 smb_SetSMBParm(outp, 6, (share & 0xf));
4928 smb_SetSMBDataLength(outp, 0);
4929 lock_ReleaseRead(&scp->rw);
4932 cm_Open(scp, 0, userp);
4934 /* send and free packet */
4935 smb_ReleaseFID(fidp);
4936 cm_ReleaseUser(userp);
4937 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4941 typedef struct smb_unlinkRock {
4946 char *maskp; /* pointer to the star pattern */
4949 cm_dirEntryList_t * matches;
4952 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4955 smb_unlinkRock_t *rockp;
4963 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4964 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4965 caseFold |= CM_FLAG_8DOT3;
4967 matchName = dep->name;
4968 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4970 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4971 !cm_Is8Dot3(dep->name)) {
4972 cm_Gen8Dot3Name(dep, shortName, NULL);
4973 matchName = shortName;
4974 /* 8.3 matches are always case insensitive */
4975 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4978 osi_Log1(smb_logp, "Found match %s",
4979 osi_LogSaveString(smb_logp, matchName));
4981 cm_DirEntryListAdd(dep->name, &rockp->matches);
4985 /* If we made a case sensitive exact match, we might as well quit now. */
4986 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4987 code = CM_ERROR_STOPNOW;
4996 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5005 smb_unlinkRock_t rock;
5014 attribute = smb_GetSMBParm(inp, 0);
5016 tp = smb_GetSMBData(inp, NULL);
5017 pathp = smb_ParseASCIIBlock(tp, &tp);
5018 if (smb_StoreAnsiFilenames)
5019 OemToChar(pathp,pathp);
5021 osi_Log1(smb_logp, "SMB receive unlink %s",
5022 osi_LogSaveString(smb_logp, pathp));
5024 spacep = inp->spacep;
5025 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5027 userp = smb_GetUserFromVCP(vcp, inp);
5029 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5031 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5033 cm_ReleaseUser(userp);
5034 return CM_ERROR_NOSUCHPATH;
5036 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5039 cm_ReleaseUser(userp);
5044 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5045 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,spacep->data);
5046 cm_ReleaseSCache(dscp);
5047 cm_ReleaseUser(userp);
5048 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5049 return CM_ERROR_PATH_NOT_COVERED;
5051 return CM_ERROR_BADSHARENAME;
5053 #endif /* DFS_SUPPORT */
5055 /* otherwise, scp points to the parent directory. */
5062 rock.maskp = smb_FindMask(pathp);
5063 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5066 thyper.HighPart = 0;
5071 rock.matches = NULL;
5073 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5074 * match. If that fails, we do a case insensitve match.
5076 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5077 !smb_IsStarMask(rock.maskp)) {
5078 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5081 thyper.HighPart = 0;
5082 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5087 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5089 if (code == CM_ERROR_STOPNOW)
5092 if (code == 0 && rock.matches) {
5093 cm_dirEntryList_t * entry;
5095 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5097 osi_Log1(smb_logp, "Unlinking %s",
5098 osi_LogSaveString(smb_logp, entry->name));
5099 code = cm_Unlink(dscp, entry->name, userp, &req);
5101 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5102 smb_NotifyChange(FILE_ACTION_REMOVED,
5103 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5104 dscp, entry->name, NULL, TRUE);
5108 cm_DirEntryListFree(&rock.matches);
5110 cm_ReleaseUser(userp);
5112 cm_ReleaseSCache(dscp);
5114 if (code == 0 && !rock.any)
5115 code = CM_ERROR_NOSUCHFILE;
5119 typedef struct smb_renameRock {
5120 cm_scache_t *odscp; /* old dir */
5121 cm_scache_t *ndscp; /* new dir */
5122 cm_user_t *userp; /* user */
5123 cm_req_t *reqp; /* request struct */
5124 smb_vc_t *vcp; /* virtual circuit */
5125 char *maskp; /* pointer to star pattern of old file name */
5126 int flags; /* tilde, casefold, etc */
5127 char *newNamep; /* ptr to the new file's name */
5128 char oldName[MAX_PATH];
5132 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5135 smb_renameRock_t *rockp;
5138 char shortName[13]="";
5140 rockp = (smb_renameRock_t *) vrockp;
5142 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5143 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5144 caseFold |= CM_FLAG_8DOT3;
5146 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5148 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5149 !cm_Is8Dot3(dep->name)) {
5150 cm_Gen8Dot3Name(dep, shortName, NULL);
5151 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5156 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5157 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5158 code = CM_ERROR_STOPNOW;
5168 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5171 cm_space_t *spacep = NULL;
5172 smb_renameRock_t rock;
5173 cm_scache_t *oldDscp = NULL;
5174 cm_scache_t *newDscp = NULL;
5175 cm_scache_t *tmpscp= NULL;
5176 cm_scache_t *tmpscp2 = NULL;
5186 userp = smb_GetUserFromVCP(vcp, inp);
5187 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5189 cm_ReleaseUser(userp);
5190 return CM_ERROR_NOSUCHPATH;
5194 spacep = inp->spacep;
5195 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5197 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5198 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5199 userp, tidPathp, &req, &oldDscp);
5201 cm_ReleaseUser(userp);
5206 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5207 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5208 cm_ReleaseSCache(oldDscp);
5209 cm_ReleaseUser(userp);
5210 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5211 return CM_ERROR_PATH_NOT_COVERED;
5213 return CM_ERROR_BADSHARENAME;
5215 #endif /* DFS_SUPPORT */
5217 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5218 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5219 userp, tidPathp, &req, &newDscp);
5222 cm_ReleaseSCache(oldDscp);
5223 cm_ReleaseUser(userp);
5228 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5229 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5230 cm_ReleaseSCache(oldDscp);
5231 cm_ReleaseSCache(newDscp);
5232 cm_ReleaseUser(userp);
5233 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5234 return CM_ERROR_PATH_NOT_COVERED;
5236 return CM_ERROR_BADSHARENAME;
5238 #endif /* DFS_SUPPORT */
5241 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5242 * next, get the component names, and lower case them.
5245 /* handle the old name first */
5247 oldLastNamep = oldPathp;
5251 /* and handle the new name, too */
5253 newLastNamep = newPathp;
5257 /* TODO: The old name could be a wildcard. The new name must not be */
5259 /* do the vnode call */
5260 rock.odscp = oldDscp;
5261 rock.ndscp = newDscp;
5265 rock.maskp = oldLastNamep;
5266 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5267 rock.newNamep = newLastNamep;
5268 rock.oldName[0] = '\0';
5271 /* Check if the file already exists; if so return error */
5272 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5273 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5274 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5276 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5277 osi_LogSaveString(smb_logp, newLastNamep));
5279 /* Check if the old and the new names differ only in case. If so return
5280 * success, else return CM_ERROR_EXISTS
5282 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5284 /* This would be a success only if the old file is *as same as* the new file */
5285 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5287 if (tmpscp == tmpscp2)
5290 code = CM_ERROR_EXISTS;
5291 cm_ReleaseSCache(tmpscp2);
5294 code = CM_ERROR_NOSUCHFILE;
5297 /* file exist, do not rename, also fixes move */
5298 osi_Log0(smb_logp, "Can't rename. Target already exists");
5299 code = CM_ERROR_EXISTS;
5303 cm_ReleaseSCache(tmpscp);
5304 cm_ReleaseSCache(newDscp);
5305 cm_ReleaseSCache(oldDscp);
5306 cm_ReleaseUser(userp);
5310 /* Now search the directory for the pattern, and do the appropriate rename when found */
5311 thyper.LowPart = 0; /* search dir from here */
5312 thyper.HighPart = 0;
5314 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5315 if (code == 0 && !rock.any) {
5317 thyper.HighPart = 0;
5318 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5319 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5321 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5323 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5324 code = cm_Rename(rock.odscp, rock.oldName,
5325 rock.ndscp, rock.newNamep, rock.userp,
5327 /* if the call worked, stop doing the search now, since we
5328 * really only want to rename one file.
5330 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5331 } else if (code == 0) {
5332 code = CM_ERROR_NOSUCHFILE;
5335 /* Handle Change Notification */
5337 * Being lazy, not distinguishing between files and dirs in this
5338 * filter, since we'd have to do a lookup.
5341 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5342 if (oldDscp == newDscp) {
5343 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5344 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5345 filter, oldDscp, oldLastNamep,
5346 newLastNamep, TRUE);
5348 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5349 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5350 filter, oldDscp, oldLastNamep,
5352 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5353 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5354 filter, newDscp, newLastNamep,
5360 cm_ReleaseSCache(tmpscp);
5361 cm_ReleaseUser(userp);
5362 cm_ReleaseSCache(oldDscp);
5363 cm_ReleaseSCache(newDscp);
5368 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5371 cm_space_t *spacep = NULL;
5372 cm_scache_t *oldDscp = NULL;
5373 cm_scache_t *newDscp = NULL;
5374 cm_scache_t *tmpscp= NULL;
5375 cm_scache_t *tmpscp2 = NULL;
5376 cm_scache_t *sscp = NULL;
5385 userp = smb_GetUserFromVCP(vcp, inp);
5387 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5389 cm_ReleaseUser(userp);
5390 return CM_ERROR_NOSUCHPATH;
5395 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5397 spacep = inp->spacep;
5398 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5400 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5401 userp, tidPathp, &req, &oldDscp);
5403 cm_ReleaseUser(userp);
5408 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5409 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5410 cm_ReleaseSCache(oldDscp);
5411 cm_ReleaseUser(userp);
5412 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5413 return CM_ERROR_PATH_NOT_COVERED;
5415 return CM_ERROR_BADSHARENAME;
5417 #endif /* DFS_SUPPORT */
5419 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5420 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5421 userp, tidPathp, &req, &newDscp);
5423 cm_ReleaseSCache(oldDscp);
5424 cm_ReleaseUser(userp);
5429 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5430 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5431 cm_ReleaseSCache(newDscp);
5432 cm_ReleaseSCache(oldDscp);
5433 cm_ReleaseUser(userp);
5434 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5435 return CM_ERROR_PATH_NOT_COVERED;
5437 return CM_ERROR_BADSHARENAME;
5439 #endif /* DFS_SUPPORT */
5441 /* Now, although we did two lookups for the two directories (because the same
5442 * directory can be referenced through different paths), we only allow hard links
5443 * within the same directory. */
5444 if (oldDscp != newDscp) {
5445 cm_ReleaseSCache(oldDscp);
5446 cm_ReleaseSCache(newDscp);
5447 cm_ReleaseUser(userp);
5448 return CM_ERROR_CROSSDEVLINK;
5451 /* handle the old name first */
5453 oldLastNamep = oldPathp;
5457 /* and handle the new name, too */
5459 newLastNamep = newPathp;
5463 /* now lookup the old name */
5464 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5465 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5467 cm_ReleaseSCache(oldDscp);
5468 cm_ReleaseSCache(newDscp);
5469 cm_ReleaseUser(userp);
5473 /* Check if the file already exists; if so return error */
5474 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5475 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5476 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5478 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5479 osi_LogSaveString(smb_logp, newLastNamep));
5481 /* if the existing link is to the same file, then we return success */
5483 if(sscp == tmpscp) {
5486 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5487 code = CM_ERROR_EXISTS;
5492 cm_ReleaseSCache(tmpscp);
5493 cm_ReleaseSCache(sscp);
5494 cm_ReleaseSCache(newDscp);
5495 cm_ReleaseSCache(oldDscp);
5496 cm_ReleaseUser(userp);
5500 /* now create the hardlink */
5501 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5502 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5503 osi_Log1(smb_logp," Link returns 0x%x", code);
5505 /* Handle Change Notification */
5507 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5508 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5509 smb_NotifyChange(FILE_ACTION_ADDED,
5510 filter, newDscp, newLastNamep,
5515 cm_ReleaseSCache(tmpscp);
5516 cm_ReleaseUser(userp);
5517 cm_ReleaseSCache(sscp);
5518 cm_ReleaseSCache(oldDscp);
5519 cm_ReleaseSCache(newDscp);
5524 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5531 tp = smb_GetSMBData(inp, NULL);
5532 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5533 if (smb_StoreAnsiFilenames)
5534 OemToChar(oldPathp,oldPathp);
5535 newPathp = smb_ParseASCIIBlock(tp, &tp);
5536 if (smb_StoreAnsiFilenames)
5537 OemToChar(newPathp,newPathp);
5539 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5540 osi_LogSaveString(smb_logp, oldPathp),
5541 osi_LogSaveString(smb_logp, newPathp));
5543 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5545 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5551 typedef struct smb_rmdirRock {
5555 char *maskp; /* pointer to the star pattern */
5558 cm_dirEntryList_t * matches;
5561 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5564 smb_rmdirRock_t *rockp;
5569 rockp = (smb_rmdirRock_t *) vrockp;
5571 matchName = dep->name;
5572 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5573 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5575 match = (strcmp(matchName, rockp->maskp) == 0);
5577 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5578 !cm_Is8Dot3(dep->name)) {
5579 cm_Gen8Dot3Name(dep, shortName, NULL);
5580 matchName = shortName;
5581 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5586 cm_DirEntryListAdd(dep->name, &rockp->matches);
5592 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5600 smb_rmdirRock_t rock;
5609 tp = smb_GetSMBData(inp, NULL);
5610 pathp = smb_ParseASCIIBlock(tp, &tp);
5611 if (smb_StoreAnsiFilenames)
5612 OemToChar(pathp,pathp);
5614 spacep = inp->spacep;
5615 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5617 userp = smb_GetUserFromVCP(vcp, inp);
5619 caseFold = CM_FLAG_CASEFOLD;
5621 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5623 cm_ReleaseUser(userp);
5624 return CM_ERROR_NOSUCHPATH;
5626 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5627 userp, tidPathp, &req, &dscp);
5630 cm_ReleaseUser(userp);
5635 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5636 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
5637 cm_ReleaseSCache(dscp);
5638 cm_ReleaseUser(userp);
5639 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5640 return CM_ERROR_PATH_NOT_COVERED;
5642 return CM_ERROR_BADSHARENAME;
5644 #endif /* DFS_SUPPORT */
5646 /* otherwise, scp points to the parent directory. */
5653 rock.maskp = lastNamep;
5654 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5657 thyper.HighPart = 0;
5661 rock.matches = NULL;
5663 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5664 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5665 if (code == 0 && !rock.any) {
5667 thyper.HighPart = 0;
5668 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5669 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5672 if (code == 0 && rock.matches) {
5673 cm_dirEntryList_t * entry;
5675 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5676 osi_Log1(smb_logp, "Removing directory %s",
5677 osi_LogSaveString(smb_logp, entry->name));
5679 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5681 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5682 smb_NotifyChange(FILE_ACTION_REMOVED,
5683 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5684 dscp, entry->name, NULL, TRUE);
5688 cm_DirEntryListFree(&rock.matches);
5690 cm_ReleaseUser(userp);
5692 cm_ReleaseSCache(dscp);
5694 if (code == 0 && !rock.any)
5695 code = CM_ERROR_NOSUCHFILE;
5699 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5709 fid = smb_GetSMBParm(inp, 0);
5711 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5713 fid = smb_ChainFID(fid, inp);
5714 fidp = smb_FindFID(vcp, fid, 0);
5716 return CM_ERROR_BADFD;
5718 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5719 smb_CloseFID(vcp, fidp, NULL, 0);
5720 smb_ReleaseFID(fidp);
5721 return CM_ERROR_NOSUCHFILE;
5724 lock_ObtainMutex(&fidp->mx);
5725 if (fidp->flags & SMB_FID_IOCTL) {
5726 lock_ReleaseMutex(&fidp->mx);
5727 smb_ReleaseFID(fidp);
5728 return CM_ERROR_BADFD;
5730 lock_ReleaseMutex(&fidp->mx);
5732 userp = smb_GetUserFromVCP(vcp, inp);
5734 lock_ObtainMutex(&fidp->mx);
5735 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
5736 cm_scache_t * scp = fidp->scp;
5738 lock_ReleaseMutex(&fidp->mx);
5739 code = cm_FSync(scp, userp, &req);
5740 cm_ReleaseSCache(scp);
5743 lock_ReleaseMutex(&fidp->mx);
5746 smb_ReleaseFID(fidp);
5748 cm_ReleaseUser(userp);
5753 struct smb_FullNameRock {
5759 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5763 struct smb_FullNameRock *vrockp;
5765 vrockp = (struct smb_FullNameRock *)rockp;
5767 if (!cm_Is8Dot3(dep->name)) {
5768 cm_Gen8Dot3Name(dep, shortName, NULL);
5770 if (cm_stricmp(shortName, vrockp->name) == 0) {
5771 vrockp->fullName = strdup(dep->name);
5772 return CM_ERROR_STOPNOW;
5775 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5776 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5777 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5778 vrockp->fullName = strdup(dep->name);
5779 return CM_ERROR_STOPNOW;
5784 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5785 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5787 struct smb_FullNameRock rock;
5793 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5794 if (code == CM_ERROR_STOPNOW)
5795 *newPathp = rock.fullName;
5797 *newPathp = strdup(pathp);
5800 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5801 afs_uint32 dosTime) {
5804 cm_scache_t *dscp = NULL;
5806 cm_scache_t * scp = NULL;
5807 cm_scache_t *delscp = NULL;
5809 int nullcreator = 0;
5811 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5812 fidp, fidp->fid, scp, vcp);
5815 lock_ObtainMutex(&fidp->mx);
5816 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5817 lock_ReleaseMutex(&fidp->mx);
5818 osi_Log0(smb_logp, " No user specified. Not closing fid");
5819 return CM_ERROR_BADFD;
5822 userp = fidp->userp; /* no hold required since fidp is held
5823 throughout the function */
5824 lock_ReleaseMutex(&fidp->mx);
5829 lock_ObtainWrite(&smb_rctLock);
5831 osi_Log0(smb_logp, " Fid already closed.");
5832 lock_ReleaseWrite(&smb_rctLock);
5833 return CM_ERROR_BADFD;
5836 lock_ReleaseWrite(&smb_rctLock);
5838 lock_ObtainMutex(&fidp->mx);
5839 if (fidp->NTopen_dscp) {
5840 dscp = fidp->NTopen_dscp;
5841 cm_HoldSCache(dscp);
5844 if (fidp->NTopen_pathp) {
5845 pathp = strdup(fidp->NTopen_pathp);
5853 /* Don't jump the gun on an async raw write */
5854 while (fidp->raw_writers) {
5855 lock_ReleaseMutex(&fidp->mx);
5856 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5857 lock_ObtainMutex(&fidp->mx);
5860 /* watch for ioctl closes, and read-only opens */
5862 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5863 == SMB_FID_OPENWRITE) {
5864 if (dosTime != 0 && dosTime != -1) {
5865 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5866 /* This fixes defect 10958 */
5867 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5868 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5870 if (smb_AsyncStore != 2) {
5871 lock_ReleaseMutex(&fidp->mx);
5872 code = cm_FSync(scp, userp, &req);
5873 lock_ObtainMutex(&fidp->mx);
5879 /* unlock any pending locks */
5880 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5881 scp->fileType == CM_SCACHETYPE_FILE) {
5885 lock_ReleaseMutex(&fidp->mx);
5887 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5889 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5890 lock_ObtainWrite(&scp->rw);
5892 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5893 CM_SCACHESYNC_NEEDCALLBACK
5894 | CM_SCACHESYNC_GETSTATUS
5895 | CM_SCACHESYNC_LOCK);
5899 "smb CoreClose SyncOp failure code 0x%x", tcode);
5900 goto post_syncopdone;
5903 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5905 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5909 lock_ReleaseWrite(&scp->rw);
5910 lock_ObtainMutex(&fidp->mx);
5913 if (fidp->flags & SMB_FID_DELONCLOSE) {
5916 lock_ReleaseMutex(&fidp->mx);
5918 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
5923 smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
5924 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5925 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5928 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5929 smb_NotifyChange(FILE_ACTION_REMOVED,
5930 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5931 dscp, fullPathp, NULL, TRUE);
5934 code = cm_Unlink(dscp, fullPathp, userp, &req);
5937 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5938 smb_NotifyChange(FILE_ACTION_REMOVED,
5939 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5940 dscp, fullPathp, NULL, TRUE);
5944 lock_ObtainMutex(&fidp->mx);
5945 fidp->flags &= ~SMB_FID_DELONCLOSE;
5948 /* if this was a newly created file, then clear the creator
5949 * in the stat cache entry. */
5950 if (fidp->flags & SMB_FID_CREATED) {
5952 fidp->flags &= ~SMB_FID_CREATED;
5955 if (fidp->flags & SMB_FID_NTOPEN) {
5956 cm_ReleaseSCache(fidp->NTopen_dscp);
5957 fidp->NTopen_dscp = NULL;
5958 free(fidp->NTopen_pathp);
5959 fidp->NTopen_pathp = NULL;
5960 fidp->flags &= ~SMB_FID_NTOPEN;
5962 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
5963 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
5966 if (fidp->NTopen_wholepathp) {
5967 free(fidp->NTopen_wholepathp);
5968 fidp->NTopen_wholepathp = NULL;
5972 cm_ReleaseSCache(fidp->scp);
5975 lock_ReleaseMutex(&fidp->mx);
5978 cm_ReleaseSCache(dscp);
5982 lock_ObtainWrite(&delscp->rw);
5984 delscp->flags |= CM_SCACHEFLAG_DELETED;
5985 lock_ReleaseWrite(&delscp->rw);
5987 cm_ReleaseSCache(delscp);
5991 lock_ObtainWrite(&scp->rw);
5992 if (nullcreator && scp->creator == userp)
5993 scp->creator = NULL;
5994 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5995 lock_ReleaseWrite(&scp->rw);
5996 cm_ReleaseSCache(scp);
6005 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6013 fid = smb_GetSMBParm(inp, 0);
6014 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6016 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6018 fid = smb_ChainFID(fid, inp);
6019 fidp = smb_FindFID(vcp, fid, 0);
6021 return CM_ERROR_BADFD;
6024 userp = smb_GetUserFromVCP(vcp, inp);
6026 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6028 smb_ReleaseFID(fidp);
6029 cm_ReleaseUser(userp);
6034 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6036 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6037 cm_user_t *userp, long *readp)
6043 osi_hyper_t fileLength;
6045 osi_hyper_t lastByte;
6046 osi_hyper_t bufferOffset;
6050 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6053 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6054 fidp->fid, offsetp->LowPart, count);
6058 lock_ObtainMutex(&fidp->mx);
6059 /* make sure we have a readable FD */
6060 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6061 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6062 fidp->fid, fidp->flags);
6063 lock_ReleaseMutex(&fidp->mx);
6064 code = CM_ERROR_BADFDOP;
6075 lock_ObtainWrite(&scp->rw);
6077 if (offset.HighPart == 0) {
6078 chunk = offset.LowPart >> cm_logChunkSize;
6079 if (chunk != fidp->curr_chunk) {
6080 fidp->prev_chunk = fidp->curr_chunk;
6081 fidp->curr_chunk = chunk;
6083 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6086 lock_ReleaseMutex(&fidp->mx);
6088 /* start by looking up the file's end */
6089 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6090 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6094 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6096 /* now we have the entry locked, look up the length */
6097 fileLength = scp->length;
6099 /* adjust count down so that it won't go past EOF */
6100 thyper.LowPart = count;
6101 thyper.HighPart = 0;
6102 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6104 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6105 /* we'd read past EOF, so just stop at fileLength bytes.
6106 * Start by computing how many bytes remain in the file.
6108 thyper = LargeIntegerSubtract(fileLength, offset);
6110 /* if we are past EOF, read 0 bytes */
6111 if (LargeIntegerLessThanZero(thyper))
6114 count = thyper.LowPart;
6119 /* now, copy the data one buffer at a time,
6120 * until we've filled the request packet
6123 /* if we've copied all the data requested, we're done */
6124 if (count <= 0) break;
6126 /* otherwise, load up a buffer of data */
6127 thyper.HighPart = offset.HighPart;
6128 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6129 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6132 buf_Release(bufferp);
6135 lock_ReleaseWrite(&scp->rw);
6137 code = buf_Get(scp, &thyper, &bufferp);
6139 lock_ObtainWrite(&scp->rw);
6140 if (code) goto done;
6141 bufferOffset = thyper;
6143 /* now get the data in the cache */
6145 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6146 CM_SCACHESYNC_NEEDCALLBACK |
6147 CM_SCACHESYNC_READ);
6151 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6153 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6155 /* otherwise, load the buffer and try again */
6156 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6160 buf_Release(bufferp);
6164 } /* if (wrong buffer) ... */
6166 /* now we have the right buffer loaded. Copy out the
6167 * data from here to the user's buffer.
6169 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6171 /* and figure out how many bytes we want from this buffer */
6172 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6173 if (nbytes > count) nbytes = count; /* don't go past EOF */
6175 /* now copy the data */
6176 memcpy(op, bufferp->datap + bufIndex, nbytes);
6178 /* adjust counters, pointers, etc. */
6181 thyper.LowPart = nbytes;
6182 thyper.HighPart = 0;
6183 offset = LargeIntegerAdd(thyper, offset);
6187 lock_ReleaseWrite(&scp->rw);
6189 buf_Release(bufferp);
6191 if (code == 0 && sequential)
6192 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6194 cm_ReleaseSCache(scp);
6197 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6198 fidp->fid, code, *readp);
6203 * smb_WriteData -- common code for Write and Raw Write
6205 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6206 cm_user_t *userp, long *writtenp)
6208 osi_hyper_t offset = *offsetp;
6211 cm_scache_t *scp = NULL;
6212 osi_hyper_t fileLength; /* file's length at start of write */
6213 osi_hyper_t minLength; /* don't read past this */
6214 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6215 cm_buf_t *bufferp = NULL;
6216 osi_hyper_t thyper; /* hyper tmp variable */
6217 osi_hyper_t bufferOffset;
6218 afs_uint32 bufIndex; /* index in buffer where our data is */
6219 int doWriteBack = 0;
6220 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6224 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6225 fidp->fid, offsetp->LowPart, count);
6229 lock_ObtainMutex(&fidp->mx);
6230 /* make sure we have a writable FD */
6231 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6232 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6233 fidp->fid, fidp->flags);
6234 lock_ReleaseMutex(&fidp->mx);
6235 code = CM_ERROR_BADFDOP;
6243 lock_ReleaseMutex(&fidp->mx);
6245 lock_ObtainWrite(&scp->rw);
6246 /* start by looking up the file's end */
6247 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6248 CM_SCACHESYNC_NEEDCALLBACK
6249 | CM_SCACHESYNC_SETSTATUS
6250 | CM_SCACHESYNC_GETSTATUS);
6254 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6256 /* now we have the entry locked, look up the length */
6257 fileLength = scp->length;
6258 minLength = fileLength;
6259 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6260 minLength = scp->serverLength;
6262 /* adjust file length if we extend past EOF */
6263 thyper.LowPart = count;
6264 thyper.HighPart = 0;
6265 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6266 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6267 /* we'd write past EOF, so extend the file */
6268 scp->mask |= CM_SCACHEMASK_LENGTH;
6269 scp->length = thyper;
6270 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6272 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6274 /* now, if the new position (thyper) and the old (offset) are in
6275 * different storeback windows, remember to store back the previous
6276 * storeback window when we're done with the write.
6278 * the purpose of this logic is to slow down the CIFS client
6279 * in order to avoid the client disconnecting during the CLOSE
6280 * operation if there are too many dirty buffers left to write
6281 * than can be accomplished during 45 seconds. This used to be
6282 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6283 * so that we can read larger amounts of data at a time.
6285 if (smb_AsyncStore == 1 &&
6286 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
6287 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
6288 /* they're different */
6290 writeBackOffset.HighPart = offset.HighPart;
6291 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
6296 /* now, copy the data one buffer at a time, until we've filled the
6299 /* if we've copied all the data requested, we're done */
6303 /* handle over quota or out of space */
6304 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6305 *writtenp = written;
6306 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6310 /* otherwise, load up a buffer of data */
6311 thyper.HighPart = offset.HighPart;
6312 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6313 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6316 lock_ReleaseMutex(&bufferp->mx);
6317 buf_Release(bufferp);
6320 lock_ReleaseWrite(&scp->rw);
6322 code = buf_Get(scp, &thyper, &bufferp);
6324 lock_ObtainMutex(&bufferp->mx);
6325 lock_ObtainWrite(&scp->rw);
6326 if (code) goto done;
6328 bufferOffset = thyper;
6330 /* now get the data in the cache */
6332 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6333 CM_SCACHESYNC_NEEDCALLBACK
6334 | CM_SCACHESYNC_WRITE
6335 | CM_SCACHESYNC_BUFLOCKED);
6339 cm_SyncOpDone(scp, bufferp,
6340 CM_SCACHESYNC_NEEDCALLBACK
6341 | CM_SCACHESYNC_WRITE
6342 | CM_SCACHESYNC_BUFLOCKED);
6344 /* If we're overwriting the entire buffer, or
6345 * if we're writing at or past EOF, mark the
6346 * buffer as current so we don't call
6347 * cm_GetBuffer. This skips the fetch from the
6348 * server in those cases where we're going to
6349 * obliterate all the data in the buffer anyway,
6350 * or in those cases where there is no useful
6351 * data at the server to start with.
6353 * Use minLength instead of scp->length, since
6354 * the latter has already been updated by this
6357 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6358 || LargeIntegerEqualTo(offset, bufferp->offset)
6359 && (count >= cm_data.buf_blockSize
6360 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6361 ConvertLongToLargeInteger(count)),
6363 if (count < cm_data.buf_blockSize
6364 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
6365 memset(bufferp->datap, 0,
6366 cm_data.buf_blockSize);
6367 bufferp->dataVersion = scp->dataVersion;
6370 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6372 /* otherwise, load the buffer and try again */
6373 lock_ReleaseMutex(&bufferp->mx);
6374 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6376 lock_ReleaseWrite(&scp->rw);
6377 lock_ObtainMutex(&bufferp->mx);
6378 lock_ObtainWrite(&scp->rw);
6382 lock_ReleaseMutex(&bufferp->mx);
6383 buf_Release(bufferp);
6387 } /* if (wrong buffer) ... */
6389 /* now we have the right buffer loaded. Copy out the
6390 * data from here to the user's buffer.
6392 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6394 /* and figure out how many bytes we want from this buffer */
6395 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6397 nbytes = count; /* don't go past end of request */
6399 /* now copy the data */
6400 memcpy(bufferp->datap + bufIndex, op, nbytes);
6401 buf_SetDirty(bufferp, bufIndex, nbytes);
6403 /* and record the last writer */
6404 if (bufferp->userp != userp) {
6407 cm_ReleaseUser(bufferp->userp);
6408 bufferp->userp = userp;
6411 /* adjust counters, pointers, etc. */
6415 thyper.LowPart = nbytes;
6416 thyper.HighPart = 0;
6417 offset = LargeIntegerAdd(thyper, offset);
6421 lock_ReleaseWrite(&scp->rw);
6424 lock_ReleaseMutex(&bufferp->mx);
6425 buf_Release(bufferp);
6428 lock_ObtainMutex(&fidp->mx);
6429 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6430 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6431 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6432 fidp->NTopen_dscp, fidp->NTopen_pathp,
6435 lock_ReleaseMutex(&fidp->mx);
6438 if (smb_AsyncStore > 0) {
6442 lock_ObtainWrite(&scp->rw);
6443 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6445 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6446 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6448 lock_ReleaseWrite(&scp->rw);
6449 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6450 writeBackOffset.HighPart,
6451 smb_AsyncStoreSize, 0, userp);
6452 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6455 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
6459 cm_ReleaseSCache(scp);
6462 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6463 fidp->fid, code, *writtenp);
6467 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6470 unsigned short count;
6472 unsigned short hint;
6473 long written = 0, total_written = 0;
6478 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6480 int inDataBlockCount;
6482 fd = smb_GetSMBParm(inp, 0);
6483 count = smb_GetSMBParm(inp, 1);
6484 offset.HighPart = 0; /* too bad */
6485 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6486 hint = smb_GetSMBParm(inp, 4);
6488 op = smb_GetSMBData(inp, NULL);
6489 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6491 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6492 fd, offset.LowPart, count);
6494 fd = smb_ChainFID(fd, inp);
6495 fidp = smb_FindFID(vcp, fd, 0);
6497 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6498 return CM_ERROR_BADFD;
6501 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6502 smb_CloseFID(vcp, fidp, NULL, 0);
6503 smb_ReleaseFID(fidp);
6504 return CM_ERROR_NOSUCHFILE;
6507 lock_ObtainMutex(&fidp->mx);
6508 if (fidp->flags & SMB_FID_IOCTL) {
6509 lock_ReleaseMutex(&fidp->mx);
6510 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6511 smb_ReleaseFID(fidp);
6512 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6515 lock_ReleaseMutex(&fidp->mx);
6516 userp = smb_GetUserFromVCP(vcp, inp);
6520 LARGE_INTEGER LOffset;
6521 LARGE_INTEGER LLength;
6523 pid = ((smb_t *) inp)->pid;
6524 key = cm_GenerateKey(vcp->vcID, pid, fd);
6526 LOffset.HighPart = offset.HighPart;
6527 LOffset.LowPart = offset.LowPart;
6528 LLength.HighPart = 0;
6529 LLength.LowPart = count;
6531 lock_ObtainWrite(&fidp->scp->rw);
6532 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6533 lock_ReleaseWrite(&fidp->scp->rw);
6536 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6541 /* special case: 0 bytes transferred means truncate to this position */
6545 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6549 truncAttr.mask = CM_ATTRMASK_LENGTH;
6550 truncAttr.length.LowPart = offset.LowPart;
6551 truncAttr.length.HighPart = 0;
6552 lock_ObtainMutex(&fidp->mx);
6553 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6554 fidp->flags |= SMB_FID_LENGTHSETDONE;
6555 lock_ReleaseMutex(&fidp->mx);
6556 smb_SetSMBParm(outp, 0, 0 /* count */);
6557 smb_SetSMBDataLength(outp, 0);
6562 * Work around bug in NT client
6564 * When copying a file, the NT client should first copy the data,
6565 * then copy the last write time. But sometimes the NT client does
6566 * these in the wrong order, so the data copies would inadvertently
6567 * cause the last write time to be overwritten. We try to detect this,
6568 * and don't set client mod time if we think that would go against the
6571 lock_ObtainMutex(&fidp->mx);
6572 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6573 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6574 fidp->scp->clientModTime = time(NULL);
6576 lock_ReleaseMutex(&fidp->mx);
6579 while ( code == 0 && count > 0 ) {
6580 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6581 if (code == 0 && written == 0)
6582 code = CM_ERROR_PARTIALWRITE;
6584 offset = LargeIntegerAdd(offset,
6585 ConvertLongToLargeInteger(written));
6586 count -= (unsigned short)written;
6587 total_written += written;
6591 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6592 total_written, code);
6594 /* set the packet data length to 3 bytes for the data block header,
6595 * plus the size of the data.
6597 smb_SetSMBParm(outp, 0, total_written);
6598 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6599 smb_SetSMBParm(outp, 3, hint);
6600 smb_SetSMBDataLength(outp, 0);
6603 smb_ReleaseFID(fidp);
6604 cm_ReleaseUser(userp);
6609 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6610 NCB *ncbp, raw_write_cont_t *rwcp)
6619 fd = smb_GetSMBParm(inp, 0);
6620 fidp = smb_FindFID(vcp, fd, 0);
6622 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6623 smb_CloseFID(vcp, fidp, NULL, 0);
6624 smb_ReleaseFID(fidp);
6628 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6629 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6631 userp = smb_GetUserFromVCP(vcp, inp);
6634 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6636 if (rwcp->writeMode & 0x1) { /* synchronous */
6639 smb_FormatResponsePacket(vcp, inp, outp);
6640 op = (smb_t *) outp;
6641 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6642 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6643 smb_SetSMBDataLength(outp, 0);
6644 smb_SendPacket(vcp, outp);
6645 smb_FreePacket(outp);
6647 else { /* asynchronous */
6648 lock_ObtainMutex(&fidp->mx);
6649 fidp->raw_writers--;
6650 if (fidp->raw_writers == 0)
6651 thrd_SetEvent(fidp->raw_write_event);
6652 lock_ReleaseMutex(&fidp->mx);
6655 /* Give back raw buffer */
6656 lock_ObtainMutex(&smb_RawBufLock);
6657 *((char **)rawBuf) = smb_RawBufs;
6658 smb_RawBufs = rawBuf;
6659 lock_ReleaseMutex(&smb_RawBufLock);
6661 smb_ReleaseFID(fidp);
6662 cm_ReleaseUser(userp);
6665 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6670 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6673 long count, written = 0, total_written = 0;
6680 unsigned short writeMode;
6682 fd = smb_GetSMBParm(inp, 0);
6683 totalCount = smb_GetSMBParm(inp, 1);
6684 count = smb_GetSMBParm(inp, 10);
6685 writeMode = smb_GetSMBParm(inp, 7);
6687 op = (char *) inp->data;
6688 op += smb_GetSMBParm(inp, 11);
6690 offset.HighPart = 0;
6691 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6693 if (*inp->wctp == 14) {
6694 /* we received a 64-bit file offset */
6695 #ifdef AFS_LARGEFILES
6696 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6698 if (LargeIntegerLessThanZero(offset)) {
6700 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6701 offset.HighPart, offset.LowPart);
6702 return CM_ERROR_BADSMB;
6705 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6707 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6708 return CM_ERROR_BADSMB;
6711 offset.HighPart = 0;
6714 offset.HighPart = 0; /* 32-bit file offset */
6718 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6719 fd, offset.HighPart, offset.LowPart, count);
6721 " WriteRaw WriteMode 0x%x",
6724 fd = smb_ChainFID(fd, inp);
6725 fidp = smb_FindFID(vcp, fd, 0);
6727 return CM_ERROR_BADFD;
6730 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6731 smb_CloseFID(vcp, fidp, NULL, 0);
6732 smb_ReleaseFID(fidp);
6733 return CM_ERROR_NOSUCHFILE;
6739 LARGE_INTEGER LOffset;
6740 LARGE_INTEGER LLength;
6742 pid = ((smb_t *) inp)->pid;
6743 key = cm_GenerateKey(vcp->vcID, pid, fd);
6745 LOffset.HighPart = offset.HighPart;
6746 LOffset.LowPart = offset.LowPart;
6747 LLength.HighPart = 0;
6748 LLength.LowPart = count;
6750 lock_ObtainWrite(&fidp->scp->rw);
6751 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6752 lock_ReleaseWrite(&fidp->scp->rw);
6755 smb_ReleaseFID(fidp);
6760 userp = smb_GetUserFromVCP(vcp, inp);
6763 * Work around bug in NT client
6765 * When copying a file, the NT client should first copy the data,
6766 * then copy the last write time. But sometimes the NT client does
6767 * these in the wrong order, so the data copies would inadvertently
6768 * cause the last write time to be overwritten. We try to detect this,
6769 * and don't set client mod time if we think that would go against the
6772 lock_ObtainMutex(&fidp->mx);
6773 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6774 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6775 fidp->scp->clientModTime = time(NULL);
6777 lock_ReleaseMutex(&fidp->mx);
6780 while ( code == 0 && count > 0 ) {
6781 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6782 if (code == 0 && written == 0)
6783 code = CM_ERROR_PARTIALWRITE;
6785 offset = LargeIntegerAdd(offset,
6786 ConvertLongToLargeInteger(written));
6789 total_written += written;
6793 /* Get a raw buffer */
6796 lock_ObtainMutex(&smb_RawBufLock);
6798 /* Get a raw buf, from head of list */
6799 rawBuf = smb_RawBufs;
6800 smb_RawBufs = *(char **)smb_RawBufs;
6803 code = CM_ERROR_USESTD;
6805 lock_ReleaseMutex(&smb_RawBufLock);
6808 /* Don't allow a premature Close */
6809 if (code == 0 && (writeMode & 1) == 0) {
6810 lock_ObtainMutex(&fidp->mx);
6811 fidp->raw_writers++;
6812 thrd_ResetEvent(fidp->raw_write_event);
6813 lock_ReleaseMutex(&fidp->mx);
6816 smb_ReleaseFID(fidp);
6817 cm_ReleaseUser(userp);
6820 smb_SetSMBParm(outp, 0, total_written);
6821 smb_SetSMBDataLength(outp, 0);
6822 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6827 offset = LargeIntegerAdd(offset,
6828 ConvertLongToLargeInteger(count));
6832 rwcp->offset.HighPart = offset.HighPart;
6833 rwcp->offset.LowPart = offset.LowPart;
6834 rwcp->count = totalCount - count;
6835 rwcp->writeMode = writeMode;
6836 rwcp->alreadyWritten = total_written;
6838 /* set the packet data length to 3 bytes for the data block header,
6839 * plus the size of the data.
6841 smb_SetSMBParm(outp, 0, 0xffff);
6842 smb_SetSMBDataLength(outp, 0);
6847 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6850 long count, finalCount;
6858 fd = smb_GetSMBParm(inp, 0);
6859 count = smb_GetSMBParm(inp, 1);
6860 offset.HighPart = 0; /* too bad */
6861 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6863 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6864 fd, offset.LowPart, count);
6866 fd = smb_ChainFID(fd, inp);
6867 fidp = smb_FindFID(vcp, fd, 0);
6869 return CM_ERROR_BADFD;
6871 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6872 smb_CloseFID(vcp, fidp, NULL, 0);
6873 smb_ReleaseFID(fidp);
6874 return CM_ERROR_NOSUCHFILE;
6877 lock_ObtainMutex(&fidp->mx);
6878 if (fidp->flags & SMB_FID_IOCTL) {
6879 lock_ReleaseMutex(&fidp->mx);
6880 code = smb_IoctlRead(fidp, vcp, inp, outp);
6881 smb_ReleaseFID(fidp);
6884 lock_ReleaseMutex(&fidp->mx);
6887 LARGE_INTEGER LOffset, LLength;
6890 pid = ((smb_t *) inp)->pid;
6891 key = cm_GenerateKey(vcp->vcID, pid, fd);
6893 LOffset.HighPart = 0;
6894 LOffset.LowPart = offset.LowPart;
6895 LLength.HighPart = 0;
6896 LLength.LowPart = count;
6898 lock_ObtainWrite(&fidp->scp->rw);
6899 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6900 lock_ReleaseWrite(&fidp->scp->rw);
6903 smb_ReleaseFID(fidp);
6907 userp = smb_GetUserFromVCP(vcp, inp);
6909 /* remember this for final results */
6910 smb_SetSMBParm(outp, 0, count);
6911 smb_SetSMBParm(outp, 1, 0);
6912 smb_SetSMBParm(outp, 2, 0);
6913 smb_SetSMBParm(outp, 3, 0);
6914 smb_SetSMBParm(outp, 4, 0);
6916 /* set the packet data length to 3 bytes for the data block header,
6917 * plus the size of the data.
6919 smb_SetSMBDataLength(outp, count+3);
6921 /* get op ptr after putting in the parms, since otherwise we don't
6922 * know where the data really is.
6924 op = smb_GetSMBData(outp, NULL);
6926 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6927 *op++ = 1; /* data block marker */
6928 *op++ = (unsigned char) (count & 0xff);
6929 *op++ = (unsigned char) ((count >> 8) & 0xff);
6931 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6933 /* fix some things up */
6934 smb_SetSMBParm(outp, 0, finalCount);
6935 smb_SetSMBDataLength(outp, finalCount+3);
6937 smb_ReleaseFID(fidp);
6939 cm_ReleaseUser(userp);
6943 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6950 cm_scache_t *dscp; /* dir we're dealing with */
6951 cm_scache_t *scp; /* file we're creating */
6953 int initialModeBits;
6963 /* compute initial mode bits based on read-only flag in attributes */
6964 initialModeBits = 0777;
6966 tp = smb_GetSMBData(inp, NULL);
6967 pathp = smb_ParseASCIIBlock(tp, &tp);
6968 if (smb_StoreAnsiFilenames)
6969 OemToChar(pathp,pathp);
6971 if (strcmp(pathp, "\\") == 0)
6972 return CM_ERROR_EXISTS;
6974 spacep = inp->spacep;
6975 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6977 userp = smb_GetUserFromVCP(vcp, inp);
6979 caseFold = CM_FLAG_CASEFOLD;
6981 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6983 cm_ReleaseUser(userp);
6984 return CM_ERROR_NOSUCHPATH;
6987 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6988 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6989 userp, tidPathp, &req, &dscp);
6992 cm_ReleaseUser(userp);
6997 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6998 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
6999 cm_ReleaseSCache(dscp);
7000 cm_ReleaseUser(userp);
7001 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7002 return CM_ERROR_PATH_NOT_COVERED;
7004 return CM_ERROR_BADSHARENAME;
7006 #endif /* DFS_SUPPORT */
7008 /* otherwise, scp points to the parent directory. Do a lookup, and
7009 * fail if we find it. Otherwise, we do the create.
7015 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7016 if (scp) cm_ReleaseSCache(scp);
7017 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7018 if (code == 0) code = CM_ERROR_EXISTS;
7019 cm_ReleaseSCache(dscp);
7020 cm_ReleaseUser(userp);
7024 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7025 setAttr.clientModTime = time(NULL);
7026 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7027 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7028 smb_NotifyChange(FILE_ACTION_ADDED,
7029 FILE_NOTIFY_CHANGE_DIR_NAME,
7030 dscp, lastNamep, NULL, TRUE);
7032 /* we don't need this any longer */
7033 cm_ReleaseSCache(dscp);
7036 /* something went wrong creating or truncating the file */
7037 cm_ReleaseUser(userp);
7041 /* otherwise we succeeded */
7042 smb_SetSMBDataLength(outp, 0);
7043 cm_ReleaseUser(userp);
7048 BOOL smb_IsLegalFilename(char *filename)
7051 * Find the longest substring of filename that does not contain
7052 * any of the chars in illegalChars. If that substring is less
7053 * than the length of the whole string, then one or more of the
7054 * illegal chars is in filename.
7056 if (strcspn(filename, illegalChars) < strlen(filename))
7062 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7070 cm_scache_t *dscp; /* dir we're dealing with */
7071 cm_scache_t *scp; /* file we're creating */
7073 int initialModeBits;
7081 int created = 0; /* the file was new */
7086 excl = (inp->inCom == 0x03)? 0 : 1;
7088 attributes = smb_GetSMBParm(inp, 0);
7089 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7091 /* compute initial mode bits based on read-only flag in attributes */
7092 initialModeBits = 0666;
7093 if (attributes & SMB_ATTR_READONLY)
7094 initialModeBits &= ~0222;
7096 tp = smb_GetSMBData(inp, NULL);
7097 pathp = smb_ParseASCIIBlock(tp, &tp);
7098 if (smb_StoreAnsiFilenames)
7099 OemToChar(pathp,pathp);
7101 spacep = inp->spacep;
7102 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7104 userp = smb_GetUserFromVCP(vcp, inp);
7106 caseFold = CM_FLAG_CASEFOLD;
7108 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7110 cm_ReleaseUser(userp);
7111 return CM_ERROR_NOSUCHPATH;
7113 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7114 userp, tidPathp, &req, &dscp);
7117 cm_ReleaseUser(userp);
7122 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7123 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7124 cm_ReleaseSCache(dscp);
7125 cm_ReleaseUser(userp);
7126 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7127 return CM_ERROR_PATH_NOT_COVERED;
7129 return CM_ERROR_BADSHARENAME;
7131 #endif /* DFS_SUPPORT */
7133 /* otherwise, scp points to the parent directory. Do a lookup, and
7134 * truncate the file if we find it, otherwise we create the file.
7141 if (!smb_IsLegalFilename(lastNamep))
7142 return CM_ERROR_BADNTFILENAME;
7144 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7145 #ifdef DEBUG_VERBOSE
7148 hexp = osi_HexifyString( lastNamep );
7149 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7154 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7155 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7156 cm_ReleaseSCache(dscp);
7157 cm_ReleaseUser(userp);
7161 /* if we get here, if code is 0, the file exists and is represented by
7162 * scp. Otherwise, we have to create it.
7166 /* oops, file shouldn't be there */
7167 cm_ReleaseSCache(dscp);
7168 cm_ReleaseSCache(scp);
7169 cm_ReleaseUser(userp);
7170 return CM_ERROR_EXISTS;
7173 setAttr.mask = CM_ATTRMASK_LENGTH;
7174 setAttr.length.LowPart = 0;
7175 setAttr.length.HighPart = 0;
7176 code = cm_SetAttr(scp, &setAttr, userp, &req);
7179 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7180 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7181 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7185 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7186 smb_NotifyChange(FILE_ACTION_ADDED,
7187 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7188 dscp, lastNamep, NULL, TRUE);
7189 } else if (!excl && code == CM_ERROR_EXISTS) {
7190 /* not an exclusive create, and someone else tried
7191 * creating it already, then we open it anyway. We
7192 * don't bother retrying after this, since if this next
7193 * fails, that means that the file was deleted after
7194 * we started this call.
7196 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7199 setAttr.mask = CM_ATTRMASK_LENGTH;
7200 setAttr.length.LowPart = 0;
7201 setAttr.length.HighPart = 0;
7202 code = cm_SetAttr(scp, &setAttr, userp, &req);
7207 /* we don't need this any longer */
7208 cm_ReleaseSCache(dscp);
7211 /* something went wrong creating or truncating the file */
7212 if (scp) cm_ReleaseSCache(scp);
7213 cm_ReleaseUser(userp);
7217 /* make sure we only open files */
7218 if (scp->fileType != CM_SCACHETYPE_FILE) {
7219 cm_ReleaseSCache(scp);
7220 cm_ReleaseUser(userp);
7221 return CM_ERROR_ISDIR;
7224 /* now all we have to do is open the file itself */
7225 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7226 osi_assertx(fidp, "null smb_fid_t");
7230 lock_ObtainMutex(&fidp->mx);
7231 /* always create it open for read/write */
7232 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7234 /* remember that the file was newly created */
7236 fidp->flags |= SMB_FID_CREATED;
7238 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7240 /* save a pointer to the vnode */
7242 lock_ObtainWrite(&scp->rw);
7243 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7244 lock_ReleaseWrite(&scp->rw);
7247 fidp->userp = userp;
7248 lock_ReleaseMutex(&fidp->mx);
7250 smb_SetSMBParm(outp, 0, fidp->fid);
7251 smb_SetSMBDataLength(outp, 0);
7253 cm_Open(scp, 0, userp);
7255 smb_ReleaseFID(fidp);
7256 cm_ReleaseUser(userp);
7257 /* leave scp held since we put it in fidp->scp */
7261 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7264 osi_hyper_t new_offset;
7275 fd = smb_GetSMBParm(inp, 0);
7276 whence = smb_GetSMBParm(inp, 1);
7277 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7279 /* try to find the file descriptor */
7280 fd = smb_ChainFID(fd, inp);
7281 fidp = smb_FindFID(vcp, fd, 0);
7283 return CM_ERROR_BADFD;
7285 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7286 smb_CloseFID(vcp, fidp, NULL, 0);
7287 smb_ReleaseFID(fidp);
7288 return CM_ERROR_NOSUCHFILE;
7291 lock_ObtainMutex(&fidp->mx);
7292 if (fidp->flags & SMB_FID_IOCTL) {
7293 lock_ReleaseMutex(&fidp->mx);
7294 smb_ReleaseFID(fidp);
7295 return CM_ERROR_BADFD;
7297 lock_ReleaseMutex(&fidp->mx);
7299 userp = smb_GetUserFromVCP(vcp, inp);
7301 lock_ObtainMutex(&fidp->mx);
7304 lock_ReleaseMutex(&fidp->mx);
7305 lock_ObtainWrite(&scp->rw);
7306 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7307 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7309 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7311 /* offset from current offset */
7312 new_offset = LargeIntegerAdd(fidp->offset,
7313 ConvertLongToLargeInteger(offset));
7315 else if (whence == 2) {
7316 /* offset from current EOF */
7317 new_offset = LargeIntegerAdd(scp->length,
7318 ConvertLongToLargeInteger(offset));
7320 new_offset = ConvertLongToLargeInteger(offset);
7323 fidp->offset = new_offset;
7324 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7325 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7326 smb_SetSMBDataLength(outp, 0);
7328 lock_ReleaseWrite(&scp->rw);
7329 smb_ReleaseFID(fidp);
7330 cm_ReleaseSCache(scp);
7331 cm_ReleaseUser(userp);
7335 /* dispatch all of the requests received in a packet. Due to chaining, this may
7336 * be more than one request.
7338 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7339 NCB *ncbp, raw_write_cont_t *rwcp)
7343 unsigned long code = 0;
7344 unsigned char *outWctp;
7345 int nparms; /* # of bytes of parameters */
7347 int nbytes; /* bytes of data, excluding count */
7350 unsigned short errCode;
7351 unsigned long NTStatus;
7353 unsigned char errClass;
7354 unsigned int oldGen;
7355 DWORD oldTime, newTime;
7357 /* get easy pointer to the data */
7358 smbp = (smb_t *) inp->data;
7360 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7361 /* setup the basic parms for the initial request in the packet */
7362 inp->inCom = smbp->com;
7363 inp->wctp = &smbp->wct;
7365 inp->ncb_length = ncbp->ncb_length;
7370 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7371 /* log it and discard it */
7372 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7373 __FILE__, __LINE__, ncbp->ncb_length);
7374 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7378 /* We are an ongoing op */
7379 thrd_Increment(&ongoingOps);
7381 /* set up response packet for receiving output */
7382 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7383 smb_FormatResponsePacket(vcp, inp, outp);
7384 outWctp = outp->wctp;
7386 /* Remember session generation number and time */
7387 oldGen = sessionGen;
7388 oldTime = GetTickCount();
7390 while (inp->inCom != 0xff) {
7391 dp = &smb_dispatchTable[inp->inCom];
7393 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7394 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7395 code = outp->resumeCode;
7399 /* process each request in the packet; inCom, wctp and inCount
7400 * are already set up.
7402 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7405 /* now do the dispatch */
7406 /* start by formatting the response record a little, as a default */
7407 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7409 outWctp[1] = 0xff; /* no operation */
7410 outWctp[2] = 0; /* padding */
7415 /* not a chained request, this is a more reasonable default */
7416 outWctp[0] = 0; /* wct of zero */
7417 outWctp[1] = 0; /* and bcc (word) of zero */
7421 /* once set, stays set. Doesn't matter, since we never chain
7422 * "no response" calls.
7424 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7428 /* we have a recognized operation */
7429 char * opName = myCrt_Dispatch(inp->inCom);
7431 if (inp->inCom == 0x1d)
7433 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7435 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",opName,vcp,vcp->lana,vcp->lsn);
7436 code = (*(dp->procp)) (vcp, inp, outp);
7437 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7439 if ( code == CM_ERROR_BADSMB ||
7440 code == CM_ERROR_BADOP )
7442 #endif /* LOG_PACKET */
7445 newTime = GetTickCount();
7446 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
7448 if (oldGen != sessionGen) {
7449 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7450 newTime - oldTime, ncbp->ncb_length);
7451 osi_Log3(smb_logp, "Request %s straddled session startup, "
7452 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
7456 /* bad opcode, fail the request, after displaying it */
7457 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7460 #endif /* LOG_PACKET */
7463 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7464 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7465 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7466 if (code == IDCANCEL)
7469 code = CM_ERROR_BADOP;
7472 /* catastrophic failure: log as much as possible */
7473 if (code == CM_ERROR_BADSMB) {
7474 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7478 #endif /* LOG_PACKET */
7479 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7482 code = CM_ERROR_INVAL;
7485 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7486 thrd_Decrement(&ongoingOps);
7491 /* now, if we failed, turn the current response into an empty
7492 * one, and fill in the response packet's error code.
7495 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7496 smb_MapNTError(code, &NTStatus);
7497 outWctp = outp->wctp;
7498 smbp = (smb_t *) &outp->data;
7499 if (code != CM_ERROR_PARTIALWRITE
7500 && code != CM_ERROR_BUFFERTOOSMALL
7501 && code != CM_ERROR_GSSCONTINUE) {
7502 /* nuke wct and bcc. For a partial
7503 * write or an in-process authentication handshake,
7504 * assume they're OK.
7510 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7511 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7512 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7513 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7514 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7518 smb_MapCoreError(code, vcp, &errCode, &errClass);
7519 outWctp = outp->wctp;
7520 smbp = (smb_t *) &outp->data;
7521 if (code != CM_ERROR_PARTIALWRITE) {
7522 /* nuke wct and bcc. For a partial
7523 * write, assume they're OK.
7529 smbp->errLow = (unsigned char) (errCode & 0xff);
7530 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7531 smbp->rcls = errClass;
7534 } /* error occurred */
7536 /* if we're here, we've finished one request. Look to see if
7537 * this is a chained opcode. If it is, setup things to process
7538 * the chained request, and setup the output buffer to hold the
7539 * chained response. Start by finding the next input record.
7541 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7542 break; /* not a chained req */
7543 tp = inp->wctp; /* points to start of last request */
7544 /* in a chained request, the first two
7545 * parm fields are required, and are
7546 * AndXCommand/AndXReserved and
7548 if (tp[0] < 2) break;
7549 if (tp[1] == 0xff) break; /* no more chained opcodes */
7551 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7554 /* and now append the next output request to the end of this
7555 * last request. Begin by finding out where the last response
7556 * ends, since that's where we'll put our new response.
7558 outWctp = outp->wctp; /* ptr to out parameters */
7559 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7560 nparms = outWctp[0] << 1;
7561 tp = outWctp + nparms + 1; /* now points to bcc field */
7562 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7563 tp += 2 /* for the count itself */ + nbytes;
7564 /* tp now points to the new output record; go back and patch the
7565 * second parameter (off2) to point to the new record.
7567 temp = (unsigned int)(tp - outp->data);
7568 outWctp[3] = (unsigned char) (temp & 0xff);
7569 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7570 outWctp[2] = 0; /* padding */
7571 outWctp[1] = inp->inCom; /* next opcode */
7573 /* finally, setup for the next iteration */
7576 } /* while loop over all requests in the packet */
7578 /* now send the output packet, and return */
7580 smb_SendPacket(vcp, outp);
7581 thrd_Decrement(&ongoingOps);
7586 /* Wait for Netbios() calls to return, and make the results available to server
7587 * threads. Note that server threads can't wait on the NCBevents array
7588 * themselves, because NCB events are manual-reset, and the servers would race
7589 * each other to reset them.
7591 void smb_ClientWaiter(void *parmp)
7596 while (smbShutdownFlag == 0) {
7597 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7599 if (code == WAIT_OBJECT_0)
7602 /* error checking */
7603 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7605 int abandonIdx = code - WAIT_ABANDONED_0;
7606 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7609 if (code == WAIT_IO_COMPLETION)
7611 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7615 if (code == WAIT_TIMEOUT)
7617 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7620 if (code == WAIT_FAILED)
7622 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7625 idx = code - WAIT_OBJECT_0;
7627 /* check idx range! */
7628 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7630 /* this is fatal - log as much as possible */
7631 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7632 osi_assertx(0, "invalid index");
7635 thrd_ResetEvent(NCBevents[idx]);
7636 thrd_SetEvent(NCBreturns[0][idx]);
7641 * Try to have one NCBRECV request waiting for every live session. Not more
7642 * than one, because if there is more than one, it's hard to handle Write Raw.
7644 void smb_ServerWaiter(void *parmp)
7647 int idx_session, idx_NCB;
7650 while (smbShutdownFlag == 0) {
7652 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7654 if (code == WAIT_OBJECT_0)
7657 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7659 int abandonIdx = code - WAIT_ABANDONED_0;
7660 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7663 if (code == WAIT_IO_COMPLETION)
7665 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7669 if (code == WAIT_TIMEOUT)
7671 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7674 if (code == WAIT_FAILED)
7676 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7679 idx_session = code - WAIT_OBJECT_0;
7681 /* check idx range! */
7682 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7684 /* this is fatal - log as much as possible */
7685 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7686 osi_assertx(0, "invalid index");
7691 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7693 if (code == WAIT_OBJECT_0) {
7694 if (smbShutdownFlag == 1)
7700 /* error checking */
7701 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7703 int abandonIdx = code - WAIT_ABANDONED_0;
7704 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7707 if (code == WAIT_IO_COMPLETION)
7709 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7713 if (code == WAIT_TIMEOUT)
7715 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7718 if (code == WAIT_FAILED)
7720 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7723 idx_NCB = code - WAIT_OBJECT_0;
7725 /* check idx range! */
7726 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7728 /* this is fatal - log as much as possible */
7729 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7730 osi_assertx(0, "invalid index");
7733 /* Link them together */
7734 NCBsessions[idx_NCB] = idx_session;
7737 ncbp = NCBs[idx_NCB];
7738 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7739 ncbp->ncb_command = NCBRECV | ASYNCH;
7740 ncbp->ncb_lana_num = lanas[idx_session];
7741 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7742 ncbp->ncb_event = NCBevents[idx_NCB];
7743 ncbp->ncb_length = SMB_PACKETSIZE;
7749 * The top level loop for handling SMB request messages. Each server thread
7750 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7751 * NCB and buffer for the incoming request are loaned to us.
7753 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7754 * to immediately send a request for the rest of the data. This must come
7755 * before any other traffic for that session, so we delay setting the session
7756 * event until that data has come in.
7758 void smb_Server(VOID *parmp)
7760 INT_PTR myIdx = (INT_PTR) parmp;
7764 smb_packet_t *outbufp;
7766 int idx_NCB, idx_session;
7768 smb_vc_t *vcp = NULL;
7771 rx_StartClientThread();
7774 outbufp = GetPacket();
7775 outbufp->ncbp = outncbp;
7783 smb_ResetServerPriority();
7785 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7788 /* terminate silently if shutdown flag is set */
7789 if (code == WAIT_OBJECT_0) {
7790 if (smbShutdownFlag == 1) {
7791 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7797 /* error checking */
7798 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7800 int abandonIdx = code - WAIT_ABANDONED_0;
7801 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7804 if (code == WAIT_IO_COMPLETION)
7806 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7810 if (code == WAIT_TIMEOUT)
7812 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7815 if (code == WAIT_FAILED)
7817 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7820 idx_NCB = code - WAIT_OBJECT_0;
7822 /* check idx range! */
7823 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7825 /* this is fatal - log as much as possible */
7826 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7827 osi_assertx(0, "invalid index");
7830 ncbp = NCBs[idx_NCB];
7831 idx_session = NCBsessions[idx_NCB];
7832 rc = ncbp->ncb_retcode;
7834 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7835 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7839 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7843 /* Can this happen? Or is it just my UNIX paranoia? */
7844 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7849 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7852 /* Client closed session */
7853 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7855 lock_ObtainMutex(&vcp->mx);
7856 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7857 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7859 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7860 lock_ReleaseMutex(&vcp->mx);
7861 lock_ObtainWrite(&smb_globalLock);
7862 dead_sessions[vcp->session] = TRUE;
7863 lock_ReleaseWrite(&smb_globalLock);
7864 smb_CleanupDeadVC(vcp);
7868 lock_ReleaseMutex(&vcp->mx);
7874 /* Treat as transient error */
7875 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7878 "dispatch smb recv failed, message incomplete, ncb_length %d",
7881 "SMB message incomplete, "
7882 "length %d", ncbp->ncb_length);
7885 * We used to discard the packet.
7886 * Instead, try handling it normally.
7890 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7894 /* A weird error code. Log it, sleep, and continue. */
7895 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7897 lock_ObtainMutex(&vcp->mx);
7898 if (vcp && vcp->errorCount++ > 3) {
7899 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7900 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7901 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7903 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7904 lock_ReleaseMutex(&vcp->mx);
7905 lock_ObtainWrite(&smb_globalLock);
7906 dead_sessions[vcp->session] = TRUE;
7907 lock_ReleaseWrite(&smb_globalLock);
7908 smb_CleanupDeadVC(vcp);
7912 lock_ReleaseMutex(&vcp->mx);
7918 lock_ReleaseMutex(&vcp->mx);
7920 thrd_SetEvent(SessionEvents[idx_session]);
7925 /* Success, so now dispatch on all the data in the packet */
7927 smb_concurrentCalls++;
7928 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7929 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7932 * If at this point vcp is NULL (implies that packet was invalid)
7933 * then we are in big trouble. This means either :
7934 * a) we have the wrong NCB.
7935 * b) Netbios screwed up the call.
7936 * c) The VC was already marked dead before we were able to
7938 * Obviously this implies that
7939 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7940 * lanas[idx_session] != ncbp->ncb_lana_num )
7941 * Either way, we can't do anything with this packet.
7942 * Log, sleep and resume.
7945 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7949 ncbp->ncb_lana_num);
7951 /* Also log in the trace log. */
7952 osi_Log4(smb_logp, "Server: VCP does not exist!"
7953 "LSNs[idx_session]=[%d],"
7954 "lanas[idx_session]=[%d],"
7955 "ncbp->ncb_lsn=[%d],"
7956 "ncbp->ncb_lana_num=[%d]",
7960 ncbp->ncb_lana_num);
7962 /* thrd_Sleep(1000); Don't bother sleeping */
7963 thrd_SetEvent(SessionEvents[idx_session]);
7964 smb_concurrentCalls--;
7968 smb_SetRequestStartTime();
7970 vcp->errorCount = 0;
7971 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7972 smbp = (smb_t *)bufp->data;
7977 if (smbp->com == 0x1d) {
7978 /* Special handling for Write Raw */
7979 raw_write_cont_t rwc;
7980 EVENT_HANDLE rwevent;
7981 char eventName[MAX_PATH];
7983 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7984 if (rwc.code == 0) {
7985 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7986 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7987 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7988 ncbp->ncb_command = NCBRECV | ASYNCH;
7989 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7990 ncbp->ncb_lana_num = vcp->lana;
7991 ncbp->ncb_buffer = rwc.buf;
7992 ncbp->ncb_length = 65535;
7993 ncbp->ncb_event = rwevent;
7995 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7996 thrd_CloseHandle(rwevent);
7998 thrd_SetEvent(SessionEvents[idx_session]);
8000 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8002 else if (smbp->com == 0xa0) {
8004 * Serialize the handling for NT Transact
8007 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8008 thrd_SetEvent(SessionEvents[idx_session]);
8010 thrd_SetEvent(SessionEvents[idx_session]);
8011 /* TODO: what else needs to be serialized? */
8012 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8015 __except( smb_ServerExceptionFilter() ) {
8018 smb_concurrentCalls--;
8021 thrd_SetEvent(NCBavails[idx_NCB]);
8028 * Exception filter for the server threads. If an exception occurs in the
8029 * dispatch routines, which is where exceptions are most common, then do a
8030 * force trace and give control to upstream exception handlers. Useful for
8033 DWORD smb_ServerExceptionFilter(void) {
8034 /* While this is not the best time to do a trace, if it succeeds, then
8035 * we have a trace (assuming tracing was enabled). Otherwise, this should
8036 * throw a second exception.
8038 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8039 afsd_ForceTrace(TRUE);
8040 buf_ForceTrace(TRUE);
8041 return EXCEPTION_CONTINUE_SEARCH;
8045 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8046 * If the number of server threads is M, and the number of live sessions is
8047 * N, then the number of NCB's in use at any time either waiting for, or
8048 * holding, received messages is M + N, so that is how many NCB's get created.
8050 void InitNCBslot(int idx)
8052 struct smb_packet *bufp;
8053 EVENT_HANDLE retHandle;
8055 char eventName[MAX_PATH];
8057 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8059 NCBs[idx] = GetNCB();
8060 sprintf(eventName,"NCBavails[%d]", idx);
8061 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8062 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8063 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8064 sprintf(eventName,"NCBevents[%d]", idx);
8065 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, 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,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8069 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8070 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8071 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8072 for (i=0; i<smb_NumServerThreads; i++)
8073 NCBreturns[i][idx] = retHandle;
8075 bufp->spacep = cm_GetSpace();
8079 /* listen for new connections */
8080 void smb_Listener(void *parmp)
8086 afs_uint32 session, thread;
8087 smb_vc_t *vcp = NULL;
8089 char rname[NCBNAMSZ+1];
8090 char cname[MAX_COMPUTERNAME_LENGTH+1];
8091 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8092 INT_PTR lana = (INT_PTR) parmp;
8093 char eventName[MAX_PATH];
8095 sprintf(eventName,"smb_Listener_lana_%d", (char)lana);
8096 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8097 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8098 thrd_ResetEvent(ListenerShutdown[lana]);
8102 /* retrieve computer name */
8103 GetComputerName(cname, &cnamelen);
8106 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8107 memset(ncbp, 0, sizeof(NCB));
8110 ncbp->ncb_command = NCBLISTEN;
8111 ncbp->ncb_rto = 0; /* No receive timeout */
8112 ncbp->ncb_sto = 0; /* No send timeout */
8114 /* pad out with spaces instead of null termination */
8115 len = (long)strlen(smb_localNamep);
8116 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8117 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8119 strcpy(ncbp->ncb_callname, "*");
8120 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8122 ncbp->ncb_lana_num = (UCHAR)lana;
8124 code = Netbios(ncbp);
8126 if (code == NRC_NAMERR) {
8127 /* An smb shutdown or Vista resume must have taken place */
8129 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8130 ncbp->ncb_lana_num, code);
8132 if (lock_TryMutex(&smb_StartedLock)) {
8133 lana_list.lana[i] = LANA_INVALID;
8134 lock_ReleaseMutex(&smb_StartedLock);
8137 } else if (code == NRC_BRIDGE || code != 0) {
8138 int lanaRemaining = 0;
8140 while (!lock_TryMutex(&smb_StartedLock)) {
8141 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8147 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8148 ncbp->ncb_lana_num, ncb_error_string(code));
8150 for (i = 0; i < lana_list.length; i++) {
8151 if (lana_list.lana[i] == lana) {
8152 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8153 lana_list.lana[i] = LANA_INVALID;
8155 if (lana_list.lana[i] != LANA_INVALID)
8159 if (lanaRemaining == 0) {
8160 cm_VolStatus_Network_Stopped(cm_NetbiosName
8165 smb_ListenerState = SMB_LISTENER_STOPPED;
8166 smb_LANadapter = LANA_INVALID;
8167 lana_list.length = 0;
8169 lock_ReleaseMutex(&smb_StartedLock);
8173 else if (code != 0) {
8174 char tbuffer[AFSPATHMAX];
8176 /* terminate silently if shutdown flag is set */
8177 while (!lock_TryMutex(&smb_StartedLock)) {
8178 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8184 "NCBLISTEN lana=%d failed with code %d [%s]",
8185 ncbp->ncb_lana_num, code, ncb_error_string(code));
8187 "Client exiting due to network failure. Please restart client.\n");
8190 "Client exiting due to network failure. Please restart client.\n"
8191 "NCBLISTEN lana=%d failed with code %d [%s]",
8192 ncbp->ncb_lana_num, code, ncb_error_string(code));
8194 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8195 MB_OK|MB_SERVICE_NOTIFICATION);
8196 osi_panic(tbuffer, __FILE__, __LINE__);
8198 lock_ReleaseMutex(&smb_StartedLock);
8203 /* check for remote conns */
8204 /* first get remote name and insert null terminator */
8205 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8206 for (i=NCBNAMSZ; i>0; i--) {
8207 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8213 /* compare with local name */
8215 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8216 flags |= SMB_VCFLAG_REMOTECONN;
8219 lock_ObtainMutex(&smb_ListenerLock);
8221 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8222 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8224 /* now ncbp->ncb_lsn is the connection ID */
8225 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8226 if (vcp->session == 0) {
8227 /* New generation */
8228 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8231 /* Log session startup */
8233 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8234 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8235 #endif /* NOTSERVICE */
8236 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8237 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8239 if (reportSessionStartups) {
8240 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8243 lock_ObtainMutex(&vcp->mx);
8244 strcpy(vcp->rname, rname);
8245 vcp->flags |= flags;
8246 lock_ReleaseMutex(&vcp->mx);
8248 /* Allocate slot in session arrays */
8249 /* Re-use dead session if possible, otherwise add one more */
8250 /* But don't look at session[0], it is reserved */
8251 lock_ObtainWrite(&smb_globalLock);
8252 for (session = 1; session < numSessions; session++) {
8253 if (dead_sessions[session]) {
8254 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8255 dead_sessions[session] = FALSE;
8259 lock_ReleaseWrite(&smb_globalLock);
8261 /* We are re-using an existing VC because the lsn and lana
8263 session = vcp->session;
8265 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8267 /* Log session startup */
8269 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8270 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8271 #endif /* NOTSERVICE */
8272 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8273 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8275 if (reportSessionStartups) {
8276 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8280 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8281 unsigned long code = CM_ERROR_ALLBUSY;
8282 smb_packet_t * outp = GetPacket();
8283 unsigned char *outWctp;
8286 smb_FormatResponsePacket(vcp, NULL, outp);
8289 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8290 unsigned long NTStatus;
8291 smb_MapNTError(code, &NTStatus);
8292 outWctp = outp->wctp;
8293 smbp = (smb_t *) &outp->data;
8297 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8298 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8299 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8300 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8301 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8303 unsigned short errCode;
8304 unsigned char errClass;
8305 smb_MapCoreError(code, vcp, &errCode, &errClass);
8306 outWctp = outp->wctp;
8307 smbp = (smb_t *) &outp->data;
8311 smbp->errLow = (unsigned char) (errCode & 0xff);
8312 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8313 smbp->rcls = errClass;
8315 smb_SendPacket(vcp, outp);
8316 smb_FreePacket(outp);
8318 lock_ObtainMutex(&vcp->mx);
8319 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8320 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8322 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8323 lock_ReleaseMutex(&vcp->mx);
8324 lock_ObtainWrite(&smb_globalLock);
8325 dead_sessions[vcp->session] = TRUE;
8326 lock_ReleaseWrite(&smb_globalLock);
8327 smb_CleanupDeadVC(vcp);
8329 lock_ReleaseMutex(&vcp->mx);
8332 /* assert that we do not exceed the maximum number of sessions or NCBs.
8333 * we should probably want to wait for a session to be freed in case
8336 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8337 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8339 lock_ObtainMutex(&vcp->mx);
8340 vcp->session = session;
8341 lock_ReleaseMutex(&vcp->mx);
8342 lock_ObtainWrite(&smb_globalLock);
8343 LSNs[session] = ncbp->ncb_lsn;
8344 lanas[session] = ncbp->ncb_lana_num;
8345 lock_ReleaseWrite(&smb_globalLock);
8347 if (session == numSessions) {
8348 /* Add new NCB for new session */
8349 char eventName[MAX_PATH];
8351 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8353 InitNCBslot(numNCBs);
8354 lock_ObtainWrite(&smb_globalLock);
8356 lock_ReleaseWrite(&smb_globalLock);
8357 thrd_SetEvent(NCBavails[0]);
8358 thrd_SetEvent(NCBevents[0]);
8359 for (thread = 0; thread < smb_NumServerThreads; thread++)
8360 thrd_SetEvent(NCBreturns[thread][0]);
8361 /* Also add new session event */
8362 sprintf(eventName, "SessionEvents[%d]", session);
8363 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8364 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8365 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8366 lock_ObtainWrite(&smb_globalLock);
8368 lock_ReleaseWrite(&smb_globalLock);
8369 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8370 thrd_SetEvent(SessionEvents[0]);
8372 thrd_SetEvent(SessionEvents[session]);
8378 lock_ReleaseMutex(&smb_ListenerLock);
8379 } /* dispatch while loop */
8383 thrd_SetEvent(ListenerShutdown[lana]);
8388 smb_LanAdapterChangeThread(void *param)
8391 * Give the IPAddrDaemon thread a chance
8392 * to block before we trigger.
8395 smb_LanAdapterChange(0);
8398 void smb_SetLanAdapterChangeDetected(void)
8403 lock_ObtainMutex(&smb_StartedLock);
8405 if (!powerStateSuspended) {
8406 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
8407 NULL, 0, &lpid, "smb_LanAdapterChange");
8408 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
8409 thrd_CloseHandle(phandle);
8412 smb_LanAdapterChangeDetected = 1;
8413 lock_ReleaseMutex(&smb_StartedLock);
8416 void smb_LanAdapterChange(int locked) {
8417 lana_number_t lanaNum;
8419 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
8421 LANA_ENUM temp_list;
8426 afsi_log("smb_LanAdapterChange");
8429 lock_ObtainMutex(&smb_StartedLock);
8431 smb_LanAdapterChangeDetected = 0;
8433 if (!powerStateSuspended &&
8434 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
8435 LANA_NETBIOS_NAME_FULL)) &&
8436 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
8437 if ( isGateway != bGateway ||
8438 strcmp(cm_NetbiosName, NetbiosName) ) {
8441 NCB *ncbp = GetNCB();
8442 ncbp->ncb_command = NCBENUM;
8443 ncbp->ncb_buffer = (PUCHAR)&temp_list;
8444 ncbp->ncb_length = sizeof(temp_list);
8445 code = Netbios(ncbp);
8447 if (temp_list.length != lana_list.length)
8450 for (i=0; i<lana_list.length; i++) {
8451 if ( temp_list.lana[i] != lana_list.lana[i] ) {
8463 afsi_log("Lan Adapter Change detected");
8464 smb_StopListeners(1);
8465 smb_RestartListeners(1);
8468 lock_ReleaseMutex(&smb_StartedLock);
8471 /* initialize Netbios */
8472 int smb_NetbiosInit(int locked)
8475 int i, lana, code, l;
8477 int delname_tried=0;
8480 lana_number_t lanaNum;
8483 lock_ObtainMutex(&smb_StartedLock);
8485 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
8486 smb_ListenerState != SMB_LISTENER_STOPPED) {
8489 lock_ReleaseMutex(&smb_StartedLock);
8492 /* setup the NCB system */
8495 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8496 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8497 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8499 if (smb_LANadapter != LANA_INVALID)
8500 afsi_log("LAN adapter number %d", smb_LANadapter);
8502 afsi_log("LAN adapter number not determined");
8505 afsi_log("Set for gateway service");
8507 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8509 /* something went horribly wrong. We can't proceed without a netbios name */
8511 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8512 osi_panic(buf, __FILE__, __LINE__);
8515 /* remember the name */
8516 len = (int)strlen(cm_NetbiosName);
8518 free(smb_localNamep);
8519 smb_localNamep = malloc(len+1);
8520 strcpy(smb_localNamep, cm_NetbiosName);
8521 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8524 if (smb_LANadapter == LANA_INVALID) {
8525 ncbp->ncb_command = NCBENUM;
8526 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8527 ncbp->ncb_length = sizeof(lana_list);
8528 code = Netbios(ncbp);
8530 afsi_log("Netbios NCBENUM error code %d", code);
8531 osi_panic(s, __FILE__, __LINE__);
8535 lana_list.length = 1;
8536 lana_list.lana[0] = smb_LANadapter;
8539 for (i = 0; i < lana_list.length; i++) {
8540 /* reset the adaptor: in Win32, this is required for every process, and
8541 * acts as an init call, not as a real hardware reset.
8543 ncbp->ncb_command = NCBRESET;
8544 ncbp->ncb_callname[0] = 100;
8545 ncbp->ncb_callname[2] = 100;
8546 ncbp->ncb_lana_num = lana_list.lana[i];
8547 code = Netbios(ncbp);
8549 code = ncbp->ncb_retcode;
8551 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8552 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
8554 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8558 /* and declare our name so we can receive connections */
8559 memset(ncbp, 0, sizeof(*ncbp));
8560 len=lstrlen(smb_localNamep);
8561 memset(smb_sharename,' ',NCBNAMSZ);
8562 memcpy(smb_sharename,smb_localNamep,len);
8563 afsi_log("lana_list.length %d", lana_list.length);
8565 /* Keep the name so we can unregister it later */
8566 for (l = 0; l < lana_list.length; l++) {
8567 lana = lana_list.lana[l];
8569 ncbp->ncb_command = NCBADDNAME;
8570 ncbp->ncb_lana_num = lana;
8571 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8572 code = Netbios(ncbp);
8574 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8575 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8577 char name[NCBNAMSZ+1];
8579 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8580 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8584 code = ncbp->ncb_retcode;
8587 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8590 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8591 if (code == NRC_BRIDGE) { /* invalid LANA num */
8592 lana_list.lana[l] = LANA_INVALID;
8595 else if (code == NRC_DUPNAME) {
8596 afsi_log("Name already exists; try to delete it");
8597 memset(ncbp, 0, sizeof(*ncbp));
8598 ncbp->ncb_command = NCBDELNAME;
8599 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8600 ncbp->ncb_lana_num = lana;
8601 code = Netbios(ncbp);
8603 code = ncbp->ncb_retcode;
8605 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8607 if (code != 0 || delname_tried) {
8608 lana_list.lana[l] = LANA_INVALID;
8610 else if (code == 0) {
8611 if (!delname_tried) {
8619 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8620 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8624 smb_LANadapter = lana;
8625 lana_found = 1; /* at least one worked */
8629 osi_assertx(lana_list.length >= 0, "empty lana list");
8631 afsi_log("No valid LANA numbers found!");
8632 lana_list.length = 0;
8633 smb_LANadapter = LANA_INVALID;
8634 smb_ListenerState = SMB_LISTENER_STOPPED;
8635 cm_VolStatus_Network_Stopped(cm_NetbiosName
8642 /* we're done with the NCB now */
8645 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
8646 if (lana_list.length > 0)
8647 osi_assert(smb_LANadapter != LANA_INVALID);
8650 lock_ReleaseMutex(&smb_StartedLock);
8652 return (lana_list.length > 0 ? 1 : 0);
8655 void smb_StartListeners(int locked)
8662 lock_ObtainMutex(&smb_StartedLock);
8664 if (smb_ListenerState == SMB_LISTENER_STARTED) {
8666 lock_ReleaseMutex(&smb_StartedLock);
8670 afsi_log("smb_StartListeners");
8671 smb_ListenerState = SMB_LISTENER_STARTED;
8672 cm_VolStatus_Network_Started(cm_NetbiosName
8678 for (i = 0; i < lana_list.length; i++) {
8679 if (lana_list.lana[i] == LANA_INVALID)
8681 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8682 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8683 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
8684 thrd_CloseHandle(phandle);
8687 lock_ReleaseMutex(&smb_StartedLock);
8690 void smb_RestartListeners(int locked)
8693 lock_ObtainMutex(&smb_StartedLock);
8695 if (powerStateSuspended)
8696 afsi_log("smb_RestartListeners called while suspended");
8698 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
8699 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8700 if (smb_NetbiosInit(1))
8701 smb_StartListeners(1);
8702 } else if (smb_LanAdapterChangeDetected) {
8703 smb_LanAdapterChange(1);
8707 lock_ReleaseMutex(&smb_StartedLock);
8710 void smb_StopListener(NCB *ncbp, int lana, int wait)
8714 memset(ncbp, 0, sizeof(*ncbp));
8715 ncbp->ncb_command = NCBDELNAME;
8716 ncbp->ncb_lana_num = lana;
8717 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8718 code = Netbios(ncbp);
8720 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8721 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8723 /* and then reset the LANA; this will cause the listener threads to exit */
8724 ncbp->ncb_command = NCBRESET;
8725 ncbp->ncb_callname[0] = 100;
8726 ncbp->ncb_callname[2] = 100;
8727 ncbp->ncb_lana_num = lana;
8728 code = Netbios(ncbp);
8730 code = ncbp->ncb_retcode;
8732 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8734 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8738 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
8741 void smb_StopListeners(int locked)
8747 lock_ObtainMutex(&smb_StartedLock);
8749 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8751 lock_ReleaseMutex(&smb_StartedLock);
8755 afsi_log("smb_StopListeners");
8756 smb_ListenerState = SMB_LISTENER_STOPPED;
8757 cm_VolStatus_Network_Stopped(cm_NetbiosName
8765 /* Unregister the SMB name */
8766 for (l = 0; l < lana_list.length; l++) {
8767 lana = lana_list.lana[l];
8769 if (lana != LANA_INVALID) {
8770 smb_StopListener(ncbp, lana, TRUE);
8772 /* mark the adapter invalid */
8773 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8777 /* force a re-evaluation of the network adapters */
8778 lana_list.length = 0;
8779 smb_LANadapter = LANA_INVALID;
8782 lock_ReleaseMutex(&smb_StartedLock);
8785 void smb_Init(osi_log_t *logp, int useV3,
8795 EVENT_HANDLE retHandle;
8796 char eventName[MAX_PATH];
8797 int startListeners = 0;
8799 smb_TlsRequestSlot = TlsAlloc();
8801 smb_MBfunc = aMBfunc;
8805 /* Initialize smb_localZero */
8806 myTime.tm_isdst = -1; /* compute whether on DST or not */
8807 myTime.tm_year = 70;
8813 smb_localZero = mktime(&myTime);
8815 #ifndef USE_NUMERIC_TIME_CONV
8816 /* Initialize kludge-GMT */
8817 smb_CalculateNowTZ();
8818 #endif /* USE_NUMERIC_TIME_CONV */
8819 #ifdef AFS_FREELANCE_CLIENT
8820 /* Make sure the root.afs volume has the correct time */
8821 cm_noteLocalMountPointChange();
8824 /* initialize the remote debugging log */
8827 /* and the global lock */
8828 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8829 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8831 /* Raw I/O data structures */
8832 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8834 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8835 lock_InitializeMutex(&smb_StartedLock, "smb started lock");
8837 /* 4 Raw I/O buffers */
8838 smb_RawBufs = calloc(65536,1);
8839 *((char **)smb_RawBufs) = NULL;
8840 for (i=0; i<3; i++) {
8841 char *rawBuf = calloc(65536,1);
8842 *((char **)rawBuf) = smb_RawBufs;
8843 smb_RawBufs = rawBuf;
8846 /* global free lists */
8847 smb_ncbFreeListp = NULL;
8848 smb_packetFreeListp = NULL;
8850 lock_ObtainMutex(&smb_StartedLock);
8851 startListeners = smb_NetbiosInit(1);
8853 /* Initialize listener and server structures */
8855 memset(dead_sessions, 0, sizeof(dead_sessions));
8856 sprintf(eventName, "SessionEvents[0]");
8857 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8858 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8859 afsi_log("Event Object Already Exists: %s", eventName);
8861 smb_NumServerThreads = nThreads;
8862 sprintf(eventName, "NCBavails[0]");
8863 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8864 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8865 afsi_log("Event Object Already Exists: %s", eventName);
8866 sprintf(eventName, "NCBevents[0]");
8867 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8868 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8869 afsi_log("Event Object Already Exists: %s", eventName);
8870 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8871 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8872 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8873 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8874 afsi_log("Event Object Already Exists: %s", eventName);
8875 for (i = 0; i < smb_NumServerThreads; i++) {
8876 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8877 NCBreturns[i][0] = retHandle;
8880 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8881 for (i = 0; i < smb_NumServerThreads; i++) {
8882 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8883 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8884 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8885 afsi_log("Event Object Already Exists: %s", eventName);
8886 InitNCBslot((int)(i+1));
8888 numNCBs = smb_NumServerThreads + 1;
8890 /* Initialize dispatch table */
8891 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8892 /* Prepare the table for unknown operations */
8893 for(i=0; i<= SMB_NOPCODES; i++) {
8894 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8896 /* Fill in the ones we do know */
8897 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8898 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8899 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8900 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8901 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8902 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8903 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8904 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8905 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8906 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8907 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8908 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8909 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8910 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8911 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8912 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8913 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8914 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8915 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8916 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8917 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8918 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8919 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8920 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8921 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8922 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8923 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8924 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8925 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8926 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8927 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8928 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8929 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8930 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8931 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8932 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8933 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8934 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8935 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8936 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8937 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8938 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8939 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8940 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8941 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8942 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8943 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8944 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8945 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8946 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8947 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8948 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8949 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8950 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8951 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8952 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8953 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8954 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8955 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8956 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8957 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8958 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8959 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8960 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8961 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8962 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8963 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8964 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8965 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8966 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8967 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8968 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8969 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8970 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8972 /* setup tran 2 dispatch table */
8973 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8974 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8975 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8976 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8977 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8978 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8979 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8980 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8981 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8982 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8983 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8984 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8985 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8986 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8987 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8988 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8989 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8990 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8992 /* setup the rap dispatch table */
8993 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8994 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8995 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8996 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8997 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9001 /* if we are doing SMB authentication we have register outselves as a logon process */
9002 if (smb_authType != SMB_AUTH_NONE) {
9003 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9004 LSA_STRING afsProcessName;
9005 LSA_OPERATIONAL_MODE dummy; /*junk*/
9007 afsProcessName.Buffer = "OpenAFSClientDaemon";
9008 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9009 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9011 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9013 if (nts == STATUS_SUCCESS) {
9014 LSA_STRING packageName;
9015 /* we are registered. Find out the security package id */
9016 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9017 packageName.Length = (USHORT)strlen(packageName.Buffer);
9018 packageName.MaximumLength = packageName.Length + 1;
9019 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9020 if (nts == STATUS_SUCCESS) {
9022 * This code forces Windows to authenticate against the Logon Cache
9023 * first instead of attempting to authenticate against the Domain
9024 * Controller. When the Windows logon cache is enabled this improves
9025 * performance by removing the network access and works around a bug
9026 * seen at sites which are using a MIT Kerberos principal to login
9027 * to machines joined to a non-root domain in a multi-domain forest.
9028 * MsV1_0SetProcessOption was added in Windows XP.
9030 PVOID pResponse = NULL;
9031 ULONG cbResponse = 0;
9032 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9034 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9035 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9036 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9037 OptionsRequest.DisableOptions = FALSE;
9039 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9042 sizeof(OptionsRequest),
9048 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9049 char message[AFSPATHMAX];
9050 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9052 OutputDebugString(message);
9055 OutputDebugString("MsV1_0SetProcessOption success");
9056 afsi_log("MsV1_0SetProcessOption success");
9058 /* END - code from Larry */
9060 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9061 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9062 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9064 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9066 /* something went wrong. We report the error and revert back to no authentication
9067 because we can't perform any auth requests without a successful lsa handle
9068 or sec package id. */
9069 afsi_log("Reverting to NO SMB AUTH");
9070 smb_authType = SMB_AUTH_NONE;
9073 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9075 /* something went wrong. We report the error and revert back to no authentication
9076 because we can't perform any auth requests without a successful lsa handle
9077 or sec package id. */
9078 afsi_log("Reverting to NO SMB AUTH");
9079 smb_authType = SMB_AUTH_NONE;
9083 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9084 * time prevents the failure of authentication when logged into Windows with an
9085 * external Kerberos principal mapped to a local account.
9087 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9088 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9089 * then the only option is NTLMSSP anyway; so just fallback.
9094 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9095 if (secBlobLength == 0) {
9096 smb_authType = SMB_AUTH_NTLM;
9097 afsi_log("Reverting to SMB AUTH NTLM");
9106 /* Now get ourselves a domain name. */
9107 /* For now we are using the local computer name as the domain name.
9108 * It is actually the domain for local logins, and we are acting as
9109 * a local SMB server.
9111 bufsize = sizeof(smb_ServerDomainName) - 1;
9112 GetComputerName(smb_ServerDomainName, &bufsize);
9113 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9114 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
9117 /* Start listeners, waiters, servers, and daemons */
9119 smb_StartListeners(1);
9121 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9122 NULL, 0, &lpid, "smb_ClientWaiter");
9123 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9124 thrd_CloseHandle(phandle);
9126 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9127 NULL, 0, &lpid, "smb_ServerWaiter");
9128 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9129 thrd_CloseHandle(phandle);
9131 for (i=0; i<smb_NumServerThreads; i++) {
9132 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9133 (void *) i, 0, &lpid, "smb_Server");
9134 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9135 thrd_CloseHandle(phandle);
9138 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9139 NULL, 0, &lpid, "smb_Daemon");
9140 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9141 thrd_CloseHandle(phandle);
9143 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9144 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9145 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9146 thrd_CloseHandle(phandle);
9148 lock_ReleaseMutex(&smb_StartedLock);
9152 void smb_Shutdown(void)
9159 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9161 /* setup the NCB system */
9164 /* Block new sessions by setting shutdown flag */
9165 smbShutdownFlag = 1;
9167 /* Hang up all sessions */
9168 memset((char *)ncbp, 0, sizeof(NCB));
9169 for (i = 1; i < numSessions; i++)
9171 if (dead_sessions[i])
9174 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9175 ncbp->ncb_command = NCBHANGUP;
9176 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9177 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9178 code = Netbios(ncbp);
9179 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9180 if (code == 0) code = ncbp->ncb_retcode;
9182 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9183 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9187 /* Trigger the shutdown of all SMB threads */
9188 for (i = 0; i < smb_NumServerThreads; i++)
9189 thrd_SetEvent(NCBreturns[i][0]);
9191 thrd_SetEvent(NCBevents[0]);
9192 thrd_SetEvent(SessionEvents[0]);
9193 thrd_SetEvent(NCBavails[0]);
9195 for (i = 0;i < smb_NumServerThreads; i++) {
9196 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9197 if (code == WAIT_OBJECT_0) {
9200 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9201 thrd_SetEvent(NCBreturns[i--][0]);
9205 /* Delete Netbios name */
9206 memset((char *)ncbp, 0, sizeof(NCB));
9207 for (i = 0; i < lana_list.length; i++) {
9208 if (lana_list.lana[i] == LANA_INVALID) continue;
9209 ncbp->ncb_command = NCBDELNAME;
9210 ncbp->ncb_lana_num = lana_list.lana[i];
9211 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9212 code = Netbios(ncbp);
9214 code = ncbp->ncb_retcode;
9216 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9217 ncbp->ncb_lana_num, code);
9222 /* Release the reference counts held by the VCs */
9223 lock_ObtainWrite(&smb_rctLock);
9224 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9229 if (vcp->magic != SMB_VC_MAGIC)
9230 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9231 __FILE__, __LINE__);
9233 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9235 if (fidp->scp != NULL) {
9238 lock_ObtainMutex(&fidp->mx);
9239 if (fidp->scp != NULL) {
9242 lock_ObtainWrite(&scp->rw);
9243 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9244 lock_ReleaseWrite(&scp->rw);
9245 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9246 cm_ReleaseSCache(scp);
9248 lock_ReleaseMutex(&fidp->mx);
9252 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9254 smb_ReleaseVCNoLock(tidp->vcp);
9256 cm_user_t *userp = tidp->userp;
9258 cm_ReleaseUser(userp);
9262 lock_ReleaseWrite(&smb_rctLock);
9264 TlsFree(smb_TlsRequestSlot);
9267 /* Get the UNC \\<servername>\<sharename> prefix. */
9268 char *smb_GetSharename()
9272 /* Make sure we have been properly initialized. */
9273 if (smb_localNamep == NULL)
9276 /* Allocate space for \\<servername>\<sharename>, plus the
9279 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9280 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9286 void smb_LogPacket(smb_packet_t *packet)
9289 unsigned length, paramlen, datalen, i, j;
9291 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9293 if (!packet) return;
9295 osi_Log0(smb_logp, "*** SMB packet dump ***");
9297 vp = (BYTE *) packet->data;
9299 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9300 length = paramlen + 2 + datalen;
9303 for (i=0;i < length; i+=16)
9305 memset( buf, ' ', 80 );
9310 buf[strlen(buf)] = ' ';
9312 cp = (BYTE*) buf + 7;
9314 for (j=0;j < 16 && (i+j)<length; j++)
9316 *(cp++) = hex[vp[i+j] >> 4];
9317 *(cp++) = hex[vp[i+j] & 0xf];
9327 for (j=0;j < 16 && (i+j)<length;j++)
9329 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9340 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9343 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9345 #endif /* LOG_PACKET */
9348 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9356 lock_ObtainRead(&smb_rctLock);
9358 sprintf(output, "begin dumping smb_vc_t\r\n");
9359 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9361 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9365 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9366 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9367 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9369 sprintf(output, "begin dumping smb_fid_t\r\n");
9370 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9372 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9374 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",
9375 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9376 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9377 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9378 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9381 sprintf(output, "done dumping smb_fid_t\r\n");
9382 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9385 sprintf(output, "done dumping smb_vc_t\r\n");
9386 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9388 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9389 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9391 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9395 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9396 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9397 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9399 sprintf(output, "begin dumping smb_fid_t\r\n");
9400 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9402 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9404 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",
9405 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9406 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9407 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9408 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9411 sprintf(output, "done dumping smb_fid_t\r\n");
9412 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9415 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9416 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9419 lock_ReleaseRead(&smb_rctLock);
9423 long smb_IsNetworkStarted(void)
9426 lock_ObtainWrite(&smb_globalLock);
9427 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
9428 lock_ReleaseWrite(&smb_globalLock);