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>
17 #include <sys/timeb.h>
29 #include <rx/rx_prototypes.h>
32 #include <WINNT\afsreg.h>
35 #include "lanahelper.h"
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
41 int smbShutdownFlag = 0;
43 int smb_LogoffTokenTransfer;
44 time_t smb_LogoffTransferTimeout;
46 int smb_StoreAnsiFilenames = 0;
48 DWORD last_msg_time = 0;
52 unsigned int sessionGen = 0;
54 extern void afsi_log(char *pattern, ...);
55 extern HANDLE afsi_file;
57 osi_hyper_t hzero = {0, 0};
58 osi_hyper_t hones = {0xFFFFFFFF, -1};
61 osi_rwlock_t smb_globalLock;
62 osi_rwlock_t smb_rctLock;
63 osi_mutex_t smb_ListenerLock;
66 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
69 long smb_maxObsConcurrentCalls=0;
70 long smb_concurrentCalls=0;
72 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
74 smb_packet_t *smb_packetFreeListp;
75 smb_ncb_t *smb_ncbFreeListp;
77 int smb_NumServerThreads;
79 int numNCBs, numSessions, numVCs;
81 int smb_maxVCPerServer;
82 int smb_maxMpxRequests;
84 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
86 ULONG smb_lsaSecPackage;
87 LSA_STRING smb_lsaLogonOrigin;
89 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
90 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
91 EVENT_HANDLE **NCBreturns;
92 EVENT_HANDLE **NCBShutdown;
93 EVENT_HANDLE *smb_ServerShutdown;
94 DWORD NCBsessions[NCB_MAX];
96 struct smb_packet *bufs[NCB_MAX];
98 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
99 EVENT_HANDLE SessionEvents[SESSION_MAX];
100 unsigned short LSNs[SESSION_MAX];
101 int lanas[SESSION_MAX];
102 BOOL dead_sessions[SESSION_MAX];
106 osi_mutex_t smb_RawBufLock;
108 #define SMB_RAW_BUFS 4
110 int smb_RawBufSel[SMB_RAW_BUFS];
115 #define SMB_MASKFLAG_TILDE 1
116 #define SMB_MASKFLAG_CASEFOLD 2
118 #define RAWTIMEOUT INFINITE
121 typedef struct raw_write_cont {
134 /* dir search stuff */
135 long smb_dirSearchCounter = 1;
136 smb_dirSearch_t *smb_firstDirSearchp;
137 smb_dirSearch_t *smb_lastDirSearchp;
139 /* hide dot files? */
140 int smb_hideDotFiles;
142 /* global state about V3 protocols */
143 int smb_useV3; /* try to negotiate V3 */
146 static showErrors = 1;
147 /* MessageBox or something like it */
148 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
152 * Time in Unix format of midnight, 1/1/1970 local time.
153 * When added to dosUTime, gives Unix (AFS) time.
155 time_t smb_localZero = 0;
157 #define USE_NUMERIC_TIME_CONV 1
159 #ifndef USE_NUMERIC_TIME_CONV
160 /* Time difference for converting to kludge-GMT */
161 afs_uint32 smb_NowTZ;
162 #endif /* USE_NUMERIC_TIME_CONV */
164 char *smb_localNamep = NULL;
166 smb_vc_t *smb_allVCsp;
167 smb_vc_t *smb_deadVCsp;
169 smb_username_t *usernamesp = NULL;
171 smb_waitingLockRequest_t *smb_allWaitingLocks;
173 DWORD smb_TlsRequestSlot = -1;
176 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
177 NCB *ncbp, raw_write_cont_t *rwcp);
178 void smb_NetbiosInit();
180 #ifndef AFS_WIN95_ENV
181 DWORD smb_ServerExceptionFilter(void);
184 extern char cm_HostName[];
185 extern char cm_confDir[];
189 #define LPTSTR char *
190 #define GetComputerName(str, sizep) \
191 strcpy((str), cm_HostName); \
192 *(sizep) = strlen(cm_HostName)
196 void smb_LogPacket(smb_packet_t *packet);
197 #endif /* LOG_PACKET */
199 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
200 int smb_ServerDomainNameLength = 0;
201 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
202 int smb_ServerOSLength = sizeof(smb_ServerOS);
203 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
204 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
206 /* Faux server GUID. This is never checked. */
207 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
209 void smb_ResetServerPriority()
211 void * p = TlsGetValue(smb_TlsRequestSlot);
214 TlsSetValue(smb_TlsRequestSlot, NULL);
215 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
219 void smb_SetRequestStartTime()
221 time_t * tp = malloc(sizeof(time_t));
225 if (!TlsSetValue(smb_TlsRequestSlot, tp))
230 void smb_UpdateServerPriority()
232 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
235 time_t now = osi_Time();
237 /* Give one priority boost for each 15 seconds */
238 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
243 const char * ncb_error_string(int code)
247 case 0x01: s = "llegal buffer length"; break;
248 case 0x03: s = "illegal command"; break;
249 case 0x05: s = "command timed out"; break;
250 case 0x06: s = "message incomplete, issue another command"; break;
251 case 0x07: s = "illegal buffer address"; break;
252 case 0x08: s = "session number out of range"; break;
253 case 0x09: s = "no resource available"; break;
254 case 0x0a: s = "session closed"; break;
255 case 0x0b: s = "command cancelled"; break;
256 case 0x0d: s = "duplicate name"; break;
257 case 0x0e: s = "name table full"; break;
258 case 0x0f: s = "no deletions, name has active sessions"; break;
259 case 0x11: s = "local session table full"; break;
260 case 0x12: s = "remote session table full"; break;
261 case 0x13: s = "illegal name number"; break;
262 case 0x14: s = "no callname"; break;
263 case 0x15: s = "cannot put * in NCB_NAME"; break;
264 case 0x16: s = "name in use on remote adapter"; break;
265 case 0x17: s = "name deleted"; break;
266 case 0x18: s = "session ended abnormally"; break;
267 case 0x19: s = "name conflict detected"; break;
268 case 0x21: s = "interface busy, IRET before retrying"; break;
269 case 0x22: s = "too many commands outstanding, retry later";break;
270 case 0x23: s = "ncb_lana_num field invalid"; break;
271 case 0x24: s = "command completed while cancel occurring "; break;
272 case 0x26: s = "command not valid to cancel"; break;
273 case 0x30: s = "name defined by anther local process"; break;
274 case 0x34: s = "environment undefined. RESET required"; break;
275 case 0x35: s = "required OS resources exhausted"; break;
276 case 0x36: s = "max number of applications exceeded"; break;
277 case 0x37: s = "no saps available for netbios"; break;
278 case 0x38: s = "requested resources are not available"; break;
279 case 0x39: s = "invalid ncb address or length > segment"; break;
280 case 0x3B: s = "invalid NCB DDID"; break;
281 case 0x3C: s = "lock of user area failed"; break;
282 case 0x3f: s = "NETBIOS not loaded"; break;
283 case 0x40: s = "system error"; break;
284 default: s = "unknown error";
290 char * myCrt_Dispatch(int i)
295 return "(00)ReceiveCoreMakeDir";
297 return "(01)ReceiveCoreRemoveDir";
299 return "(02)ReceiveCoreOpen";
301 return "(03)ReceiveCoreCreate";
303 return "(04)ReceiveCoreClose";
305 return "(05)ReceiveCoreFlush";
307 return "(06)ReceiveCoreUnlink";
309 return "(07)ReceiveCoreRename";
311 return "(08)ReceiveCoreGetFileAttributes";
313 return "(09)ReceiveCoreSetFileAttributes";
315 return "(0a)ReceiveCoreRead";
317 return "(0b)ReceiveCoreWrite";
319 return "(0c)ReceiveCoreLockRecord";
321 return "(0d)ReceiveCoreUnlockRecord";
323 return "(0e)SendCoreBadOp";
325 return "(0f)ReceiveCoreCreate";
327 return "(10)ReceiveCoreCheckPath";
329 return "(11)SendCoreBadOp";
331 return "(12)ReceiveCoreSeek";
333 return "(1a)ReceiveCoreReadRaw";
335 return "(1d)ReceiveCoreWriteRawDummy";
337 return "(22)ReceiveV3SetAttributes";
339 return "(23)ReceiveV3GetAttributes";
341 return "(24)ReceiveV3LockingX";
343 return "(25)ReceiveV3Trans";
345 return "(26)ReceiveV3Trans[aux]";
347 return "(29)SendCoreBadOp";
349 return "(2b)ReceiveCoreEcho";
351 return "(2d)ReceiveV3OpenX";
353 return "(2e)ReceiveV3ReadX";
355 return "(32)ReceiveV3Tran2A";
357 return "(33)ReceiveV3Tran2A[aux]";
359 return "(34)ReceiveV3FindClose";
361 return "(35)ReceiveV3FindNotifyClose";
363 return "(70)ReceiveCoreTreeConnect";
365 return "(71)ReceiveCoreTreeDisconnect";
367 return "(72)ReceiveNegotiate";
369 return "(73)ReceiveV3SessionSetupX";
371 return "(74)ReceiveV3UserLogoffX";
373 return "(75)ReceiveV3TreeConnectX";
375 return "(80)ReceiveCoreGetDiskAttributes";
377 return "(81)ReceiveCoreSearchDir";
381 return "(83)FindUnique";
383 return "(84)FindClose";
385 return "(A0)ReceiveNTTransact";
387 return "(A2)ReceiveNTCreateX";
389 return "(A4)ReceiveNTCancel";
391 return "(A5)ReceiveNTRename";
393 return "(C0)OpenPrintFile";
395 return "(C1)WritePrintFile";
397 return "(C2)ClosePrintFile";
399 return "(C3)GetPrintQueue";
401 return "(D8)ReadBulk";
403 return "(D9)WriteBulk";
405 return "(DA)WriteBulkData";
407 return "unknown SMB op";
411 char * myCrt_2Dispatch(int i)
416 return "unknown SMB op-2";
418 return "S(00)CreateFile";
420 return "S(01)FindFirst";
422 return "S(02)FindNext"; /* FindNext */
424 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
428 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
430 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
432 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
434 return "S(08)??_ReceiveTran2SetFileInfo";
436 return "S(09)??_ReceiveTran2FSCTL";
438 return "S(0a)_ReceiveTran2IOCTL";
440 return "S(0b)_ReceiveTran2FindNotifyFirst";
442 return "S(0c)_ReceiveTran2FindNotifyNext";
444 return "S(0d)_ReceiveTran2CreateDirectory";
446 return "S(0e)_ReceiveTran2SessionSetup";
448 return "S(10)_ReceiveTran2GetDfsReferral";
450 return "S(11)_ReceiveTran2ReportDfsInconsistency";
454 char * myCrt_RapDispatch(int i)
459 return "unknown RAP OP";
461 return "RAP(0)NetShareEnum";
463 return "RAP(1)NetShareGetInfo";
465 return "RAP(13)NetServerGetInfo";
467 return "RAP(63)NetWkStaGetInfo";
471 /* scache must be locked */
472 unsigned int smb_Attributes(cm_scache_t *scp)
476 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
477 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
478 scp->fileType == CM_SCACHETYPE_INVALID)
480 attrs = SMB_ATTR_DIRECTORY;
481 #ifdef SPECIAL_FOLDERS
482 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
483 #endif /* SPECIAL_FOLDERS */
484 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
485 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
490 * We used to mark a file RO if it was in an RO volume, but that
491 * turns out to be impolitic in NT. See defect 10007.
494 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
495 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
497 if ((scp->unixModeBits & 0222) == 0)
498 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
504 /* Check if the named file/dir is a dotfile/dotdir */
505 /* String pointed to by lastComp can have leading slashes, but otherwise should have
506 no other patch components */
507 unsigned int smb_IsDotFile(char *lastComp) {
510 /* skip over slashes */
511 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
516 /* nulls, curdir and parent dir doesn't count */
522 if(*(s+1) == '.' && !*(s + 2))
529 static int ExtractBits(WORD bits, short start, short len)
536 num = bits << (16 - end);
537 num = num >> ((16 - end) + start);
543 void ShowUnixTime(char *FuncName, time_t unixTime)
548 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
550 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
551 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
553 int day, month, year, sec, min, hour;
556 day = ExtractBits(wDate, 0, 5);
557 month = ExtractBits(wDate, 5, 4);
558 year = ExtractBits(wDate, 9, 7) + 1980;
560 sec = ExtractBits(wTime, 0, 5);
561 min = ExtractBits(wTime, 5, 6);
562 hour = ExtractBits(wTime, 11, 5);
564 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
565 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
571 /* Determine if we are observing daylight savings time */
572 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
574 TIME_ZONE_INFORMATION timeZoneInformation;
575 SYSTEMTIME utc, local, localDST;
577 /* Get the time zone info. NT uses this to calc if we are in DST. */
578 GetTimeZoneInformation(&timeZoneInformation);
580 /* Return the daylight bias */
581 *pDstBias = timeZoneInformation.DaylightBias;
583 /* Return the bias */
584 *pBias = timeZoneInformation.Bias;
586 /* Now determine if DST is being observed */
588 /* Get the UTC (GMT) time */
591 /* Convert UTC time to local time using the time zone info. If we are
592 observing DST, the calculated local time will include this.
594 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
596 /* Set the daylight bias to 0. The daylight bias is the amount of change
597 * in time that we use for daylight savings time. By setting this to 0
598 * we cause there to be no change in time during daylight savings time.
600 timeZoneInformation.DaylightBias = 0;
602 /* Convert the utc time to local time again, but this time without any
603 adjustment for daylight savings time.
605 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
607 /* If the two times are different, then it means that the localDST that
608 we calculated includes the daylight bias, and therefore we are
609 observing daylight savings time.
611 *pDST = localDST.wHour != local.wHour;
614 /* Determine if we are observing daylight savings time */
615 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
621 *pDstBias = -60; /* where can this be different? */
627 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
629 BOOL dst; /* Will be TRUE if observing DST */
630 LONG dstBias; /* Offset from local time if observing DST */
631 LONG bias; /* Offset from GMT for local time */
634 * This function will adjust the last write time to compensate
635 * for two bugs in the smb client:
637 * 1) During Daylight Savings Time, the LastWriteTime is ahead
638 * in time by the DaylightBias (ignoring the sign - the
639 * DaylightBias is always stored as a negative number). If
640 * the DaylightBias is -60, then the LastWriteTime will be
641 * ahead by 60 minutes.
643 * 2) If the local time zone is a positive offset from GMT, then
644 * the LastWriteTime will be the correct local time plus the
645 * Bias (ignoring the sign - a positive offset from GMT is
646 * always stored as a negative Bias). If the Bias is -120,
647 * then the LastWriteTime will be ahead by 120 minutes.
649 * These bugs can occur at the same time.
652 GetTimeZoneInfo(&dst, &dstBias, &bias);
654 /* First adjust for DST */
656 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
658 /* Now adjust for a positive offset from GMT (a negative bias). */
660 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
663 #ifndef USE_NUMERIC_TIME_CONV
665 * Calculate the difference (in seconds) between local time and GMT.
666 * This enables us to convert file times to kludge-GMT.
672 struct tm gmt_tm, local_tm;
673 int days, hours, minutes, seconds;
676 gmt_tm = *(gmtime(&t));
677 local_tm = *(localtime(&t));
679 days = local_tm.tm_yday - gmt_tm.tm_yday;
680 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
681 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
682 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
686 #endif /* USE_NUMERIC_TIME_CONV */
689 #ifdef USE_NUMERIC_TIME_CONV
690 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
692 // Note that LONGLONG is a 64-bit value
695 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
696 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
697 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
700 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
705 time_t ersatz_unixTime;
708 * Must use kludge-GMT instead of real GMT.
709 * kludge-GMT is computed by adding time zone difference to localtime.
712 * ltp = gmtime(&unixTime);
714 ersatz_unixTime = unixTime - smb_NowTZ;
715 ltp = localtime(&ersatz_unixTime);
717 /* if we fail, make up something */
720 localJunk.tm_year = 89 - 20;
721 localJunk.tm_mon = 4;
722 localJunk.tm_mday = 12;
723 localJunk.tm_hour = 0;
724 localJunk.tm_min = 0;
725 localJunk.tm_sec = 0;
728 stm.wYear = ltp->tm_year + 1900;
729 stm.wMonth = ltp->tm_mon + 1;
730 stm.wDayOfWeek = ltp->tm_wday;
731 stm.wDay = ltp->tm_mday;
732 stm.wHour = ltp->tm_hour;
733 stm.wMinute = ltp->tm_min;
734 stm.wSecond = ltp->tm_sec;
735 stm.wMilliseconds = 0;
737 SystemTimeToFileTime(&stm, largeTimep);
739 #endif /* USE_NUMERIC_TIME_CONV */
741 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
743 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
744 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
745 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
747 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
749 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
750 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
752 *ft = LargeIntegerMultiplyByLong(*ft, 60);
753 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
756 ut = ConvertLongToLargeInteger(unixTime);
757 ut = LargeIntegerMultiplyByLong(ut, 10000000);
758 *ft = LargeIntegerAdd(*ft, ut);
763 #ifdef USE_NUMERIC_TIME_CONV
764 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
766 // Note that LONGLONG is a 64-bit value
769 ll = largeTimep->dwHighDateTime;
771 ll += largeTimep->dwLowDateTime;
773 ll -= 116444736000000000;
776 *unixTimep = (DWORD)ll;
778 #else /* USE_NUMERIC_TIME_CONV */
779 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
785 FileTimeToSystemTime(largeTimep, &stm);
787 lt.tm_year = stm.wYear - 1900;
788 lt.tm_mon = stm.wMonth - 1;
789 lt.tm_wday = stm.wDayOfWeek;
790 lt.tm_mday = stm.wDay;
791 lt.tm_hour = stm.wHour;
792 lt.tm_min = stm.wMinute;
793 lt.tm_sec = stm.wSecond;
796 save_timezone = _timezone;
797 _timezone += smb_NowTZ;
798 *unixTimep = mktime(<);
799 _timezone = save_timezone;
801 #endif /* USE_NUMERIC_TIME_CONV */
803 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
805 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
806 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
807 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
811 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
812 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
813 a = LargeIntegerMultiplyByLong(a, 60);
814 a = LargeIntegerMultiplyByLong(a, 10000000);
816 /* subtract it from ft */
817 a = LargeIntegerSubtract(*ft, a);
819 /* divide down to seconds */
820 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
824 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
834 /* if we fail, make up something */
837 localJunk.tm_year = 89 - 20;
838 localJunk.tm_mon = 4;
839 localJunk.tm_mday = 12;
840 localJunk.tm_hour = 0;
841 localJunk.tm_min = 0;
842 localJunk.tm_sec = 0;
845 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
846 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
847 *searchTimep = (dosDate<<16) | dosTime;
850 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
852 unsigned short dosDate;
853 unsigned short dosTime;
856 dosDate = (unsigned short) (searchTime & 0xffff);
857 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
859 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
860 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
861 localTm.tm_mday = (dosDate) & 0x1f;
862 localTm.tm_hour = (dosTime>>11) & 0x1f;
863 localTm.tm_min = (dosTime >> 5) & 0x3f;
864 localTm.tm_sec = (dosTime & 0x1f) * 2;
865 localTm.tm_isdst = -1; /* compute whether DST in effect */
867 *unixTimep = mktime(&localTm);
870 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
872 time_t diff_t = unixTime - smb_localZero;
873 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
874 osi_assert(diff_t < _UI32_MAX);
876 *dosUTimep = (afs_uint32)diff_t;
879 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
882 *unixTimep = dosTime + smb_localZero;
884 /* dosTime seems to be already adjusted for GMT */
885 *unixTimep = dosTime;
889 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
893 lock_ObtainWrite(&smb_rctLock);
894 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
895 if (vcp->magic != SMB_VC_MAGIC)
896 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
899 if (lsn == vcp->lsn && lana == vcp->lana &&
900 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
901 smb_HoldVCNoLock(vcp);
905 if (!vcp && (flags & SMB_FLAG_CREATE)) {
906 vcp = malloc(sizeof(*vcp));
907 memset(vcp, 0, sizeof(*vcp));
908 lock_ObtainWrite(&smb_globalLock);
909 vcp->vcID = ++numVCs;
910 lock_ReleaseWrite(&smb_globalLock);
911 vcp->magic = SMB_VC_MAGIC;
912 vcp->refCount = 2; /* smb_allVCsp and caller */
915 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
916 vcp->nextp = smb_allVCsp;
918 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
923 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
924 /* We must obtain a challenge for extended auth
925 * in case the client negotiates smb v3
927 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
928 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
929 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
930 ULONG lsaRespSize = 0;
932 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
934 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
941 if (nts != STATUS_SUCCESS)
942 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
943 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
944 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
946 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
947 LsaFreeReturnBuffer(lsaResp);
950 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
952 if (numVCs >= CM_SESSION_RESERVED) {
953 lock_ObtainWrite(&smb_globalLock);
955 lock_ReleaseWrite(&smb_globalLock);
956 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
959 lock_ReleaseWrite(&smb_rctLock);
963 int smb_IsStarMask(char *maskp)
968 for(i=0; i<11; i++) {
970 if (tc == '?' || tc == '*' || tc == '>')
976 void smb_ReleaseVCInternal(smb_vc_t *vcp)
983 if (vcp->refCount == 0) {
984 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
985 /* remove VCP from smb_deadVCsp */
986 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
992 lock_FinalizeMutex(&vcp->mx);
993 memset(vcp,0,sizeof(smb_vc_t));
996 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
1000 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
1001 avcp?"not ":"",vcp, vcp->refCount);
1003 GenerateMiniDump(NULL);
1005 /* This is a wrong. However, I suspect that there is an undercount
1006 * and I don't want to release 1.4.1 in a state that will allow
1007 * smb_vc_t objects to be deallocated while still in the
1008 * smb_allVCsp list. The list is supposed to keep a reference
1009 * to the smb_vc_t. Put it back.
1016 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1018 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1019 smb_ReleaseVCInternal(vcp);
1022 void smb_ReleaseVC(smb_vc_t *vcp)
1024 lock_ObtainWrite(&smb_rctLock);
1025 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1026 smb_ReleaseVCInternal(vcp);
1027 lock_ReleaseWrite(&smb_rctLock);
1030 void smb_HoldVCNoLock(smb_vc_t *vcp)
1033 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1036 void smb_HoldVC(smb_vc_t *vcp)
1038 lock_ObtainWrite(&smb_rctLock);
1040 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1041 lock_ReleaseWrite(&smb_rctLock);
1044 void smb_CleanupDeadVC(smb_vc_t *vcp)
1046 smb_fid_t *fidpIter;
1047 smb_fid_t *fidpNext;
1049 smb_tid_t *tidpIter;
1050 smb_tid_t *tidpNext;
1052 smb_user_t *uidpIter;
1053 smb_user_t *uidpNext;
1057 lock_ObtainMutex(&vcp->mx);
1058 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1059 lock_ReleaseMutex(&vcp->mx);
1060 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1063 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1064 lock_ReleaseMutex(&vcp->mx);
1065 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1067 lock_ObtainWrite(&smb_rctLock);
1068 /* remove VCP from smb_allVCsp */
1069 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1070 if ((*vcpp)->magic != SMB_VC_MAGIC)
1071 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1072 __FILE__, __LINE__);
1075 vcp->nextp = smb_deadVCsp;
1077 /* Hold onto the reference until we are done with this function */
1082 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1083 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1085 if (fidpIter->delete)
1088 fid = fidpIter->fid;
1089 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1091 smb_HoldFIDNoLock(fidpIter);
1092 lock_ReleaseWrite(&smb_rctLock);
1094 smb_CloseFID(vcp, fidpIter, NULL, 0);
1095 smb_ReleaseFID(fidpIter);
1097 lock_ObtainWrite(&smb_rctLock);
1098 fidpNext = vcp->fidsp;
1101 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1102 tidpNext = tidpIter->nextp;
1103 if (tidpIter->delete)
1105 tidpIter->delete = 1;
1107 tid = tidpIter->tid;
1108 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1110 smb_HoldTIDNoLock(tidpIter);
1111 lock_ReleaseWrite(&smb_rctLock);
1113 smb_ReleaseTID(tidpIter);
1115 lock_ObtainWrite(&smb_rctLock);
1116 tidpNext = vcp->tidsp;
1119 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1120 uidpNext = uidpIter->nextp;
1121 if (uidpIter->delete)
1123 uidpIter->delete = 1;
1125 /* do not add an additional reference count for the smb_user_t
1126 * as the smb_vc_t already is holding a reference */
1127 lock_ReleaseWrite(&smb_rctLock);
1129 smb_ReleaseUID(uidpIter);
1131 lock_ObtainWrite(&smb_rctLock);
1132 uidpNext = vcp->usersp;
1135 /* The vcp is now on the deadVCsp list. We intentionally drop the
1136 * reference so that the refcount can reach 0 and we can delete it */
1137 smb_ReleaseVCNoLock(vcp);
1139 lock_ReleaseWrite(&smb_rctLock);
1140 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1143 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1147 lock_ObtainWrite(&smb_rctLock);
1148 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1149 if (tid == tidp->tid) {
1154 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1155 tidp = malloc(sizeof(*tidp));
1156 memset(tidp, 0, sizeof(*tidp));
1157 tidp->nextp = vcp->tidsp;
1160 smb_HoldVCNoLock(vcp);
1162 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1165 lock_ReleaseWrite(&smb_rctLock);
1169 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1174 void smb_ReleaseTID(smb_tid_t *tidp)
1181 lock_ObtainWrite(&smb_rctLock);
1182 osi_assert(tidp->refCount-- > 0);
1183 if (tidp->refCount == 0 && (tidp->delete)) {
1184 ltpp = &tidp->vcp->tidsp;
1185 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1189 osi_assert(tp != NULL);
1191 lock_FinalizeMutex(&tidp->mx);
1192 userp = tidp->userp; /* remember to drop ref later */
1194 smb_ReleaseVCNoLock(tidp->vcp);
1197 lock_ReleaseWrite(&smb_rctLock);
1199 cm_ReleaseUser(userp);
1202 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1204 smb_user_t *uidp = NULL;
1206 lock_ObtainWrite(&smb_rctLock);
1207 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1208 if (uid == uidp->userID) {
1210 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1212 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1216 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1217 uidp = malloc(sizeof(*uidp));
1218 memset(uidp, 0, sizeof(*uidp));
1219 uidp->nextp = vcp->usersp;
1220 uidp->refCount = 2; /* one for the vcp and one for the caller */
1222 smb_HoldVCNoLock(vcp);
1224 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1226 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1228 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1230 lock_ReleaseWrite(&smb_rctLock);
1234 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1236 smb_username_t *unp= NULL;
1238 lock_ObtainWrite(&smb_rctLock);
1239 for(unp = usernamesp; unp; unp = unp->nextp) {
1240 if (stricmp(unp->name, usern) == 0 &&
1241 stricmp(unp->machine, machine) == 0) {
1246 if (!unp && (flags & SMB_FLAG_CREATE)) {
1247 unp = malloc(sizeof(*unp));
1248 memset(unp, 0, sizeof(*unp));
1250 unp->nextp = usernamesp;
1251 unp->name = strdup(usern);
1252 unp->machine = strdup(machine);
1254 lock_InitializeMutex(&unp->mx, "username_t mutex");
1255 if (flags & SMB_FLAG_AFSLOGON)
1256 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1259 lock_ReleaseWrite(&smb_rctLock);
1263 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1265 smb_user_t *uidp= NULL;
1267 lock_ObtainWrite(&smb_rctLock);
1268 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1271 if (stricmp(uidp->unp->name, usern) == 0) {
1273 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1274 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1279 lock_ReleaseWrite(&smb_rctLock);
1283 void smb_ReleaseUsername(smb_username_t *unp)
1286 smb_username_t **lupp;
1287 cm_user_t *userp = NULL;
1288 time_t now = osi_Time();
1290 lock_ObtainWrite(&smb_rctLock);
1291 osi_assert(unp->refCount-- > 0);
1292 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1293 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1295 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1299 osi_assert(up != NULL);
1301 up->nextp = NULL; /* do not remove this */
1302 lock_FinalizeMutex(&unp->mx);
1308 lock_ReleaseWrite(&smb_rctLock);
1311 cm_ReleaseUser(userp);
1315 void smb_HoldUIDNoLock(smb_user_t *uidp)
1320 void smb_ReleaseUID(smb_user_t *uidp)
1324 smb_username_t *unp = NULL;
1326 lock_ObtainWrite(&smb_rctLock);
1327 osi_assert(uidp->refCount-- > 0);
1328 if (uidp->refCount == 0) {
1329 lupp = &uidp->vcp->usersp;
1330 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1334 osi_assert(up != NULL);
1336 lock_FinalizeMutex(&uidp->mx);
1338 smb_ReleaseVCNoLock(uidp->vcp);
1342 lock_ReleaseWrite(&smb_rctLock);
1346 cm_ReleaseUserVCRef(unp->userp);
1347 smb_ReleaseUsername(unp);
1351 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1353 cm_user_t *up = NULL;
1358 lock_ObtainMutex(&uidp->mx);
1360 up = uidp->unp->userp;
1363 lock_ReleaseMutex(&uidp->mx);
1369 /* retrieve a held reference to a user structure corresponding to an incoming
1371 * corresponding release function is cm_ReleaseUser.
1373 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1376 cm_user_t *up = NULL;
1379 smbp = (smb_t *) inp;
1380 uidp = smb_FindUID(vcp, smbp->uid, 0);
1384 up = smb_GetUserFromUID(uidp);
1386 smb_ReleaseUID(uidp);
1391 * Return a pointer to a pathname extracted from a TID structure. The
1392 * TID structure is not held; assume it won't go away.
1394 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1399 tidp = smb_FindTID(vcp, tid, 0);
1403 if (tidp->flags & SMB_TIDFLAG_IPC) {
1404 code = CM_ERROR_TIDIPC;
1405 /* tidp->pathname would be NULL, but that's fine */
1407 *treepath = tidp->pathname;
1408 smb_ReleaseTID(tidp);
1413 /* check to see if we have a chained fid, that is, a fid that comes from an
1414 * OpenAndX message that ran earlier in this packet. In this case, the fid
1415 * field in a read, for example, request, isn't set, since the value is
1416 * supposed to be inherited from the openAndX call.
1418 int smb_ChainFID(int fid, smb_packet_t *inp)
1420 if (inp->fid == 0 || inp->inCount == 0)
1426 /* are we a priv'd user? What does this mean on NT? */
1427 int smb_SUser(cm_user_t *userp)
1432 /* find a file ID. If we pass in 0 we select an unused File ID.
1433 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1434 * smb_fid_t data structure if desired File ID cannot be found.
1436 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1441 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1444 lock_ObtainWrite(&smb_rctLock);
1445 /* figure out if we need to allocate a new file ID */
1448 fid = vcp->fidCounter;
1452 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1453 if (fid == fidp->fid) {
1456 if (fid == 0xFFFF) {
1458 "New FID number wraps on vcp 0x%x", vcp);
1468 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1469 char eventName[MAX_PATH];
1471 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1472 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1473 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1474 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1475 thrd_CloseHandle(event);
1477 if (fid == 0xFFFF) {
1478 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1484 fidp = malloc(sizeof(*fidp));
1485 memset(fidp, 0, sizeof(*fidp));
1486 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1489 smb_HoldVCNoLock(vcp);
1490 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1492 fidp->curr_chunk = fidp->prev_chunk = -2;
1493 fidp->raw_write_event = event;
1495 vcp->fidCounter = fid+1;
1496 if (vcp->fidCounter == 0xFFFF) {
1497 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1499 vcp->fidCounter = 1;
1504 lock_ReleaseWrite(&smb_rctLock);
1508 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1513 void smb_ReleaseFID(smb_fid_t *fidp)
1515 cm_scache_t *scp = NULL;
1516 cm_user_t *userp = NULL;
1517 smb_vc_t *vcp = NULL;
1518 smb_ioctl_t *ioctlp;
1520 lock_ObtainMutex(&fidp->mx);
1521 lock_ObtainWrite(&smb_rctLock);
1522 osi_assert(fidp->refCount-- > 0);
1523 if (fidp->refCount == 0 && (fidp->delete)) {
1526 scp = fidp->scp; /* release after lock is released */
1528 userp = fidp->userp;
1532 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1533 thrd_CloseHandle(fidp->raw_write_event);
1535 /* and see if there is ioctl stuff to free */
1536 ioctlp = fidp->ioctlp;
1539 cm_FreeSpace(ioctlp->prefix);
1540 if (ioctlp->inAllocp)
1541 free(ioctlp->inAllocp);
1542 if (ioctlp->outAllocp)
1543 free(ioctlp->outAllocp);
1546 lock_ReleaseMutex(&fidp->mx);
1547 lock_FinalizeMutex(&fidp->mx);
1551 smb_ReleaseVCNoLock(vcp);
1553 lock_ReleaseMutex(&fidp->mx);
1555 lock_ReleaseWrite(&smb_rctLock);
1557 /* now release the scache structure */
1559 cm_ReleaseSCache(scp);
1562 cm_ReleaseUser(userp);
1566 * Case-insensitive search for one string in another;
1567 * used to find variable names in submount pathnames.
1569 static char *smb_stristr(char *str1, char *str2)
1573 for (cursor = str1; *cursor; cursor++)
1574 if (stricmp(cursor, str2) == 0)
1581 * Substitute a variable value for its name in a submount pathname. Variable
1582 * name has been identified by smb_stristr() and is in substr. Variable name
1583 * length (plus one) is in substr_size. Variable value is in newstr.
1585 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1590 strcpy(temp, substr + substr_size - 1);
1591 strcpy(substr, newstr);
1595 char VNUserName[] = "%USERNAME%";
1596 char VNLCUserName[] = "%LCUSERNAME%";
1597 char VNComputerName[] = "%COMPUTERNAME%";
1598 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1601 /* List available shares */
1602 int smb_ListShares()
1606 char shareBuf[4096];
1614 /*strcpy(shareNameList[num_shares], "all");
1615 strcpy(pathNameList[num_shares++], "/afs");*/
1616 fprintf(stderr, "The following shares are available:\n");
1617 fprintf(stderr, "Share Name (AFS Path)\n");
1618 fprintf(stderr, "---------------------\n");
1619 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1622 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1623 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1625 strcpy(sbmtpath, cm_confDir);
1627 strcat(sbmtpath, "/afsdsbmt.ini");
1628 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1629 shareBuf, sizeof(shareBuf),
1635 this_share = shareBuf;
1639 /*strcpy(shareNameList[num_shares], this_share);*/
1640 len = GetPrivateProfileString("AFS Submounts", this_share,
1647 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1650 if (*p == '\\') *p = '/'; /* change to / */
1654 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1655 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1658 while (*this_share != 0) this_share++; /* find next NUL */
1659 this_share++; /* skip past the NUL */
1660 } while (*this_share != 0); /* stop at final NUL */
1666 typedef struct smb_findShare_rock {
1670 } smb_findShare_rock_t;
1672 #define SMB_FINDSHARE_EXACT_MATCH 1
1673 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1675 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1679 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1680 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1681 if(!stricmp(dep->name, vrock->shareName))
1682 matchType = SMB_FINDSHARE_EXACT_MATCH;
1684 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1685 if(vrock->match) free(vrock->match);
1686 vrock->match = strdup(dep->name);
1687 vrock->matchType = matchType;
1689 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1690 return CM_ERROR_STOPNOW;
1696 /* find a shareName in the table of submounts */
1697 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1701 char pathName[1024];
1706 char sbmtpath[MAX_PATH];
1711 DWORD allSubmount = 1;
1713 /* if allSubmounts == 0, only return the //mountRoot/all share
1714 * if in fact it has been been created in the subMounts table.
1715 * This is to allow sites that want to restrict access to the
1718 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1719 0, KEY_QUERY_VALUE, &parmKey);
1720 if (code == ERROR_SUCCESS) {
1721 len = sizeof(allSubmount);
1722 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1723 (BYTE *) &allSubmount, &len);
1724 if (code != ERROR_SUCCESS) {
1727 RegCloseKey (parmKey);
1730 if (allSubmount && _stricmp(shareName, "all") == 0) {
1735 /* In case, the all share is disabled we need to still be able
1736 * to handle ioctl requests
1738 if (_stricmp(shareName, "ioctl$") == 0) {
1739 *pathNamep = strdup("/.__ioctl__");
1743 if (_stricmp(shareName, "IPC$") == 0 ||
1744 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1745 _stricmp(shareName, "DESKTOP.INI") == 0
1752 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1753 0, KEY_QUERY_VALUE, &parmKey);
1754 if (code == ERROR_SUCCESS) {
1755 len = sizeof(pathName);
1756 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1757 (BYTE *) pathName, &len);
1758 if (code != ERROR_SUCCESS)
1760 RegCloseKey (parmKey);
1765 strcpy(sbmtpath, cm_confDir);
1766 strcat(sbmtpath, "/afsdsbmt.ini");
1767 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1768 pathName, sizeof(pathName), sbmtpath);
1770 if (len != 0 && len != sizeof(pathName) - 1) {
1771 /* We can accept either unix or PC style AFS pathnames. Convert
1772 * Unix-style to PC style here for internal use.
1775 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1776 p += strlen(cm_mountRoot); /* skip mount path */
1779 if (*q == '/') *q = '\\'; /* change to \ */
1785 if (var = smb_stristr(p, VNUserName)) {
1786 if (uidp && uidp->unp)
1787 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1789 smb_subst(p, var, sizeof(VNUserName)," ");
1791 else if (var = smb_stristr(p, VNLCUserName))
1793 if (uidp && uidp->unp)
1794 strcpy(temp, uidp->unp->name);
1798 smb_subst(p, var, sizeof(VNLCUserName), temp);
1800 else if (var = smb_stristr(p, VNComputerName))
1802 sizeTemp = sizeof(temp);
1803 GetComputerName((LPTSTR)temp, &sizeTemp);
1804 smb_subst(p, var, sizeof(VNComputerName), temp);
1806 else if (var = smb_stristr(p, VNLCComputerName))
1808 sizeTemp = sizeof(temp);
1809 GetComputerName((LPTSTR)temp, &sizeTemp);
1811 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1816 *pathNamep = strdup(p);
1821 /* First lookup shareName in root.afs */
1823 smb_findShare_rock_t vrock;
1825 char * p = shareName;
1828 /* attempt to locate a partial match in root.afs. This is because
1829 when using the ANSI RAP calls, the share name is limited to 13 chars
1830 and hence is truncated. Of course we prefer exact matches. */
1832 thyper.HighPart = 0;
1835 vrock.shareName = shareName;
1837 vrock.matchType = 0;
1839 cm_HoldSCache(cm_data.rootSCachep);
1840 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1841 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1842 cm_ReleaseSCache(cm_data.rootSCachep);
1844 if (vrock.matchType) {
1845 sprintf(pathName,"/%s/",vrock.match);
1846 *pathNamep = strdup(strlwr(pathName));
1851 /* if we get here, there was no match for the share in root.afs */
1852 /* so try to create \\<netbiosName>\<cellname> */
1857 /* Get the full name for this cell */
1858 code = cm_SearchCellFile(p, temp, 0, 0);
1859 #ifdef AFS_AFSDB_ENV
1860 if (code && cm_dnsEnabled) {
1862 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1865 /* construct the path */
1867 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1868 *pathNamep = strdup(strlwr(pathName));
1877 /* Client-side offline caching policy types */
1878 #define CSC_POLICY_MANUAL 0
1879 #define CSC_POLICY_DOCUMENTS 1
1880 #define CSC_POLICY_PROGRAMS 2
1881 #define CSC_POLICY_DISABLE 3
1883 int smb_FindShareCSCPolicy(char *shareName)
1889 int retval = CSC_POLICY_MANUAL;
1891 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1892 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1895 REG_OPTION_NON_VOLATILE,
1901 len = sizeof(policy);
1902 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1904 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1906 else if (stricmp(policy, "documents") == 0)
1908 retval = CSC_POLICY_DOCUMENTS;
1910 else if (stricmp(policy, "programs") == 0)
1912 retval = CSC_POLICY_PROGRAMS;
1914 else if (stricmp(policy, "disable") == 0)
1916 retval = CSC_POLICY_DISABLE;
1919 RegCloseKey(hkCSCPolicy);
1923 /* find a dir search structure by cookie value, and return it held.
1924 * Must be called with smb_globalLock held.
1926 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1928 smb_dirSearch_t *dsp;
1930 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1931 if (dsp->cookie == cookie) {
1932 if (dsp != smb_firstDirSearchp) {
1933 /* move to head of LRU queue, too, if we're not already there */
1934 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1935 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1936 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1937 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1938 if (!smb_lastDirSearchp)
1939 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1941 lock_ObtainMutex(&dsp->mx);
1943 lock_ReleaseMutex(&dsp->mx);
1949 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1950 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1951 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1957 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1959 lock_ObtainWrite(&smb_globalLock);
1960 lock_ObtainMutex(&dsp->mx);
1961 dsp->flags |= SMB_DIRSEARCH_DELETE;
1962 if (dsp->scp != NULL) {
1963 lock_ObtainMutex(&dsp->scp->mx);
1964 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1965 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1966 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1967 dsp->scp->bulkStatProgress = hones;
1969 lock_ReleaseMutex(&dsp->scp->mx);
1971 lock_ReleaseMutex(&dsp->mx);
1972 lock_ReleaseWrite(&smb_globalLock);
1975 /* Must be called with the smb_globalLock held */
1976 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1978 cm_scache_t *scp = NULL;
1980 lock_ObtainMutex(&dsp->mx);
1981 osi_assert(dsp->refCount-- > 0);
1982 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1983 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1984 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1985 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1986 lock_ReleaseMutex(&dsp->mx);
1987 lock_FinalizeMutex(&dsp->mx);
1991 lock_ReleaseMutex(&dsp->mx);
1993 /* do this now to avoid spurious locking hierarchy creation */
1995 cm_ReleaseSCache(scp);
1998 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2000 lock_ObtainWrite(&smb_globalLock);
2001 smb_ReleaseDirSearchNoLock(dsp);
2002 lock_ReleaseWrite(&smb_globalLock);
2005 /* find a dir search structure by cookie value, and return it held */
2006 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2008 smb_dirSearch_t *dsp;
2010 lock_ObtainWrite(&smb_globalLock);
2011 dsp = smb_FindDirSearchNoLock(cookie);
2012 lock_ReleaseWrite(&smb_globalLock);
2016 /* GC some dir search entries, in the address space expected by the specific protocol.
2017 * Must be called with smb_globalLock held; release the lock temporarily.
2019 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2020 void smb_GCDirSearches(int isV3)
2022 smb_dirSearch_t *prevp;
2023 smb_dirSearch_t *tp;
2024 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2028 victimCount = 0; /* how many have we got so far */
2029 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
2030 /* we'll move tp from queue, so
2033 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
2034 /* if no one is using this guy, and we're either in the new protocol,
2035 * or we're in the old one and this is a small enough ID to be useful
2036 * to the old protocol, GC this guy.
2038 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2039 /* hold and delete */
2040 lock_ObtainMutex(&tp->mx);
2041 tp->flags |= SMB_DIRSEARCH_DELETE;
2042 lock_ReleaseMutex(&tp->mx);
2043 victimsp[victimCount++] = tp;
2047 /* don't do more than this */
2048 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2052 /* now release them */
2053 for (i = 0; i < victimCount; i++) {
2054 smb_ReleaseDirSearchNoLock(victimsp[i]);
2058 /* function for allocating a dir search entry. We need these to remember enough context
2059 * since we don't get passed the path from call to call during a directory search.
2061 * Returns a held dir search structure, and bumps the reference count on the vnode,
2062 * since it saves a pointer to the vnode.
2064 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2066 smb_dirSearch_t *dsp;
2072 lock_ObtainWrite(&smb_globalLock);
2075 /* what's the biggest ID allowed in this version of the protocol */
2076 maxAllowed = isV3 ? 65535 : 255;
2077 if (smb_dirSearchCounter > maxAllowed)
2078 smb_dirSearchCounter = 1;
2080 start = smb_dirSearchCounter;
2083 /* twice so we have enough tries to find guys we GC after one pass;
2084 * 10 extra is just in case I mis-counted.
2086 if (++counter > 2*maxAllowed+10)
2087 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2089 if (smb_dirSearchCounter > maxAllowed) {
2090 smb_dirSearchCounter = 1;
2092 if (smb_dirSearchCounter == start) {
2094 smb_GCDirSearches(isV3);
2097 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2099 /* don't need to watch for refcount zero and deleted, since
2100 * we haven't dropped the global lock.
2102 lock_ObtainMutex(&dsp->mx);
2104 lock_ReleaseMutex(&dsp->mx);
2105 ++smb_dirSearchCounter;
2109 dsp = malloc(sizeof(*dsp));
2110 memset(dsp, 0, sizeof(*dsp));
2111 dsp->cookie = smb_dirSearchCounter;
2112 ++smb_dirSearchCounter;
2114 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2115 dsp->lastTime = osi_Time();
2116 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2117 if (!smb_lastDirSearchp)
2118 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2121 lock_ReleaseWrite(&smb_globalLock);
2125 static smb_packet_t *GetPacket(void)
2129 unsigned int npar, seg, tb_sel;
2132 lock_ObtainWrite(&smb_globalLock);
2133 tbp = smb_packetFreeListp;
2135 smb_packetFreeListp = tbp->nextp;
2136 lock_ReleaseWrite(&smb_globalLock);
2139 tbp = calloc(65540,1);
2141 tbp = malloc(sizeof(smb_packet_t));
2143 tbp->magic = SMB_PACKETMAGIC;
2146 tbp->resumeCode = 0;
2152 tbp->ncb_length = 0;
2157 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
2160 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2162 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
2164 osi_panic("",__FILE__,__LINE__);
2167 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
2172 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
2173 tbp->dos_pkt_sel = tb_sel;
2176 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2181 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2185 memcpy(tbp, pkt, sizeof(smb_packet_t));
2186 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2188 smb_HoldVC(tbp->vcp);
2192 static NCB *GetNCB(void)
2197 unsigned int npar, seg, tb_sel;
2200 lock_ObtainWrite(&smb_globalLock);
2201 tbp = smb_ncbFreeListp;
2203 smb_ncbFreeListp = tbp->nextp;
2204 lock_ReleaseWrite(&smb_globalLock);
2207 tbp = calloc(sizeof(*tbp),1);
2209 tbp = malloc(sizeof(*tbp));
2210 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
2213 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2215 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2217 osi_panic("",__FILE__,__LINE__);
2219 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2224 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
2225 tbp->dos_ncb_sel = tb_sel;
2227 tbp->magic = SMB_NCBMAGIC;
2230 osi_assert(tbp->magic == SMB_NCBMAGIC);
2232 memset(&tbp->ncb, 0, sizeof(NCB));
2235 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2240 void smb_FreePacket(smb_packet_t *tbp)
2242 smb_vc_t * vcp = NULL;
2243 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2245 lock_ObtainWrite(&smb_globalLock);
2246 tbp->nextp = smb_packetFreeListp;
2247 smb_packetFreeListp = tbp;
2248 tbp->magic = SMB_PACKETMAGIC;
2252 tbp->resumeCode = 0;
2258 tbp->ncb_length = 0;
2260 lock_ReleaseWrite(&smb_globalLock);
2266 static void FreeNCB(NCB *bufferp)
2270 tbp = (smb_ncb_t *) bufferp;
2271 osi_assert(tbp->magic == SMB_NCBMAGIC);
2273 lock_ObtainWrite(&smb_globalLock);
2274 tbp->nextp = smb_ncbFreeListp;
2275 smb_ncbFreeListp = tbp;
2276 lock_ReleaseWrite(&smb_globalLock);
2279 /* get a ptr to the data part of a packet, and its count */
2280 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2284 unsigned char *afterParmsp;
2286 parmBytes = *smbp->wctp << 1;
2287 afterParmsp = smbp->wctp + parmBytes + 1;
2289 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2290 if (nbytesp) *nbytesp = dataBytes;
2292 /* don't forget to skip the data byte count, since it follows
2293 * the parameters; that's where the "2" comes from below.
2295 return (unsigned char *) (afterParmsp + 2);
2298 /* must set all the returned parameters before playing around with the
2299 * data region, since the data region is located past the end of the
2300 * variable number of parameters.
2302 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2304 unsigned char *afterParmsp;
2306 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2308 *afterParmsp++ = dsize & 0xff;
2309 *afterParmsp = (dsize>>8) & 0xff;
2312 /* return the parm'th parameter in the smbp packet */
2313 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2316 unsigned char *parmDatap;
2318 parmCount = *smbp->wctp;
2320 if (parm >= parmCount) {
2323 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2324 parm, parmCount, smbp->ncb_length);
2325 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2326 parm, parmCount, smbp->ncb_length);
2328 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2329 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2331 osi_panic(s, __FILE__, __LINE__);
2333 parmDatap = smbp->wctp + (2*parm) + 1;
2335 return parmDatap[0] + (parmDatap[1] << 8);
2338 /* return the parm'th parameter in the smbp packet */
2339 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2342 unsigned char *parmDatap;
2344 parmCount = *smbp->wctp;
2346 if (parm * 2 + offset >= parmCount * 2) {
2349 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2350 parm, offset, parmCount, smbp->ncb_length);
2352 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2353 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2355 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2356 parm, offset, parmCount, smbp->ncb_length);
2357 osi_panic(s, __FILE__, __LINE__);
2359 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2361 return parmDatap[0] + (parmDatap[1] << 8);
2364 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2368 /* make sure we have enough slots */
2369 if (*smbp->wctp <= slot)
2370 *smbp->wctp = slot+1;
2372 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2373 *parmDatap++ = parmValue & 0xff;
2374 *parmDatap = (parmValue>>8) & 0xff;
2377 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2381 /* make sure we have enough slots */
2382 if (*smbp->wctp <= slot)
2383 *smbp->wctp = slot+2;
2385 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2386 *parmDatap++ = parmValue & 0xff;
2387 *parmDatap++ = (parmValue>>8) & 0xff;
2388 *parmDatap++ = (parmValue>>16) & 0xff;
2389 *parmDatap++ = (parmValue>>24) & 0xff;
2392 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2397 /* make sure we have enough slots */
2398 if (*smbp->wctp <= slot)
2399 *smbp->wctp = slot+4;
2401 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2403 *parmDatap++ = *parmValuep++;
2406 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2410 /* make sure we have enough slots */
2411 if (*smbp->wctp <= slot) {
2412 if (smbp->oddByte) {
2414 *smbp->wctp = slot+1;
2419 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2420 *parmDatap++ = parmValue & 0xff;
2423 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2427 lastSlashp = strrchr(inPathp, '\\');
2429 *lastComponentp = lastSlashp;
2432 if (inPathp == lastSlashp)
2434 *outPathp++ = *inPathp++;
2443 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2448 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2453 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2459 tlen = inp[0] + (inp[1]<<8);
2460 inp += 2; /* skip length field */
2463 *chainpp = inp + tlen;
2472 /* format a packet as a response */
2473 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2478 outp = (smb_t *) op;
2480 /* zero the basic structure through the smb_wct field, and zero the data
2481 * size field, assuming that wct stays zero; otherwise, you have to
2482 * explicitly set the data size field, too.
2484 inSmbp = (smb_t *) inp;
2485 memset(outp, 0, sizeof(smb_t)+2);
2491 outp->com = inSmbp->com;
2492 outp->tid = inSmbp->tid;
2493 outp->pid = inSmbp->pid;
2494 outp->uid = inSmbp->uid;
2495 outp->mid = inSmbp->mid;
2496 outp->res[0] = inSmbp->res[0];
2497 outp->res[1] = inSmbp->res[1];
2498 op->inCom = inSmbp->com;
2500 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2501 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2503 /* copy fields in generic packet area */
2504 op->wctp = &outp->wct;
2507 /* send a (probably response) packet; vcp tells us to whom to send it.
2508 * we compute the length by looking at wct and bcc fields.
2510 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2527 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2530 memset((char *)ncbp, 0, sizeof(NCB));
2532 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2533 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2534 extra += tp[0] + (tp[1]<<8);
2535 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2536 extra += 3; /* wct and length fields */
2538 ncbp->ncb_length = extra; /* bytes to send */
2539 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2540 ncbp->ncb_lana_num = vcp->lana;
2541 ncbp->ncb_command = NCBSEND; /* op means send data */
2543 ncbp->ncb_buffer = (char *) inp;/* packet */
2544 code = Netbios(ncbp);
2546 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2547 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2549 /* copy header information from virtual to DOS address space */
2550 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2551 code = Netbios(ncbp, dos_ncb);
2555 const char * s = ncb_error_string(code);
2556 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2558 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2561 lock_ObtainMutex(&vcp->mx);
2562 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2563 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2565 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2566 lock_ReleaseMutex(&vcp->mx);
2567 lock_ObtainWrite(&smb_globalLock);
2568 dead_sessions[vcp->session] = TRUE;
2569 lock_ReleaseWrite(&smb_globalLock);
2570 smb_CleanupDeadVC(vcp);
2572 lock_ReleaseMutex(&vcp->mx);
2580 void smb_MapNTError(long code, unsigned long *NTStatusp)
2582 unsigned long NTStatus;
2584 /* map CM_ERROR_* errors to NT 32-bit status codes */
2585 /* NT Status codes are listed in ntstatus.h not winerror.h */
2586 if (code == CM_ERROR_NOSUCHCELL) {
2587 NTStatus = 0xC000000FL; /* No such file */
2589 else if (code == CM_ERROR_NOSUCHVOLUME) {
2590 NTStatus = 0xC000000FL; /* No such file */
2592 else if (code == CM_ERROR_TIMEDOUT) {
2594 NTStatus = 0xC00000CFL; /* Sharing Paused */
2596 NTStatus = 0x00000102L; /* Timeout */
2599 else if (code == CM_ERROR_RETRY) {
2600 NTStatus = 0xC000022DL; /* Retry */
2602 else if (code == CM_ERROR_NOACCESS) {
2603 NTStatus = 0xC0000022L; /* Access denied */
2605 else if (code == CM_ERROR_READONLY) {
2606 NTStatus = 0xC00000A2L; /* Write protected */
2608 else if (code == CM_ERROR_NOSUCHFILE) {
2609 NTStatus = 0xC000000FL; /* No such file */
2611 else if (code == CM_ERROR_NOSUCHPATH) {
2612 NTStatus = 0xC000003AL; /* Object path not found */
2614 else if (code == CM_ERROR_TOOBIG) {
2615 NTStatus = 0xC000007BL; /* Invalid image format */
2617 else if (code == CM_ERROR_INVAL) {
2618 NTStatus = 0xC000000DL; /* Invalid parameter */
2620 else if (code == CM_ERROR_BADFD) {
2621 NTStatus = 0xC0000008L; /* Invalid handle */
2623 else if (code == CM_ERROR_BADFDOP) {
2624 NTStatus = 0xC0000022L; /* Access denied */
2626 else if (code == CM_ERROR_EXISTS) {
2627 NTStatus = 0xC0000035L; /* Object name collision */
2629 else if (code == CM_ERROR_NOTEMPTY) {
2630 NTStatus = 0xC0000101L; /* Directory not empty */
2632 else if (code == CM_ERROR_CROSSDEVLINK) {
2633 NTStatus = 0xC00000D4L; /* Not same device */
2635 else if (code == CM_ERROR_NOTDIR) {
2636 NTStatus = 0xC0000103L; /* Not a directory */
2638 else if (code == CM_ERROR_ISDIR) {
2639 NTStatus = 0xC00000BAL; /* File is a directory */
2641 else if (code == CM_ERROR_BADOP) {
2643 /* I have no idea where this comes from */
2644 NTStatus = 0xC09820FFL; /* SMB no support */
2646 NTStatus = 0xC00000BBL; /* Not supported */
2647 #endif /* COMMENT */
2649 else if (code == CM_ERROR_BADSHARENAME) {
2650 NTStatus = 0xC00000CCL; /* Bad network name */
2652 else if (code == CM_ERROR_NOIPC) {
2654 NTStatus = 0xC0000022L; /* Access Denied */
2656 NTStatus = 0xC000013DL; /* Remote Resources */
2659 else if (code == CM_ERROR_CLOCKSKEW) {
2660 NTStatus = 0xC0000133L; /* Time difference at DC */
2662 else if (code == CM_ERROR_BADTID) {
2663 NTStatus = 0xC0982005L; /* SMB bad TID */
2665 else if (code == CM_ERROR_USESTD) {
2666 NTStatus = 0xC09820FBL; /* SMB use standard */
2668 else if (code == CM_ERROR_QUOTA) {
2670 NTStatus = 0xC0000044L; /* Quota exceeded */
2672 NTStatus = 0xC000007FL; /* Disk full */
2675 else if (code == CM_ERROR_SPACE) {
2676 NTStatus = 0xC000007FL; /* Disk full */
2678 else if (code == CM_ERROR_ATSYS) {
2679 NTStatus = 0xC0000033L; /* Object name invalid */
2681 else if (code == CM_ERROR_BADNTFILENAME) {
2682 NTStatus = 0xC0000033L; /* Object name invalid */
2684 else if (code == CM_ERROR_WOULDBLOCK) {
2685 NTStatus = 0xC0000055L; /* Lock not granted */
2687 else if (code == CM_ERROR_SHARING_VIOLATION) {
2688 NTStatus = 0xC0000043L; /* Sharing violation */
2690 else if (code == CM_ERROR_LOCK_CONFLICT) {
2691 NTStatus = 0xC0000054L; /* Lock conflict */
2693 else if (code == CM_ERROR_PARTIALWRITE) {
2694 NTStatus = 0xC000007FL; /* Disk full */
2696 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2697 NTStatus = 0xC0000023L; /* Buffer too small */
2699 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2700 NTStatus = 0xC0000035L; /* Object name collision */
2702 else if (code == CM_ERROR_BADPASSWORD) {
2703 NTStatus = 0xC000006DL; /* unknown username or bad password */
2705 else if (code == CM_ERROR_BADLOGONTYPE) {
2706 NTStatus = 0xC000015BL; /* logon type not granted */
2708 else if (code == CM_ERROR_GSSCONTINUE) {
2709 NTStatus = 0xC0000016L; /* more processing required */
2711 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2713 NTStatus = 0xC0000280L; /* reparse point not resolved */
2715 NTStatus = 0xC0000022L; /* Access Denied */
2718 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2719 NTStatus = 0xC0000257L; /* Path Not Covered */
2722 else if (code == CM_ERROR_ALLBUSY) {
2723 NTStatus = 0xC00000BFL; /* Network Busy */
2725 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2726 NTStatus = 0xC0000350L; /* Remote Host Down */
2729 /* we do not want to be telling the SMB/CIFS client that
2730 * the AFS Client Service is busy or down.
2732 else if (code == CM_ERROR_ALLBUSY ||
2733 code == CM_ERROR_ALLOFFLINE ||
2734 code == CM_ERROR_ALLDOWN) {
2735 NTStatus = 0xC00000BEL; /* Bad Network Path */
2738 else if (code == RXKADUNKNOWNKEY) {
2739 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2741 NTStatus = 0xC0982001L; /* SMB non-specific error */
2744 *NTStatusp = NTStatus;
2745 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2748 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2749 unsigned char *classp)
2751 unsigned char class;
2752 unsigned short error;
2754 /* map CM_ERROR_* errors to SMB errors */
2755 if (code == CM_ERROR_NOSUCHCELL) {
2757 error = 3; /* bad path */
2759 else if (code == CM_ERROR_NOSUCHVOLUME) {
2761 error = 3; /* bad path */
2763 else if (code == CM_ERROR_TIMEDOUT) {
2765 error = 81; /* server is paused */
2767 else if (code == CM_ERROR_RETRY) {
2768 class = 2; /* shouldn't happen */
2771 else if (code == CM_ERROR_NOACCESS) {
2773 error = 4; /* bad access */
2775 else if (code == CM_ERROR_READONLY) {
2777 error = 19; /* read only */
2779 else if (code == CM_ERROR_NOSUCHFILE) {
2781 error = 2; /* ENOENT! */
2783 else if (code == CM_ERROR_NOSUCHPATH) {
2785 error = 3; /* Bad path */
2787 else if (code == CM_ERROR_TOOBIG) {
2789 error = 11; /* bad format */
2791 else if (code == CM_ERROR_INVAL) {
2792 class = 2; /* server non-specific error code */
2795 else if (code == CM_ERROR_BADFD) {
2797 error = 6; /* invalid file handle */
2799 else if (code == CM_ERROR_BADFDOP) {
2800 class = 1; /* invalid op on FD */
2803 else if (code == CM_ERROR_EXISTS) {
2805 error = 80; /* file already exists */
2807 else if (code == CM_ERROR_NOTEMPTY) {
2809 error = 5; /* delete directory not empty */
2811 else if (code == CM_ERROR_CROSSDEVLINK) {
2813 error = 17; /* EXDEV */
2815 else if (code == CM_ERROR_NOTDIR) {
2816 class = 1; /* bad path */
2819 else if (code == CM_ERROR_ISDIR) {
2820 class = 1; /* access denied; DOS doesn't have a good match */
2823 else if (code == CM_ERROR_BADOP) {
2827 else if (code == CM_ERROR_BADSHARENAME) {
2831 else if (code == CM_ERROR_NOIPC) {
2833 error = 4; /* bad access */
2835 else if (code == CM_ERROR_CLOCKSKEW) {
2836 class = 1; /* invalid function */
2839 else if (code == CM_ERROR_BADTID) {
2843 else if (code == CM_ERROR_USESTD) {
2847 else if (code == CM_ERROR_REMOTECONN) {
2851 else if (code == CM_ERROR_QUOTA) {
2852 if (vcp->flags & SMB_VCFLAG_USEV3) {
2854 error = 39; /* disk full */
2858 error = 5; /* access denied */
2861 else if (code == CM_ERROR_SPACE) {
2862 if (vcp->flags & SMB_VCFLAG_USEV3) {
2864 error = 39; /* disk full */
2868 error = 5; /* access denied */
2871 else if (code == CM_ERROR_PARTIALWRITE) {
2873 error = 39; /* disk full */
2875 else if (code == CM_ERROR_ATSYS) {
2877 error = 2; /* ENOENT */
2879 else if (code == CM_ERROR_WOULDBLOCK) {
2881 error = 33; /* lock conflict */
2883 else if (code == CM_ERROR_LOCK_CONFLICT) {
2885 error = 33; /* lock conflict */
2887 else if (code == CM_ERROR_SHARING_VIOLATION) {
2889 error = 33; /* lock conflict */
2891 else if (code == CM_ERROR_NOFILES) {
2893 error = 18; /* no files in search */
2895 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2897 error = 183; /* Samba uses this */
2899 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2900 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2902 error = 2; /* bad password */
2904 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2906 error = 3; /* bad path */
2915 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2918 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2920 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2921 return CM_ERROR_BADOP;
2924 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2926 unsigned short EchoCount, i;
2927 char *data, *outdata;
2930 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2932 for (i=1; i<=EchoCount; i++) {
2933 data = smb_GetSMBData(inp, &dataSize);
2934 smb_SetSMBParm(outp, 0, i);
2935 smb_SetSMBDataLength(outp, dataSize);
2936 outdata = smb_GetSMBData(outp, NULL);
2937 memcpy(outdata, data, dataSize);
2938 smb_SendPacket(vcp, outp);
2944 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2947 long count, minCount, finalCount;
2952 cm_user_t *userp = NULL;
2956 char *rawBuf = NULL;
2958 dos_ptr rawBuf = NULL;
2965 fd = smb_GetSMBParm(inp, 0);
2966 count = smb_GetSMBParm(inp, 3);
2967 minCount = smb_GetSMBParm(inp, 4);
2968 offset.HighPart = 0; /* too bad */
2969 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2971 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2972 fd, offset.LowPart, count);
2974 fidp = smb_FindFID(vcp, fd, 0);
2978 pid = ((smb_t *) inp)->pid;
2980 LARGE_INTEGER LOffset, LLength;
2983 key = cm_GenerateKey(vcp->vcID, pid, fd);
2985 LOffset.HighPart = 0;
2986 LOffset.LowPart = offset.LowPart;
2987 LLength.HighPart = 0;
2988 LLength.LowPart = count;
2990 lock_ObtainMutex(&fidp->scp->mx);
2991 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2992 lock_ReleaseMutex(&fidp->scp->mx);
2998 lock_ObtainMutex(&smb_RawBufLock);
3000 /* Get a raw buf, from head of list */
3001 rawBuf = smb_RawBufs;
3003 smb_RawBufs = *(char **)smb_RawBufs;
3005 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
3008 lock_ReleaseMutex(&smb_RawBufLock);
3012 lock_ObtainMutex(&fidp->mx);
3013 if (fidp->flags & SMB_FID_IOCTL)
3015 lock_ReleaseMutex(&fidp->mx);
3017 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3019 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
3022 /* Give back raw buffer */
3023 lock_ObtainMutex(&smb_RawBufLock);
3025 *((char **) rawBuf) = smb_RawBufs;
3027 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3030 smb_RawBufs = rawBuf;
3031 lock_ReleaseMutex(&smb_RawBufLock);
3034 smb_ReleaseFID(fidp);
3037 lock_ReleaseMutex(&fidp->mx);
3039 userp = smb_GetUserFromVCP(vcp, inp);
3042 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3044 /* have to give ReadData flag so it will treat buffer as DOS mem. */
3045 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
3046 userp, &finalCount, TRUE /* rawFlag */);
3053 cm_ReleaseUser(userp);
3056 smb_ReleaseFID(fidp);
3061 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
3063 memset((char *)ncbp, 0, sizeof(NCB));
3065 ncbp->ncb_length = (unsigned short) finalCount;
3066 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3067 ncbp->ncb_lana_num = vcp->lana;
3068 ncbp->ncb_command = NCBSEND;
3069 ncbp->ncb_buffer = rawBuf;
3072 code = Netbios(ncbp);
3074 code = Netbios(ncbp, dos_ncb);
3077 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3080 /* Give back raw buffer */
3081 lock_ObtainMutex(&smb_RawBufLock);
3083 *((char **) rawBuf) = smb_RawBufs;
3085 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3088 smb_RawBufs = rawBuf;
3089 lock_ReleaseMutex(&smb_RawBufLock);
3095 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3097 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3102 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3104 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3109 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3116 int protoIndex; /* index we're using */
3121 char protocol_array[10][1024]; /* protocol signature of the client */
3122 int caps; /* capabilities */
3125 TIME_ZONE_INFORMATION tzi;
3127 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3130 namep = smb_GetSMBData(inp, &dbytes);
3133 coreProtoIndex = -1; /* not found */
3136 while(namex < dbytes) {
3137 osi_Log1(smb_logp, "Protocol %s",
3138 osi_LogSaveString(smb_logp, namep+1));
3139 strcpy(protocol_array[tcounter], namep+1);
3141 /* namep points at the first protocol, or really, a 0x02
3142 * byte preceding the null-terminated ASCII name.
3144 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3145 coreProtoIndex = tcounter;
3147 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3148 v3ProtoIndex = tcounter;
3150 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3151 NTProtoIndex = tcounter;
3154 /* compute size of protocol entry */
3155 entryLength = (int)strlen(namep+1);
3156 entryLength += 2; /* 0x02 bytes and null termination */
3158 /* advance over this protocol entry */
3159 namex += entryLength;
3160 namep += entryLength;
3161 tcounter++; /* which proto entry we're looking at */
3164 lock_ObtainMutex(&vcp->mx);
3165 if (NTProtoIndex != -1) {
3166 protoIndex = NTProtoIndex;
3167 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3169 else if (v3ProtoIndex != -1) {
3170 protoIndex = v3ProtoIndex;
3171 vcp->flags |= SMB_VCFLAG_USEV3;
3173 else if (coreProtoIndex != -1) {
3174 protoIndex = coreProtoIndex;
3175 vcp->flags |= SMB_VCFLAG_USECORE;
3177 else protoIndex = -1;
3178 lock_ReleaseMutex(&vcp->mx);
3180 if (protoIndex == -1)
3181 return CM_ERROR_INVAL;
3182 else if (NTProtoIndex != -1) {
3183 smb_SetSMBParm(outp, 0, protoIndex);
3184 if (smb_authType != SMB_AUTH_NONE) {
3185 smb_SetSMBParmByte(outp, 1,
3186 NEGOTIATE_SECURITY_USER_LEVEL |
3187 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3189 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3191 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3192 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3193 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3194 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3195 /* The session key is not a well documented field however most clients
3196 * will echo back the session key to the server. Currently we are using
3197 * the same value for all sessions. We should generate a random value
3198 * and store it into the vcp
3200 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3201 smb_SetSMBParm(outp, 8, 1);
3203 * Tried changing the capabilities to support for W2K - defect 117695
3204 * Maybe something else needs to be changed here?
3208 smb_SetSMBParmLong(outp, 9, 0x43fd);
3210 smb_SetSMBParmLong(outp, 9, 0x251);
3213 * 32-bit error codes *
3218 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3220 NTNEGOTIATE_CAPABILITY_DFS |
3222 NTNEGOTIATE_CAPABILITY_NTFIND |
3223 NTNEGOTIATE_CAPABILITY_RAWMODE |
3224 NTNEGOTIATE_CAPABILITY_NTSMB;
3226 if ( smb_authType == SMB_AUTH_EXTENDED )
3227 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3229 smb_SetSMBParmLong(outp, 9, caps);
3231 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3232 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3233 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3235 GetTimeZoneInformation(&tzi);
3236 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3238 if (smb_authType == SMB_AUTH_NTLM) {
3239 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3240 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3241 /* paste in encryption key */
3242 datap = smb_GetSMBData(outp, NULL);
3243 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3244 /* and the faux domain name */
3245 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3246 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3250 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3252 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3254 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3256 datap = smb_GetSMBData(outp, NULL);
3257 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3260 datap += sizeof(smb_ServerGUID);
3261 memcpy(datap, secBlob, secBlobLength);
3265 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3266 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3269 else if (v3ProtoIndex != -1) {
3270 smb_SetSMBParm(outp, 0, protoIndex);
3272 /* NOTE: Extended authentication cannot be negotiated with v3
3273 * therefore we fail over to NTLM
3275 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3276 smb_SetSMBParm(outp, 1,
3277 NEGOTIATE_SECURITY_USER_LEVEL |
3278 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3280 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3282 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3283 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3284 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3285 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3286 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3287 smb_SetSMBParm(outp, 7, 1);
3289 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3290 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3291 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3293 GetTimeZoneInformation(&tzi);
3294 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3296 /* NOTE: Extended authentication cannot be negotiated with v3
3297 * therefore we fail over to NTLM
3299 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3300 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3301 smb_SetSMBParm(outp, 12, 0); /* resvd */
3302 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3303 datap = smb_GetSMBData(outp, NULL);
3304 /* paste in a new encryption key */
3305 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3306 /* and the faux domain name */
3307 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3309 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3310 smb_SetSMBParm(outp, 12, 0); /* resvd */
3311 smb_SetSMBDataLength(outp, 0);
3314 else if (coreProtoIndex != -1) { /* not really supported anymore */
3315 smb_SetSMBParm(outp, 0, protoIndex);
3316 smb_SetSMBDataLength(outp, 0);
3321 void smb_CheckVCs(void)
3323 smb_vc_t * vcp, *nextp;
3324 smb_packet_t * outp = GetPacket();
3327 lock_ObtainWrite(&smb_rctLock);
3328 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3330 if (vcp->magic != SMB_VC_MAGIC)
3331 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3332 __FILE__, __LINE__);
3336 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3339 smb_HoldVCNoLock(vcp);
3341 smb_HoldVCNoLock(nextp);
3342 smb_FormatResponsePacket(vcp, NULL, outp);
3343 smbp = (smb_t *)outp;
3344 outp->inCom = smbp->com = 0x2b /* Echo */;
3352 smb_SetSMBParm(outp, 0, 0);
3353 smb_SetSMBDataLength(outp, 0);
3354 lock_ReleaseWrite(&smb_rctLock);
3356 smb_SendPacket(vcp, outp);
3358 lock_ObtainWrite(&smb_rctLock);
3359 smb_ReleaseVCNoLock(vcp);
3361 smb_ReleaseVCNoLock(nextp);
3363 lock_ReleaseWrite(&smb_rctLock);
3364 smb_FreePacket(outp);
3367 void smb_Daemon(void *parmp)
3369 afs_uint32 count = 0;
3370 smb_username_t **unpp;
3373 while(smbShutdownFlag == 0) {
3377 if (smbShutdownFlag == 1)
3380 if ((count % 72) == 0) { /* every five minutes */
3382 time_t old_localZero = smb_localZero;
3384 /* Initialize smb_localZero */
3385 myTime.tm_isdst = -1; /* compute whether on DST or not */
3386 myTime.tm_year = 70;
3392 smb_localZero = mktime(&myTime);
3394 #ifndef USE_NUMERIC_TIME_CONV
3395 smb_CalculateNowTZ();
3396 #endif /* USE_NUMERIC_TIME_CONV */
3397 #ifdef AFS_FREELANCE
3398 if ( smb_localZero != old_localZero )
3399 cm_noteLocalMountPointChange();
3405 /* GC smb_username_t objects that will no longer be used */
3407 lock_ObtainWrite(&smb_rctLock);
3408 for ( unpp=&usernamesp; *unpp; ) {
3410 smb_username_t *unp;
3412 lock_ObtainMutex(&(*unpp)->mx);
3413 if ( (*unpp)->refCount > 0 ||
3414 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3415 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3417 else if (!smb_LogoffTokenTransfer ||
3418 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3420 lock_ReleaseMutex(&(*unpp)->mx);
3428 lock_FinalizeMutex(&unp->mx);
3434 lock_ReleaseWrite(&smb_rctLock);
3435 cm_ReleaseUser(userp);
3436 lock_ObtainWrite(&smb_rctLock);
3439 unpp = &(*unpp)->nextp;
3442 lock_ReleaseWrite(&smb_rctLock);
3444 /* XXX GC dir search entries */
3448 void smb_WaitingLocksDaemon()
3450 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3451 smb_waitingLock_t *wl, *wlNext;
3454 smb_packet_t *inp, *outp;
3458 while (smbShutdownFlag == 0) {
3459 lock_ObtainWrite(&smb_globalLock);
3460 nwlRequest = smb_allWaitingLocks;
3461 if (nwlRequest == NULL) {
3462 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3467 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3474 lock_ObtainWrite(&smb_globalLock);
3476 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3478 wlRequest = nwlRequest;
3479 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3480 lock_ReleaseWrite(&smb_globalLock);
3484 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3485 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3488 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3490 /* wl->state is either _DONE or _WAITING. _ERROR
3491 would no longer be on the queue. */
3492 code = cm_RetryLock( wl->lockp,
3493 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3496 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3497 } else if (code != CM_ERROR_WOULDBLOCK) {
3498 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3503 if (code == CM_ERROR_WOULDBLOCK) {
3506 if (wlRequest->timeRemaining != 0xffffffff
3507 && (wlRequest->timeRemaining -= 1000) < 0)
3519 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3522 scp = wlRequest->scp;
3526 lock_ObtainMutex(&scp->mx);
3528 for (wl = wlRequest->locks; wl; wl = wlNext) {
3529 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3531 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3532 wl->LLength, wl->key, NULL, &req);
3534 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3539 lock_ReleaseMutex(&scp->mx);
3543 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3546 for (wl = wlRequest->locks; wl; wl = wlNext) {
3547 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3548 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3553 vcp = wlRequest->vcp;
3554 inp = wlRequest->inp;
3555 outp = wlRequest->outp;
3557 ncbp->ncb_length = inp->ncb_length;
3558 inp->spacep = cm_GetSpace();
3560 /* Remove waitingLock from list */
3561 lock_ObtainWrite(&smb_globalLock);
3562 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3564 lock_ReleaseWrite(&smb_globalLock);
3566 /* Resume packet processing */
3568 smb_SetSMBDataLength(outp, 0);
3569 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3570 outp->resumeCode = code;
3572 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3575 cm_FreeSpace(inp->spacep);
3576 smb_FreePacket(inp);
3577 smb_FreePacket(outp);
3579 cm_ReleaseSCache(wlRequest->scp);
3582 } while (nwlRequest && smbShutdownFlag == 0);
3587 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3589 osi_Log0(smb_logp, "SMB receive get disk attributes");
3591 smb_SetSMBParm(outp, 0, 32000);
3592 smb_SetSMBParm(outp, 1, 64);
3593 smb_SetSMBParm(outp, 2, 1024);
3594 smb_SetSMBParm(outp, 3, 30000);
3595 smb_SetSMBParm(outp, 4, 0);
3596 smb_SetSMBDataLength(outp, 0);
3600 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3604 unsigned short newTid;
3605 char shareName[256];
3613 osi_Log0(smb_logp, "SMB receive tree connect");
3615 /* parse input parameters */
3616 tp = smb_GetSMBData(inp, NULL);
3617 pathp = smb_ParseASCIIBlock(tp, &tp);
3618 if (smb_StoreAnsiFilenames)
3619 OemToChar(pathp,pathp);
3620 passwordp = smb_ParseASCIIBlock(tp, &tp);
3621 tp = strrchr(pathp, '\\');
3623 return CM_ERROR_BADSMB;
3624 strcpy(shareName, tp+1);
3626 lock_ObtainMutex(&vcp->mx);
3627 newTid = vcp->tidCounter++;
3628 lock_ReleaseMutex(&vcp->mx);
3630 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3631 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3632 userp = smb_GetUserFromUID(uidp);
3633 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3635 smb_ReleaseUID(uidp);
3637 smb_ReleaseTID(tidp);
3638 return CM_ERROR_BADSHARENAME;
3640 lock_ObtainMutex(&tidp->mx);
3641 tidp->userp = userp;
3642 tidp->pathname = sharePath;
3643 lock_ReleaseMutex(&tidp->mx);
3644 smb_ReleaseTID(tidp);
3646 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3647 smb_SetSMBParm(rsp, 1, newTid);
3648 smb_SetSMBDataLength(rsp, 0);
3650 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3654 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3658 if (*inp++ != 0x1) return NULL;
3659 tlen = inp[0] + (inp[1]<<8);
3660 inp += 2; /* skip length field */
3663 *chainpp = inp + tlen;
3666 if (lengthp) *lengthp = tlen;
3671 /* set maskp to the mask part of the incoming path.
3672 * Mask is 11 bytes long (8.3 with the dot elided).
3673 * Returns true if succeeds with a valid name, otherwise it does
3674 * its best, but returns false.
3676 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3684 /* starts off valid */
3687 /* mask starts out all blanks */
3688 memset(maskp, ' ', 11);
3690 /* find last backslash, or use whole thing if there is none */
3691 tp = strrchr(pathp, '\\');
3692 if (!tp) tp = pathp;
3693 else tp++; /* skip slash */
3697 /* names starting with a dot are illegal */
3698 if (*tp == '.') valid8Dot3 = 0;
3702 if (tc == 0) return valid8Dot3;
3703 if (tc == '.' || tc == '"') break;
3704 if (i < 8) *up++ = tc;
3705 else valid8Dot3 = 0;
3708 /* if we get here, tp point after the dot */
3709 up = maskp+8; /* ext goes here */
3716 if (tc == '.' || tc == '"')
3719 /* copy extension if not too long */
3729 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3739 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3741 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3745 /* otherwise, we have a valid 8.3 name; see if we have a match,
3746 * treating '?' as a wildcard in maskp (but not in the file name).
3748 tp1 = umask; /* real name, in mask format */
3749 tp2 = maskp; /* mask, in mask format */
3750 for(i=0; i<11; i++) {
3751 tc1 = *tp1++; /* char from real name */
3752 tc2 = *tp2++; /* char from mask */
3753 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3754 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3757 if (tc2 == '?' && tc1 != ' ')
3764 /* we got a match */
3768 char *smb_FindMask(char *pathp)
3772 tp = strrchr(pathp, '\\'); /* find last slash */
3775 return tp+1; /* skip the slash */
3777 return pathp; /* no slash, return the entire path */
3780 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3782 unsigned char *pathp;
3784 unsigned char mask[11];
3785 unsigned char *statBlockp;
3786 unsigned char initStatBlock[21];
3789 osi_Log0(smb_logp, "SMB receive search volume");
3791 /* pull pathname and stat block out of request */
3792 tp = smb_GetSMBData(inp, NULL);
3793 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3794 osi_assert(pathp != NULL);
3795 if (smb_StoreAnsiFilenames)
3796 OemToChar(pathp,pathp);
3797 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3798 osi_assert(statBlockp != NULL);
3800 statBlockp = initStatBlock;
3804 /* for returning to caller */
3805 smb_Get8Dot3MaskFromPath(mask, pathp);
3807 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3808 tp = smb_GetSMBData(outp, NULL);
3810 *tp++ = 43; /* bytes in a dir entry */
3811 *tp++ = 0; /* high byte in counter */
3813 /* now marshall the dir entry, starting with the search status */
3814 *tp++ = statBlockp[0]; /* Reserved */
3815 memcpy(tp, mask, 11); tp += 11; /* FileName */
3817 /* now pass back server use info, with 1st byte non-zero */
3819 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3821 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3823 *tp++ = 0x8; /* attribute: volume */
3833 /* 4 byte file size */
3839 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3840 memset(tp, ' ', 13);
3843 /* set the length of the data part of the packet to 43 + 3, for the dir
3844 * entry plus the 5 and the length fields.
3846 smb_SetSMBDataLength(outp, 46);
3850 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3851 cm_user_t *userp, cm_req_t *reqp)
3859 smb_dirListPatch_t *patchp;
3860 smb_dirListPatch_t *npatchp;
3862 for (patchp = *dirPatchespp; patchp; patchp =
3863 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3865 dptr = patchp->dptr;
3867 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3869 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3870 *dptr++ = SMB_ATTR_HIDDEN;
3873 lock_ObtainMutex(&scp->mx);
3874 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3875 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3877 lock_ReleaseMutex(&scp->mx);
3878 cm_ReleaseSCache(scp);
3879 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3880 *dptr++ = SMB_ATTR_HIDDEN;
3884 attr = smb_Attributes(scp);
3885 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3886 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3887 attr |= SMB_ATTR_HIDDEN;
3891 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3894 shortTemp = (unsigned short) (dosTime & 0xffff);
3895 *((u_short *)dptr) = shortTemp;
3898 /* and copy out date */
3899 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3900 *((u_short *)dptr) = shortTemp;
3903 /* copy out file length */
3904 *((u_long *)dptr) = scp->length.LowPart;
3906 lock_ReleaseMutex(&scp->mx);
3907 cm_ReleaseSCache(scp);
3910 /* now free the patches */
3911 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3912 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3916 /* and mark the list as empty */
3917 *dirPatchespp = NULL;
3922 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3931 smb_dirListPatch_t *dirListPatchesp;
3932 smb_dirListPatch_t *curPatchp;
3936 osi_hyper_t dirLength;
3937 osi_hyper_t bufferOffset;
3938 osi_hyper_t curOffset;
3940 unsigned char *inCookiep;
3941 smb_dirSearch_t *dsp;
3945 unsigned long clientCookie;
3946 cm_pageHeader_t *pageHeaderp;
3947 cm_user_t *userp = NULL;
3954 long nextEntryCookie;
3955 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3956 char resByte; /* reserved byte from the cookie */
3957 char *op; /* output data ptr */
3958 char *origOp; /* original value of op */
3959 cm_space_t *spacep; /* for pathname buffer */
3970 maxCount = smb_GetSMBParm(inp, 0);
3972 dirListPatchesp = NULL;
3974 caseFold = CM_FLAG_CASEFOLD;
3976 tp = smb_GetSMBData(inp, NULL);
3977 pathp = smb_ParseASCIIBlock(tp, &tp);
3978 if (smb_StoreAnsiFilenames)
3979 OemToChar(pathp,pathp);
3980 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3982 /* bail out if request looks bad */
3983 if (!tp || !pathp) {
3984 return CM_ERROR_BADSMB;
3987 /* We can handle long names */
3988 if (vcp->flags & SMB_VCFLAG_USENT)
3989 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3991 /* make sure we got a whole search status */
3992 if (dataLength < 21) {
3993 nextCookie = 0; /* start at the beginning of the dir */
3996 attribute = smb_GetSMBParm(inp, 1);
3998 /* handle volume info in another function */
3999 if (attribute & 0x8)
4000 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4002 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
4003 maxCount, osi_LogSaveString(smb_logp, pathp));
4005 if (*pathp == 0) { /* null pathp, treat as root dir */
4006 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4007 return CM_ERROR_NOFILES;
4011 dsp = smb_NewDirSearch(0);
4012 dsp->attribute = attribute;
4013 smb_Get8Dot3MaskFromPath(mask, pathp);
4014 memcpy(dsp->mask, mask, 11);
4016 /* track if this is likely to match a lot of entries */
4017 if (smb_IsStarMask(mask))
4022 /* pull the next cookie value out of the search status block */
4023 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4024 + (inCookiep[16]<<24);
4025 dsp = smb_FindDirSearch(inCookiep[12]);
4027 /* can't find dir search status; fatal error */
4028 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
4029 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
4030 return CM_ERROR_BADFD;
4032 attribute = dsp->attribute;
4033 resByte = inCookiep[0];
4035 /* copy out client cookie, in host byte order. Don't bother
4036 * interpreting it, since we're just passing it through, anyway.
4038 memcpy(&clientCookie, &inCookiep[17], 4);
4040 memcpy(mask, dsp->mask, 11);
4042 /* assume we're doing a star match if it has continued for more
4048 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4049 nextCookie, dsp->cookie, attribute);
4051 userp = smb_GetUserFromVCP(vcp, inp);
4053 /* try to get the vnode for the path name next */
4054 lock_ObtainMutex(&dsp->mx);
4060 spacep = inp->spacep;
4061 smb_StripLastComponent(spacep->data, NULL, pathp);
4062 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4064 lock_ReleaseMutex(&dsp->mx);
4065 cm_ReleaseUser(userp);
4066 smb_DeleteDirSearch(dsp);
4067 smb_ReleaseDirSearch(dsp);
4068 return CM_ERROR_NOFILES;
4070 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4071 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4074 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4075 cm_ReleaseSCache(scp);
4076 lock_ReleaseMutex(&dsp->mx);
4077 cm_ReleaseUser(userp);
4078 smb_DeleteDirSearch(dsp);
4079 smb_ReleaseDirSearch(dsp);
4080 if ( WANTS_DFS_PATHNAMES(inp) )
4081 return CM_ERROR_PATH_NOT_COVERED;
4083 return CM_ERROR_BADSHARENAME;
4085 #endif /* DFS_SUPPORT */
4088 /* we need one hold for the entry we just stored into,
4089 * and one for our own processing. When we're done with this
4090 * function, we'll drop the one for our own processing.
4091 * We held it once from the namei call, and so we do another hold
4095 lock_ObtainMutex(&scp->mx);
4096 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4097 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4098 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4099 dsp->flags |= SMB_DIRSEARCH_BULKST;
4101 lock_ReleaseMutex(&scp->mx);
4104 lock_ReleaseMutex(&dsp->mx);
4106 cm_ReleaseUser(userp);
4107 smb_DeleteDirSearch(dsp);
4108 smb_ReleaseDirSearch(dsp);
4112 /* reserves space for parameter; we'll adjust it again later to the
4113 * real count of the # of entries we returned once we've actually
4114 * assembled the directory listing.
4116 smb_SetSMBParm(outp, 0, 0);
4118 /* get the directory size */
4119 lock_ObtainMutex(&scp->mx);
4120 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4121 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4123 lock_ReleaseMutex(&scp->mx);
4124 cm_ReleaseSCache(scp);
4125 cm_ReleaseUser(userp);
4126 smb_DeleteDirSearch(dsp);
4127 smb_ReleaseDirSearch(dsp);
4131 dirLength = scp->length;
4133 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4134 curOffset.HighPart = 0;
4135 curOffset.LowPart = nextCookie;
4136 origOp = op = smb_GetSMBData(outp, NULL);
4137 /* and write out the basic header */
4138 *op++ = 5; /* variable block */
4139 op += 2; /* skip vbl block length; we'll fill it in later */
4143 /* make sure that curOffset.LowPart doesn't point to the first
4144 * 32 bytes in the 2nd through last dir page, and that it doesn't
4145 * point at the first 13 32-byte chunks in the first dir page,
4146 * since those are dir and page headers, and don't contain useful
4149 temp = curOffset.LowPart & (2048-1);
4150 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4151 /* we're in the first page */
4152 if (temp < 13*32) temp = 13*32;
4155 /* we're in a later dir page */
4156 if (temp < 32) temp = 32;
4159 /* make sure the low order 5 bits are zero */
4162 /* now put temp bits back ito curOffset.LowPart */
4163 curOffset.LowPart &= ~(2048-1);
4164 curOffset.LowPart |= temp;
4166 /* check if we've returned all the names that will fit in the
4169 if (returnedNames >= maxCount) {
4170 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4171 returnedNames, maxCount);
4175 /* check if we've passed the dir's EOF */
4176 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4178 /* see if we can use the bufferp we have now; compute in which page
4179 * the current offset would be, and check whether that's the offset
4180 * of the buffer we have. If not, get the buffer.
4182 thyper.HighPart = curOffset.HighPart;
4183 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4184 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4187 buf_Release(bufferp);
4190 lock_ReleaseMutex(&scp->mx);
4191 lock_ObtainRead(&scp->bufCreateLock);
4192 code = buf_Get(scp, &thyper, &bufferp);
4193 lock_ReleaseRead(&scp->bufCreateLock);
4194 lock_ObtainMutex(&dsp->mx);
4196 /* now, if we're doing a star match, do bulk fetching of all of
4197 * the status info for files in the dir.
4200 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4201 lock_ObtainMutex(&scp->mx);
4202 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4203 LargeIntegerGreaterThanOrEqualTo(thyper,
4204 scp->bulkStatProgress)) {
4205 /* Don't bulk stat if risking timeout */
4206 int now = GetTickCount();
4207 if (now - req.startTime > 5000) {
4208 scp->bulkStatProgress = thyper;
4209 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4210 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4212 cm_TryBulkStat(scp, &thyper, userp, &req);
4215 lock_ObtainMutex(&scp->mx);
4217 lock_ReleaseMutex(&dsp->mx);
4219 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4223 bufferOffset = thyper;
4225 /* now get the data in the cache */
4227 code = cm_SyncOp(scp, bufferp, userp, &req,
4229 CM_SCACHESYNC_NEEDCALLBACK |
4230 CM_SCACHESYNC_READ);
4232 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4236 if (cm_HaveBuffer(scp, bufferp, 0)) {
4237 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4241 /* otherwise, load the buffer and try again */
4242 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4244 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4245 scp, bufferp, code);
4250 buf_Release(bufferp);
4254 } /* if (wrong buffer) ... */
4256 /* now we have the buffer containing the entry we're interested in; copy
4257 * it out if it represents a non-deleted entry.
4259 entryInDir = curOffset.LowPart & (2048-1);
4260 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4262 /* page header will help tell us which entries are free. Page header
4263 * can change more often than once per buffer, since AFS 3 dir page size
4264 * may be less than (but not more than a buffer package buffer.
4266 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4267 temp &= ~(2048 - 1); /* turn off intra-page bits */
4268 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4270 /* now determine which entry we're looking at in the page. If it is
4271 * free (there's a free bitmap at the start of the dir), we should
4272 * skip these 32 bytes.
4274 slotInPage = (entryInDir & 0x7e0) >> 5;
4275 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4276 /* this entry is free */
4277 numDirChunks = 1; /* only skip this guy */
4281 tp = bufferp->datap + entryInBuffer;
4282 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4284 /* while we're here, compute the next entry's location, too,
4285 * since we'll need it when writing out the cookie into the dir
4288 * XXXX Probably should do more sanity checking.
4290 numDirChunks = cm_NameEntries(dep->name, NULL);
4292 /* compute the offset of the cookie representing the next entry */
4293 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4295 /* Compute 8.3 name if necessary */
4296 actualName = dep->name;
4297 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4298 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4299 actualName = shortName;
4302 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4303 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4304 osi_LogSaveString(smb_logp, actualName));
4306 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4307 /* this is one of the entries to use: it is not deleted
4308 * and it matches the star pattern we're looking for.
4311 /* Eliminate entries that don't match requested
4314 /* no hidden files */
4315 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4316 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4320 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4322 /* We have already done the cm_TryBulkStat above */
4323 fid.cell = scp->fid.cell;
4324 fid.volume = scp->fid.volume;
4325 fid.vnode = ntohl(dep->fid.vnode);
4326 fid.unique = ntohl(dep->fid.unique);
4327 fileType = cm_FindFileType(&fid);
4328 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4329 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4331 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4332 fileType == CM_SCACHETYPE_DFSLINK ||
4333 fileType == CM_SCACHETYPE_INVALID)
4334 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4339 memcpy(op, mask, 11); op += 11;
4340 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4341 *op++ = (char)(nextEntryCookie & 0xff);
4342 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4343 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4344 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4345 memcpy(op, &clientCookie, 4); op += 4;
4347 /* now we emit the attribute. This is sort of tricky,
4348 * since we need to really stat the file to find out
4349 * what type of entry we've got. Right now, we're
4350 * copying out data from a buffer, while holding the
4351 * scp locked, so it isn't really convenient to stat
4352 * something now. We'll put in a place holder now,
4353 * and make a second pass before returning this to get
4354 * the real attributes. So, we just skip the data for
4355 * now, and adjust it later. We allocate a patch
4356 * record to make it easy to find this point later.
4357 * The replay will happen at a time when it is safe to
4358 * unlock the directory.
4360 curPatchp = malloc(sizeof(*curPatchp));
4361 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4362 curPatchp->dptr = op;
4363 curPatchp->fid.cell = scp->fid.cell;
4364 curPatchp->fid.volume = scp->fid.volume;
4365 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4366 curPatchp->fid.unique = ntohl(dep->fid.unique);
4368 /* do hidden attribute here since name won't be around when applying
4372 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4373 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4375 curPatchp->flags = 0;
4377 op += 9; /* skip attr, time, date and size */
4379 /* zero out name area. The spec says to pad with
4380 * spaces, but Samba doesn't, and neither do we.
4384 /* finally, we get to copy out the name; we know that
4385 * it fits in 8.3 or the pattern wouldn't match, but it
4386 * never hurts to be sure.
4388 strncpy(op, actualName, 13);
4389 if (smb_StoreAnsiFilenames)
4392 /* Uppercase if requested by client */
4393 if (!KNOWS_LONG_NAMES(inp))
4398 /* now, adjust the # of entries copied */
4400 } /* if we're including this name */
4403 /* and adjust curOffset to be where the new cookie is */
4404 thyper.HighPart = 0;
4405 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4406 curOffset = LargeIntegerAdd(thyper, curOffset);
4407 } /* while copying data for dir listing */
4409 /* release the mutex */
4410 lock_ReleaseMutex(&scp->mx);
4411 if (bufferp) buf_Release(bufferp);
4413 /* apply and free last set of patches; if not doing a star match, this
4414 * will be empty, but better safe (and freeing everything) than sorry.
4416 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4418 /* special return code for unsuccessful search */
4419 if (code == 0 && dataLength < 21 && returnedNames == 0)
4420 code = CM_ERROR_NOFILES;
4422 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4423 returnedNames, code);
4426 smb_DeleteDirSearch(dsp);
4427 smb_ReleaseDirSearch(dsp);
4428 cm_ReleaseSCache(scp);
4429 cm_ReleaseUser(userp);
4433 /* finalize the output buffer */
4434 smb_SetSMBParm(outp, 0, returnedNames);
4435 temp = (long) (op - origOp);
4436 smb_SetSMBDataLength(outp, temp);
4438 /* the data area is a variable block, which has a 5 (already there)
4439 * followed by the length of the # of data bytes. We now know this to
4440 * be "temp," although that includes the 3 bytes of vbl block header.
4441 * Deduct for them and fill in the length field.
4443 temp -= 3; /* deduct vbl block info */
4444 osi_assert(temp == (43 * returnedNames));
4445 origOp[1] = (char)(temp & 0xff);
4446 origOp[2] = (char)((temp>>8) & 0xff);
4447 if (returnedNames == 0)
4448 smb_DeleteDirSearch(dsp);
4449 smb_ReleaseDirSearch(dsp);
4450 cm_ReleaseSCache(scp);
4451 cm_ReleaseUser(userp);
4455 /* verify that this is a valid path to a directory. I don't know why they
4456 * don't use the get file attributes call.
4458 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4462 cm_scache_t *rootScp;
4463 cm_scache_t *newScp;
4472 pathp = smb_GetSMBData(inp, NULL);
4473 pathp = smb_ParseASCIIBlock(pathp, NULL);
4475 return CM_ERROR_BADFD;
4476 if (smb_StoreAnsiFilenames)
4477 OemToChar(pathp,pathp);
4478 osi_Log1(smb_logp, "SMB receive check path %s",
4479 osi_LogSaveString(smb_logp, pathp));
4481 rootScp = cm_data.rootSCachep;
4483 userp = smb_GetUserFromVCP(vcp, inp);
4485 caseFold = CM_FLAG_CASEFOLD;
4487 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4489 cm_ReleaseUser(userp);
4490 return CM_ERROR_NOSUCHPATH;
4492 code = cm_NameI(rootScp, pathp,
4493 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4494 userp, tidPathp, &req, &newScp);
4497 cm_ReleaseUser(userp);
4502 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4503 cm_ReleaseSCache(newScp);
4504 cm_ReleaseUser(userp);
4505 if ( WANTS_DFS_PATHNAMES(inp) )
4506 return CM_ERROR_PATH_NOT_COVERED;
4508 return CM_ERROR_BADSHARENAME;
4510 #endif /* DFS_SUPPORT */
4512 /* now lock the vnode with a callback; returns with newScp locked */
4513 lock_ObtainMutex(&newScp->mx);
4514 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4515 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4516 if (code && code != CM_ERROR_NOACCESS) {
4517 lock_ReleaseMutex(&newScp->mx);
4518 cm_ReleaseSCache(newScp);
4519 cm_ReleaseUser(userp);
4523 attrs = smb_Attributes(newScp);
4525 if (!(attrs & SMB_ATTR_DIRECTORY))
4526 code = CM_ERROR_NOTDIR;
4528 lock_ReleaseMutex(&newScp->mx);
4530 cm_ReleaseSCache(newScp);
4531 cm_ReleaseUser(userp);
4535 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4539 cm_scache_t *rootScp;
4540 unsigned short attribute;
4542 cm_scache_t *newScp;
4551 /* decode basic attributes we're passed */
4552 attribute = smb_GetSMBParm(inp, 0);
4553 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4555 pathp = smb_GetSMBData(inp, NULL);
4556 pathp = smb_ParseASCIIBlock(pathp, NULL);
4558 return CM_ERROR_BADSMB;
4559 if (smb_StoreAnsiFilenames)
4560 OemToChar(pathp,pathp);
4562 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4563 dosTime, attribute);
4565 rootScp = cm_data.rootSCachep;
4567 userp = smb_GetUserFromVCP(vcp, inp);
4569 caseFold = CM_FLAG_CASEFOLD;
4571 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4573 cm_ReleaseUser(userp);
4574 return CM_ERROR_NOSUCHFILE;
4576 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4577 tidPathp, &req, &newScp);
4580 cm_ReleaseUser(userp);
4585 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4586 cm_ReleaseSCache(newScp);
4587 cm_ReleaseUser(userp);
4588 if ( WANTS_DFS_PATHNAMES(inp) )
4589 return CM_ERROR_PATH_NOT_COVERED;
4591 return CM_ERROR_BADSHARENAME;
4593 #endif /* DFS_SUPPORT */
4595 /* now lock the vnode with a callback; returns with newScp locked; we
4596 * need the current status to determine what the new status is, in some
4599 lock_ObtainMutex(&newScp->mx);
4600 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4601 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4603 lock_ReleaseMutex(&newScp->mx);
4604 cm_ReleaseSCache(newScp);
4605 cm_ReleaseUser(userp);
4609 /* Check for RO volume */
4610 if (newScp->flags & CM_SCACHEFLAG_RO) {
4611 lock_ReleaseMutex(&newScp->mx);
4612 cm_ReleaseSCache(newScp);
4613 cm_ReleaseUser(userp);
4614 return CM_ERROR_READONLY;
4617 /* prepare for setattr call */
4620 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4621 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4623 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4624 /* we're told to make a writable file read-only */
4625 attr.unixModeBits = newScp->unixModeBits & ~0222;
4626 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4628 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4629 /* we're told to make a read-only file writable */
4630 attr.unixModeBits = newScp->unixModeBits | 0222;
4631 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4633 lock_ReleaseMutex(&newScp->mx);
4635 /* now call setattr */
4637 code = cm_SetAttr(newScp, &attr, userp, &req);
4641 cm_ReleaseSCache(newScp);
4642 cm_ReleaseUser(userp);
4647 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4651 cm_scache_t *rootScp;
4652 cm_scache_t *newScp, *dscp;
4664 pathp = smb_GetSMBData(inp, NULL);
4665 pathp = smb_ParseASCIIBlock(pathp, NULL);
4667 return CM_ERROR_BADSMB;
4669 if (*pathp == 0) /* null path */
4672 if (smb_StoreAnsiFilenames)
4673 OemToChar(pathp,pathp);
4675 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4676 osi_LogSaveString(smb_logp, pathp));
4678 rootScp = cm_data.rootSCachep;
4680 userp = smb_GetUserFromVCP(vcp, inp);
4682 /* we shouldn't need this for V3 requests, but we seem to */
4683 caseFold = CM_FLAG_CASEFOLD;
4685 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4687 cm_ReleaseUser(userp);
4688 return CM_ERROR_NOSUCHFILE;
4692 * XXX Strange hack XXX
4694 * As of Patch 5 (16 July 97), we are having the following problem:
4695 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4696 * requests to look up "desktop.ini" in all the subdirectories.
4697 * This can cause zillions of timeouts looking up non-existent cells
4698 * and volumes, especially in the top-level directory.
4700 * We have not found any way to avoid this or work around it except
4701 * to explicitly ignore the requests for mount points that haven't
4702 * yet been evaluated and for directories that haven't yet been
4705 * We should modify this hack to provide a fake desktop.ini file
4706 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4708 spacep = inp->spacep;
4709 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4710 #ifndef SPECIAL_FOLDERS
4711 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4712 code = cm_NameI(rootScp, spacep->data,
4713 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4714 userp, tidPathp, &req, &dscp);
4717 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4718 if ( WANTS_DFS_PATHNAMES(inp) )
4719 return CM_ERROR_PATH_NOT_COVERED;
4721 return CM_ERROR_BADSHARENAME;
4723 #endif /* DFS_SUPPORT */
4724 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4725 code = CM_ERROR_NOSUCHFILE;
4726 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4727 cm_buf_t *bp = buf_Find(dscp, &hzero);
4731 code = CM_ERROR_NOSUCHFILE;
4733 cm_ReleaseSCache(dscp);
4735 cm_ReleaseUser(userp);
4740 #endif /* SPECIAL_FOLDERS */
4742 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4743 tidPathp, &req, &newScp);
4745 cm_ReleaseUser(userp);
4750 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4751 cm_ReleaseSCache(newScp);
4752 cm_ReleaseUser(userp);
4753 if ( WANTS_DFS_PATHNAMES(inp) )
4754 return CM_ERROR_PATH_NOT_COVERED;
4756 return CM_ERROR_BADSHARENAME;
4758 #endif /* DFS_SUPPORT */
4760 /* now lock the vnode with a callback; returns with newScp locked */
4761 lock_ObtainMutex(&newScp->mx);
4762 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4763 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4765 lock_ReleaseMutex(&newScp->mx);
4766 cm_ReleaseSCache(newScp);
4767 cm_ReleaseUser(userp);
4772 /* use smb_Attributes instead. Also the fact that a file is
4773 * in a readonly volume doesn't mean it shojuld be marked as RO
4775 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4776 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4777 newScp->fileType == CM_SCACHETYPE_INVALID)
4778 attrs = SMB_ATTR_DIRECTORY;
4781 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4782 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4784 attrs = smb_Attributes(newScp);
4787 smb_SetSMBParm(outp, 0, attrs);
4789 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4790 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4791 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4792 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4793 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4794 smb_SetSMBParm(outp, 5, 0);
4795 smb_SetSMBParm(outp, 6, 0);
4796 smb_SetSMBParm(outp, 7, 0);
4797 smb_SetSMBParm(outp, 8, 0);
4798 smb_SetSMBParm(outp, 9, 0);
4799 smb_SetSMBDataLength(outp, 0);
4800 lock_ReleaseMutex(&newScp->mx);
4802 cm_ReleaseSCache(newScp);
4803 cm_ReleaseUser(userp);
4808 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4812 osi_Log0(smb_logp, "SMB receive tree disconnect");
4814 /* find the tree and free it */
4815 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4817 lock_ObtainWrite(&smb_rctLock);
4819 lock_ReleaseWrite(&smb_rctLock);
4820 smb_ReleaseTID(tidp);
4826 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4844 pathp = smb_GetSMBData(inp, NULL);
4845 pathp = smb_ParseASCIIBlock(pathp, NULL);
4846 if (smb_StoreAnsiFilenames)
4847 OemToChar(pathp,pathp);
4849 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4851 #ifdef DEBUG_VERBOSE
4855 hexpath = osi_HexifyString( pathp );
4856 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4861 share = smb_GetSMBParm(inp, 0);
4862 attribute = smb_GetSMBParm(inp, 1);
4864 spacep = inp->spacep;
4865 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4866 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4867 /* special case magic file name for receiving IOCTL requests
4868 * (since IOCTL calls themselves aren't getting through).
4870 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4871 smb_SetupIoctlFid(fidp, spacep);
4872 smb_SetSMBParm(outp, 0, fidp->fid);
4873 smb_SetSMBParm(outp, 1, 0); /* attrs */
4874 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4875 smb_SetSMBParm(outp, 3, 0);
4876 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4877 smb_SetSMBParm(outp, 5, 0x7fff);
4878 /* pass the open mode back */
4879 smb_SetSMBParm(outp, 6, (share & 0xf));
4880 smb_SetSMBDataLength(outp, 0);
4881 smb_ReleaseFID(fidp);
4885 userp = smb_GetUserFromVCP(vcp, inp);
4887 caseFold = CM_FLAG_CASEFOLD;
4889 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4891 cm_ReleaseUser(userp);
4892 return CM_ERROR_NOSUCHPATH;
4894 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4895 tidPathp, &req, &scp);
4898 cm_ReleaseUser(userp);
4903 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4904 cm_ReleaseSCache(scp);
4905 cm_ReleaseUser(userp);
4906 if ( WANTS_DFS_PATHNAMES(inp) )
4907 return CM_ERROR_PATH_NOT_COVERED;
4909 return CM_ERROR_BADSHARENAME;
4911 #endif /* DFS_SUPPORT */
4913 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4915 cm_ReleaseSCache(scp);
4916 cm_ReleaseUser(userp);
4920 /* don't need callback to check file type, since file types never
4921 * change, and namei and cm_Lookup all stat the object at least once on
4922 * a successful return.
4924 if (scp->fileType != CM_SCACHETYPE_FILE) {
4925 cm_ReleaseSCache(scp);
4926 cm_ReleaseUser(userp);
4927 return CM_ERROR_ISDIR;
4930 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4933 /* save a pointer to the vnode */
4937 fidp->userp = userp;
4939 lock_ObtainMutex(&fidp->mx);
4940 if ((share & 0xf) == 0)
4941 fidp->flags |= SMB_FID_OPENREAD;
4942 else if ((share & 0xf) == 1)
4943 fidp->flags |= SMB_FID_OPENWRITE;
4945 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4946 lock_ReleaseMutex(&fidp->mx);
4948 lock_ObtainMutex(&scp->mx);
4949 smb_SetSMBParm(outp, 0, fidp->fid);
4950 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4951 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4952 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4953 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4954 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4955 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4956 /* pass the open mode back; XXXX add access checks */
4957 smb_SetSMBParm(outp, 6, (share & 0xf));
4958 smb_SetSMBDataLength(outp, 0);
4959 lock_ReleaseMutex(&scp->mx);
4962 cm_Open(scp, 0, userp);
4964 /* send and free packet */
4965 smb_ReleaseFID(fidp);
4966 cm_ReleaseUser(userp);
4967 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4971 typedef struct smb_unlinkRock {
4976 char *maskp; /* pointer to the star pattern */
4981 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4984 smb_unlinkRock_t *rockp;
4992 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4993 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4994 caseFold |= CM_FLAG_8DOT3;
4996 matchName = dep->name;
4997 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4999 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5000 !cm_Is8Dot3(dep->name)) {
5001 cm_Gen8Dot3Name(dep, shortName, NULL);
5002 matchName = shortName;
5003 /* 8.3 matches are always case insensitive */
5004 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5007 osi_Log1(smb_logp, "Unlinking %s",
5008 osi_LogSaveString(smb_logp, matchName));
5009 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
5010 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5011 smb_NotifyChange(FILE_ACTION_REMOVED,
5012 FILE_NOTIFY_CHANGE_FILE_NAME,
5013 dscp, dep->name, NULL, TRUE);
5017 /* If we made a case sensitive exact match, we might as well quit now. */
5018 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
5019 code = CM_ERROR_STOPNOW;
5027 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5036 smb_unlinkRock_t rock;
5045 attribute = smb_GetSMBParm(inp, 0);
5047 tp = smb_GetSMBData(inp, NULL);
5048 pathp = smb_ParseASCIIBlock(tp, &tp);
5049 if (smb_StoreAnsiFilenames)
5050 OemToChar(pathp,pathp);
5052 osi_Log1(smb_logp, "SMB receive unlink %s",
5053 osi_LogSaveString(smb_logp, pathp));
5055 spacep = inp->spacep;
5056 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5058 userp = smb_GetUserFromVCP(vcp, inp);
5060 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5062 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5064 cm_ReleaseUser(userp);
5065 return CM_ERROR_NOSUCHPATH;
5067 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5070 cm_ReleaseUser(userp);
5075 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5076 cm_ReleaseSCache(dscp);
5077 cm_ReleaseUser(userp);
5078 if ( WANTS_DFS_PATHNAMES(inp) )
5079 return CM_ERROR_PATH_NOT_COVERED;
5081 return CM_ERROR_BADSHARENAME;
5083 #endif /* DFS_SUPPORT */
5085 /* otherwise, scp points to the parent directory. */
5092 rock.maskp = smb_FindMask(pathp);
5093 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5096 thyper.HighPart = 0;
5102 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5103 * match. If that fails, we do a case insensitve match.
5105 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5106 !smb_IsStarMask(rock.maskp)) {
5107 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5110 thyper.HighPart = 0;
5111 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5116 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5118 if (code == CM_ERROR_STOPNOW)
5121 cm_ReleaseUser(userp);
5123 cm_ReleaseSCache(dscp);
5125 if (code == 0 && !rock.any)
5126 code = CM_ERROR_NOSUCHFILE;
5130 typedef struct smb_renameRock {
5131 cm_scache_t *odscp; /* old dir */
5132 cm_scache_t *ndscp; /* new dir */
5133 cm_user_t *userp; /* user */
5134 cm_req_t *reqp; /* request struct */
5135 smb_vc_t *vcp; /* virtual circuit */
5136 char *maskp; /* pointer to star pattern of old file name */
5137 int flags; /* tilde, casefold, etc */
5138 char *newNamep; /* ptr to the new file's name */
5141 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5144 smb_renameRock_t *rockp;
5149 rockp = (smb_renameRock_t *) vrockp;
5151 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5152 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5153 caseFold |= CM_FLAG_8DOT3;
5155 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5157 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5158 !cm_Is8Dot3(dep->name)) {
5159 cm_Gen8Dot3Name(dep, shortName, NULL);
5160 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5163 code = cm_Rename(rockp->odscp, dep->name,
5164 rockp->ndscp, rockp->newNamep, rockp->userp,
5166 /* if the call worked, stop doing the search now, since we
5167 * really only want to rename one file.
5170 code = CM_ERROR_STOPNOW;
5179 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5182 cm_space_t *spacep = NULL;
5183 smb_renameRock_t rock;
5184 cm_scache_t *oldDscp = NULL;
5185 cm_scache_t *newDscp = NULL;
5186 cm_scache_t *tmpscp= NULL;
5187 cm_scache_t *tmpscp2 = NULL;
5197 userp = smb_GetUserFromVCP(vcp, inp);
5198 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5200 cm_ReleaseUser(userp);
5201 return CM_ERROR_NOSUCHPATH;
5205 spacep = inp->spacep;
5206 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5208 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5209 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5210 userp, tidPathp, &req, &oldDscp);
5212 cm_ReleaseUser(userp);
5217 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5218 cm_ReleaseSCache(oldDscp);
5219 cm_ReleaseUser(userp);
5220 if ( WANTS_DFS_PATHNAMES(inp) )
5221 return CM_ERROR_PATH_NOT_COVERED;
5223 return CM_ERROR_BADSHARENAME;
5225 #endif /* DFS_SUPPORT */
5227 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5228 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5229 userp, tidPathp, &req, &newDscp);
5232 cm_ReleaseSCache(oldDscp);
5233 cm_ReleaseUser(userp);
5238 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5239 cm_ReleaseSCache(oldDscp);
5240 cm_ReleaseSCache(newDscp);
5241 cm_ReleaseUser(userp);
5242 if ( WANTS_DFS_PATHNAMES(inp) )
5243 return CM_ERROR_PATH_NOT_COVERED;
5245 return CM_ERROR_BADSHARENAME;
5247 #endif /* DFS_SUPPORT */
5250 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5251 * next, get the component names, and lower case them.
5254 /* handle the old name first */
5256 oldLastNamep = oldPathp;
5260 /* and handle the new name, too */
5262 newLastNamep = newPathp;
5266 /* TODO: The old name could be a wildcard. The new name must not be */
5268 /* do the vnode call */
5269 rock.odscp = oldDscp;
5270 rock.ndscp = newDscp;
5274 rock.maskp = oldLastNamep;
5275 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5276 rock.newNamep = newLastNamep;
5278 /* Check if the file already exists; if so return error */
5279 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5280 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5281 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5282 osi_LogSaveString(afsd_logp, newLastNamep));
5284 /* Check if the old and the new names differ only in case. If so return
5285 * success, else return CM_ERROR_EXISTS
5287 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5289 /* This would be a success only if the old file is *as same as* the new file */
5290 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5292 if (tmpscp == tmpscp2)
5295 code = CM_ERROR_EXISTS;
5296 cm_ReleaseSCache(tmpscp2);
5299 code = CM_ERROR_NOSUCHFILE;
5302 /* file exist, do not rename, also fixes move */
5303 osi_Log0(smb_logp, "Can't rename. Target already exists");
5304 code = CM_ERROR_EXISTS;
5308 cm_ReleaseSCache(tmpscp);
5309 cm_ReleaseSCache(newDscp);
5310 cm_ReleaseSCache(oldDscp);
5311 cm_ReleaseUser(userp);
5315 /* Now search the directory for the pattern, and do the appropriate rename when found */
5316 thyper.LowPart = 0; /* search dir from here */
5317 thyper.HighPart = 0;
5319 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5320 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5322 if (code == CM_ERROR_STOPNOW)
5325 code = CM_ERROR_NOSUCHFILE;
5327 /* Handle Change Notification */
5329 * Being lazy, not distinguishing between files and dirs in this
5330 * filter, since we'd have to do a lookup.
5332 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5333 if (oldDscp == newDscp) {
5334 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5335 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5336 filter, oldDscp, oldLastNamep,
5337 newLastNamep, TRUE);
5339 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5340 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5341 filter, oldDscp, oldLastNamep,
5343 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5344 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5345 filter, newDscp, newLastNamep,
5350 cm_ReleaseSCache(tmpscp);
5351 cm_ReleaseUser(userp);
5352 cm_ReleaseSCache(oldDscp);
5353 cm_ReleaseSCache(newDscp);
5358 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5361 cm_space_t *spacep = NULL;
5362 cm_scache_t *oldDscp = NULL;
5363 cm_scache_t *newDscp = NULL;
5364 cm_scache_t *tmpscp= NULL;
5365 cm_scache_t *tmpscp2 = NULL;
5366 cm_scache_t *sscp = NULL;
5375 userp = smb_GetUserFromVCP(vcp, inp);
5377 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5379 cm_ReleaseUser(userp);
5380 return CM_ERROR_NOSUCHPATH;
5385 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5387 spacep = inp->spacep;
5388 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5390 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5391 userp, tidPathp, &req, &oldDscp);
5393 cm_ReleaseUser(userp);
5398 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5399 cm_ReleaseSCache(oldDscp);
5400 cm_ReleaseUser(userp);
5401 if ( WANTS_DFS_PATHNAMES(inp) )
5402 return CM_ERROR_PATH_NOT_COVERED;
5404 return CM_ERROR_BADSHARENAME;
5406 #endif /* DFS_SUPPORT */
5408 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5409 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5410 userp, tidPathp, &req, &newDscp);
5412 cm_ReleaseSCache(oldDscp);
5413 cm_ReleaseUser(userp);
5418 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5419 cm_ReleaseSCache(newDscp);
5420 cm_ReleaseSCache(oldDscp);
5421 cm_ReleaseUser(userp);
5422 if ( WANTS_DFS_PATHNAMES(inp) )
5423 return CM_ERROR_PATH_NOT_COVERED;
5425 return CM_ERROR_BADSHARENAME;
5427 #endif /* DFS_SUPPORT */
5429 /* Now, although we did two lookups for the two directories (because the same
5430 * directory can be referenced through different paths), we only allow hard links
5431 * within the same directory. */
5432 if (oldDscp != newDscp) {
5433 cm_ReleaseSCache(oldDscp);
5434 cm_ReleaseSCache(newDscp);
5435 cm_ReleaseUser(userp);
5436 return CM_ERROR_CROSSDEVLINK;
5439 /* handle the old name first */
5441 oldLastNamep = oldPathp;
5445 /* and handle the new name, too */
5447 newLastNamep = newPathp;
5451 /* now lookup the old name */
5452 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5453 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5455 cm_ReleaseSCache(oldDscp);
5456 cm_ReleaseSCache(newDscp);
5457 cm_ReleaseUser(userp);
5461 /* Check if the file already exists; if so return error */
5462 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5463 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5464 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5465 osi_LogSaveString(afsd_logp, newLastNamep));
5467 /* if the existing link is to the same file, then we return success */
5469 if(sscp == tmpscp) {
5472 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5473 code = CM_ERROR_EXISTS;
5478 cm_ReleaseSCache(tmpscp);
5479 cm_ReleaseSCache(sscp);
5480 cm_ReleaseSCache(newDscp);
5481 cm_ReleaseSCache(oldDscp);
5482 cm_ReleaseUser(userp);
5486 /* now create the hardlink */
5487 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5488 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5489 osi_Log1(smb_logp," Link returns 0x%x", code);
5491 /* Handle Change Notification */
5493 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5494 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5495 smb_NotifyChange(FILE_ACTION_ADDED,
5496 filter, newDscp, newLastNamep,
5501 cm_ReleaseSCache(tmpscp);
5502 cm_ReleaseUser(userp);
5503 cm_ReleaseSCache(sscp);
5504 cm_ReleaseSCache(oldDscp);
5505 cm_ReleaseSCache(newDscp);
5510 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5516 tp = smb_GetSMBData(inp, NULL);
5517 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5518 if (smb_StoreAnsiFilenames)
5519 OemToChar(oldPathp,oldPathp);
5520 newPathp = smb_ParseASCIIBlock(tp, &tp);
5521 if (smb_StoreAnsiFilenames)
5522 OemToChar(newPathp,newPathp);
5524 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5525 osi_LogSaveString(smb_logp, oldPathp),
5526 osi_LogSaveString(smb_logp, newPathp));
5528 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5533 typedef struct smb_rmdirRock {
5537 char *maskp; /* pointer to the star pattern */
5542 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5545 smb_rmdirRock_t *rockp;
5550 rockp = (smb_rmdirRock_t *) vrockp;
5552 matchName = dep->name;
5553 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5554 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5556 match = (strcmp(matchName, rockp->maskp) == 0);
5558 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5559 !cm_Is8Dot3(dep->name)) {
5560 cm_Gen8Dot3Name(dep, shortName, NULL);
5561 matchName = shortName;
5562 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5565 osi_Log1(smb_logp, "Removing directory %s",
5566 osi_LogSaveString(smb_logp, matchName));
5567 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5568 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5569 smb_NotifyChange(FILE_ACTION_REMOVED,
5570 FILE_NOTIFY_CHANGE_DIR_NAME,
5571 dscp, dep->name, NULL, TRUE);
5580 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5588 smb_rmdirRock_t rock;
5597 tp = smb_GetSMBData(inp, NULL);
5598 pathp = smb_ParseASCIIBlock(tp, &tp);
5599 if (smb_StoreAnsiFilenames)
5600 OemToChar(pathp,pathp);
5602 spacep = inp->spacep;
5603 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5605 userp = smb_GetUserFromVCP(vcp, inp);
5607 caseFold = CM_FLAG_CASEFOLD;
5609 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5611 cm_ReleaseUser(userp);
5612 return CM_ERROR_NOSUCHPATH;
5614 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5615 userp, tidPathp, &req, &dscp);
5618 cm_ReleaseUser(userp);
5623 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5624 cm_ReleaseSCache(dscp);
5625 cm_ReleaseUser(userp);
5626 if ( WANTS_DFS_PATHNAMES(inp) )
5627 return CM_ERROR_PATH_NOT_COVERED;
5629 return CM_ERROR_BADSHARENAME;
5631 #endif /* DFS_SUPPORT */
5633 /* otherwise, scp points to the parent directory. */
5640 rock.maskp = lastNamep;
5641 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5644 thyper.HighPart = 0;
5648 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5649 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5650 if (code == 0 && !rock.any) {
5652 thyper.HighPart = 0;
5653 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5654 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5657 cm_ReleaseUser(userp);
5659 cm_ReleaseSCache(dscp);
5661 if (code == 0 && !rock.any)
5662 code = CM_ERROR_NOSUCHFILE;
5666 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5676 fid = smb_GetSMBParm(inp, 0);
5678 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5680 fid = smb_ChainFID(fid, inp);
5681 fidp = smb_FindFID(vcp, fid, 0);
5683 return CM_ERROR_BADFD;
5685 lock_ObtainMutex(&fidp->mx);
5686 if (fidp->flags & SMB_FID_IOCTL) {
5687 lock_ReleaseMutex(&fidp->mx);
5688 smb_ReleaseFID(fidp);
5689 return CM_ERROR_BADFD;
5691 lock_ReleaseMutex(&fidp->mx);
5693 userp = smb_GetUserFromVCP(vcp, inp);
5695 lock_ObtainMutex(&fidp->mx);
5696 if (fidp->flags & SMB_FID_OPENWRITE) {
5697 cm_scache_t * scp = fidp->scp;
5699 lock_ReleaseMutex(&fidp->mx);
5700 code = cm_FSync(scp, userp, &req);
5701 cm_ReleaseSCache(scp);
5704 lock_ReleaseMutex(&fidp->mx);
5707 smb_ReleaseFID(fidp);
5709 cm_ReleaseUser(userp);
5714 struct smb_FullNameRock {
5720 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5724 struct smb_FullNameRock *vrockp;
5726 vrockp = (struct smb_FullNameRock *)rockp;
5728 if (!cm_Is8Dot3(dep->name)) {
5729 cm_Gen8Dot3Name(dep, shortName, NULL);
5731 if (cm_stricmp(shortName, vrockp->name) == 0) {
5732 vrockp->fullName = strdup(dep->name);
5733 return CM_ERROR_STOPNOW;
5736 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5737 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5738 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5739 vrockp->fullName = strdup(dep->name);
5740 return CM_ERROR_STOPNOW;
5745 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5746 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5748 struct smb_FullNameRock rock;
5754 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5755 if (code == CM_ERROR_STOPNOW)
5756 *newPathp = rock.fullName;
5758 *newPathp = strdup(pathp);
5761 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5762 afs_uint32 dosTime) {
5765 cm_scache_t *dscp = fidp->NTopen_dscp;
5766 char *pathp = fidp->NTopen_pathp;
5769 osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
5770 fidp, fidp->fid, vcp);
5773 lock_ObtainMutex(&fidp->mx);
5774 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5775 lock_ReleaseMutex(&fidp->mx);
5776 osi_Log0(smb_logp, " No user specified. Not closing fid");
5777 return CM_ERROR_BADFD;
5780 userp = fidp->userp; /* no hold required since fidp is held
5781 throughout the function */
5782 lock_ReleaseMutex(&fidp->mx);
5787 lock_ObtainWrite(&smb_rctLock);
5789 osi_Log0(smb_logp, " Fid already closed.");
5790 lock_ReleaseWrite(&smb_rctLock);
5791 return CM_ERROR_BADFD;
5794 lock_ReleaseWrite(&smb_rctLock);
5796 lock_ObtainMutex(&fidp->mx);
5797 /* Don't jump the gun on an async raw write */
5798 while (fidp->raw_writers) {
5799 lock_ReleaseMutex(&fidp->mx);
5800 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5801 lock_ObtainMutex(&fidp->mx);
5808 /* watch for ioctl closes, and read-only opens */
5810 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5811 == SMB_FID_OPENWRITE) {
5812 if (dosTime != 0 && dosTime != -1) {
5813 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5814 /* This fixes defect 10958 */
5815 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5816 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5818 lock_ReleaseMutex(&fidp->mx);
5819 code = cm_FSync(scp, userp, &req);
5820 lock_ObtainMutex(&fidp->mx);
5825 /* unlock any pending locks */
5826 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5827 scp->fileType == CM_SCACHETYPE_FILE) {
5831 lock_ReleaseMutex(&fidp->mx);
5833 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5835 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5836 lock_ObtainMutex(&scp->mx);
5838 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5839 CM_SCACHESYNC_NEEDCALLBACK
5840 | CM_SCACHESYNC_GETSTATUS
5841 | CM_SCACHESYNC_LOCK);
5845 "smb CoreClose SyncOp failure code 0x%x", tcode);
5846 goto post_syncopdone;
5849 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5851 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5855 lock_ReleaseMutex(&scp->mx);
5856 lock_ObtainMutex(&fidp->mx);
5859 if (fidp->flags & SMB_FID_DELONCLOSE) {
5862 lock_ReleaseMutex(&fidp->mx);
5863 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5864 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5865 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5866 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5867 smb_NotifyChange(FILE_ACTION_REMOVED,
5868 FILE_NOTIFY_CHANGE_DIR_NAME,
5869 dscp, fullPathp, NULL, TRUE);
5871 code = cm_Unlink(dscp, fullPathp, userp, &req);
5872 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5873 smb_NotifyChange(FILE_ACTION_REMOVED,
5874 FILE_NOTIFY_CHANGE_FILE_NAME,
5875 dscp, fullPathp, NULL, TRUE);
5878 lock_ObtainMutex(&fidp->mx);
5879 fidp->flags &= ~SMB_FID_DELONCLOSE;
5882 /* if this was a newly created file, then clear the creator
5883 * in the stat cache entry. */
5884 if (fidp->flags & SMB_FID_CREATED) {
5885 lock_ObtainMutex(&scp->mx);
5886 if (scp->creator == userp)
5887 scp->creator = NULL;
5888 lock_ReleaseMutex(&scp->mx);
5889 fidp->flags &= ~SMB_FID_CREATED;
5892 if (fidp->flags & SMB_FID_NTOPEN) {
5893 fidp->NTopen_dscp = NULL;
5894 fidp->NTopen_pathp = NULL;
5895 fidp->flags &= ~SMB_FID_NTOPEN;
5897 if (fidp->NTopen_wholepathp) {
5898 free(fidp->NTopen_wholepathp);
5899 fidp->NTopen_wholepathp = NULL;
5901 lock_ReleaseMutex(&fidp->mx);
5904 cm_ReleaseSCache(dscp);
5907 cm_ReleaseSCache(scp);
5915 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5923 fid = smb_GetSMBParm(inp, 0);
5924 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5926 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5928 fid = smb_ChainFID(fid, inp);
5929 fidp = smb_FindFID(vcp, fid, 0);
5931 return CM_ERROR_BADFD;
5934 userp = smb_GetUserFromVCP(vcp, inp);
5936 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5938 smb_ReleaseFID(fidp);
5939 cm_ReleaseUser(userp);
5944 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5947 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5948 cm_user_t *userp, long *readp)
5950 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5951 cm_user_t *userp, long *readp, int dosflag)
5958 osi_hyper_t fileLength;
5960 osi_hyper_t lastByte;
5961 osi_hyper_t bufferOffset;
5962 long bufIndex, nbytes;
5972 lock_ObtainMutex(&fidp->mx);
5974 lock_ObtainMutex(&scp->mx);
5976 if (offset.HighPart == 0) {
5977 chunk = offset.LowPart >> cm_logChunkSize;
5978 if (chunk != fidp->curr_chunk) {
5979 fidp->prev_chunk = fidp->curr_chunk;
5980 fidp->curr_chunk = chunk;
5982 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5985 lock_ReleaseMutex(&fidp->mx);
5987 /* start by looking up the file's end */
5988 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5989 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5990 if (code) goto done;
5992 /* now we have the entry locked, look up the length */
5993 fileLength = scp->length;
5995 /* adjust count down so that it won't go past EOF */
5996 thyper.LowPart = count;
5997 thyper.HighPart = 0;
5998 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6000 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6001 /* we'd read past EOF, so just stop at fileLength bytes.
6002 * Start by computing how many bytes remain in the file.
6004 thyper = LargeIntegerSubtract(fileLength, offset);
6006 /* if we are past EOF, read 0 bytes */
6007 if (LargeIntegerLessThanZero(thyper))
6010 count = thyper.LowPart;
6015 /* now, copy the data one buffer at a time,
6016 * until we've filled the request packet
6019 /* if we've copied all the data requested, we're done */
6020 if (count <= 0) break;
6022 /* otherwise, load up a buffer of data */
6023 thyper.HighPart = offset.HighPart;
6024 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6025 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6028 buf_Release(bufferp);
6031 lock_ReleaseMutex(&scp->mx);
6033 lock_ObtainRead(&scp->bufCreateLock);
6034 code = buf_Get(scp, &thyper, &bufferp);
6035 lock_ReleaseRead(&scp->bufCreateLock);
6037 lock_ObtainMutex(&scp->mx);
6038 if (code) goto done;
6039 bufferOffset = thyper;
6041 /* now get the data in the cache */
6043 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6044 CM_SCACHESYNC_NEEDCALLBACK |
6045 CM_SCACHESYNC_READ);
6046 if (code) goto done;
6048 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6050 /* otherwise, load the buffer and try again */
6051 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6055 buf_Release(bufferp);
6059 } /* if (wrong buffer) ... */
6061 /* now we have the right buffer loaded. Copy out the
6062 * data from here to the user's buffer.
6064 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6066 /* and figure out how many bytes we want from this buffer */
6067 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6068 if (nbytes > count) nbytes = count; /* don't go past EOF */
6070 /* now copy the data */
6073 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
6076 memcpy(op, bufferp->datap + bufIndex, nbytes);
6078 /* adjust counters, pointers, etc. */
6081 thyper.LowPart = nbytes;
6082 thyper.HighPart = 0;
6083 offset = LargeIntegerAdd(thyper, offset);
6087 lock_ReleaseMutex(&scp->mx);
6089 buf_Release(bufferp);
6091 if (code == 0 && sequential)
6092 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6098 * smb_WriteData -- common code for Write and Raw Write
6101 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6102 cm_user_t *userp, long *writtenp)
6104 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6105 cm_user_t *userp, long *writtenp, int dosflag)
6112 osi_hyper_t fileLength; /* file's length at start of write */
6113 osi_hyper_t minLength; /* don't read past this */
6114 long nbytes; /* # of bytes to transfer this iteration */
6116 osi_hyper_t thyper; /* hyper tmp variable */
6117 osi_hyper_t bufferOffset;
6118 long bufIndex; /* index in buffer where our data is */
6120 osi_hyper_t writeBackOffset;/* offset of region to write back when
6125 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6126 fidp->fid, offsetp->LowPart, count);
6136 lock_ObtainMutex(&fidp->mx);
6137 /* make sure we have a writable FD */
6138 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6139 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6140 fidp->fid, fidp->flags);
6141 lock_ReleaseMutex(&fidp->mx);
6142 code = CM_ERROR_BADFDOP;
6148 lock_ReleaseMutex(&fidp->mx);
6150 lock_ObtainMutex(&scp->mx);
6151 /* start by looking up the file's end */
6152 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6153 CM_SCACHESYNC_NEEDCALLBACK
6154 | CM_SCACHESYNC_SETSTATUS
6155 | CM_SCACHESYNC_GETSTATUS);
6159 /* now we have the entry locked, look up the length */
6160 fileLength = scp->length;
6161 minLength = fileLength;
6162 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6163 minLength = scp->serverLength;
6165 /* adjust file length if we extend past EOF */
6166 thyper.LowPart = count;
6167 thyper.HighPart = 0;
6168 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6169 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6170 /* we'd write past EOF, so extend the file */
6171 scp->mask |= CM_SCACHEMASK_LENGTH;
6172 scp->length = thyper;
6173 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6175 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6177 /* now, if the new position (thyper) and the old (offset) are in
6178 * different storeback windows, remember to store back the previous
6179 * storeback window when we're done with the write.
6181 if ((thyper.LowPart & (-cm_chunkSize)) !=
6182 (offset.LowPart & (-cm_chunkSize))) {
6183 /* they're different */
6185 writeBackOffset.HighPart = offset.HighPart;
6186 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6191 /* now, copy the data one buffer at a time, until we've filled the
6194 /* if we've copied all the data requested, we're done */
6198 /* handle over quota or out of space */
6199 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6200 *writtenp = written;
6201 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6205 /* otherwise, load up a buffer of data */
6206 thyper.HighPart = offset.HighPart;
6207 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6208 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6211 lock_ReleaseMutex(&bufferp->mx);
6212 buf_Release(bufferp);
6215 lock_ReleaseMutex(&scp->mx);
6217 lock_ObtainRead(&scp->bufCreateLock);
6218 code = buf_Get(scp, &thyper, &bufferp);
6219 lock_ReleaseRead(&scp->bufCreateLock);
6221 lock_ObtainMutex(&bufferp->mx);
6222 lock_ObtainMutex(&scp->mx);
6223 if (code) goto done;
6225 bufferOffset = thyper;
6227 /* now get the data in the cache */
6229 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6230 CM_SCACHESYNC_NEEDCALLBACK
6231 | CM_SCACHESYNC_WRITE
6232 | CM_SCACHESYNC_BUFLOCKED);
6236 /* If we're overwriting the entire buffer, or
6237 * if we're writing at or past EOF, mark the
6238 * buffer as current so we don't call
6239 * cm_GetBuffer. This skips the fetch from the
6240 * server in those cases where we're going to
6241 * obliterate all the data in the buffer anyway,
6242 * or in those cases where there is no useful
6243 * data at the server to start with.
6245 * Use minLength instead of scp->length, since
6246 * the latter has already been updated by this
6249 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6250 || LargeIntegerEqualTo(offset, bufferp->offset)
6251 && (count >= cm_data.buf_blockSize
6252 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6253 ConvertLongToLargeInteger(count)),
6255 if (count < cm_data.buf_blockSize
6256 && bufferp->dataVersion == -1)
6257 memset(bufferp->datap, 0,
6258 cm_data.buf_blockSize);
6259 bufferp->dataVersion = scp->dataVersion;
6262 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6264 /* otherwise, load the buffer and try again */
6265 lock_ReleaseMutex(&bufferp->mx);
6266 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6268 lock_ReleaseMutex(&scp->mx);
6269 lock_ObtainMutex(&bufferp->mx);
6270 lock_ObtainMutex(&scp->mx);
6274 lock_ReleaseMutex(&bufferp->mx);
6275 buf_Release(bufferp);
6279 } /* if (wrong buffer) ... */
6281 /* now we have the right buffer loaded. Copy out the
6282 * data from here to the user's buffer.
6284 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6286 /* and figure out how many bytes we want from this buffer */
6287 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6289 nbytes = count; /* don't go past end of request */
6291 /* now copy the data */
6294 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
6297 memcpy(bufferp->datap + bufIndex, op, nbytes);
6298 buf_SetDirty(bufferp);
6300 /* and record the last writer */
6301 if (bufferp->userp != userp) {
6304 cm_ReleaseUser(bufferp->userp);
6305 bufferp->userp = userp;
6308 /* adjust counters, pointers, etc. */
6312 thyper.LowPart = nbytes;
6313 thyper.HighPart = 0;
6314 offset = LargeIntegerAdd(thyper, offset);
6318 lock_ReleaseMutex(&scp->mx);
6321 lock_ReleaseMutex(&bufferp->mx);
6322 buf_Release(bufferp);
6325 lock_ObtainMutex(&fidp->mx);
6326 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6327 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6328 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6329 fidp->NTopen_dscp, fidp->NTopen_pathp,
6332 lock_ReleaseMutex(&fidp->mx);
6334 if (code == 0 && doWriteBack) {
6336 lock_ObtainMutex(&scp->mx);
6337 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6339 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6340 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6342 lock_ReleaseMutex(&scp->mx);
6343 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6344 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6347 cm_ReleaseSCache(scp);
6349 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6350 fidp->fid, code, *writtenp);
6354 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6357 long count, written = 0, total_written = 0;
6363 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6365 int inDataBlockCount;
6367 fd = smb_GetSMBParm(inp, 0);
6368 count = smb_GetSMBParm(inp, 1);
6369 offset.HighPart = 0; /* too bad */
6370 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6372 op = smb_GetSMBData(inp, NULL);
6373 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6375 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6376 fd, offset.LowPart, count);
6378 fd = smb_ChainFID(fd, inp);
6379 fidp = smb_FindFID(vcp, fd, 0);
6381 return CM_ERROR_BADFD;
6383 lock_ObtainMutex(&fidp->mx);
6384 if (fidp->flags & SMB_FID_IOCTL) {
6385 lock_ReleaseMutex(&fidp->mx);
6386 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6387 smb_ReleaseFID(fidp);
6390 lock_ReleaseMutex(&fidp->mx);
6391 userp = smb_GetUserFromVCP(vcp, inp);
6393 /* special case: 0 bytes transferred means truncate to this position */
6399 truncAttr.mask = CM_ATTRMASK_LENGTH;
6400 truncAttr.length.LowPart = offset.LowPart;
6401 truncAttr.length.HighPart = 0;
6402 lock_ObtainMutex(&fidp->mx);
6403 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6404 fidp->flags |= SMB_FID_LENGTHSETDONE;
6405 lock_ReleaseMutex(&fidp->mx);
6406 smb_SetSMBParm(outp, 0, /* count */ 0);
6407 smb_SetSMBDataLength(outp, 0);
6413 LARGE_INTEGER LOffset;
6414 LARGE_INTEGER LLength;
6416 pid = ((smb_t *) inp)->pid;
6417 key = cm_GenerateKey(vcp->vcID, pid, fd);
6419 LOffset.HighPart = offset.HighPart;
6420 LOffset.LowPart = offset.LowPart;
6421 LLength.HighPart = 0;
6422 LLength.LowPart = count;
6424 lock_ObtainMutex(&fidp->scp->mx);
6425 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6426 lock_ReleaseMutex(&fidp->scp->mx);
6433 * Work around bug in NT client
6435 * When copying a file, the NT client should first copy the data,
6436 * then copy the last write time. But sometimes the NT client does
6437 * these in the wrong order, so the data copies would inadvertently
6438 * cause the last write time to be overwritten. We try to detect this,
6439 * and don't set client mod time if we think that would go against the
6442 lock_ObtainMutex(&fidp->mx);
6443 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6444 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6445 fidp->scp->clientModTime = time(NULL);
6447 lock_ReleaseMutex(&fidp->mx);
6450 while ( code == 0 && count > 0 ) {
6452 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6454 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6456 if (code == 0 && written == 0)
6457 code = CM_ERROR_PARTIALWRITE;
6459 offset.LowPart += written;
6461 total_written += written;
6465 /* set the packet data length to 3 bytes for the data block header,
6466 * plus the size of the data.
6468 smb_SetSMBParm(outp, 0, total_written);
6469 smb_SetSMBDataLength(outp, 0);
6472 smb_ReleaseFID(fidp);
6473 cm_ReleaseUser(userp);
6478 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6479 NCB *ncbp, raw_write_cont_t *rwcp)
6492 fd = smb_GetSMBParm(inp, 0);
6493 fidp = smb_FindFID(vcp, fd, 0);
6495 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
6496 rwcp->offset.LowPart, rwcp->count);
6498 userp = smb_GetUserFromVCP(vcp, inp);
6502 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6505 rawBuf = (dos_ptr) rwcp->buf;
6506 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6507 (unsigned char *) rawBuf, userp,
6511 if (rwcp->writeMode & 0x1) { /* synchronous */
6514 smb_FormatResponsePacket(vcp, inp, outp);
6515 op = (smb_t *) outp;
6516 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6517 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6518 smb_SetSMBDataLength(outp, 0);
6519 smb_SendPacket(vcp, outp);
6520 smb_FreePacket(outp);
6522 else { /* asynchronous */
6523 lock_ObtainMutex(&fidp->mx);
6524 fidp->raw_writers--;
6525 if (fidp->raw_writers == 0)
6526 thrd_SetEvent(fidp->raw_write_event);
6527 lock_ReleaseMutex(&fidp->mx);
6530 /* Give back raw buffer */
6531 lock_ObtainMutex(&smb_RawBufLock);
6533 *((char **)rawBuf) = smb_RawBufs;
6535 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6537 smb_RawBufs = rawBuf;
6538 lock_ReleaseMutex(&smb_RawBufLock);
6540 smb_ReleaseFID(fidp);
6541 cm_ReleaseUser(userp);
6544 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6549 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6552 long count, written = 0, total_written = 0;
6559 unsigned short writeMode;
6566 fd = smb_GetSMBParm(inp, 0);
6567 totalCount = smb_GetSMBParm(inp, 1);
6568 count = smb_GetSMBParm(inp, 10);
6569 offset.HighPart = 0; /* too bad */
6570 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6571 writeMode = smb_GetSMBParm(inp, 7);
6573 op = (char *) inp->data;
6574 op += smb_GetSMBParm(inp, 11);
6577 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
6578 fd, offset.LowPart, count, writeMode);
6580 fd = smb_ChainFID(fd, inp);
6581 fidp = smb_FindFID(vcp, fd, 0);
6583 return CM_ERROR_BADFD;
6589 LARGE_INTEGER LOffset;
6590 LARGE_INTEGER LLength;
6592 pid = ((smb_t *) inp)->pid;
6593 key = cm_GenerateKey(vcp->vcID, pid, fd);
6595 LOffset.HighPart = offset.HighPart;
6596 LOffset.LowPart = offset.LowPart;
6597 LLength.HighPart = 0;
6598 LLength.LowPart = count;
6600 lock_ObtainMutex(&fidp->scp->mx);
6601 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6602 lock_ReleaseMutex(&fidp->scp->mx);
6605 smb_ReleaseFID(fidp);
6610 userp = smb_GetUserFromVCP(vcp, inp);
6613 * Work around bug in NT client
6615 * When copying a file, the NT client should first copy the data,
6616 * then copy the last write time. But sometimes the NT client does
6617 * these in the wrong order, so the data copies would inadvertently
6618 * cause the last write time to be overwritten. We try to detect this,
6619 * and don't set client mod time if we think that would go against the
6622 lock_ObtainMutex(&fidp->mx);
6623 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6624 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6625 fidp->scp->clientModTime = time(NULL);
6627 lock_ReleaseMutex(&fidp->mx);
6630 while ( code == 0 && count > 0 ) {
6632 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6634 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6636 if (code == 0 && written == 0)
6637 code = CM_ERROR_PARTIALWRITE;
6639 offset.LowPart += written;
6641 total_written += written;
6645 /* Get a raw buffer */
6648 lock_ObtainMutex(&smb_RawBufLock);
6650 /* Get a raw buf, from head of list */
6651 rawBuf = smb_RawBufs;
6653 smb_RawBufs = *(char **)smb_RawBufs;
6655 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6659 code = CM_ERROR_USESTD;
6661 lock_ReleaseMutex(&smb_RawBufLock);
6664 /* Don't allow a premature Close */
6665 if (code == 0 && (writeMode & 1) == 0) {
6666 lock_ObtainMutex(&fidp->mx);
6667 fidp->raw_writers++;
6668 thrd_ResetEvent(fidp->raw_write_event);
6669 lock_ReleaseMutex(&fidp->mx);
6672 smb_ReleaseFID(fidp);
6673 cm_ReleaseUser(userp);
6676 smb_SetSMBParm(outp, 0, total_written);
6677 smb_SetSMBDataLength(outp, 0);
6678 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6685 rwcp->offset.HighPart = 0;
6686 rwcp->offset.LowPart = offset.LowPart + count;
6687 rwcp->count = totalCount - count;
6688 rwcp->writeMode = writeMode;
6689 rwcp->alreadyWritten = total_written;
6691 /* set the packet data length to 3 bytes for the data block header,
6692 * plus the size of the data.
6694 smb_SetSMBParm(outp, 0, 0xffff);
6695 smb_SetSMBDataLength(outp, 0);
6700 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6703 long count, finalCount;
6711 fd = smb_GetSMBParm(inp, 0);
6712 count = smb_GetSMBParm(inp, 1);
6713 offset.HighPart = 0; /* too bad */
6714 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6716 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6717 fd, offset.LowPart, count);
6719 fd = smb_ChainFID(fd, inp);
6720 fidp = smb_FindFID(vcp, fd, 0);
6722 return CM_ERROR_BADFD;
6724 lock_ObtainMutex(&fidp->mx);
6725 if (fidp->flags & SMB_FID_IOCTL) {
6726 lock_ReleaseMutex(&fidp->mx);
6727 code = smb_IoctlRead(fidp, vcp, inp, outp);
6728 smb_ReleaseFID(fidp);
6731 lock_ReleaseMutex(&fidp->mx);
6734 LARGE_INTEGER LOffset, LLength;
6737 pid = ((smb_t *) inp)->pid;
6738 key = cm_GenerateKey(vcp->vcID, pid, fd);
6740 LOffset.HighPart = 0;
6741 LOffset.LowPart = offset.LowPart;
6742 LLength.HighPart = 0;
6743 LLength.LowPart = count;
6745 lock_ObtainMutex(&fidp->scp->mx);
6746 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6747 lock_ReleaseMutex(&fidp->scp->mx);
6750 smb_ReleaseFID(fidp);
6754 userp = smb_GetUserFromVCP(vcp, inp);
6756 /* remember this for final results */
6757 smb_SetSMBParm(outp, 0, count);
6758 smb_SetSMBParm(outp, 1, 0);
6759 smb_SetSMBParm(outp, 2, 0);
6760 smb_SetSMBParm(outp, 3, 0);
6761 smb_SetSMBParm(outp, 4, 0);
6763 /* set the packet data length to 3 bytes for the data block header,
6764 * plus the size of the data.
6766 smb_SetSMBDataLength(outp, count+3);
6768 /* get op ptr after putting in the parms, since otherwise we don't
6769 * know where the data really is.
6771 op = smb_GetSMBData(outp, NULL);
6773 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6774 *op++ = 1; /* data block marker */
6775 *op++ = (unsigned char) (count & 0xff);
6776 *op++ = (unsigned char) ((count >> 8) & 0xff);
6779 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6781 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6784 /* fix some things up */
6785 smb_SetSMBParm(outp, 0, finalCount);
6786 smb_SetSMBDataLength(outp, finalCount+3);
6788 smb_ReleaseFID(fidp);
6790 cm_ReleaseUser(userp);
6794 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6801 cm_scache_t *dscp; /* dir we're dealing with */
6802 cm_scache_t *scp; /* file we're creating */
6804 int initialModeBits;
6814 /* compute initial mode bits based on read-only flag in attributes */
6815 initialModeBits = 0777;
6817 tp = smb_GetSMBData(inp, NULL);
6818 pathp = smb_ParseASCIIBlock(tp, &tp);
6819 if (smb_StoreAnsiFilenames)
6820 OemToChar(pathp,pathp);
6822 if (strcmp(pathp, "\\") == 0)
6823 return CM_ERROR_EXISTS;
6825 spacep = inp->spacep;
6826 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6828 userp = smb_GetUserFromVCP(vcp, inp);
6830 caseFold = CM_FLAG_CASEFOLD;
6832 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6834 cm_ReleaseUser(userp);
6835 return CM_ERROR_NOSUCHPATH;
6838 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6839 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6840 userp, tidPathp, &req, &dscp);
6843 cm_ReleaseUser(userp);
6848 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6849 cm_ReleaseSCache(dscp);
6850 cm_ReleaseUser(userp);
6851 if ( WANTS_DFS_PATHNAMES(inp) )
6852 return CM_ERROR_PATH_NOT_COVERED;
6854 return CM_ERROR_BADSHARENAME;
6856 #endif /* DFS_SUPPORT */
6858 /* otherwise, scp points to the parent directory. Do a lookup, and
6859 * fail if we find it. Otherwise, we do the create.
6865 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6866 if (scp) cm_ReleaseSCache(scp);
6867 if (code != CM_ERROR_NOSUCHFILE) {
6868 if (code == 0) code = CM_ERROR_EXISTS;
6869 cm_ReleaseSCache(dscp);
6870 cm_ReleaseUser(userp);
6874 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6875 setAttr.clientModTime = time(NULL);
6876 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6877 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6878 smb_NotifyChange(FILE_ACTION_ADDED,
6879 FILE_NOTIFY_CHANGE_DIR_NAME,
6880 dscp, lastNamep, NULL, TRUE);
6882 /* we don't need this any longer */
6883 cm_ReleaseSCache(dscp);
6886 /* something went wrong creating or truncating the file */
6887 cm_ReleaseUser(userp);
6891 /* otherwise we succeeded */
6892 smb_SetSMBDataLength(outp, 0);
6893 cm_ReleaseUser(userp);
6898 BOOL smb_IsLegalFilename(char *filename)
6901 * Find the longest substring of filename that does not contain
6902 * any of the chars in illegalChars. If that substring is less
6903 * than the length of the whole string, then one or more of the
6904 * illegal chars is in filename.
6906 if (strcspn(filename, illegalChars) < strlen(filename))
6912 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6920 cm_scache_t *dscp; /* dir we're dealing with */
6921 cm_scache_t *scp; /* file we're creating */
6923 int initialModeBits;
6931 int created = 0; /* the file was new */
6936 excl = (inp->inCom == 0x03)? 0 : 1;
6938 attributes = smb_GetSMBParm(inp, 0);
6939 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6941 /* compute initial mode bits based on read-only flag in attributes */
6942 initialModeBits = 0666;
6943 if (attributes & 1) initialModeBits &= ~0222;
6945 tp = smb_GetSMBData(inp, NULL);
6946 pathp = smb_ParseASCIIBlock(tp, &tp);
6947 if (smb_StoreAnsiFilenames)
6948 OemToChar(pathp,pathp);
6950 spacep = inp->spacep;
6951 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6953 userp = smb_GetUserFromVCP(vcp, inp);
6955 caseFold = CM_FLAG_CASEFOLD;
6957 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6959 cm_ReleaseUser(userp);
6960 return CM_ERROR_NOSUCHPATH;
6962 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6963 userp, tidPathp, &req, &dscp);
6966 cm_ReleaseUser(userp);
6971 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6972 cm_ReleaseSCache(dscp);
6973 cm_ReleaseUser(userp);
6974 if ( WANTS_DFS_PATHNAMES(inp) )
6975 return CM_ERROR_PATH_NOT_COVERED;
6977 return CM_ERROR_BADSHARENAME;
6979 #endif /* DFS_SUPPORT */
6981 /* otherwise, scp points to the parent directory. Do a lookup, and
6982 * truncate the file if we find it, otherwise we create the file.
6989 if (!smb_IsLegalFilename(lastNamep))
6990 return CM_ERROR_BADNTFILENAME;
6992 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6993 #ifdef DEBUG_VERBOSE
6996 hexp = osi_HexifyString( lastNamep );
6997 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7002 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7003 if (code && code != CM_ERROR_NOSUCHFILE) {
7004 cm_ReleaseSCache(dscp);
7005 cm_ReleaseUser(userp);
7009 /* if we get here, if code is 0, the file exists and is represented by
7010 * scp. Otherwise, we have to create it.
7014 /* oops, file shouldn't be there */
7015 cm_ReleaseSCache(dscp);
7016 cm_ReleaseSCache(scp);
7017 cm_ReleaseUser(userp);
7018 return CM_ERROR_EXISTS;
7021 setAttr.mask = CM_ATTRMASK_LENGTH;
7022 setAttr.length.LowPart = 0;
7023 setAttr.length.HighPart = 0;
7024 code = cm_SetAttr(scp, &setAttr, userp, &req);
7027 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7028 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7029 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7033 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7034 smb_NotifyChange(FILE_ACTION_ADDED,
7035 FILE_NOTIFY_CHANGE_FILE_NAME,
7036 dscp, lastNamep, NULL, TRUE);
7037 } else if (!excl && code == CM_ERROR_EXISTS) {
7038 /* not an exclusive create, and someone else tried
7039 * creating it already, then we open it anyway. We
7040 * don't bother retrying after this, since if this next
7041 * fails, that means that the file was deleted after
7042 * we started this call.
7044 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7047 setAttr.mask = CM_ATTRMASK_LENGTH;
7048 setAttr.length.LowPart = 0;
7049 setAttr.length.HighPart = 0;
7050 code = cm_SetAttr(scp, &setAttr, userp, &req);
7055 /* we don't need this any longer */
7056 cm_ReleaseSCache(dscp);
7059 /* something went wrong creating or truncating the file */
7060 if (scp) cm_ReleaseSCache(scp);
7061 cm_ReleaseUser(userp);
7065 /* make sure we only open files */
7066 if (scp->fileType != CM_SCACHETYPE_FILE) {
7067 cm_ReleaseSCache(scp);
7068 cm_ReleaseUser(userp);
7069 return CM_ERROR_ISDIR;
7072 /* now all we have to do is open the file itself */
7073 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7078 lock_ObtainMutex(&fidp->mx);
7079 /* always create it open for read/write */
7080 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
7082 /* remember that the file was newly created */
7084 fidp->flags |= SMB_FID_CREATED;
7086 /* save a pointer to the vnode */
7089 fidp->userp = userp;
7090 lock_ReleaseMutex(&fidp->mx);
7092 smb_SetSMBParm(outp, 0, fidp->fid);
7093 smb_SetSMBDataLength(outp, 0);
7095 cm_Open(scp, 0, userp);
7097 smb_ReleaseFID(fidp);
7098 cm_ReleaseUser(userp);
7099 /* leave scp held since we put it in fidp->scp */
7103 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7116 fd = smb_GetSMBParm(inp, 0);
7117 whence = smb_GetSMBParm(inp, 1);
7118 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7120 /* try to find the file descriptor */
7121 fd = smb_ChainFID(fd, inp);
7122 fidp = smb_FindFID(vcp, fd, 0);
7125 return CM_ERROR_BADFD;
7127 lock_ObtainMutex(&fidp->mx);
7128 if (fidp->flags & SMB_FID_IOCTL) {
7129 lock_ReleaseMutex(&fidp->mx);
7130 smb_ReleaseFID(fidp);
7131 return CM_ERROR_BADFD;
7133 lock_ReleaseMutex(&fidp->mx);
7135 userp = smb_GetUserFromVCP(vcp, inp);
7137 lock_ObtainMutex(&fidp->mx);
7140 lock_ReleaseMutex(&fidp->mx);
7141 lock_ObtainMutex(&scp->mx);
7142 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7143 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7146 /* offset from current offset */
7147 offset += fidp->offset;
7149 else if (whence == 2) {
7150 /* offset from current EOF */
7151 offset += scp->length.LowPart;
7153 fidp->offset = offset;
7154 smb_SetSMBParm(outp, 0, offset & 0xffff);
7155 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
7156 smb_SetSMBDataLength(outp, 0);
7158 lock_ReleaseMutex(&scp->mx);
7159 smb_ReleaseFID(fidp);
7160 cm_ReleaseSCache(scp);
7161 cm_ReleaseUser(userp);
7165 /* dispatch all of the requests received in a packet. Due to chaining, this may
7166 * be more than one request.
7168 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7169 NCB *ncbp, raw_write_cont_t *rwcp)
7173 unsigned long code = 0;
7174 unsigned char *outWctp;
7175 int nparms; /* # of bytes of parameters */
7177 int nbytes; /* bytes of data, excluding count */
7180 unsigned short errCode;
7181 unsigned long NTStatus;
7183 unsigned char errClass;
7184 unsigned int oldGen;
7185 DWORD oldTime, newTime;
7187 /* get easy pointer to the data */
7188 smbp = (smb_t *) inp->data;
7190 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7191 /* setup the basic parms for the initial request in the packet */
7192 inp->inCom = smbp->com;
7193 inp->wctp = &smbp->wct;
7195 inp->ncb_length = ncbp->ncb_length;
7200 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7201 /* log it and discard it */
7203 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7204 __FILE__, __LINE__, ncbp->ncb_length);
7206 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7210 /* We are an ongoing op */
7211 thrd_Increment(&ongoingOps);
7213 /* set up response packet for receiving output */
7214 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7215 smb_FormatResponsePacket(vcp, inp, outp);
7216 outWctp = outp->wctp;
7218 /* Remember session generation number and time */
7219 oldGen = sessionGen;
7220 oldTime = GetTickCount();
7222 while (inp->inCom != 0xff) {
7223 dp = &smb_dispatchTable[inp->inCom];
7225 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7226 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7227 code = outp->resumeCode;
7231 /* process each request in the packet; inCom, wctp and inCount
7232 * are already set up.
7234 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7237 /* now do the dispatch */
7238 /* start by formatting the response record a little, as a default */
7239 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7241 outWctp[1] = 0xff; /* no operation */
7242 outWctp[2] = 0; /* padding */
7247 /* not a chained request, this is a more reasonable default */
7248 outWctp[0] = 0; /* wct of zero */
7249 outWctp[1] = 0; /* and bcc (word) of zero */
7253 /* once set, stays set. Doesn't matter, since we never chain
7254 * "no response" calls.
7256 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7260 /* we have a recognized operation */
7262 if (inp->inCom == 0x1d)
7264 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7266 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7267 code = (*(dp->procp)) (vcp, inp, outp);
7268 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7270 if ( code == CM_ERROR_BADSMB ||
7271 code == CM_ERROR_BADOP )
7273 #endif /* LOG_PACKET */
7276 if (oldGen != sessionGen) {
7277 newTime = GetTickCount();
7279 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7280 newTime - oldTime, ncbp->ncb_length);
7282 osi_Log2(smb_logp, "Pkt straddled session startup, "
7283 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7287 /* bad opcode, fail the request, after displaying it */
7288 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7291 #endif /* LOG_PACKET */
7295 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7296 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7297 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7298 if (code == IDCANCEL)
7302 code = CM_ERROR_BADOP;
7305 /* catastrophic failure: log as much as possible */
7306 if (code == CM_ERROR_BADSMB) {
7308 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7313 #endif /* LOG_PACKET */
7314 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7317 code = CM_ERROR_INVAL;
7320 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7321 thrd_Decrement(&ongoingOps);
7326 /* now, if we failed, turn the current response into an empty
7327 * one, and fill in the response packet's error code.
7330 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7331 smb_MapNTError(code, &NTStatus);
7332 outWctp = outp->wctp;
7333 smbp = (smb_t *) &outp->data;
7334 if (code != CM_ERROR_PARTIALWRITE
7335 && code != CM_ERROR_BUFFERTOOSMALL
7336 && code != CM_ERROR_GSSCONTINUE) {
7337 /* nuke wct and bcc. For a partial
7338 * write or an in-process authentication handshake,
7339 * assume they're OK.
7345 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7346 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7347 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7348 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7349 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7353 smb_MapCoreError(code, vcp, &errCode, &errClass);
7354 outWctp = outp->wctp;
7355 smbp = (smb_t *) &outp->data;
7356 if (code != CM_ERROR_PARTIALWRITE) {
7357 /* nuke wct and bcc. For a partial
7358 * write, assume they're OK.
7364 smbp->errLow = (unsigned char) (errCode & 0xff);
7365 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7366 smbp->rcls = errClass;
7369 } /* error occurred */
7371 /* if we're here, we've finished one request. Look to see if
7372 * this is a chained opcode. If it is, setup things to process
7373 * the chained request, and setup the output buffer to hold the
7374 * chained response. Start by finding the next input record.
7376 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7377 break; /* not a chained req */
7378 tp = inp->wctp; /* points to start of last request */
7379 /* in a chained request, the first two
7380 * parm fields are required, and are
7381 * AndXCommand/AndXReserved and
7383 if (tp[0] < 2) break;
7384 if (tp[1] == 0xff) break; /* no more chained opcodes */
7386 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7389 /* and now append the next output request to the end of this
7390 * last request. Begin by finding out where the last response
7391 * ends, since that's where we'll put our new response.
7393 outWctp = outp->wctp; /* ptr to out parameters */
7394 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7395 nparms = outWctp[0] << 1;
7396 tp = outWctp + nparms + 1; /* now points to bcc field */
7397 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7398 tp += 2 /* for the count itself */ + nbytes;
7399 /* tp now points to the new output record; go back and patch the
7400 * second parameter (off2) to point to the new record.
7402 temp = (unsigned int)(tp - outp->data);
7403 outWctp[3] = (unsigned char) (temp & 0xff);
7404 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7405 outWctp[2] = 0; /* padding */
7406 outWctp[1] = inp->inCom; /* next opcode */
7408 /* finally, setup for the next iteration */
7411 } /* while loop over all requests in the packet */
7413 /* now send the output packet, and return */
7415 smb_SendPacket(vcp, outp);
7416 thrd_Decrement(&ongoingOps);
7422 /* Wait for Netbios() calls to return, and make the results available to server
7423 * threads. Note that server threads can't wait on the NCBevents array
7424 * themselves, because NCB events are manual-reset, and the servers would race
7425 * each other to reset them.
7427 void smb_ClientWaiter(void *parmp)
7432 while (smbShutdownFlag == 0) {
7433 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7435 if (code == WAIT_OBJECT_0)
7438 /* error checking */
7439 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7441 int abandonIdx = code - WAIT_ABANDONED_0;
7442 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7445 if (code == WAIT_IO_COMPLETION)
7447 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7451 if (code == WAIT_TIMEOUT)
7453 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7456 if (code == WAIT_FAILED)
7458 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7461 idx = code - WAIT_OBJECT_0;
7463 /* check idx range! */
7464 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7466 /* this is fatal - log as much as possible */
7467 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7471 thrd_ResetEvent(NCBevents[idx]);
7472 thrd_SetEvent(NCBreturns[0][idx]);
7478 * Try to have one NCBRECV request waiting for every live session. Not more
7479 * than one, because if there is more than one, it's hard to handle Write Raw.
7481 void smb_ServerWaiter(void *parmp)
7484 int idx_session, idx_NCB;
7490 while (smbShutdownFlag == 0) {
7492 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7494 if (code == WAIT_OBJECT_0)
7497 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7499 int abandonIdx = code - WAIT_ABANDONED_0;
7500 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7503 if (code == WAIT_IO_COMPLETION)
7505 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7509 if (code == WAIT_TIMEOUT)
7511 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7514 if (code == WAIT_FAILED)
7516 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7519 idx_session = code - WAIT_OBJECT_0;
7521 /* check idx range! */
7522 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7524 /* this is fatal - log as much as possible */
7525 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7531 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7533 if (code == WAIT_OBJECT_0) {
7534 if (smbShutdownFlag == 1)
7540 /* error checking */
7541 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7543 int abandonIdx = code - WAIT_ABANDONED_0;
7544 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7547 if (code == WAIT_IO_COMPLETION)
7549 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7553 if (code == WAIT_TIMEOUT)
7555 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7558 if (code == WAIT_FAILED)
7560 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7563 idx_NCB = code - WAIT_OBJECT_0;
7565 /* check idx range! */
7566 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7568 /* this is fatal - log as much as possible */
7569 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7573 /* Link them together */
7574 NCBsessions[idx_NCB] = idx_session;
7577 ncbp = NCBs[idx_NCB];
7578 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7579 ncbp->ncb_command = NCBRECV | ASYNCH;
7580 ncbp->ncb_lana_num = lanas[idx_session];
7582 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7583 ncbp->ncb_event = NCBevents[idx_NCB];
7584 ncbp->ncb_length = SMB_PACKETSIZE;
7587 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7588 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7589 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7590 ncbp->ncb_length = SMB_PACKETSIZE;
7591 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7592 Netbios(ncbp, dos_ncb);
7598 * The top level loop for handling SMB request messages. Each server thread
7599 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7600 * NCB and buffer for the incoming request are loaned to us.
7602 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7603 * to immediately send a request for the rest of the data. This must come
7604 * before any other traffic for that session, so we delay setting the session
7605 * event until that data has come in.
7607 void smb_Server(VOID *parmp)
7609 INT_PTR myIdx = (INT_PTR) parmp;
7613 smb_packet_t *outbufp;
7615 int idx_NCB, idx_session;
7617 smb_vc_t *vcp = NULL;
7623 rx_StartClientThread();
7626 outbufp = GetPacket();
7627 outbufp->ncbp = outncbp;
7635 smb_ResetServerPriority();
7637 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7640 /* terminate silently if shutdown flag is set */
7641 if (code == WAIT_OBJECT_0) {
7642 if (smbShutdownFlag == 1) {
7643 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7649 /* error checking */
7650 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7652 int abandonIdx = code - WAIT_ABANDONED_0;
7653 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7656 if (code == WAIT_IO_COMPLETION)
7658 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7662 if (code == WAIT_TIMEOUT)
7664 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7667 if (code == WAIT_FAILED)
7669 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7672 idx_NCB = code - WAIT_OBJECT_0;
7674 /* check idx range! */
7675 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7677 /* this is fatal - log as much as possible */
7678 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7682 ncbp = NCBs[idx_NCB];
7684 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7686 idx_session = NCBsessions[idx_NCB];
7687 rc = ncbp->ncb_retcode;
7689 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7690 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7694 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7698 /* Can this happen? Or is it just my UNIX paranoia? */
7699 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7705 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7709 /* Client closed session */
7710 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7712 lock_ObtainMutex(&vcp->mx);
7713 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7714 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7716 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7717 lock_ReleaseMutex(&vcp->mx);
7718 lock_ObtainWrite(&smb_globalLock);
7719 dead_sessions[vcp->session] = TRUE;
7720 lock_ReleaseWrite(&smb_globalLock);
7721 smb_CleanupDeadVC(vcp);
7725 lock_ReleaseMutex(&vcp->mx);
7731 /* Treat as transient error */
7733 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7737 "dispatch smb recv failed, message incomplete, ncb_length %d",
7740 "SMB message incomplete, "
7741 "length %d", ncbp->ncb_length);
7744 * We used to discard the packet.
7745 * Instead, try handling it normally.
7749 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7753 /* A weird error code. Log it, sleep, and continue. */
7754 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7756 lock_ObtainMutex(&vcp->mx);
7757 if (vcp && vcp->errorCount++ > 3) {
7758 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7759 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7760 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7762 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7763 lock_ReleaseMutex(&vcp->mx);
7764 lock_ObtainWrite(&smb_globalLock);
7765 dead_sessions[vcp->session] = TRUE;
7766 lock_ReleaseWrite(&smb_globalLock);
7767 smb_CleanupDeadVC(vcp);
7771 lock_ReleaseMutex(&vcp->mx);
7777 lock_ReleaseMutex(&vcp->mx);
7779 thrd_SetEvent(SessionEvents[idx_session]);
7784 /* Success, so now dispatch on all the data in the packet */
7786 smb_concurrentCalls++;
7787 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7788 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7791 * If at this point vcp is NULL (implies that packet was invalid)
7792 * then we are in big trouble. This means either :
7793 * a) we have the wrong NCB.
7794 * b) Netbios screwed up the call.
7795 * c) The VC was already marked dead before we were able to
7797 * Obviously this implies that
7798 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7799 * lanas[idx_session] != ncbp->ncb_lana_num )
7800 * Either way, we can't do anything with this packet.
7801 * Log, sleep and resume.
7804 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7808 ncbp->ncb_lana_num);
7810 /* Also log in the trace log. */
7811 osi_Log4(smb_logp, "Server: VCP does not exist!"
7812 "LSNs[idx_session]=[%d],"
7813 "lanas[idx_session]=[%d],"
7814 "ncbp->ncb_lsn=[%d],"
7815 "ncbp->ncb_lana_num=[%d]",
7819 ncbp->ncb_lana_num);
7821 /* thrd_Sleep(1000); Don't bother sleeping */
7822 thrd_SetEvent(SessionEvents[idx_session]);
7823 smb_concurrentCalls--;
7827 smb_SetRequestStartTime();
7829 vcp->errorCount = 0;
7830 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7832 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7833 /* copy whole packet to virtual memory */
7834 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7836 bufp->dos_pkt / 16, bufp);*/
7838 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7840 smbp = (smb_t *)bufp->data;
7843 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7847 if (smbp->com == 0x1d) {
7848 /* Special handling for Write Raw */
7849 raw_write_cont_t rwc;
7850 EVENT_HANDLE rwevent;
7851 char eventName[MAX_PATH];
7853 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7854 if (rwc.code == 0) {
7855 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7856 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7857 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7858 ncbp->ncb_command = NCBRECV | ASYNCH;
7859 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7860 ncbp->ncb_lana_num = vcp->lana;
7861 ncbp->ncb_buffer = rwc.buf;
7862 ncbp->ncb_length = 65535;
7863 ncbp->ncb_event = rwevent;
7867 Netbios(ncbp, dos_ncb);
7869 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7870 thrd_CloseHandle(rwevent);
7872 thrd_SetEvent(SessionEvents[idx_session]);
7874 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7876 else if (smbp->com == 0xa0) {
7878 * Serialize the handling for NT Transact
7881 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7882 thrd_SetEvent(SessionEvents[idx_session]);
7884 thrd_SetEvent(SessionEvents[idx_session]);
7885 /* TODO: what else needs to be serialized? */
7886 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7888 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7890 __except( smb_ServerExceptionFilter() ) {
7894 smb_concurrentCalls--;
7897 thrd_SetEvent(NCBavails[idx_NCB]);
7904 * Exception filter for the server threads. If an exception occurs in the
7905 * dispatch routines, which is where exceptions are most common, then do a
7906 * force trace and give control to upstream exception handlers. Useful for
7909 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7910 DWORD smb_ServerExceptionFilter(void) {
7911 /* While this is not the best time to do a trace, if it succeeds, then
7912 * we have a trace (assuming tracing was enabled). Otherwise, this should
7913 * throw a second exception.
7915 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7916 afsd_ForceTrace(TRUE);
7917 buf_ForceTrace(TRUE);
7918 return EXCEPTION_CONTINUE_SEARCH;
7923 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7924 * If the number of server threads is M, and the number of live sessions is
7925 * N, then the number of NCB's in use at any time either waiting for, or
7926 * holding, received messages is M + N, so that is how many NCB's get created.
7928 void InitNCBslot(int idx)
7930 struct smb_packet *bufp;
7931 EVENT_HANDLE retHandle;
7933 char eventName[MAX_PATH];
7935 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7937 NCBs[idx] = GetNCB();
7938 sprintf(eventName,"NCBavails[%d]", idx);
7939 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7940 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7941 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7943 sprintf(eventName,"NCBevents[%d]", idx);
7944 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7945 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7946 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7948 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7949 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7950 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7951 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7952 for (i=0; i<smb_NumServerThreads; i++)
7953 NCBreturns[i][idx] = retHandle;
7955 bufp->spacep = cm_GetSpace();
7959 /* listen for new connections */
7960 void smb_Listener(void *parmp)
7966 int session, thread;
7967 smb_vc_t *vcp = NULL;
7969 char rname[NCBNAMSZ+1];
7970 char cname[MAX_COMPUTERNAME_LENGTH+1];
7971 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7976 INT_PTR lana = (INT_PTR) parmp;
7980 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7983 /* retrieve computer name */
7984 GetComputerName(cname, &cnamelen);
7988 memset(ncbp, 0, sizeof(NCB));
7991 ncbp->ncb_command = NCBLISTEN;
7992 ncbp->ncb_rto = 0; /* No receive timeout */
7993 ncbp->ncb_sto = 0; /* No send timeout */
7995 /* pad out with spaces instead of null termination */
7996 len = (long)strlen(smb_localNamep);
7997 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7998 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8000 strcpy(ncbp->ncb_callname, "*");
8001 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8003 ncbp->ncb_lana_num = (UCHAR)lana;
8006 code = Netbios(ncbp);
8008 code = Netbios(ncbp, dos_ncb);
8017 /* terminate silently if shutdown flag is set */
8018 if (smbShutdownFlag == 1) {
8027 "NCBLISTEN lana=%d failed with code %d",
8028 ncbp->ncb_lana_num, code);
8030 "Client exiting due to network failure. Please restart client.\n");
8034 "Client exiting due to network failure. Please restart client.\n"
8035 "NCBLISTEN lana=%d failed with code %d",
8036 ncbp->ncb_lana_num, code);
8038 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8039 MB_OK|MB_SERVICE_NOTIFICATION);
8040 osi_assert(tbuffer);
8043 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
8044 ncbp->ncb_lana_num, code);
8045 fprintf(stderr, "\nClient exiting due to network failure "
8046 "(possibly due to power-saving mode)\n");
8047 fprintf(stderr, "Please restart client.\n");
8048 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
8052 /* check for remote conns */
8053 /* first get remote name and insert null terminator */
8054 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8055 for (i=NCBNAMSZ; i>0; i--) {
8056 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8062 /* compare with local name */
8064 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8065 flags |= SMB_VCFLAG_REMOTECONN;
8068 lock_ObtainMutex(&smb_ListenerLock);
8070 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8071 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8073 /* now ncbp->ncb_lsn is the connection ID */
8074 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8075 if (vcp->session == 0) {
8076 /* New generation */
8077 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8080 /* Log session startup */
8082 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8083 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8084 #endif /* NOTSERVICE */
8085 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8086 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8088 if (reportSessionStartups) {
8090 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8093 fprintf(stderr, "%s: New session %d starting from host %s\n",
8094 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8099 lock_ObtainMutex(&vcp->mx);
8100 strcpy(vcp->rname, rname);
8101 vcp->flags |= flags;
8102 lock_ReleaseMutex(&vcp->mx);
8104 /* Allocate slot in session arrays */
8105 /* Re-use dead session if possible, otherwise add one more */
8106 /* But don't look at session[0], it is reserved */
8107 lock_ObtainWrite(&smb_globalLock);
8108 for (session = 1; session < numSessions; session++) {
8109 if (dead_sessions[session]) {
8110 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8111 dead_sessions[session] = FALSE;
8115 lock_ReleaseWrite(&smb_globalLock);
8117 /* We are re-using an existing VC because the lsn and lana
8119 session = vcp->session;
8121 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8123 /* Log session startup */
8125 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8126 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8127 #endif /* NOTSERVICE */
8128 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8129 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8131 if (reportSessionStartups) {
8133 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8136 fprintf(stderr, "%s: Re-using session %d starting from host %s\n",
8137 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8143 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8144 unsigned long code = CM_ERROR_ALLBUSY;
8145 smb_packet_t * outp = GetPacket();
8146 unsigned char *outWctp;
8149 smb_FormatResponsePacket(vcp, NULL, outp);
8152 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8153 unsigned long NTStatus;
8154 smb_MapNTError(code, &NTStatus);
8155 outWctp = outp->wctp;
8156 smbp = (smb_t *) &outp->data;
8160 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8161 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8162 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8163 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8164 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8166 unsigned short errCode;
8167 unsigned char errClass;
8168 smb_MapCoreError(code, vcp, &errCode, &errClass);
8169 outWctp = outp->wctp;
8170 smbp = (smb_t *) &outp->data;
8174 smbp->errLow = (unsigned char) (errCode & 0xff);
8175 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8176 smbp->rcls = errClass;
8178 smb_SendPacket(vcp, outp);
8179 smb_FreePacket(outp);
8181 lock_ObtainMutex(&vcp->mx);
8182 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8183 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8185 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8186 lock_ReleaseMutex(&vcp->mx);
8187 lock_ObtainWrite(&smb_globalLock);
8188 dead_sessions[vcp->session] = TRUE;
8189 lock_ReleaseWrite(&smb_globalLock);
8190 smb_CleanupDeadVC(vcp);
8192 lock_ReleaseMutex(&vcp->mx);
8195 /* assert that we do not exceed the maximum number of sessions or NCBs.
8196 * we should probably want to wait for a session to be freed in case
8199 osi_assert(session < SESSION_MAX - 1);
8200 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8202 lock_ObtainMutex(&vcp->mx);
8203 vcp->session = session;
8204 lock_ReleaseMutex(&vcp->mx);
8205 lock_ObtainWrite(&smb_globalLock);
8206 LSNs[session] = ncbp->ncb_lsn;
8207 lanas[session] = ncbp->ncb_lana_num;
8208 lock_ReleaseWrite(&smb_globalLock);
8210 if (session == numSessions) {
8211 /* Add new NCB for new session */
8212 char eventName[MAX_PATH];
8214 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8216 InitNCBslot(numNCBs);
8217 lock_ObtainWrite(&smb_globalLock);
8219 lock_ReleaseWrite(&smb_globalLock);
8220 thrd_SetEvent(NCBavails[0]);
8221 thrd_SetEvent(NCBevents[0]);
8222 for (thread = 0; thread < smb_NumServerThreads; thread++)
8223 thrd_SetEvent(NCBreturns[thread][0]);
8224 /* Also add new session event */
8225 sprintf(eventName, "SessionEvents[%d]", session);
8226 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8227 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8228 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8229 lock_ObtainWrite(&smb_globalLock);
8231 lock_ReleaseWrite(&smb_globalLock);
8232 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8233 thrd_SetEvent(SessionEvents[0]);
8235 thrd_SetEvent(SessionEvents[session]);
8241 lock_ReleaseMutex(&smb_ListenerLock);
8242 } /* dispatch while loop */
8245 /* initialize Netbios */
8246 void smb_NetbiosInit()
8252 int i, lana, code, l;
8254 int delname_tried=0;
8257 OSVERSIONINFO Version;
8259 /* Get the version of Windows */
8260 memset(&Version, 0x00, sizeof(Version));
8261 Version.dwOSVersionInfoSize = sizeof(Version);
8262 GetVersionEx(&Version);
8264 /* setup the NCB system */
8267 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8271 if (smb_LANadapter == -1) {
8272 ncbp->ncb_command = NCBENUM;
8273 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8274 ncbp->ncb_length = sizeof(lana_list);
8275 code = Netbios(ncbp);
8277 afsi_log("Netbios NCBENUM error code %d", code);
8278 osi_panic(s, __FILE__, __LINE__);
8282 lana_list.length = 1;
8283 lana_list.lana[0] = smb_LANadapter;
8286 for (i = 0; i < lana_list.length; i++) {
8287 /* reset the adaptor: in Win32, this is required for every process, and
8288 * acts as an init call, not as a real hardware reset.
8290 ncbp->ncb_command = NCBRESET;
8291 ncbp->ncb_callname[0] = 100;
8292 ncbp->ncb_callname[2] = 100;
8293 ncbp->ncb_lana_num = lana_list.lana[i];
8294 code = Netbios(ncbp);
8296 code = ncbp->ncb_retcode;
8298 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8299 lana_list.lana[i] = 255; /* invalid lana */
8301 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8305 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
8306 we will just fake the LANA list */
8307 if (smb_LANadapter == -1) {
8308 for (i = 0; i < 8; i++)
8309 lana_list.lana[i] = i;
8310 lana_list.length = 8;
8313 lana_list.length = 1;
8314 lana_list.lana[0] = smb_LANadapter;
8318 /* and declare our name so we can receive connections */
8319 memset(ncbp, 0, sizeof(*ncbp));
8320 len=lstrlen(smb_localNamep);
8321 memset(smb_sharename,' ',NCBNAMSZ);
8322 memcpy(smb_sharename,smb_localNamep,len);
8323 afsi_log("lana_list.length %d", lana_list.length);
8325 /* Keep the name so we can unregister it later */
8326 for (l = 0; l < lana_list.length; l++) {
8327 lana = lana_list.lana[l];
8329 ncbp->ncb_command = NCBADDNAME;
8330 ncbp->ncb_lana_num = lana;
8331 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8333 code = Netbios(ncbp);
8335 code = Netbios(ncbp, dos_ncb);
8338 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8339 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8341 char name[NCBNAMSZ+1];
8343 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8344 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8347 if (code == 0) code = ncbp->ncb_retcode;
8349 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8351 /* we only use one LANA with djgpp */
8352 lana_list.lana[0] = lana;
8353 lana_list.length = 1;
8357 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8358 if (code == NRC_BRIDGE) { /* invalid LANA num */
8359 lana_list.lana[l] = 255;
8362 else if (code == NRC_DUPNAME) {
8363 afsi_log("Name already exists; try to delete it");
8364 memset(ncbp, 0, sizeof(*ncbp));
8365 ncbp->ncb_command = NCBDELNAME;
8366 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8367 ncbp->ncb_lana_num = lana;
8369 code = Netbios(ncbp);
8371 code = Netbios(ncbp, dos_ncb);
8374 code = ncbp->ncb_retcode;
8376 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8378 if (code != 0 || delname_tried) {
8379 lana_list.lana[l] = 255;
8381 else if (code == 0) {
8382 if (!delname_tried) {
8390 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8391 lana_list.lana[l] = 255; /* invalid lana */
8392 osi_panic(s, __FILE__, __LINE__);
8396 lana_found = 1; /* at least one worked */
8403 osi_assert(lana_list.length >= 0);
8405 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8408 /* we're done with the NCB now */
8412 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8429 EVENT_HANDLE retHandle;
8430 char eventName[MAX_PATH];
8432 smb_TlsRequestSlot = TlsAlloc();
8435 smb_MBfunc = aMBfunc;
8439 smb_LANadapter = LANadapt;
8441 /* Initialize smb_localZero */
8442 myTime.tm_isdst = -1; /* compute whether on DST or not */
8443 myTime.tm_year = 70;
8449 smb_localZero = mktime(&myTime);
8451 #ifndef USE_NUMERIC_TIME_CONV
8452 /* Initialize kludge-GMT */
8453 smb_CalculateNowTZ();
8454 #endif /* USE_NUMERIC_TIME_CONV */
8455 #ifdef AFS_FREELANCE_CLIENT
8456 /* Make sure the root.afs volume has the correct time */
8457 cm_noteLocalMountPointChange();
8460 /* initialize the remote debugging log */
8463 /* remember the name */
8464 len = (int)strlen(snamep);
8465 smb_localNamep = malloc(len+1);
8466 strcpy(smb_localNamep, snamep);
8467 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8469 /* and the global lock */
8470 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8471 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8473 /* Raw I/O data structures */
8474 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8476 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8478 /* 4 Raw I/O buffers */
8480 smb_RawBufs = calloc(65536,1);
8481 *((char **)smb_RawBufs) = NULL;
8482 for (i=0; i<3; i++) {
8483 char *rawBuf = calloc(65536,1);
8484 *((char **)rawBuf) = smb_RawBufs;
8485 smb_RawBufs = rawBuf;
8488 npar = 65536 >> 4; /* number of paragraphs */
8489 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8491 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8493 osi_panic("",__FILE__,__LINE__);
8496 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8499 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8501 _farpokel(_dos_ds, smb_RawBufs, NULL);
8502 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8503 npar = 65536 >> 4; /* number of paragraphs */
8504 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8506 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8508 osi_panic("",__FILE__,__LINE__);
8511 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8514 rawBuf = (seg * 16) + 0; /* DOS physical address */
8515 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8516 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8517 smb_RawBufs = rawBuf;
8521 /* global free lists */
8522 smb_ncbFreeListp = NULL;
8523 smb_packetFreeListp = NULL;
8527 /* Initialize listener and server structures */
8529 memset(dead_sessions, 0, sizeof(dead_sessions));
8530 sprintf(eventName, "SessionEvents[0]");
8531 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8532 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8533 afsi_log("Event Object Already Exists: %s", eventName);
8535 smb_NumServerThreads = nThreads;
8536 sprintf(eventName, "NCBavails[0]");
8537 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8538 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8539 afsi_log("Event Object Already Exists: %s", eventName);
8540 sprintf(eventName, "NCBevents[0]");
8541 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8542 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8543 afsi_log("Event Object Already Exists: %s", eventName);
8544 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8545 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8546 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8547 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8548 afsi_log("Event Object Already Exists: %s", eventName);
8549 for (i = 0; i < smb_NumServerThreads; i++) {
8550 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8551 NCBreturns[i][0] = retHandle;
8554 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8555 for (i = 0; i < smb_NumServerThreads; i++) {
8556 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8557 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8558 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8559 afsi_log("Event Object Already Exists: %s", eventName);
8560 InitNCBslot((int)(i+1));
8562 numNCBs = smb_NumServerThreads + 1;
8564 /* Initialize dispatch table */
8565 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8566 /* Prepare the table for unknown operations */
8567 for(i=0; i<= SMB_NOPCODES; i++) {
8568 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8570 /* Fill in the ones we do know */
8571 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8572 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8573 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8574 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8575 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8576 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8577 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8578 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8579 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8580 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8581 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8582 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8583 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8584 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8585 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8586 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8587 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8588 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8589 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8590 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8591 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8592 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8593 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8594 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8595 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8596 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8597 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8598 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8599 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8600 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8601 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8602 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8603 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8604 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8605 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8606 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8607 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8608 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8609 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8610 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8611 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8612 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8613 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8614 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8615 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8616 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8617 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8618 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8619 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8620 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8621 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8622 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8623 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8624 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8625 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8626 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8627 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8628 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8629 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8630 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8631 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8632 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8633 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8634 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8635 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8636 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8637 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8638 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8639 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8640 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8641 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8642 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8644 /* setup tran 2 dispatch table */
8645 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8646 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8647 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8648 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8649 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8650 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8651 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8652 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8653 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8654 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8655 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8656 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8657 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8658 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8659 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8660 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8661 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8663 /* setup the rap dispatch table */
8664 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8665 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8666 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8667 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8668 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8672 /* if we are doing SMB authentication we have register outselves as a logon process */
8673 if (smb_authType != SMB_AUTH_NONE) {
8674 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8675 LSA_STRING afsProcessName;
8676 LSA_OPERATIONAL_MODE dummy; /*junk*/
8678 afsProcessName.Buffer = "OpenAFSClientDaemon";
8679 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8680 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8682 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8684 if (nts == STATUS_SUCCESS) {
8685 LSA_STRING packageName;
8686 /* we are registered. Find out the security package id */
8687 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8688 packageName.Length = (USHORT)strlen(packageName.Buffer);
8689 packageName.MaximumLength = packageName.Length + 1;
8690 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8691 if (nts == STATUS_SUCCESS) {
8693 * This code forces Windows to authenticate against the Logon Cache
8694 * first instead of attempting to authenticate against the Domain
8695 * Controller. When the Windows logon cache is enabled this improves
8696 * performance by removing the network access and works around a bug
8697 * seen at sites which are using a MIT Kerberos principal to login
8698 * to machines joined to a non-root domain in a multi-domain forest.
8700 PVOID pResponse = NULL;
8701 ULONG cbResponse = 0;
8702 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8704 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8705 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8706 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8707 OptionsRequest.DisableOptions = FALSE;
8709 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8712 sizeof(OptionsRequest),
8718 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8720 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8722 OutputDebugString(message);
8725 OutputDebugString("MsV1_0SetProcessOption success");
8726 afsi_log("MsV1_0SetProcessOption success");
8728 /* END - code from Larry */
8730 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8731 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8732 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8734 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8736 /* something went wrong. We report the error and revert back to no authentication
8737 because we can't perform any auth requests without a successful lsa handle
8738 or sec package id. */
8739 afsi_log("Reverting to NO SMB AUTH");
8740 smb_authType = SMB_AUTH_NONE;
8743 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8745 /* something went wrong. We report the error and revert back to no authentication
8746 because we can't perform any auth requests without a successful lsa handle
8747 or sec package id. */
8748 afsi_log("Reverting to NO SMB AUTH");
8749 smb_authType = SMB_AUTH_NONE;
8753 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8754 * time prevents the failure of authentication when logged into Windows with an
8755 * external Kerberos principal mapped to a local account.
8757 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8758 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8759 * then the only option is NTLMSSP anyway; so just fallback.
8764 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8765 if (secBlobLength == 0) {
8766 smb_authType = SMB_AUTH_NTLM;
8767 afsi_log("Reverting to SMB AUTH NTLM");
8776 /* Now get ourselves a domain name. */
8777 /* For now we are using the local computer name as the domain name.
8778 * It is actually the domain for local logins, and we are acting as
8779 * a local SMB server.
8781 bufsize = sizeof(smb_ServerDomainName) - 1;
8782 GetComputerName(smb_ServerDomainName, &bufsize);
8783 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8784 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8787 /* Start listeners, waiters, servers, and daemons */
8789 for (i = 0; i < lana_list.length; i++) {
8790 if (lana_list.lana[i] == 255)
8792 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8793 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8794 osi_assert(phandle != NULL);
8795 thrd_CloseHandle(phandle);
8799 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8800 NULL, 0, &lpid, "smb_ClientWaiter");
8801 osi_assert(phandle != NULL);
8802 thrd_CloseHandle(phandle);
8805 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8806 NULL, 0, &lpid, "smb_ServerWaiter");
8807 osi_assert(phandle != NULL);
8808 thrd_CloseHandle(phandle);
8810 for (i=0; i<smb_NumServerThreads; i++) {
8811 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8812 (void *) i, 0, &lpid, "smb_Server");
8813 osi_assert(phandle != NULL);
8814 thrd_CloseHandle(phandle);
8817 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8818 NULL, 0, &lpid, "smb_Daemon");
8819 osi_assert(phandle != NULL);
8820 thrd_CloseHandle(phandle);
8822 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8823 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8824 osi_assert(phandle != NULL);
8825 thrd_CloseHandle(phandle);
8834 void smb_Shutdown(void)
8844 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8846 /* setup the NCB system */
8849 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8852 /* Block new sessions by setting shutdown flag */
8853 smbShutdownFlag = 1;
8855 /* Hang up all sessions */
8856 memset((char *)ncbp, 0, sizeof(NCB));
8857 for (i = 1; i < numSessions; i++)
8859 if (dead_sessions[i])
8862 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8863 ncbp->ncb_command = NCBHANGUP;
8864 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8865 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8867 code = Netbios(ncbp);
8869 code = Netbios(ncbp, dos_ncb);
8871 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8872 if (code == 0) code = ncbp->ncb_retcode;
8874 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8875 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8879 /* Trigger the shutdown of all SMB threads */
8880 for (i = 0; i < smb_NumServerThreads; i++)
8881 thrd_SetEvent(NCBreturns[i][0]);
8883 thrd_SetEvent(NCBevents[0]);
8884 thrd_SetEvent(SessionEvents[0]);
8885 thrd_SetEvent(NCBavails[0]);
8887 for (i = 0;i < smb_NumServerThreads; i++) {
8888 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8889 if (code == WAIT_OBJECT_0) {
8892 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8893 thrd_SetEvent(NCBreturns[i--][0]);
8897 /* Delete Netbios name */
8898 memset((char *)ncbp, 0, sizeof(NCB));
8899 for (i = 0; i < lana_list.length; i++) {
8900 if (lana_list.lana[i] == 255) continue;
8901 ncbp->ncb_command = NCBDELNAME;
8902 ncbp->ncb_lana_num = lana_list.lana[i];
8903 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8905 code = Netbios(ncbp);
8907 code = Netbios(ncbp, dos_ncb);
8910 code = ncbp->ncb_retcode;
8912 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8913 ncbp->ncb_lana_num, code);
8918 /* Release the reference counts held by the VCs */
8919 lock_ObtainWrite(&smb_rctLock);
8920 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8925 if (vcp->magic != SMB_VC_MAGIC)
8926 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8927 __FILE__, __LINE__);
8929 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8931 if (fidp->scp != NULL) {
8934 lock_ObtainMutex(&fidp->mx);
8935 if (fidp->scp != NULL) {
8938 cm_ReleaseSCache(scp);
8940 lock_ReleaseMutex(&fidp->mx);
8944 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8946 smb_ReleaseVCNoLock(tidp->vcp);
8948 cm_user_t *userp = tidp->userp;
8950 lock_ReleaseWrite(&smb_rctLock);
8951 cm_ReleaseUser(userp);
8952 lock_ObtainWrite(&smb_rctLock);
8956 lock_ReleaseWrite(&smb_rctLock);
8958 TlsFree(smb_TlsRequestSlot);
8961 /* Get the UNC \\<servername>\<sharename> prefix. */
8962 char *smb_GetSharename()
8966 /* Make sure we have been properly initialized. */
8967 if (smb_localNamep == NULL)
8970 /* Allocate space for \\<servername>\<sharename>, plus the
8973 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8974 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8980 void smb_LogPacket(smb_packet_t *packet)
8983 unsigned length, paramlen, datalen, i, j;
8985 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8987 if (!packet) return;
8989 osi_Log0(smb_logp, "*** SMB packet dump ***");
8991 vp = (BYTE *) packet->data;
8993 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8994 length = paramlen + 2 + datalen;
8997 for (i=0;i < length; i+=16)
8999 memset( buf, ' ', 80 );
9004 buf[strlen(buf)] = ' ';
9006 cp = (BYTE*) buf + 7;
9008 for (j=0;j < 16 && (i+j)<length; j++)
9010 *(cp++) = hex[vp[i+j] >> 4];
9011 *(cp++) = hex[vp[i+j] & 0xf];
9021 for (j=0;j < 16 && (i+j)<length;j++)
9023 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9034 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9037 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9039 #endif /* LOG_PACKET */
9042 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9050 lock_ObtainRead(&smb_rctLock);
9052 sprintf(output, "begin dumping smb_vc_t\n");
9053 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9055 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9059 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9060 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9061 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9063 sprintf(output, "begin dumping smb_fid_t\n");
9064 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9066 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9068 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
9069 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9070 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9071 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9072 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9075 sprintf(output, "done dumping smb_fid_t\n");
9076 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9079 sprintf(output, "done dumping smb_vc_t\n");
9080 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9082 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9083 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9085 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9089 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9090 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9091 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9093 sprintf(output, "begin dumping smb_fid_t\n");
9094 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9096 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9098 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
9099 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9100 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9101 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9102 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9105 sprintf(output, "done dumping smb_fid_t\n");
9106 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9109 sprintf(output, "done dumping DEAD smb_vc_t\n");
9110 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9112 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9113 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9115 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9119 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9120 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9121 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9123 sprintf(output, "begin dumping smb_fid_t\n");
9124 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9126 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9128 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
9129 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9130 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9131 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9132 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9135 sprintf(output, "done dumping smb_fid_t\n");
9136 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9139 sprintf(output, "done dumping DEAD smb_vc_t\n");
9140 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9143 lock_ReleaseRead(&smb_rctLock);