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 attrs = SMB_ATTR_DIRECTORY;
4780 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4781 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4783 attrs = smb_Attributes(newScp);
4786 smb_SetSMBParm(outp, 0, attrs);
4788 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4789 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4790 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4791 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4792 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4793 smb_SetSMBParm(outp, 5, 0);
4794 smb_SetSMBParm(outp, 6, 0);
4795 smb_SetSMBParm(outp, 7, 0);
4796 smb_SetSMBParm(outp, 8, 0);
4797 smb_SetSMBParm(outp, 9, 0);
4798 smb_SetSMBDataLength(outp, 0);
4799 lock_ReleaseMutex(&newScp->mx);
4801 cm_ReleaseSCache(newScp);
4802 cm_ReleaseUser(userp);
4807 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4811 osi_Log0(smb_logp, "SMB receive tree disconnect");
4813 /* find the tree and free it */
4814 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4816 lock_ObtainWrite(&smb_rctLock);
4818 lock_ReleaseWrite(&smb_rctLock);
4819 smb_ReleaseTID(tidp);
4825 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4843 pathp = smb_GetSMBData(inp, NULL);
4844 pathp = smb_ParseASCIIBlock(pathp, NULL);
4845 if (smb_StoreAnsiFilenames)
4846 OemToChar(pathp,pathp);
4848 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4850 #ifdef DEBUG_VERBOSE
4854 hexpath = osi_HexifyString( pathp );
4855 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4860 share = smb_GetSMBParm(inp, 0);
4861 attribute = smb_GetSMBParm(inp, 1);
4863 spacep = inp->spacep;
4864 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4865 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4866 /* special case magic file name for receiving IOCTL requests
4867 * (since IOCTL calls themselves aren't getting through).
4869 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4870 smb_SetupIoctlFid(fidp, spacep);
4871 smb_SetSMBParm(outp, 0, fidp->fid);
4872 smb_SetSMBParm(outp, 1, 0); /* attrs */
4873 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4874 smb_SetSMBParm(outp, 3, 0);
4875 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4876 smb_SetSMBParm(outp, 5, 0x7fff);
4877 /* pass the open mode back */
4878 smb_SetSMBParm(outp, 6, (share & 0xf));
4879 smb_SetSMBDataLength(outp, 0);
4880 smb_ReleaseFID(fidp);
4884 userp = smb_GetUserFromVCP(vcp, inp);
4886 caseFold = CM_FLAG_CASEFOLD;
4888 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4890 cm_ReleaseUser(userp);
4891 return CM_ERROR_NOSUCHPATH;
4893 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4894 tidPathp, &req, &scp);
4897 cm_ReleaseUser(userp);
4902 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4903 cm_ReleaseSCache(scp);
4904 cm_ReleaseUser(userp);
4905 if ( WANTS_DFS_PATHNAMES(inp) )
4906 return CM_ERROR_PATH_NOT_COVERED;
4908 return CM_ERROR_BADSHARENAME;
4910 #endif /* DFS_SUPPORT */
4912 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4914 cm_ReleaseSCache(scp);
4915 cm_ReleaseUser(userp);
4919 /* don't need callback to check file type, since file types never
4920 * change, and namei and cm_Lookup all stat the object at least once on
4921 * a successful return.
4923 if (scp->fileType != CM_SCACHETYPE_FILE) {
4924 cm_ReleaseSCache(scp);
4925 cm_ReleaseUser(userp);
4926 return CM_ERROR_ISDIR;
4929 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4932 /* save a pointer to the vnode */
4936 fidp->userp = userp;
4938 lock_ObtainMutex(&fidp->mx);
4939 if ((share & 0xf) == 0)
4940 fidp->flags |= SMB_FID_OPENREAD;
4941 else if ((share & 0xf) == 1)
4942 fidp->flags |= SMB_FID_OPENWRITE;
4944 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4945 lock_ReleaseMutex(&fidp->mx);
4947 lock_ObtainMutex(&scp->mx);
4948 smb_SetSMBParm(outp, 0, fidp->fid);
4949 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4950 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4951 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4952 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4953 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4954 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4955 /* pass the open mode back; XXXX add access checks */
4956 smb_SetSMBParm(outp, 6, (share & 0xf));
4957 smb_SetSMBDataLength(outp, 0);
4958 lock_ReleaseMutex(&scp->mx);
4961 cm_Open(scp, 0, userp);
4963 /* send and free packet */
4964 smb_ReleaseFID(fidp);
4965 cm_ReleaseUser(userp);
4966 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4970 typedef struct smb_unlinkRock {
4975 char *maskp; /* pointer to the star pattern */
4980 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4983 smb_unlinkRock_t *rockp;
4991 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4992 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4993 caseFold |= CM_FLAG_8DOT3;
4995 matchName = dep->name;
4996 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4998 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4999 !cm_Is8Dot3(dep->name)) {
5000 cm_Gen8Dot3Name(dep, shortName, NULL);
5001 matchName = shortName;
5002 /* 8.3 matches are always case insensitive */
5003 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5006 osi_Log1(smb_logp, "Unlinking %s",
5007 osi_LogSaveString(smb_logp, matchName));
5008 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
5009 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5010 smb_NotifyChange(FILE_ACTION_REMOVED,
5011 FILE_NOTIFY_CHANGE_FILE_NAME,
5012 dscp, dep->name, NULL, TRUE);
5016 /* If we made a case sensitive exact match, we might as well quit now. */
5017 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
5018 code = CM_ERROR_STOPNOW;
5026 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5035 smb_unlinkRock_t rock;
5044 attribute = smb_GetSMBParm(inp, 0);
5046 tp = smb_GetSMBData(inp, NULL);
5047 pathp = smb_ParseASCIIBlock(tp, &tp);
5048 if (smb_StoreAnsiFilenames)
5049 OemToChar(pathp,pathp);
5051 osi_Log1(smb_logp, "SMB receive unlink %s",
5052 osi_LogSaveString(smb_logp, pathp));
5054 spacep = inp->spacep;
5055 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5057 userp = smb_GetUserFromVCP(vcp, inp);
5059 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5061 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5063 cm_ReleaseUser(userp);
5064 return CM_ERROR_NOSUCHPATH;
5066 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5069 cm_ReleaseUser(userp);
5074 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5075 cm_ReleaseSCache(dscp);
5076 cm_ReleaseUser(userp);
5077 if ( WANTS_DFS_PATHNAMES(inp) )
5078 return CM_ERROR_PATH_NOT_COVERED;
5080 return CM_ERROR_BADSHARENAME;
5082 #endif /* DFS_SUPPORT */
5084 /* otherwise, scp points to the parent directory. */
5091 rock.maskp = smb_FindMask(pathp);
5092 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5095 thyper.HighPart = 0;
5101 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5102 * match. If that fails, we do a case insensitve match.
5104 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5105 !smb_IsStarMask(rock.maskp)) {
5106 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5109 thyper.HighPart = 0;
5110 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5115 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5117 if (code == CM_ERROR_STOPNOW)
5120 cm_ReleaseUser(userp);
5122 cm_ReleaseSCache(dscp);
5124 if (code == 0 && !rock.any)
5125 code = CM_ERROR_NOSUCHFILE;
5129 typedef struct smb_renameRock {
5130 cm_scache_t *odscp; /* old dir */
5131 cm_scache_t *ndscp; /* new dir */
5132 cm_user_t *userp; /* user */
5133 cm_req_t *reqp; /* request struct */
5134 smb_vc_t *vcp; /* virtual circuit */
5135 char *maskp; /* pointer to star pattern of old file name */
5136 int flags; /* tilde, casefold, etc */
5137 char *newNamep; /* ptr to the new file's name */
5140 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5143 smb_renameRock_t *rockp;
5148 rockp = (smb_renameRock_t *) vrockp;
5150 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5151 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5152 caseFold |= CM_FLAG_8DOT3;
5154 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5156 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5157 !cm_Is8Dot3(dep->name)) {
5158 cm_Gen8Dot3Name(dep, shortName, NULL);
5159 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5162 code = cm_Rename(rockp->odscp, dep->name,
5163 rockp->ndscp, rockp->newNamep, rockp->userp,
5165 /* if the call worked, stop doing the search now, since we
5166 * really only want to rename one file.
5169 code = CM_ERROR_STOPNOW;
5178 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5181 cm_space_t *spacep = NULL;
5182 smb_renameRock_t rock;
5183 cm_scache_t *oldDscp = NULL;
5184 cm_scache_t *newDscp = NULL;
5185 cm_scache_t *tmpscp= NULL;
5186 cm_scache_t *tmpscp2 = NULL;
5196 userp = smb_GetUserFromVCP(vcp, inp);
5197 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5199 cm_ReleaseUser(userp);
5200 return CM_ERROR_NOSUCHPATH;
5204 spacep = inp->spacep;
5205 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5207 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5208 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5209 userp, tidPathp, &req, &oldDscp);
5211 cm_ReleaseUser(userp);
5216 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5217 cm_ReleaseSCache(oldDscp);
5218 cm_ReleaseUser(userp);
5219 if ( WANTS_DFS_PATHNAMES(inp) )
5220 return CM_ERROR_PATH_NOT_COVERED;
5222 return CM_ERROR_BADSHARENAME;
5224 #endif /* DFS_SUPPORT */
5226 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5227 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5228 userp, tidPathp, &req, &newDscp);
5231 cm_ReleaseSCache(oldDscp);
5232 cm_ReleaseUser(userp);
5237 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5238 cm_ReleaseSCache(oldDscp);
5239 cm_ReleaseSCache(newDscp);
5240 cm_ReleaseUser(userp);
5241 if ( WANTS_DFS_PATHNAMES(inp) )
5242 return CM_ERROR_PATH_NOT_COVERED;
5244 return CM_ERROR_BADSHARENAME;
5246 #endif /* DFS_SUPPORT */
5249 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5250 * next, get the component names, and lower case them.
5253 /* handle the old name first */
5255 oldLastNamep = oldPathp;
5259 /* and handle the new name, too */
5261 newLastNamep = newPathp;
5265 /* TODO: The old name could be a wildcard. The new name must not be */
5267 /* do the vnode call */
5268 rock.odscp = oldDscp;
5269 rock.ndscp = newDscp;
5273 rock.maskp = oldLastNamep;
5274 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5275 rock.newNamep = newLastNamep;
5277 /* Check if the file already exists; if so return error */
5278 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5279 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5280 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5281 osi_LogSaveString(afsd_logp, newLastNamep));
5283 /* Check if the old and the new names differ only in case. If so return
5284 * success, else return CM_ERROR_EXISTS
5286 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5288 /* This would be a success only if the old file is *as same as* the new file */
5289 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5291 if (tmpscp == tmpscp2)
5294 code = CM_ERROR_EXISTS;
5295 cm_ReleaseSCache(tmpscp2);
5298 code = CM_ERROR_NOSUCHFILE;
5301 /* file exist, do not rename, also fixes move */
5302 osi_Log0(smb_logp, "Can't rename. Target already exists");
5303 code = CM_ERROR_EXISTS;
5307 cm_ReleaseSCache(tmpscp);
5308 cm_ReleaseSCache(newDscp);
5309 cm_ReleaseSCache(oldDscp);
5310 cm_ReleaseUser(userp);
5314 /* Now search the directory for the pattern, and do the appropriate rename when found */
5315 thyper.LowPart = 0; /* search dir from here */
5316 thyper.HighPart = 0;
5318 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5319 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5321 if (code == CM_ERROR_STOPNOW)
5324 code = CM_ERROR_NOSUCHFILE;
5326 /* Handle Change Notification */
5328 * Being lazy, not distinguishing between files and dirs in this
5329 * filter, since we'd have to do a lookup.
5331 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5332 if (oldDscp == newDscp) {
5333 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5334 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5335 filter, oldDscp, oldLastNamep,
5336 newLastNamep, TRUE);
5338 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5339 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5340 filter, oldDscp, oldLastNamep,
5342 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5343 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5344 filter, newDscp, newLastNamep,
5349 cm_ReleaseSCache(tmpscp);
5350 cm_ReleaseUser(userp);
5351 cm_ReleaseSCache(oldDscp);
5352 cm_ReleaseSCache(newDscp);
5357 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5360 cm_space_t *spacep = NULL;
5361 cm_scache_t *oldDscp = NULL;
5362 cm_scache_t *newDscp = NULL;
5363 cm_scache_t *tmpscp= NULL;
5364 cm_scache_t *tmpscp2 = NULL;
5365 cm_scache_t *sscp = NULL;
5374 userp = smb_GetUserFromVCP(vcp, inp);
5376 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5378 cm_ReleaseUser(userp);
5379 return CM_ERROR_NOSUCHPATH;
5384 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5386 spacep = inp->spacep;
5387 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5389 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5390 userp, tidPathp, &req, &oldDscp);
5392 cm_ReleaseUser(userp);
5397 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5398 cm_ReleaseSCache(oldDscp);
5399 cm_ReleaseUser(userp);
5400 if ( WANTS_DFS_PATHNAMES(inp) )
5401 return CM_ERROR_PATH_NOT_COVERED;
5403 return CM_ERROR_BADSHARENAME;
5405 #endif /* DFS_SUPPORT */
5407 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5408 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5409 userp, tidPathp, &req, &newDscp);
5411 cm_ReleaseSCache(oldDscp);
5412 cm_ReleaseUser(userp);
5417 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5418 cm_ReleaseSCache(newDscp);
5419 cm_ReleaseSCache(oldDscp);
5420 cm_ReleaseUser(userp);
5421 if ( WANTS_DFS_PATHNAMES(inp) )
5422 return CM_ERROR_PATH_NOT_COVERED;
5424 return CM_ERROR_BADSHARENAME;
5426 #endif /* DFS_SUPPORT */
5428 /* Now, although we did two lookups for the two directories (because the same
5429 * directory can be referenced through different paths), we only allow hard links
5430 * within the same directory. */
5431 if (oldDscp != newDscp) {
5432 cm_ReleaseSCache(oldDscp);
5433 cm_ReleaseSCache(newDscp);
5434 cm_ReleaseUser(userp);
5435 return CM_ERROR_CROSSDEVLINK;
5438 /* handle the old name first */
5440 oldLastNamep = oldPathp;
5444 /* and handle the new name, too */
5446 newLastNamep = newPathp;
5450 /* now lookup the old name */
5451 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5452 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5454 cm_ReleaseSCache(oldDscp);
5455 cm_ReleaseSCache(newDscp);
5456 cm_ReleaseUser(userp);
5460 /* Check if the file already exists; if so return error */
5461 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5462 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5463 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5464 osi_LogSaveString(afsd_logp, newLastNamep));
5466 /* if the existing link is to the same file, then we return success */
5468 if(sscp == tmpscp) {
5471 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5472 code = CM_ERROR_EXISTS;
5477 cm_ReleaseSCache(tmpscp);
5478 cm_ReleaseSCache(sscp);
5479 cm_ReleaseSCache(newDscp);
5480 cm_ReleaseSCache(oldDscp);
5481 cm_ReleaseUser(userp);
5485 /* now create the hardlink */
5486 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5487 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5488 osi_Log1(smb_logp," Link returns 0x%x", code);
5490 /* Handle Change Notification */
5492 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5493 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5494 smb_NotifyChange(FILE_ACTION_ADDED,
5495 filter, newDscp, newLastNamep,
5500 cm_ReleaseSCache(tmpscp);
5501 cm_ReleaseUser(userp);
5502 cm_ReleaseSCache(sscp);
5503 cm_ReleaseSCache(oldDscp);
5504 cm_ReleaseSCache(newDscp);
5509 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5515 tp = smb_GetSMBData(inp, NULL);
5516 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5517 if (smb_StoreAnsiFilenames)
5518 OemToChar(oldPathp,oldPathp);
5519 newPathp = smb_ParseASCIIBlock(tp, &tp);
5520 if (smb_StoreAnsiFilenames)
5521 OemToChar(newPathp,newPathp);
5523 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5524 osi_LogSaveString(smb_logp, oldPathp),
5525 osi_LogSaveString(smb_logp, newPathp));
5527 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5532 typedef struct smb_rmdirRock {
5536 char *maskp; /* pointer to the star pattern */
5541 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5544 smb_rmdirRock_t *rockp;
5549 rockp = (smb_rmdirRock_t *) vrockp;
5551 matchName = dep->name;
5552 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5553 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5555 match = (strcmp(matchName, rockp->maskp) == 0);
5557 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5558 !cm_Is8Dot3(dep->name)) {
5559 cm_Gen8Dot3Name(dep, shortName, NULL);
5560 matchName = shortName;
5561 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5564 osi_Log1(smb_logp, "Removing directory %s",
5565 osi_LogSaveString(smb_logp, matchName));
5566 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5567 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5568 smb_NotifyChange(FILE_ACTION_REMOVED,
5569 FILE_NOTIFY_CHANGE_DIR_NAME,
5570 dscp, dep->name, NULL, TRUE);
5579 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5587 smb_rmdirRock_t rock;
5596 tp = smb_GetSMBData(inp, NULL);
5597 pathp = smb_ParseASCIIBlock(tp, &tp);
5598 if (smb_StoreAnsiFilenames)
5599 OemToChar(pathp,pathp);
5601 spacep = inp->spacep;
5602 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5604 userp = smb_GetUserFromVCP(vcp, inp);
5606 caseFold = CM_FLAG_CASEFOLD;
5608 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5610 cm_ReleaseUser(userp);
5611 return CM_ERROR_NOSUCHPATH;
5613 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5614 userp, tidPathp, &req, &dscp);
5617 cm_ReleaseUser(userp);
5622 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5623 cm_ReleaseSCache(dscp);
5624 cm_ReleaseUser(userp);
5625 if ( WANTS_DFS_PATHNAMES(inp) )
5626 return CM_ERROR_PATH_NOT_COVERED;
5628 return CM_ERROR_BADSHARENAME;
5630 #endif /* DFS_SUPPORT */
5632 /* otherwise, scp points to the parent directory. */
5639 rock.maskp = lastNamep;
5640 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5643 thyper.HighPart = 0;
5647 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5648 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5649 if (code == 0 && !rock.any) {
5651 thyper.HighPart = 0;
5652 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5653 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5656 cm_ReleaseUser(userp);
5658 cm_ReleaseSCache(dscp);
5660 if (code == 0 && !rock.any)
5661 code = CM_ERROR_NOSUCHFILE;
5665 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5675 fid = smb_GetSMBParm(inp, 0);
5677 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5679 fid = smb_ChainFID(fid, inp);
5680 fidp = smb_FindFID(vcp, fid, 0);
5682 return CM_ERROR_BADFD;
5684 lock_ObtainMutex(&fidp->mx);
5685 if (fidp->flags & SMB_FID_IOCTL) {
5686 lock_ReleaseMutex(&fidp->mx);
5687 smb_ReleaseFID(fidp);
5688 return CM_ERROR_BADFD;
5690 lock_ReleaseMutex(&fidp->mx);
5692 userp = smb_GetUserFromVCP(vcp, inp);
5694 lock_ObtainMutex(&fidp->mx);
5695 if (fidp->flags & SMB_FID_OPENWRITE)
5696 code = cm_FSync(fidp->scp, userp, &req);
5699 lock_ReleaseMutex(&fidp->mx);
5701 smb_ReleaseFID(fidp);
5703 cm_ReleaseUser(userp);
5708 struct smb_FullNameRock {
5714 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5718 struct smb_FullNameRock *vrockp;
5720 vrockp = (struct smb_FullNameRock *)rockp;
5722 if (!cm_Is8Dot3(dep->name)) {
5723 cm_Gen8Dot3Name(dep, shortName, NULL);
5725 if (cm_stricmp(shortName, vrockp->name) == 0) {
5726 vrockp->fullName = strdup(dep->name);
5727 return CM_ERROR_STOPNOW;
5730 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5731 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5732 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5733 vrockp->fullName = strdup(dep->name);
5734 return CM_ERROR_STOPNOW;
5739 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5740 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5742 struct smb_FullNameRock rock;
5748 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5749 if (code == CM_ERROR_STOPNOW)
5750 *newPathp = rock.fullName;
5752 *newPathp = strdup(pathp);
5755 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5756 afs_uint32 dosTime) {
5759 cm_scache_t *dscp = fidp->NTopen_dscp;
5760 char *pathp = fidp->NTopen_pathp;
5762 osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
5763 fidp, fidp->fid, vcp);
5766 lock_ObtainMutex(&fidp->mx);
5767 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5768 lock_ReleaseMutex(&fidp->mx);
5769 osi_Log0(smb_logp, " No user specified. Not closing fid");
5770 return CM_ERROR_BADFD;
5773 userp = fidp->userp; /* no hold required since fidp is held
5774 throughout the function */
5775 lock_ReleaseMutex(&fidp->mx);
5780 lock_ObtainWrite(&smb_rctLock);
5782 osi_Log0(smb_logp, " Fid already closed.");
5783 lock_ReleaseWrite(&smb_rctLock);
5784 return CM_ERROR_BADFD;
5787 lock_ReleaseWrite(&smb_rctLock);
5789 lock_ObtainMutex(&fidp->mx);
5790 /* Don't jump the gun on an async raw write */
5791 while (fidp->raw_writers) {
5792 lock_ReleaseMutex(&fidp->mx);
5793 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5794 lock_ObtainMutex(&fidp->mx);
5797 /* watch for ioctl closes, and read-only opens */
5798 if (fidp->scp != NULL &&
5799 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5800 == SMB_FID_OPENWRITE) {
5801 if (dosTime != 0 && dosTime != -1) {
5802 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5803 /* This fixes defect 10958 */
5804 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5805 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5807 code = cm_FSync(fidp->scp, userp, &req);
5812 /* unlock any pending locks */
5813 if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
5814 fidp->scp->fileType == CM_SCACHETYPE_FILE) {
5819 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5821 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5824 lock_ObtainMutex(&scp->mx);
5826 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5827 CM_SCACHESYNC_NEEDCALLBACK
5828 | CM_SCACHESYNC_GETSTATUS
5829 | CM_SCACHESYNC_LOCK);
5833 "smb CoreClose SyncOp failure code 0x%x", tcode);
5834 goto post_syncopdone;
5837 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5839 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5843 lock_ReleaseMutex(&scp->mx);
5844 cm_ReleaseSCache(scp);
5847 if (fidp->flags & SMB_FID_DELONCLOSE) {
5850 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5851 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5852 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5853 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5854 smb_NotifyChange(FILE_ACTION_REMOVED,
5855 FILE_NOTIFY_CHANGE_DIR_NAME,
5856 dscp, fullPathp, NULL, TRUE);
5858 code = cm_Unlink(dscp, fullPathp, userp, &req);
5859 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5860 smb_NotifyChange(FILE_ACTION_REMOVED,
5861 FILE_NOTIFY_CHANGE_FILE_NAME,
5862 dscp, fullPathp, NULL, TRUE);
5865 fidp->flags &= ~SMB_FID_DELONCLOSE;
5868 /* if this was a newly created file, then clear the creator
5869 * in the stat cache entry. */
5870 if (fidp->flags & SMB_FID_CREATED) {
5871 lock_ObtainMutex(&fidp->scp->mx);
5872 if (fidp->scp->creator == userp)
5873 fidp->scp->creator = NULL;
5874 lock_ReleaseMutex(&fidp->scp->mx);
5875 fidp->flags &= ~SMB_FID_CREATED;
5878 if (fidp->flags & SMB_FID_NTOPEN) {
5879 fidp->NTopen_dscp = NULL;
5880 fidp->NTopen_pathp = NULL;
5881 fidp->flags &= ~SMB_FID_NTOPEN;
5883 if (fidp->NTopen_wholepathp) {
5884 free(fidp->NTopen_wholepathp);
5885 fidp->NTopen_wholepathp = NULL;
5887 lock_ReleaseMutex(&fidp->mx);
5890 cm_ReleaseSCache(dscp);
5898 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5906 fid = smb_GetSMBParm(inp, 0);
5907 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5909 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5911 fid = smb_ChainFID(fid, inp);
5912 fidp = smb_FindFID(vcp, fid, 0);
5914 return CM_ERROR_BADFD;
5917 userp = smb_GetUserFromVCP(vcp, inp);
5919 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5921 smb_ReleaseFID(fidp);
5922 cm_ReleaseUser(userp);
5927 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5930 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5931 cm_user_t *userp, long *readp)
5933 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5934 cm_user_t *userp, long *readp, int dosflag)
5941 osi_hyper_t fileLength;
5943 osi_hyper_t lastByte;
5944 osi_hyper_t bufferOffset;
5945 long bufIndex, nbytes;
5955 lock_ObtainMutex(&fidp->mx);
5957 lock_ObtainMutex(&scp->mx);
5959 if (offset.HighPart == 0) {
5960 chunk = offset.LowPart >> cm_logChunkSize;
5961 if (chunk != fidp->curr_chunk) {
5962 fidp->prev_chunk = fidp->curr_chunk;
5963 fidp->curr_chunk = chunk;
5965 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5969 /* start by looking up the file's end */
5970 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5971 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5972 if (code) goto done;
5974 /* now we have the entry locked, look up the length */
5975 fileLength = scp->length;
5977 /* adjust count down so that it won't go past EOF */
5978 thyper.LowPart = count;
5979 thyper.HighPart = 0;
5980 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5982 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5983 /* we'd read past EOF, so just stop at fileLength bytes.
5984 * Start by computing how many bytes remain in the file.
5986 thyper = LargeIntegerSubtract(fileLength, offset);
5988 /* if we are past EOF, read 0 bytes */
5989 if (LargeIntegerLessThanZero(thyper))
5992 count = thyper.LowPart;
5997 /* now, copy the data one buffer at a time,
5998 * until we've filled the request packet
6001 /* if we've copied all the data requested, we're done */
6002 if (count <= 0) break;
6004 /* otherwise, load up a buffer of data */
6005 thyper.HighPart = offset.HighPart;
6006 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6007 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6010 buf_Release(bufferp);
6013 lock_ReleaseMutex(&scp->mx);
6015 lock_ObtainRead(&scp->bufCreateLock);
6016 code = buf_Get(scp, &thyper, &bufferp);
6017 lock_ReleaseRead(&scp->bufCreateLock);
6019 lock_ObtainMutex(&scp->mx);
6020 if (code) goto done;
6021 bufferOffset = thyper;
6023 /* now get the data in the cache */
6025 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6026 CM_SCACHESYNC_NEEDCALLBACK |
6027 CM_SCACHESYNC_READ);
6028 if (code) goto done;
6030 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6032 /* otherwise, load the buffer and try again */
6033 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6037 buf_Release(bufferp);
6041 } /* if (wrong buffer) ... */
6043 /* now we have the right buffer loaded. Copy out the
6044 * data from here to the user's buffer.
6046 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6048 /* and figure out how many bytes we want from this buffer */
6049 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6050 if (nbytes > count) nbytes = count; /* don't go past EOF */
6052 /* now copy the data */
6055 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
6058 memcpy(op, bufferp->datap + bufIndex, nbytes);
6060 /* adjust counters, pointers, etc. */
6063 thyper.LowPart = nbytes;
6064 thyper.HighPart = 0;
6065 offset = LargeIntegerAdd(thyper, offset);
6069 lock_ReleaseMutex(&scp->mx);
6070 lock_ReleaseMutex(&fidp->mx);
6072 buf_Release(bufferp);
6074 if (code == 0 && sequential)
6075 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6081 * smb_WriteData -- common code for Write and Raw Write
6084 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6085 cm_user_t *userp, long *writtenp)
6087 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6088 cm_user_t *userp, long *writtenp, int dosflag)
6095 osi_hyper_t fileLength; /* file's length at start of write */
6096 osi_hyper_t minLength; /* don't read past this */
6097 long nbytes; /* # of bytes to transfer this iteration */
6099 osi_hyper_t thyper; /* hyper tmp variable */
6100 osi_hyper_t bufferOffset;
6101 long bufIndex; /* index in buffer where our data is */
6103 osi_hyper_t writeBackOffset;/* offset of region to write back when
6108 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6109 fidp->fid, offsetp->LowPart, count);
6119 lock_ObtainMutex(&fidp->mx);
6121 lock_ObtainMutex(&scp->mx);
6123 /* start by looking up the file's end */
6124 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6125 CM_SCACHESYNC_NEEDCALLBACK
6126 | CM_SCACHESYNC_SETSTATUS
6127 | CM_SCACHESYNC_GETSTATUS);
6131 /* make sure we have a writable FD */
6132 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6133 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6134 fidp->fid, fidp->flags);
6135 code = CM_ERROR_BADFDOP;
6139 /* now we have the entry locked, look up the length */
6140 fileLength = scp->length;
6141 minLength = fileLength;
6142 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6143 minLength = scp->serverLength;
6145 /* adjust file length if we extend past EOF */
6146 thyper.LowPart = count;
6147 thyper.HighPart = 0;
6148 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6149 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6150 /* we'd write past EOF, so extend the file */
6151 scp->mask |= CM_SCACHEMASK_LENGTH;
6152 scp->length = thyper;
6153 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6155 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6157 /* now, if the new position (thyper) and the old (offset) are in
6158 * different storeback windows, remember to store back the previous
6159 * storeback window when we're done with the write.
6161 if ((thyper.LowPart & (-cm_chunkSize)) !=
6162 (offset.LowPart & (-cm_chunkSize))) {
6163 /* they're different */
6165 writeBackOffset.HighPart = offset.HighPart;
6166 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6171 /* now, copy the data one buffer at a time, until we've filled the
6174 /* if we've copied all the data requested, we're done */
6178 /* handle over quota or out of space */
6179 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6180 *writtenp = written;
6181 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6185 /* otherwise, load up a buffer of data */
6186 thyper.HighPart = offset.HighPart;
6187 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6188 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6191 lock_ReleaseMutex(&bufferp->mx);
6192 buf_Release(bufferp);
6195 lock_ReleaseMutex(&scp->mx);
6197 lock_ObtainRead(&scp->bufCreateLock);
6198 code = buf_Get(scp, &thyper, &bufferp);
6199 lock_ReleaseRead(&scp->bufCreateLock);
6201 lock_ObtainMutex(&bufferp->mx);
6202 lock_ObtainMutex(&scp->mx);
6203 if (code) goto done;
6205 bufferOffset = thyper;
6207 /* now get the data in the cache */
6209 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6210 CM_SCACHESYNC_NEEDCALLBACK
6211 | CM_SCACHESYNC_WRITE
6212 | CM_SCACHESYNC_BUFLOCKED);
6216 /* If we're overwriting the entire buffer, or
6217 * if we're writing at or past EOF, mark the
6218 * buffer as current so we don't call
6219 * cm_GetBuffer. This skips the fetch from the
6220 * server in those cases where we're going to
6221 * obliterate all the data in the buffer anyway,
6222 * or in those cases where there is no useful
6223 * data at the server to start with.
6225 * Use minLength instead of scp->length, since
6226 * the latter has already been updated by this
6229 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6230 || LargeIntegerEqualTo(offset, bufferp->offset)
6231 && (count >= cm_data.buf_blockSize
6232 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6233 ConvertLongToLargeInteger(count)),
6235 if (count < cm_data.buf_blockSize
6236 && bufferp->dataVersion == -1)
6237 memset(bufferp->datap, 0,
6238 cm_data.buf_blockSize);
6239 bufferp->dataVersion = scp->dataVersion;
6242 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6244 /* otherwise, load the buffer and try again */
6245 lock_ReleaseMutex(&bufferp->mx);
6246 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6248 lock_ReleaseMutex(&scp->mx);
6249 lock_ObtainMutex(&bufferp->mx);
6250 lock_ObtainMutex(&scp->mx);
6254 lock_ReleaseMutex(&bufferp->mx);
6255 buf_Release(bufferp);
6259 } /* if (wrong buffer) ... */
6261 /* now we have the right buffer loaded. Copy out the
6262 * data from here to the user's buffer.
6264 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6266 /* and figure out how many bytes we want from this buffer */
6267 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6269 nbytes = count; /* don't go past end of request */
6271 /* now copy the data */
6274 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
6277 memcpy(bufferp->datap + bufIndex, op, nbytes);
6278 buf_SetDirty(bufferp);
6280 /* and record the last writer */
6281 if (bufferp->userp != userp) {
6284 cm_ReleaseUser(bufferp->userp);
6285 bufferp->userp = userp;
6288 /* adjust counters, pointers, etc. */
6292 thyper.LowPart = nbytes;
6293 thyper.HighPart = 0;
6294 offset = LargeIntegerAdd(thyper, offset);
6298 lock_ReleaseMutex(&scp->mx);
6301 lock_ReleaseMutex(&bufferp->mx);
6302 buf_Release(bufferp);
6305 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6306 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6307 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6308 fidp->NTopen_dscp, fidp->NTopen_pathp,
6311 lock_ReleaseMutex(&fidp->mx);
6313 if (code == 0 && doWriteBack) {
6315 lock_ObtainMutex(&scp->mx);
6316 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6318 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6319 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6321 lock_ReleaseMutex(&scp->mx);
6322 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6323 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6326 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6327 fidp->fid, code, *writtenp);
6331 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6334 long count, written = 0, total_written = 0;
6340 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6342 int inDataBlockCount;
6344 fd = smb_GetSMBParm(inp, 0);
6345 count = smb_GetSMBParm(inp, 1);
6346 offset.HighPart = 0; /* too bad */
6347 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6349 op = smb_GetSMBData(inp, NULL);
6350 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6352 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6353 fd, offset.LowPart, count);
6355 fd = smb_ChainFID(fd, inp);
6356 fidp = smb_FindFID(vcp, fd, 0);
6358 return CM_ERROR_BADFD;
6360 lock_ObtainMutex(&fidp->mx);
6361 if (fidp->flags & SMB_FID_IOCTL) {
6362 lock_ReleaseMutex(&fidp->mx);
6363 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6364 smb_ReleaseFID(fidp);
6367 lock_ReleaseMutex(&fidp->mx);
6368 userp = smb_GetUserFromVCP(vcp, inp);
6370 /* special case: 0 bytes transferred means truncate to this position */
6376 truncAttr.mask = CM_ATTRMASK_LENGTH;
6377 truncAttr.length.LowPart = offset.LowPart;
6378 truncAttr.length.HighPart = 0;
6379 lock_ObtainMutex(&fidp->mx);
6380 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6381 fidp->flags |= SMB_FID_LENGTHSETDONE;
6382 lock_ReleaseMutex(&fidp->mx);
6383 smb_SetSMBParm(outp, 0, /* count */ 0);
6384 smb_SetSMBDataLength(outp, 0);
6390 LARGE_INTEGER LOffset;
6391 LARGE_INTEGER LLength;
6393 pid = ((smb_t *) inp)->pid;
6394 key = cm_GenerateKey(vcp->vcID, pid, fd);
6396 LOffset.HighPart = offset.HighPart;
6397 LOffset.LowPart = offset.LowPart;
6398 LLength.HighPart = 0;
6399 LLength.LowPart = count;
6401 lock_ObtainMutex(&fidp->scp->mx);
6402 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6403 lock_ReleaseMutex(&fidp->scp->mx);
6410 * Work around bug in NT client
6412 * When copying a file, the NT client should first copy the data,
6413 * then copy the last write time. But sometimes the NT client does
6414 * these in the wrong order, so the data copies would inadvertently
6415 * cause the last write time to be overwritten. We try to detect this,
6416 * and don't set client mod time if we think that would go against the
6419 lock_ObtainMutex(&fidp->mx);
6420 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6421 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6422 fidp->scp->clientModTime = time(NULL);
6424 lock_ReleaseMutex(&fidp->mx);
6427 while ( code == 0 && count > 0 ) {
6429 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6431 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6433 if (code == 0 && written == 0)
6434 code = CM_ERROR_PARTIALWRITE;
6436 offset.LowPart += written;
6438 total_written += written;
6442 /* set the packet data length to 3 bytes for the data block header,
6443 * plus the size of the data.
6445 smb_SetSMBParm(outp, 0, total_written);
6446 smb_SetSMBDataLength(outp, 0);
6449 smb_ReleaseFID(fidp);
6450 cm_ReleaseUser(userp);
6455 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6456 NCB *ncbp, raw_write_cont_t *rwcp)
6469 fd = smb_GetSMBParm(inp, 0);
6470 fidp = smb_FindFID(vcp, fd, 0);
6472 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
6473 rwcp->offset.LowPart, rwcp->count);
6475 userp = smb_GetUserFromVCP(vcp, inp);
6479 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6482 rawBuf = (dos_ptr) rwcp->buf;
6483 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6484 (unsigned char *) rawBuf, userp,
6488 if (rwcp->writeMode & 0x1) { /* synchronous */
6491 smb_FormatResponsePacket(vcp, inp, outp);
6492 op = (smb_t *) outp;
6493 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6494 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6495 smb_SetSMBDataLength(outp, 0);
6496 smb_SendPacket(vcp, outp);
6497 smb_FreePacket(outp);
6499 else { /* asynchronous */
6500 lock_ObtainMutex(&fidp->mx);
6501 fidp->raw_writers--;
6502 if (fidp->raw_writers == 0)
6503 thrd_SetEvent(fidp->raw_write_event);
6504 lock_ReleaseMutex(&fidp->mx);
6507 /* Give back raw buffer */
6508 lock_ObtainMutex(&smb_RawBufLock);
6510 *((char **)rawBuf) = smb_RawBufs;
6512 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6514 smb_RawBufs = rawBuf;
6515 lock_ReleaseMutex(&smb_RawBufLock);
6517 smb_ReleaseFID(fidp);
6518 cm_ReleaseUser(userp);
6521 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6526 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6529 long count, written = 0, total_written = 0;
6536 unsigned short writeMode;
6543 fd = smb_GetSMBParm(inp, 0);
6544 totalCount = smb_GetSMBParm(inp, 1);
6545 count = smb_GetSMBParm(inp, 10);
6546 offset.HighPart = 0; /* too bad */
6547 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6548 writeMode = smb_GetSMBParm(inp, 7);
6550 op = (char *) inp->data;
6551 op += smb_GetSMBParm(inp, 11);
6554 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
6555 fd, offset.LowPart, count, writeMode);
6557 fd = smb_ChainFID(fd, inp);
6558 fidp = smb_FindFID(vcp, fd, 0);
6560 return CM_ERROR_BADFD;
6566 LARGE_INTEGER LOffset;
6567 LARGE_INTEGER LLength;
6569 pid = ((smb_t *) inp)->pid;
6570 key = cm_GenerateKey(vcp->vcID, pid, fd);
6572 LOffset.HighPart = offset.HighPart;
6573 LOffset.LowPart = offset.LowPart;
6574 LLength.HighPart = 0;
6575 LLength.LowPart = count;
6577 lock_ObtainMutex(&fidp->scp->mx);
6578 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6579 lock_ReleaseMutex(&fidp->scp->mx);
6582 smb_ReleaseFID(fidp);
6587 userp = smb_GetUserFromVCP(vcp, inp);
6590 * Work around bug in NT client
6592 * When copying a file, the NT client should first copy the data,
6593 * then copy the last write time. But sometimes the NT client does
6594 * these in the wrong order, so the data copies would inadvertently
6595 * cause the last write time to be overwritten. We try to detect this,
6596 * and don't set client mod time if we think that would go against the
6599 lock_ObtainMutex(&fidp->mx);
6600 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6601 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6602 fidp->scp->clientModTime = time(NULL);
6604 lock_ReleaseMutex(&fidp->mx);
6607 while ( code == 0 && count > 0 ) {
6609 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6611 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6613 if (code == 0 && written == 0)
6614 code = CM_ERROR_PARTIALWRITE;
6616 offset.LowPart += written;
6618 total_written += written;
6622 /* Get a raw buffer */
6625 lock_ObtainMutex(&smb_RawBufLock);
6627 /* Get a raw buf, from head of list */
6628 rawBuf = smb_RawBufs;
6630 smb_RawBufs = *(char **)smb_RawBufs;
6632 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6636 code = CM_ERROR_USESTD;
6638 lock_ReleaseMutex(&smb_RawBufLock);
6641 /* Don't allow a premature Close */
6642 if (code == 0 && (writeMode & 1) == 0) {
6643 lock_ObtainMutex(&fidp->mx);
6644 fidp->raw_writers++;
6645 thrd_ResetEvent(fidp->raw_write_event);
6646 lock_ReleaseMutex(&fidp->mx);
6649 smb_ReleaseFID(fidp);
6650 cm_ReleaseUser(userp);
6653 smb_SetSMBParm(outp, 0, total_written);
6654 smb_SetSMBDataLength(outp, 0);
6655 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6662 rwcp->offset.HighPart = 0;
6663 rwcp->offset.LowPart = offset.LowPart + count;
6664 rwcp->count = totalCount - count;
6665 rwcp->writeMode = writeMode;
6666 rwcp->alreadyWritten = total_written;
6668 /* set the packet data length to 3 bytes for the data block header,
6669 * plus the size of the data.
6671 smb_SetSMBParm(outp, 0, 0xffff);
6672 smb_SetSMBDataLength(outp, 0);
6677 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6680 long count, finalCount;
6688 fd = smb_GetSMBParm(inp, 0);
6689 count = smb_GetSMBParm(inp, 1);
6690 offset.HighPart = 0; /* too bad */
6691 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6693 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6694 fd, offset.LowPart, count);
6696 fd = smb_ChainFID(fd, inp);
6697 fidp = smb_FindFID(vcp, fd, 0);
6699 return CM_ERROR_BADFD;
6701 lock_ObtainMutex(&fidp->mx);
6702 if (fidp->flags & SMB_FID_IOCTL) {
6703 lock_ReleaseMutex(&fidp->mx);
6704 code = smb_IoctlRead(fidp, vcp, inp, outp);
6705 smb_ReleaseFID(fidp);
6708 lock_ReleaseMutex(&fidp->mx);
6711 LARGE_INTEGER LOffset, LLength;
6714 pid = ((smb_t *) inp)->pid;
6715 key = cm_GenerateKey(vcp->vcID, pid, fd);
6717 LOffset.HighPart = 0;
6718 LOffset.LowPart = offset.LowPart;
6719 LLength.HighPart = 0;
6720 LLength.LowPart = count;
6722 lock_ObtainMutex(&fidp->scp->mx);
6723 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6724 lock_ReleaseMutex(&fidp->scp->mx);
6727 smb_ReleaseFID(fidp);
6731 userp = smb_GetUserFromVCP(vcp, inp);
6733 /* remember this for final results */
6734 smb_SetSMBParm(outp, 0, count);
6735 smb_SetSMBParm(outp, 1, 0);
6736 smb_SetSMBParm(outp, 2, 0);
6737 smb_SetSMBParm(outp, 3, 0);
6738 smb_SetSMBParm(outp, 4, 0);
6740 /* set the packet data length to 3 bytes for the data block header,
6741 * plus the size of the data.
6743 smb_SetSMBDataLength(outp, count+3);
6745 /* get op ptr after putting in the parms, since otherwise we don't
6746 * know where the data really is.
6748 op = smb_GetSMBData(outp, NULL);
6750 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6751 *op++ = 1; /* data block marker */
6752 *op++ = (unsigned char) (count & 0xff);
6753 *op++ = (unsigned char) ((count >> 8) & 0xff);
6756 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6758 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6761 /* fix some things up */
6762 smb_SetSMBParm(outp, 0, finalCount);
6763 smb_SetSMBDataLength(outp, finalCount+3);
6765 smb_ReleaseFID(fidp);
6767 cm_ReleaseUser(userp);
6771 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6778 cm_scache_t *dscp; /* dir we're dealing with */
6779 cm_scache_t *scp; /* file we're creating */
6781 int initialModeBits;
6791 /* compute initial mode bits based on read-only flag in attributes */
6792 initialModeBits = 0777;
6794 tp = smb_GetSMBData(inp, NULL);
6795 pathp = smb_ParseASCIIBlock(tp, &tp);
6796 if (smb_StoreAnsiFilenames)
6797 OemToChar(pathp,pathp);
6799 if (strcmp(pathp, "\\") == 0)
6800 return CM_ERROR_EXISTS;
6802 spacep = inp->spacep;
6803 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6805 userp = smb_GetUserFromVCP(vcp, inp);
6807 caseFold = CM_FLAG_CASEFOLD;
6809 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6811 cm_ReleaseUser(userp);
6812 return CM_ERROR_NOSUCHPATH;
6815 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6816 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6817 userp, tidPathp, &req, &dscp);
6820 cm_ReleaseUser(userp);
6825 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6826 cm_ReleaseSCache(dscp);
6827 cm_ReleaseUser(userp);
6828 if ( WANTS_DFS_PATHNAMES(inp) )
6829 return CM_ERROR_PATH_NOT_COVERED;
6831 return CM_ERROR_BADSHARENAME;
6833 #endif /* DFS_SUPPORT */
6835 /* otherwise, scp points to the parent directory. Do a lookup, and
6836 * fail if we find it. Otherwise, we do the create.
6842 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6843 if (scp) cm_ReleaseSCache(scp);
6844 if (code != CM_ERROR_NOSUCHFILE) {
6845 if (code == 0) code = CM_ERROR_EXISTS;
6846 cm_ReleaseSCache(dscp);
6847 cm_ReleaseUser(userp);
6851 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6852 setAttr.clientModTime = time(NULL);
6853 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6854 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6855 smb_NotifyChange(FILE_ACTION_ADDED,
6856 FILE_NOTIFY_CHANGE_DIR_NAME,
6857 dscp, lastNamep, NULL, TRUE);
6859 /* we don't need this any longer */
6860 cm_ReleaseSCache(dscp);
6863 /* something went wrong creating or truncating the file */
6864 cm_ReleaseUser(userp);
6868 /* otherwise we succeeded */
6869 smb_SetSMBDataLength(outp, 0);
6870 cm_ReleaseUser(userp);
6875 BOOL smb_IsLegalFilename(char *filename)
6878 * Find the longest substring of filename that does not contain
6879 * any of the chars in illegalChars. If that substring is less
6880 * than the length of the whole string, then one or more of the
6881 * illegal chars is in filename.
6883 if (strcspn(filename, illegalChars) < strlen(filename))
6889 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6897 cm_scache_t *dscp; /* dir we're dealing with */
6898 cm_scache_t *scp; /* file we're creating */
6900 int initialModeBits;
6908 int created = 0; /* the file was new */
6913 excl = (inp->inCom == 0x03)? 0 : 1;
6915 attributes = smb_GetSMBParm(inp, 0);
6916 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6918 /* compute initial mode bits based on read-only flag in attributes */
6919 initialModeBits = 0666;
6920 if (attributes & 1) initialModeBits &= ~0222;
6922 tp = smb_GetSMBData(inp, NULL);
6923 pathp = smb_ParseASCIIBlock(tp, &tp);
6924 if (smb_StoreAnsiFilenames)
6925 OemToChar(pathp,pathp);
6927 spacep = inp->spacep;
6928 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6930 userp = smb_GetUserFromVCP(vcp, inp);
6932 caseFold = CM_FLAG_CASEFOLD;
6934 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6936 cm_ReleaseUser(userp);
6937 return CM_ERROR_NOSUCHPATH;
6939 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6940 userp, tidPathp, &req, &dscp);
6943 cm_ReleaseUser(userp);
6948 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6949 cm_ReleaseSCache(dscp);
6950 cm_ReleaseUser(userp);
6951 if ( WANTS_DFS_PATHNAMES(inp) )
6952 return CM_ERROR_PATH_NOT_COVERED;
6954 return CM_ERROR_BADSHARENAME;
6956 #endif /* DFS_SUPPORT */
6958 /* otherwise, scp points to the parent directory. Do a lookup, and
6959 * truncate the file if we find it, otherwise we create the file.
6966 if (!smb_IsLegalFilename(lastNamep))
6967 return CM_ERROR_BADNTFILENAME;
6969 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6970 #ifdef DEBUG_VERBOSE
6973 hexp = osi_HexifyString( lastNamep );
6974 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6979 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6980 if (code && code != CM_ERROR_NOSUCHFILE) {
6981 cm_ReleaseSCache(dscp);
6982 cm_ReleaseUser(userp);
6986 /* if we get here, if code is 0, the file exists and is represented by
6987 * scp. Otherwise, we have to create it.
6991 /* oops, file shouldn't be there */
6992 cm_ReleaseSCache(dscp);
6993 cm_ReleaseSCache(scp);
6994 cm_ReleaseUser(userp);
6995 return CM_ERROR_EXISTS;
6998 setAttr.mask = CM_ATTRMASK_LENGTH;
6999 setAttr.length.LowPart = 0;
7000 setAttr.length.HighPart = 0;
7001 code = cm_SetAttr(scp, &setAttr, userp, &req);
7004 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7005 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7006 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7010 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7011 smb_NotifyChange(FILE_ACTION_ADDED,
7012 FILE_NOTIFY_CHANGE_FILE_NAME,
7013 dscp, lastNamep, NULL, TRUE);
7014 } else if (!excl && code == CM_ERROR_EXISTS) {
7015 /* not an exclusive create, and someone else tried
7016 * creating it already, then we open it anyway. We
7017 * don't bother retrying after this, since if this next
7018 * fails, that means that the file was deleted after
7019 * we started this call.
7021 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7024 setAttr.mask = CM_ATTRMASK_LENGTH;
7025 setAttr.length.LowPart = 0;
7026 setAttr.length.HighPart = 0;
7027 code = cm_SetAttr(scp, &setAttr, userp, &req);
7032 /* we don't need this any longer */
7033 cm_ReleaseSCache(dscp);
7036 /* something went wrong creating or truncating the file */
7037 if (scp) cm_ReleaseSCache(scp);
7038 cm_ReleaseUser(userp);
7042 /* make sure we only open files */
7043 if (scp->fileType != CM_SCACHETYPE_FILE) {
7044 cm_ReleaseSCache(scp);
7045 cm_ReleaseUser(userp);
7046 return CM_ERROR_ISDIR;
7049 /* now all we have to do is open the file itself */
7050 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7055 lock_ObtainMutex(&fidp->mx);
7056 /* always create it open for read/write */
7057 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
7059 /* remember that the file was newly created */
7061 fidp->flags |= SMB_FID_CREATED;
7063 /* save a pointer to the vnode */
7066 fidp->userp = userp;
7067 lock_ReleaseMutex(&fidp->mx);
7069 smb_SetSMBParm(outp, 0, fidp->fid);
7070 smb_SetSMBDataLength(outp, 0);
7072 cm_Open(scp, 0, userp);
7074 smb_ReleaseFID(fidp);
7075 cm_ReleaseUser(userp);
7076 /* leave scp held since we put it in fidp->scp */
7080 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7093 fd = smb_GetSMBParm(inp, 0);
7094 whence = smb_GetSMBParm(inp, 1);
7095 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7097 /* try to find the file descriptor */
7098 fd = smb_ChainFID(fd, inp);
7099 fidp = smb_FindFID(vcp, fd, 0);
7102 return CM_ERROR_BADFD;
7104 lock_ObtainMutex(&fidp->mx);
7105 if (fidp->flags & SMB_FID_IOCTL) {
7106 lock_ReleaseMutex(&fidp->mx);
7107 smb_ReleaseFID(fidp);
7108 return CM_ERROR_BADFD;
7110 lock_ReleaseMutex(&fidp->mx);
7112 userp = smb_GetUserFromVCP(vcp, inp);
7114 lock_ObtainMutex(&fidp->mx);
7116 lock_ObtainMutex(&scp->mx);
7117 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7118 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7121 /* offset from current offset */
7122 offset += fidp->offset;
7124 else if (whence == 2) {
7125 /* offset from current EOF */
7126 offset += scp->length.LowPart;
7128 fidp->offset = offset;
7129 smb_SetSMBParm(outp, 0, offset & 0xffff);
7130 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
7131 smb_SetSMBDataLength(outp, 0);
7133 lock_ReleaseMutex(&scp->mx);
7134 lock_ReleaseMutex(&fidp->mx);
7135 smb_ReleaseFID(fidp);
7136 cm_ReleaseUser(userp);
7140 /* dispatch all of the requests received in a packet. Due to chaining, this may
7141 * be more than one request.
7143 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7144 NCB *ncbp, raw_write_cont_t *rwcp)
7148 unsigned long code = 0;
7149 unsigned char *outWctp;
7150 int nparms; /* # of bytes of parameters */
7152 int nbytes; /* bytes of data, excluding count */
7155 unsigned short errCode;
7156 unsigned long NTStatus;
7158 unsigned char errClass;
7159 unsigned int oldGen;
7160 DWORD oldTime, newTime;
7162 /* get easy pointer to the data */
7163 smbp = (smb_t *) inp->data;
7165 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7166 /* setup the basic parms for the initial request in the packet */
7167 inp->inCom = smbp->com;
7168 inp->wctp = &smbp->wct;
7170 inp->ncb_length = ncbp->ncb_length;
7175 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7176 /* log it and discard it */
7178 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7179 __FILE__, __LINE__, ncbp->ncb_length);
7181 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7185 /* We are an ongoing op */
7186 thrd_Increment(&ongoingOps);
7188 /* set up response packet for receiving output */
7189 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7190 smb_FormatResponsePacket(vcp, inp, outp);
7191 outWctp = outp->wctp;
7193 /* Remember session generation number and time */
7194 oldGen = sessionGen;
7195 oldTime = GetTickCount();
7197 while (inp->inCom != 0xff) {
7198 dp = &smb_dispatchTable[inp->inCom];
7200 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7201 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7202 code = outp->resumeCode;
7206 /* process each request in the packet; inCom, wctp and inCount
7207 * are already set up.
7209 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7212 /* now do the dispatch */
7213 /* start by formatting the response record a little, as a default */
7214 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7216 outWctp[1] = 0xff; /* no operation */
7217 outWctp[2] = 0; /* padding */
7222 /* not a chained request, this is a more reasonable default */
7223 outWctp[0] = 0; /* wct of zero */
7224 outWctp[1] = 0; /* and bcc (word) of zero */
7228 /* once set, stays set. Doesn't matter, since we never chain
7229 * "no response" calls.
7231 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7235 /* we have a recognized operation */
7237 if (inp->inCom == 0x1d)
7239 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7241 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7242 code = (*(dp->procp)) (vcp, inp, outp);
7243 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7245 if ( code == CM_ERROR_BADSMB ||
7246 code == CM_ERROR_BADOP )
7248 #endif /* LOG_PACKET */
7251 if (oldGen != sessionGen) {
7252 newTime = GetTickCount();
7254 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7255 newTime - oldTime, ncbp->ncb_length);
7257 osi_Log2(smb_logp, "Pkt straddled session startup, "
7258 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7262 /* bad opcode, fail the request, after displaying it */
7263 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7266 #endif /* LOG_PACKET */
7270 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7271 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7272 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7273 if (code == IDCANCEL)
7277 code = CM_ERROR_BADOP;
7280 /* catastrophic failure: log as much as possible */
7281 if (code == CM_ERROR_BADSMB) {
7283 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7288 #endif /* LOG_PACKET */
7289 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7292 code = CM_ERROR_INVAL;
7295 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7296 thrd_Decrement(&ongoingOps);
7301 /* now, if we failed, turn the current response into an empty
7302 * one, and fill in the response packet's error code.
7305 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7306 smb_MapNTError(code, &NTStatus);
7307 outWctp = outp->wctp;
7308 smbp = (smb_t *) &outp->data;
7309 if (code != CM_ERROR_PARTIALWRITE
7310 && code != CM_ERROR_BUFFERTOOSMALL
7311 && code != CM_ERROR_GSSCONTINUE) {
7312 /* nuke wct and bcc. For a partial
7313 * write or an in-process authentication handshake,
7314 * assume they're OK.
7320 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7321 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7322 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7323 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7324 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7328 smb_MapCoreError(code, vcp, &errCode, &errClass);
7329 outWctp = outp->wctp;
7330 smbp = (smb_t *) &outp->data;
7331 if (code != CM_ERROR_PARTIALWRITE) {
7332 /* nuke wct and bcc. For a partial
7333 * write, assume they're OK.
7339 smbp->errLow = (unsigned char) (errCode & 0xff);
7340 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7341 smbp->rcls = errClass;
7344 } /* error occurred */
7346 /* if we're here, we've finished one request. Look to see if
7347 * this is a chained opcode. If it is, setup things to process
7348 * the chained request, and setup the output buffer to hold the
7349 * chained response. Start by finding the next input record.
7351 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7352 break; /* not a chained req */
7353 tp = inp->wctp; /* points to start of last request */
7354 /* in a chained request, the first two
7355 * parm fields are required, and are
7356 * AndXCommand/AndXReserved and
7358 if (tp[0] < 2) break;
7359 if (tp[1] == 0xff) break; /* no more chained opcodes */
7361 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7364 /* and now append the next output request to the end of this
7365 * last request. Begin by finding out where the last response
7366 * ends, since that's where we'll put our new response.
7368 outWctp = outp->wctp; /* ptr to out parameters */
7369 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7370 nparms = outWctp[0] << 1;
7371 tp = outWctp + nparms + 1; /* now points to bcc field */
7372 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7373 tp += 2 /* for the count itself */ + nbytes;
7374 /* tp now points to the new output record; go back and patch the
7375 * second parameter (off2) to point to the new record.
7377 temp = (unsigned int)(tp - outp->data);
7378 outWctp[3] = (unsigned char) (temp & 0xff);
7379 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7380 outWctp[2] = 0; /* padding */
7381 outWctp[1] = inp->inCom; /* next opcode */
7383 /* finally, setup for the next iteration */
7386 } /* while loop over all requests in the packet */
7388 /* now send the output packet, and return */
7390 smb_SendPacket(vcp, outp);
7391 thrd_Decrement(&ongoingOps);
7397 /* Wait for Netbios() calls to return, and make the results available to server
7398 * threads. Note that server threads can't wait on the NCBevents array
7399 * themselves, because NCB events are manual-reset, and the servers would race
7400 * each other to reset them.
7402 void smb_ClientWaiter(void *parmp)
7407 while (smbShutdownFlag == 0) {
7408 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7410 if (code == WAIT_OBJECT_0)
7413 /* error checking */
7414 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7416 int abandonIdx = code - WAIT_ABANDONED_0;
7417 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7420 if (code == WAIT_IO_COMPLETION)
7422 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7426 if (code == WAIT_TIMEOUT)
7428 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7431 if (code == WAIT_FAILED)
7433 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7436 idx = code - WAIT_OBJECT_0;
7438 /* check idx range! */
7439 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7441 /* this is fatal - log as much as possible */
7442 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7446 thrd_ResetEvent(NCBevents[idx]);
7447 thrd_SetEvent(NCBreturns[0][idx]);
7453 * Try to have one NCBRECV request waiting for every live session. Not more
7454 * than one, because if there is more than one, it's hard to handle Write Raw.
7456 void smb_ServerWaiter(void *parmp)
7459 int idx_session, idx_NCB;
7465 while (smbShutdownFlag == 0) {
7467 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7469 if (code == WAIT_OBJECT_0)
7472 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7474 int abandonIdx = code - WAIT_ABANDONED_0;
7475 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7478 if (code == WAIT_IO_COMPLETION)
7480 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7484 if (code == WAIT_TIMEOUT)
7486 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7489 if (code == WAIT_FAILED)
7491 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7494 idx_session = code - WAIT_OBJECT_0;
7496 /* check idx range! */
7497 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7499 /* this is fatal - log as much as possible */
7500 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7506 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7508 if (code == WAIT_OBJECT_0) {
7509 if (smbShutdownFlag == 1)
7515 /* error checking */
7516 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7518 int abandonIdx = code - WAIT_ABANDONED_0;
7519 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7522 if (code == WAIT_IO_COMPLETION)
7524 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7528 if (code == WAIT_TIMEOUT)
7530 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7533 if (code == WAIT_FAILED)
7535 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7538 idx_NCB = code - WAIT_OBJECT_0;
7540 /* check idx range! */
7541 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7543 /* this is fatal - log as much as possible */
7544 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7548 /* Link them together */
7549 NCBsessions[idx_NCB] = idx_session;
7552 ncbp = NCBs[idx_NCB];
7553 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7554 ncbp->ncb_command = NCBRECV | ASYNCH;
7555 ncbp->ncb_lana_num = lanas[idx_session];
7557 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7558 ncbp->ncb_event = NCBevents[idx_NCB];
7559 ncbp->ncb_length = SMB_PACKETSIZE;
7562 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7563 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7564 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7565 ncbp->ncb_length = SMB_PACKETSIZE;
7566 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7567 Netbios(ncbp, dos_ncb);
7573 * The top level loop for handling SMB request messages. Each server thread
7574 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7575 * NCB and buffer for the incoming request are loaned to us.
7577 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7578 * to immediately send a request for the rest of the data. This must come
7579 * before any other traffic for that session, so we delay setting the session
7580 * event until that data has come in.
7582 void smb_Server(VOID *parmp)
7584 INT_PTR myIdx = (INT_PTR) parmp;
7588 smb_packet_t *outbufp;
7590 int idx_NCB, idx_session;
7592 smb_vc_t *vcp = NULL;
7598 rx_StartClientThread();
7601 outbufp = GetPacket();
7602 outbufp->ncbp = outncbp;
7610 smb_ResetServerPriority();
7612 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7615 /* terminate silently if shutdown flag is set */
7616 if (code == WAIT_OBJECT_0) {
7617 if (smbShutdownFlag == 1) {
7618 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7624 /* error checking */
7625 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7627 int abandonIdx = code - WAIT_ABANDONED_0;
7628 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7631 if (code == WAIT_IO_COMPLETION)
7633 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7637 if (code == WAIT_TIMEOUT)
7639 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7642 if (code == WAIT_FAILED)
7644 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7647 idx_NCB = code - WAIT_OBJECT_0;
7649 /* check idx range! */
7650 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7652 /* this is fatal - log as much as possible */
7653 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7657 ncbp = NCBs[idx_NCB];
7659 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7661 idx_session = NCBsessions[idx_NCB];
7662 rc = ncbp->ncb_retcode;
7664 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7665 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7669 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7673 /* Can this happen? Or is it just my UNIX paranoia? */
7674 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7680 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7684 /* Client closed session */
7685 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7687 lock_ObtainMutex(&vcp->mx);
7688 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7689 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7691 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7692 lock_ReleaseMutex(&vcp->mx);
7693 lock_ObtainWrite(&smb_globalLock);
7694 dead_sessions[vcp->session] = TRUE;
7695 lock_ReleaseWrite(&smb_globalLock);
7696 smb_CleanupDeadVC(vcp);
7700 lock_ReleaseMutex(&vcp->mx);
7706 /* Treat as transient error */
7708 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7712 "dispatch smb recv failed, message incomplete, ncb_length %d",
7715 "SMB message incomplete, "
7716 "length %d", ncbp->ncb_length);
7719 * We used to discard the packet.
7720 * Instead, try handling it normally.
7724 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7728 /* A weird error code. Log it, sleep, and continue. */
7729 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7731 lock_ObtainMutex(&vcp->mx);
7732 if (vcp && vcp->errorCount++ > 3) {
7733 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7734 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7735 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7737 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7738 lock_ReleaseMutex(&vcp->mx);
7739 lock_ObtainWrite(&smb_globalLock);
7740 dead_sessions[vcp->session] = TRUE;
7741 lock_ReleaseWrite(&smb_globalLock);
7742 smb_CleanupDeadVC(vcp);
7746 lock_ReleaseMutex(&vcp->mx);
7752 lock_ReleaseMutex(&vcp->mx);
7754 thrd_SetEvent(SessionEvents[idx_session]);
7759 /* Success, so now dispatch on all the data in the packet */
7761 smb_concurrentCalls++;
7762 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7763 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7766 * If at this point vcp is NULL (implies that packet was invalid)
7767 * then we are in big trouble. This means either :
7768 * a) we have the wrong NCB.
7769 * b) Netbios screwed up the call.
7770 * c) The VC was already marked dead before we were able to
7772 * Obviously this implies that
7773 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7774 * lanas[idx_session] != ncbp->ncb_lana_num )
7775 * Either way, we can't do anything with this packet.
7776 * Log, sleep and resume.
7779 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7783 ncbp->ncb_lana_num);
7785 /* Also log in the trace log. */
7786 osi_Log4(smb_logp, "Server: VCP does not exist!"
7787 "LSNs[idx_session]=[%d],"
7788 "lanas[idx_session]=[%d],"
7789 "ncbp->ncb_lsn=[%d],"
7790 "ncbp->ncb_lana_num=[%d]",
7794 ncbp->ncb_lana_num);
7796 /* thrd_Sleep(1000); Don't bother sleeping */
7797 thrd_SetEvent(SessionEvents[idx_session]);
7798 smb_concurrentCalls--;
7802 smb_SetRequestStartTime();
7804 vcp->errorCount = 0;
7805 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7807 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7808 /* copy whole packet to virtual memory */
7809 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7811 bufp->dos_pkt / 16, bufp);*/
7813 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7815 smbp = (smb_t *)bufp->data;
7818 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7822 if (smbp->com == 0x1d) {
7823 /* Special handling for Write Raw */
7824 raw_write_cont_t rwc;
7825 EVENT_HANDLE rwevent;
7826 char eventName[MAX_PATH];
7828 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7829 if (rwc.code == 0) {
7830 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7831 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7832 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7833 ncbp->ncb_command = NCBRECV | ASYNCH;
7834 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7835 ncbp->ncb_lana_num = vcp->lana;
7836 ncbp->ncb_buffer = rwc.buf;
7837 ncbp->ncb_length = 65535;
7838 ncbp->ncb_event = rwevent;
7842 Netbios(ncbp, dos_ncb);
7844 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7845 thrd_CloseHandle(rwevent);
7847 thrd_SetEvent(SessionEvents[idx_session]);
7849 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7851 else if (smbp->com == 0xa0) {
7853 * Serialize the handling for NT Transact
7856 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7857 thrd_SetEvent(SessionEvents[idx_session]);
7859 thrd_SetEvent(SessionEvents[idx_session]);
7860 /* TODO: what else needs to be serialized? */
7861 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7863 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7865 __except( smb_ServerExceptionFilter() ) {
7869 smb_concurrentCalls--;
7872 thrd_SetEvent(NCBavails[idx_NCB]);
7879 * Exception filter for the server threads. If an exception occurs in the
7880 * dispatch routines, which is where exceptions are most common, then do a
7881 * force trace and give control to upstream exception handlers. Useful for
7884 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7885 DWORD smb_ServerExceptionFilter(void) {
7886 /* While this is not the best time to do a trace, if it succeeds, then
7887 * we have a trace (assuming tracing was enabled). Otherwise, this should
7888 * throw a second exception.
7890 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7891 afsd_ForceTrace(TRUE);
7892 buf_ForceTrace(TRUE);
7893 return EXCEPTION_CONTINUE_SEARCH;
7898 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7899 * If the number of server threads is M, and the number of live sessions is
7900 * N, then the number of NCB's in use at any time either waiting for, or
7901 * holding, received messages is M + N, so that is how many NCB's get created.
7903 void InitNCBslot(int idx)
7905 struct smb_packet *bufp;
7906 EVENT_HANDLE retHandle;
7908 char eventName[MAX_PATH];
7910 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7912 NCBs[idx] = GetNCB();
7913 sprintf(eventName,"NCBavails[%d]", idx);
7914 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7915 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7916 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7918 sprintf(eventName,"NCBevents[%d]", idx);
7919 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7920 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7921 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7923 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7924 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7925 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7926 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7927 for (i=0; i<smb_NumServerThreads; i++)
7928 NCBreturns[i][idx] = retHandle;
7930 bufp->spacep = cm_GetSpace();
7934 /* listen for new connections */
7935 void smb_Listener(void *parmp)
7941 int session, thread;
7942 smb_vc_t *vcp = NULL;
7944 char rname[NCBNAMSZ+1];
7945 char cname[MAX_COMPUTERNAME_LENGTH+1];
7946 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7951 INT_PTR lana = (INT_PTR) parmp;
7955 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7958 /* retrieve computer name */
7959 GetComputerName(cname, &cnamelen);
7963 memset(ncbp, 0, sizeof(NCB));
7966 ncbp->ncb_command = NCBLISTEN;
7967 ncbp->ncb_rto = 0; /* No receive timeout */
7968 ncbp->ncb_sto = 0; /* No send timeout */
7970 /* pad out with spaces instead of null termination */
7971 len = (long)strlen(smb_localNamep);
7972 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7973 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7975 strcpy(ncbp->ncb_callname, "*");
7976 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7978 ncbp->ncb_lana_num = (UCHAR)lana;
7981 code = Netbios(ncbp);
7983 code = Netbios(ncbp, dos_ncb);
7992 /* terminate silently if shutdown flag is set */
7993 if (smbShutdownFlag == 1) {
8002 "NCBLISTEN lana=%d failed with code %d",
8003 ncbp->ncb_lana_num, code);
8005 "Client exiting due to network failure. Please restart client.\n");
8009 "Client exiting due to network failure. Please restart client.\n"
8010 "NCBLISTEN lana=%d failed with code %d",
8011 ncbp->ncb_lana_num, code);
8013 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8014 MB_OK|MB_SERVICE_NOTIFICATION);
8015 osi_assert(tbuffer);
8018 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
8019 ncbp->ncb_lana_num, code);
8020 fprintf(stderr, "\nClient exiting due to network failure "
8021 "(possibly due to power-saving mode)\n");
8022 fprintf(stderr, "Please restart client.\n");
8023 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
8027 /* check for remote conns */
8028 /* first get remote name and insert null terminator */
8029 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8030 for (i=NCBNAMSZ; i>0; i--) {
8031 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8037 /* compare with local name */
8039 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8040 flags |= SMB_VCFLAG_REMOTECONN;
8043 lock_ObtainMutex(&smb_ListenerLock);
8045 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8046 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8048 /* now ncbp->ncb_lsn is the connection ID */
8049 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8050 if (vcp->session == 0) {
8051 /* New generation */
8052 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8055 /* Log session startup */
8057 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8058 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8059 #endif /* NOTSERVICE */
8060 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8061 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8063 if (reportSessionStartups) {
8065 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8068 fprintf(stderr, "%s: New session %d starting from host %s\n",
8069 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8074 lock_ObtainMutex(&vcp->mx);
8075 strcpy(vcp->rname, rname);
8076 vcp->flags |= flags;
8077 lock_ReleaseMutex(&vcp->mx);
8079 /* Allocate slot in session arrays */
8080 /* Re-use dead session if possible, otherwise add one more */
8081 /* But don't look at session[0], it is reserved */
8082 lock_ObtainWrite(&smb_globalLock);
8083 for (session = 1; session < numSessions; session++) {
8084 if (dead_sessions[session]) {
8085 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8086 dead_sessions[session] = FALSE;
8090 lock_ReleaseWrite(&smb_globalLock);
8092 /* We are re-using an existing VC because the lsn and lana
8094 session = vcp->session;
8096 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8098 /* Log session startup */
8100 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8101 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8102 #endif /* NOTSERVICE */
8103 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8104 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8106 if (reportSessionStartups) {
8108 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8111 fprintf(stderr, "%s: Re-using session %d starting from host %s\n",
8112 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8118 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8119 unsigned long code = CM_ERROR_ALLBUSY;
8120 smb_packet_t * outp = GetPacket();
8121 unsigned char *outWctp;
8124 smb_FormatResponsePacket(vcp, NULL, outp);
8127 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8128 unsigned long NTStatus;
8129 smb_MapNTError(code, &NTStatus);
8130 outWctp = outp->wctp;
8131 smbp = (smb_t *) &outp->data;
8135 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8136 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8137 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8138 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8139 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8141 unsigned short errCode;
8142 unsigned char errClass;
8143 smb_MapCoreError(code, vcp, &errCode, &errClass);
8144 outWctp = outp->wctp;
8145 smbp = (smb_t *) &outp->data;
8149 smbp->errLow = (unsigned char) (errCode & 0xff);
8150 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8151 smbp->rcls = errClass;
8153 smb_SendPacket(vcp, outp);
8154 smb_FreePacket(outp);
8156 lock_ObtainMutex(&vcp->mx);
8157 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8158 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8160 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8161 lock_ReleaseMutex(&vcp->mx);
8162 lock_ObtainWrite(&smb_globalLock);
8163 dead_sessions[vcp->session] = TRUE;
8164 lock_ReleaseWrite(&smb_globalLock);
8165 smb_CleanupDeadVC(vcp);
8167 lock_ReleaseMutex(&vcp->mx);
8170 /* assert that we do not exceed the maximum number of sessions or NCBs.
8171 * we should probably want to wait for a session to be freed in case
8174 osi_assert(session < SESSION_MAX - 1);
8175 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8177 lock_ObtainMutex(&vcp->mx);
8178 vcp->session = session;
8179 lock_ReleaseMutex(&vcp->mx);
8180 lock_ObtainWrite(&smb_globalLock);
8181 LSNs[session] = ncbp->ncb_lsn;
8182 lanas[session] = ncbp->ncb_lana_num;
8183 lock_ReleaseWrite(&smb_globalLock);
8185 if (session == numSessions) {
8186 /* Add new NCB for new session */
8187 char eventName[MAX_PATH];
8189 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8191 InitNCBslot(numNCBs);
8192 lock_ObtainWrite(&smb_globalLock);
8194 lock_ReleaseWrite(&smb_globalLock);
8195 thrd_SetEvent(NCBavails[0]);
8196 thrd_SetEvent(NCBevents[0]);
8197 for (thread = 0; thread < smb_NumServerThreads; thread++)
8198 thrd_SetEvent(NCBreturns[thread][0]);
8199 /* Also add new session event */
8200 sprintf(eventName, "SessionEvents[%d]", session);
8201 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8202 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8203 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8204 lock_ObtainWrite(&smb_globalLock);
8206 lock_ReleaseWrite(&smb_globalLock);
8207 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8208 thrd_SetEvent(SessionEvents[0]);
8210 thrd_SetEvent(SessionEvents[session]);
8216 lock_ReleaseMutex(&smb_ListenerLock);
8217 } /* dispatch while loop */
8220 /* initialize Netbios */
8221 void smb_NetbiosInit()
8227 int i, lana, code, l;
8229 int delname_tried=0;
8232 OSVERSIONINFO Version;
8234 /* Get the version of Windows */
8235 memset(&Version, 0x00, sizeof(Version));
8236 Version.dwOSVersionInfoSize = sizeof(Version);
8237 GetVersionEx(&Version);
8239 /* setup the NCB system */
8242 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8246 if (smb_LANadapter == -1) {
8247 ncbp->ncb_command = NCBENUM;
8248 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8249 ncbp->ncb_length = sizeof(lana_list);
8250 code = Netbios(ncbp);
8252 afsi_log("Netbios NCBENUM error code %d", code);
8253 osi_panic(s, __FILE__, __LINE__);
8257 lana_list.length = 1;
8258 lana_list.lana[0] = smb_LANadapter;
8261 for (i = 0; i < lana_list.length; i++) {
8262 /* reset the adaptor: in Win32, this is required for every process, and
8263 * acts as an init call, not as a real hardware reset.
8265 ncbp->ncb_command = NCBRESET;
8266 ncbp->ncb_callname[0] = 100;
8267 ncbp->ncb_callname[2] = 100;
8268 ncbp->ncb_lana_num = lana_list.lana[i];
8269 code = Netbios(ncbp);
8271 code = ncbp->ncb_retcode;
8273 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8274 lana_list.lana[i] = 255; /* invalid lana */
8276 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8280 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
8281 we will just fake the LANA list */
8282 if (smb_LANadapter == -1) {
8283 for (i = 0; i < 8; i++)
8284 lana_list.lana[i] = i;
8285 lana_list.length = 8;
8288 lana_list.length = 1;
8289 lana_list.lana[0] = smb_LANadapter;
8293 /* and declare our name so we can receive connections */
8294 memset(ncbp, 0, sizeof(*ncbp));
8295 len=lstrlen(smb_localNamep);
8296 memset(smb_sharename,' ',NCBNAMSZ);
8297 memcpy(smb_sharename,smb_localNamep,len);
8298 afsi_log("lana_list.length %d", lana_list.length);
8300 /* Keep the name so we can unregister it later */
8301 for (l = 0; l < lana_list.length; l++) {
8302 lana = lana_list.lana[l];
8304 ncbp->ncb_command = NCBADDNAME;
8305 ncbp->ncb_lana_num = lana;
8306 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8308 code = Netbios(ncbp);
8310 code = Netbios(ncbp, dos_ncb);
8313 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8314 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8316 char name[NCBNAMSZ+1];
8318 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8319 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8322 if (code == 0) code = ncbp->ncb_retcode;
8324 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8326 /* we only use one LANA with djgpp */
8327 lana_list.lana[0] = lana;
8328 lana_list.length = 1;
8332 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8333 if (code == NRC_BRIDGE) { /* invalid LANA num */
8334 lana_list.lana[l] = 255;
8337 else if (code == NRC_DUPNAME) {
8338 afsi_log("Name already exists; try to delete it");
8339 memset(ncbp, 0, sizeof(*ncbp));
8340 ncbp->ncb_command = NCBDELNAME;
8341 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8342 ncbp->ncb_lana_num = lana;
8344 code = Netbios(ncbp);
8346 code = Netbios(ncbp, dos_ncb);
8349 code = ncbp->ncb_retcode;
8351 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8353 if (code != 0 || delname_tried) {
8354 lana_list.lana[l] = 255;
8356 else if (code == 0) {
8357 if (!delname_tried) {
8365 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8366 lana_list.lana[l] = 255; /* invalid lana */
8367 osi_panic(s, __FILE__, __LINE__);
8371 lana_found = 1; /* at least one worked */
8378 osi_assert(lana_list.length >= 0);
8380 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8383 /* we're done with the NCB now */
8387 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8404 EVENT_HANDLE retHandle;
8405 char eventName[MAX_PATH];
8407 smb_TlsRequestSlot = TlsAlloc();
8410 smb_MBfunc = aMBfunc;
8414 smb_LANadapter = LANadapt;
8416 /* Initialize smb_localZero */
8417 myTime.tm_isdst = -1; /* compute whether on DST or not */
8418 myTime.tm_year = 70;
8424 smb_localZero = mktime(&myTime);
8426 #ifndef USE_NUMERIC_TIME_CONV
8427 /* Initialize kludge-GMT */
8428 smb_CalculateNowTZ();
8429 #endif /* USE_NUMERIC_TIME_CONV */
8430 #ifdef AFS_FREELANCE_CLIENT
8431 /* Make sure the root.afs volume has the correct time */
8432 cm_noteLocalMountPointChange();
8435 /* initialize the remote debugging log */
8438 /* remember the name */
8439 len = (int)strlen(snamep);
8440 smb_localNamep = malloc(len+1);
8441 strcpy(smb_localNamep, snamep);
8442 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8444 /* and the global lock */
8445 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8446 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8448 /* Raw I/O data structures */
8449 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8451 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8453 /* 4 Raw I/O buffers */
8455 smb_RawBufs = calloc(65536,1);
8456 *((char **)smb_RawBufs) = NULL;
8457 for (i=0; i<3; i++) {
8458 char *rawBuf = calloc(65536,1);
8459 *((char **)rawBuf) = smb_RawBufs;
8460 smb_RawBufs = rawBuf;
8463 npar = 65536 >> 4; /* number of paragraphs */
8464 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8466 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8468 osi_panic("",__FILE__,__LINE__);
8471 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8474 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8476 _farpokel(_dos_ds, smb_RawBufs, NULL);
8477 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8478 npar = 65536 >> 4; /* number of paragraphs */
8479 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8481 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8483 osi_panic("",__FILE__,__LINE__);
8486 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8489 rawBuf = (seg * 16) + 0; /* DOS physical address */
8490 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8491 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8492 smb_RawBufs = rawBuf;
8496 /* global free lists */
8497 smb_ncbFreeListp = NULL;
8498 smb_packetFreeListp = NULL;
8502 /* Initialize listener and server structures */
8504 memset(dead_sessions, 0, sizeof(dead_sessions));
8505 sprintf(eventName, "SessionEvents[0]");
8506 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8507 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8508 afsi_log("Event Object Already Exists: %s", eventName);
8510 smb_NumServerThreads = nThreads;
8511 sprintf(eventName, "NCBavails[0]");
8512 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8513 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8514 afsi_log("Event Object Already Exists: %s", eventName);
8515 sprintf(eventName, "NCBevents[0]");
8516 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8517 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8518 afsi_log("Event Object Already Exists: %s", eventName);
8519 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8520 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8521 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8522 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8523 afsi_log("Event Object Already Exists: %s", eventName);
8524 for (i = 0; i < smb_NumServerThreads; i++) {
8525 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8526 NCBreturns[i][0] = retHandle;
8529 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8530 for (i = 0; i < smb_NumServerThreads; i++) {
8531 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8532 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8533 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8534 afsi_log("Event Object Already Exists: %s", eventName);
8535 InitNCBslot((int)(i+1));
8537 numNCBs = smb_NumServerThreads + 1;
8539 /* Initialize dispatch table */
8540 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8541 /* Prepare the table for unknown operations */
8542 for(i=0; i<= SMB_NOPCODES; i++) {
8543 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8545 /* Fill in the ones we do know */
8546 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8547 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8548 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8549 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8550 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8551 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8552 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8553 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8554 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8555 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8556 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8557 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8558 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8559 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8560 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8561 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8562 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8563 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8564 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8565 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8566 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8567 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8568 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8569 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8570 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8571 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8572 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8573 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8574 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8575 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8576 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8577 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8578 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8579 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8580 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8581 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8582 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8583 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8584 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8585 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8586 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8587 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8588 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8589 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8590 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8591 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8592 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8593 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8594 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8595 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8596 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8597 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8598 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8599 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8600 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8601 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8602 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8603 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8604 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8605 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8606 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8607 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8608 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8609 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8610 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8611 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8612 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8613 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8614 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8615 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8616 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8617 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8619 /* setup tran 2 dispatch table */
8620 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8621 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8622 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8623 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8624 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8625 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8626 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8627 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8628 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8629 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8630 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8631 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8632 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8633 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8634 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8635 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8636 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8638 /* setup the rap dispatch table */
8639 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8640 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8641 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8642 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8643 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8647 /* if we are doing SMB authentication we have register outselves as a logon process */
8648 if (smb_authType != SMB_AUTH_NONE) {
8649 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8650 LSA_STRING afsProcessName;
8651 LSA_OPERATIONAL_MODE dummy; /*junk*/
8653 afsProcessName.Buffer = "OpenAFSClientDaemon";
8654 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8655 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8657 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8659 if (nts == STATUS_SUCCESS) {
8660 LSA_STRING packageName;
8661 /* we are registered. Find out the security package id */
8662 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8663 packageName.Length = (USHORT)strlen(packageName.Buffer);
8664 packageName.MaximumLength = packageName.Length + 1;
8665 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8666 if (nts == STATUS_SUCCESS) {
8668 * This code forces Windows to authenticate against the Logon Cache
8669 * first instead of attempting to authenticate against the Domain
8670 * Controller. When the Windows logon cache is enabled this improves
8671 * performance by removing the network access and works around a bug
8672 * seen at sites which are using a MIT Kerberos principal to login
8673 * to machines joined to a non-root domain in a multi-domain forest.
8675 PVOID pResponse = NULL;
8676 ULONG cbResponse = 0;
8677 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8679 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8680 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8681 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8682 OptionsRequest.DisableOptions = FALSE;
8684 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8687 sizeof(OptionsRequest),
8693 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8695 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8697 OutputDebugString(message);
8700 OutputDebugString("MsV1_0SetProcessOption success");
8701 afsi_log("MsV1_0SetProcessOption success");
8703 /* END - code from Larry */
8705 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8706 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8707 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8709 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8711 /* something went wrong. We report the error and revert back to no authentication
8712 because we can't perform any auth requests without a successful lsa handle
8713 or sec package id. */
8714 afsi_log("Reverting to NO SMB AUTH");
8715 smb_authType = SMB_AUTH_NONE;
8718 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8720 /* something went wrong. We report the error and revert back to no authentication
8721 because we can't perform any auth requests without a successful lsa handle
8722 or sec package id. */
8723 afsi_log("Reverting to NO SMB AUTH");
8724 smb_authType = SMB_AUTH_NONE;
8728 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8729 * time prevents the failure of authentication when logged into Windows with an
8730 * external Kerberos principal mapped to a local account.
8732 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8733 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8734 * then the only option is NTLMSSP anyway; so just fallback.
8739 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8740 if (secBlobLength == 0) {
8741 smb_authType = SMB_AUTH_NTLM;
8742 afsi_log("Reverting to SMB AUTH NTLM");
8751 /* Now get ourselves a domain name. */
8752 /* For now we are using the local computer name as the domain name.
8753 * It is actually the domain for local logins, and we are acting as
8754 * a local SMB server.
8756 bufsize = sizeof(smb_ServerDomainName) - 1;
8757 GetComputerName(smb_ServerDomainName, &bufsize);
8758 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8759 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8762 /* Start listeners, waiters, servers, and daemons */
8764 for (i = 0; i < lana_list.length; i++) {
8765 if (lana_list.lana[i] == 255)
8767 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8768 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8769 osi_assert(phandle != NULL);
8770 thrd_CloseHandle(phandle);
8774 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8775 NULL, 0, &lpid, "smb_ClientWaiter");
8776 osi_assert(phandle != NULL);
8777 thrd_CloseHandle(phandle);
8780 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8781 NULL, 0, &lpid, "smb_ServerWaiter");
8782 osi_assert(phandle != NULL);
8783 thrd_CloseHandle(phandle);
8785 for (i=0; i<smb_NumServerThreads; i++) {
8786 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8787 (void *) i, 0, &lpid, "smb_Server");
8788 osi_assert(phandle != NULL);
8789 thrd_CloseHandle(phandle);
8792 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8793 NULL, 0, &lpid, "smb_Daemon");
8794 osi_assert(phandle != NULL);
8795 thrd_CloseHandle(phandle);
8797 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8798 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8799 osi_assert(phandle != NULL);
8800 thrd_CloseHandle(phandle);
8809 void smb_Shutdown(void)
8819 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8821 /* setup the NCB system */
8824 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8827 /* Block new sessions by setting shutdown flag */
8828 smbShutdownFlag = 1;
8830 /* Hang up all sessions */
8831 memset((char *)ncbp, 0, sizeof(NCB));
8832 for (i = 1; i < numSessions; i++)
8834 if (dead_sessions[i])
8837 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8838 ncbp->ncb_command = NCBHANGUP;
8839 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8840 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8842 code = Netbios(ncbp);
8844 code = Netbios(ncbp, dos_ncb);
8846 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8847 if (code == 0) code = ncbp->ncb_retcode;
8849 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8850 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8854 /* Trigger the shutdown of all SMB threads */
8855 for (i = 0; i < smb_NumServerThreads; i++)
8856 thrd_SetEvent(NCBreturns[i][0]);
8858 thrd_SetEvent(NCBevents[0]);
8859 thrd_SetEvent(SessionEvents[0]);
8860 thrd_SetEvent(NCBavails[0]);
8862 for (i = 0;i < smb_NumServerThreads; i++) {
8863 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8864 if (code == WAIT_OBJECT_0) {
8867 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8868 thrd_SetEvent(NCBreturns[i--][0]);
8872 /* Delete Netbios name */
8873 memset((char *)ncbp, 0, sizeof(NCB));
8874 for (i = 0; i < lana_list.length; i++) {
8875 if (lana_list.lana[i] == 255) continue;
8876 ncbp->ncb_command = NCBDELNAME;
8877 ncbp->ncb_lana_num = lana_list.lana[i];
8878 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8880 code = Netbios(ncbp);
8882 code = Netbios(ncbp, dos_ncb);
8885 code = ncbp->ncb_retcode;
8887 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8888 ncbp->ncb_lana_num, code);
8893 /* Release the reference counts held by the VCs */
8894 lock_ObtainWrite(&smb_rctLock);
8895 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8900 if (vcp->magic != SMB_VC_MAGIC)
8901 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8902 __FILE__, __LINE__);
8904 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8906 if (fidp->scp != NULL) {
8909 lock_ObtainMutex(&fidp->mx);
8910 if (fidp->scp != NULL) {
8913 cm_ReleaseSCache(scp);
8915 lock_ReleaseMutex(&fidp->mx);
8919 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8921 smb_ReleaseVCNoLock(tidp->vcp);
8923 cm_user_t *userp = tidp->userp;
8925 lock_ReleaseWrite(&smb_rctLock);
8926 cm_ReleaseUser(userp);
8927 lock_ObtainWrite(&smb_rctLock);
8931 lock_ReleaseWrite(&smb_rctLock);
8933 TlsFree(smb_TlsRequestSlot);
8936 /* Get the UNC \\<servername>\<sharename> prefix. */
8937 char *smb_GetSharename()
8941 /* Make sure we have been properly initialized. */
8942 if (smb_localNamep == NULL)
8945 /* Allocate space for \\<servername>\<sharename>, plus the
8948 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8949 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8955 void smb_LogPacket(smb_packet_t *packet)
8958 unsigned length, paramlen, datalen, i, j;
8960 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8962 if (!packet) return;
8964 osi_Log0(smb_logp, "*** SMB packet dump ***");
8966 vp = (BYTE *) packet->data;
8968 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8969 length = paramlen + 2 + datalen;
8972 for (i=0;i < length; i+=16)
8974 memset( buf, ' ', 80 );
8979 buf[strlen(buf)] = ' ';
8981 cp = (BYTE*) buf + 7;
8983 for (j=0;j < 16 && (i+j)<length; j++)
8985 *(cp++) = hex[vp[i+j] >> 4];
8986 *(cp++) = hex[vp[i+j] & 0xf];
8996 for (j=0;j < 16 && (i+j)<length;j++)
8998 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9009 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9012 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9014 #endif /* LOG_PACKET */
9017 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9025 lock_ObtainRead(&smb_rctLock);
9027 sprintf(output, "begin dumping smb_vc_t\n");
9028 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9030 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9034 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9035 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9036 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9038 sprintf(output, "begin dumping smb_fid_t\n");
9039 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9041 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9043 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",
9044 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9045 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9046 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9047 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9050 sprintf(output, "done dumping smb_fid_t\n");
9051 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9054 sprintf(output, "done dumping smb_vc_t\n");
9055 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9057 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9058 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9060 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9064 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9065 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9066 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9068 sprintf(output, "begin dumping smb_fid_t\n");
9069 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9071 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9073 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",
9074 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9075 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9076 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9077 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9080 sprintf(output, "done dumping smb_fid_t\n");
9081 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9084 sprintf(output, "done dumping DEAD smb_vc_t\n");
9085 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9087 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9088 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9090 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9094 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9095 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9096 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9098 sprintf(output, "begin dumping smb_fid_t\n");
9099 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9101 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9103 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",
9104 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9105 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9106 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9107 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9110 sprintf(output, "done dumping smb_fid_t\n");
9111 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9114 sprintf(output, "done dumping DEAD smb_vc_t\n");
9115 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9118 lock_ReleaseRead(&smb_rctLock);