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 smb_vc_t *active_vcp = NULL;
43 int smbShutdownFlag = 0;
45 int smb_LogoffTokenTransfer;
46 time_t smb_LogoffTransferTimeout;
48 int smb_StoreAnsiFilenames = 0;
50 DWORD last_msg_time = 0;
54 unsigned int sessionGen = 0;
56 extern void afsi_log(char *pattern, ...);
57 extern HANDLE afsi_file;
59 osi_hyper_t hzero = {0, 0};
60 osi_hyper_t hones = {0xFFFFFFFF, -1};
63 osi_rwlock_t smb_globalLock;
64 osi_rwlock_t smb_rctLock;
65 osi_mutex_t smb_ListenerLock;
68 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
71 long smb_maxObsConcurrentCalls=0;
72 long smb_concurrentCalls=0;
74 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
76 smb_packet_t *smb_packetFreeListp;
77 smb_ncb_t *smb_ncbFreeListp;
79 int smb_NumServerThreads;
81 int numNCBs, numSessions, numVCs;
83 int smb_maxVCPerServer;
84 int smb_maxMpxRequests;
86 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
88 ULONG smb_lsaSecPackage;
89 LSA_STRING smb_lsaLogonOrigin;
91 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
92 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
93 EVENT_HANDLE **NCBreturns;
94 EVENT_HANDLE **NCBShutdown;
95 EVENT_HANDLE *smb_ServerShutdown;
96 DWORD NCBsessions[NCB_MAX];
98 struct smb_packet *bufs[NCB_MAX];
100 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
101 EVENT_HANDLE SessionEvents[SESSION_MAX];
102 unsigned short LSNs[SESSION_MAX];
103 int lanas[SESSION_MAX];
104 BOOL dead_sessions[SESSION_MAX];
108 osi_mutex_t smb_RawBufLock;
110 #define SMB_RAW_BUFS 4
112 int smb_RawBufSel[SMB_RAW_BUFS];
117 #define SMB_MASKFLAG_TILDE 1
118 #define SMB_MASKFLAG_CASEFOLD 2
120 #define RAWTIMEOUT INFINITE
123 typedef struct raw_write_cont {
136 /* dir search stuff */
137 long smb_dirSearchCounter = 1;
138 smb_dirSearch_t *smb_firstDirSearchp;
139 smb_dirSearch_t *smb_lastDirSearchp;
141 /* hide dot files? */
142 int smb_hideDotFiles;
144 /* global state about V3 protocols */
145 int smb_useV3; /* try to negotiate V3 */
148 static showErrors = 1;
149 /* MessageBox or something like it */
150 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
154 * Time in Unix format of midnight, 1/1/1970 local time.
155 * When added to dosUTime, gives Unix (AFS) time.
157 time_t smb_localZero = 0;
159 #define USE_NUMERIC_TIME_CONV 1
161 #ifndef USE_NUMERIC_TIME_CONV
162 /* Time difference for converting to kludge-GMT */
163 afs_uint32 smb_NowTZ;
164 #endif /* USE_NUMERIC_TIME_CONV */
166 char *smb_localNamep = NULL;
168 smb_vc_t *smb_allVCsp;
169 smb_vc_t *smb_deadVCsp;
171 smb_username_t *usernamesp = NULL;
173 smb_waitingLockRequest_t *smb_allWaitingLocks;
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 const char * ncb_error_string(int code)
213 case 0x01: s = "llegal buffer length"; break;
214 case 0x03: s = "illegal command"; break;
215 case 0x05: s = "command timed out"; break;
216 case 0x06: s = "message incomplete, issue another command"; break;
217 case 0x07: s = "illegal buffer address"; break;
218 case 0x08: s = "session number out of range"; break;
219 case 0x09: s = "no resource available"; break;
220 case 0x0a: s = "session closed"; break;
221 case 0x0b: s = "command cancelled"; break;
222 case 0x0d: s = "duplicate name"; break;
223 case 0x0e: s = "name table full"; break;
224 case 0x0f: s = "no deletions, name has active sessions"; break;
225 case 0x11: s = "local session table full"; break;
226 case 0x12: s = "remote session table full"; break;
227 case 0x13: s = "illegal name number"; break;
228 case 0x14: s = "no callname"; break;
229 case 0x15: s = "cannot put * in NCB_NAME"; break;
230 case 0x16: s = "name in use on remote adapter"; break;
231 case 0x17: s = "name deleted"; break;
232 case 0x18: s = "session ended abnormally"; break;
233 case 0x19: s = "name conflict detected"; break;
234 case 0x21: s = "interface busy, IRET before retrying"; break;
235 case 0x22: s = "too many commands outstanding, retry later";break;
236 case 0x23: s = "ncb_lana_num field invalid"; break;
237 case 0x24: s = "command completed while cancel occurring "; break;
238 case 0x26: s = "command not valid to cancel"; break;
239 case 0x30: s = "name defined by anther local process"; break;
240 case 0x34: s = "environment undefined. RESET required"; break;
241 case 0x35: s = "required OS resources exhausted"; break;
242 case 0x36: s = "max number of applications exceeded"; break;
243 case 0x37: s = "no saps available for netbios"; break;
244 case 0x38: s = "requested resources are not available"; break;
245 case 0x39: s = "invalid ncb address or length > segment"; break;
246 case 0x3B: s = "invalid NCB DDID"; break;
247 case 0x3C: s = "lock of user area failed"; break;
248 case 0x3f: s = "NETBIOS not loaded"; break;
249 case 0x40: s = "system error"; break;
250 default: s = "unknown error";
256 char * myCrt_Dispatch(int i)
261 return "(00)ReceiveCoreMakeDir";
263 return "(01)ReceiveCoreRemoveDir";
265 return "(02)ReceiveCoreOpen";
267 return "(03)ReceiveCoreCreate";
269 return "(04)ReceiveCoreClose";
271 return "(05)ReceiveCoreFlush";
273 return "(06)ReceiveCoreUnlink";
275 return "(07)ReceiveCoreRename";
277 return "(08)ReceiveCoreGetFileAttributes";
279 return "(09)ReceiveCoreSetFileAttributes";
281 return "(0a)ReceiveCoreRead";
283 return "(0b)ReceiveCoreWrite";
285 return "(0c)ReceiveCoreLockRecord";
287 return "(0d)ReceiveCoreUnlockRecord";
289 return "(0e)SendCoreBadOp";
291 return "(0f)ReceiveCoreCreate";
293 return "(10)ReceiveCoreCheckPath";
295 return "(11)SendCoreBadOp";
297 return "(12)ReceiveCoreSeek";
299 return "(1a)ReceiveCoreReadRaw";
301 return "(1d)ReceiveCoreWriteRawDummy";
303 return "(22)ReceiveV3SetAttributes";
305 return "(23)ReceiveV3GetAttributes";
307 return "(24)ReceiveV3LockingX";
309 return "(25)ReceiveV3Trans";
311 return "(26)ReceiveV3Trans[aux]";
313 return "(29)SendCoreBadOp";
315 return "(2b)ReceiveCoreEcho";
317 return "(2d)ReceiveV3OpenX";
319 return "(2e)ReceiveV3ReadX";
321 return "(32)ReceiveV3Tran2A";
323 return "(33)ReceiveV3Tran2A[aux]";
325 return "(34)ReceiveV3FindClose";
327 return "(35)ReceiveV3FindNotifyClose";
329 return "(70)ReceiveCoreTreeConnect";
331 return "(71)ReceiveCoreTreeDisconnect";
333 return "(72)ReceiveNegotiate";
335 return "(73)ReceiveV3SessionSetupX";
337 return "(74)ReceiveV3UserLogoffX";
339 return "(75)ReceiveV3TreeConnectX";
341 return "(80)ReceiveCoreGetDiskAttributes";
343 return "(81)ReceiveCoreSearchDir";
347 return "(83)FindUnique";
349 return "(84)FindClose";
351 return "(A0)ReceiveNTTransact";
353 return "(A2)ReceiveNTCreateX";
355 return "(A4)ReceiveNTCancel";
357 return "(A5)ReceiveNTRename";
359 return "(C0)OpenPrintFile";
361 return "(C1)WritePrintFile";
363 return "(C2)ClosePrintFile";
365 return "(C3)GetPrintQueue";
367 return "(D8)ReadBulk";
369 return "(D9)WriteBulk";
371 return "(DA)WriteBulkData";
373 return "unknown SMB op";
377 char * myCrt_2Dispatch(int i)
382 return "unknown SMB op-2";
384 return "S(00)CreateFile";
386 return "S(01)FindFirst";
388 return "S(02)FindNext"; /* FindNext */
390 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
394 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
396 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
398 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
400 return "S(08)??_ReceiveTran2SetFileInfo";
402 return "S(09)??_ReceiveTran2FSCTL";
404 return "S(0a)_ReceiveTran2IOCTL";
406 return "S(0b)_ReceiveTran2FindNotifyFirst";
408 return "S(0c)_ReceiveTran2FindNotifyNext";
410 return "S(0d)_ReceiveTran2CreateDirectory";
412 return "S(0e)_ReceiveTran2SessionSetup";
414 return "S(10)_ReceiveTran2GetDfsReferral";
416 return "S(11)_ReceiveTran2ReportDfsInconsistency";
420 char * myCrt_RapDispatch(int i)
425 return "unknown RAP OP";
427 return "RAP(0)NetShareEnum";
429 return "RAP(1)NetShareGetInfo";
431 return "RAP(13)NetServerGetInfo";
433 return "RAP(63)NetWkStaGetInfo";
437 /* scache must be locked */
438 unsigned int smb_Attributes(cm_scache_t *scp)
442 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
443 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
444 scp->fileType == CM_SCACHETYPE_INVALID)
446 attrs = SMB_ATTR_DIRECTORY;
447 #ifdef SPECIAL_FOLDERS
448 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
449 #endif /* SPECIAL_FOLDERS */
450 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
451 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
456 * We used to mark a file RO if it was in an RO volume, but that
457 * turns out to be impolitic in NT. See defect 10007.
460 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
461 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
463 if ((scp->unixModeBits & 0222) == 0)
464 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
470 /* Check if the named file/dir is a dotfile/dotdir */
471 /* String pointed to by lastComp can have leading slashes, but otherwise should have
472 no other patch components */
473 unsigned int smb_IsDotFile(char *lastComp) {
476 /* skip over slashes */
477 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
482 /* nulls, curdir and parent dir doesn't count */
488 if(*(s+1) == '.' && !*(s + 2))
495 static int ExtractBits(WORD bits, short start, short len)
502 num = bits << (16 - end);
503 num = num >> ((16 - end) + start);
509 void ShowUnixTime(char *FuncName, time_t unixTime)
514 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
516 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
517 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
519 int day, month, year, sec, min, hour;
522 day = ExtractBits(wDate, 0, 5);
523 month = ExtractBits(wDate, 5, 4);
524 year = ExtractBits(wDate, 9, 7) + 1980;
526 sec = ExtractBits(wTime, 0, 5);
527 min = ExtractBits(wTime, 5, 6);
528 hour = ExtractBits(wTime, 11, 5);
530 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
531 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
537 /* Determine if we are observing daylight savings time */
538 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
540 TIME_ZONE_INFORMATION timeZoneInformation;
541 SYSTEMTIME utc, local, localDST;
543 /* Get the time zone info. NT uses this to calc if we are in DST. */
544 GetTimeZoneInformation(&timeZoneInformation);
546 /* Return the daylight bias */
547 *pDstBias = timeZoneInformation.DaylightBias;
549 /* Return the bias */
550 *pBias = timeZoneInformation.Bias;
552 /* Now determine if DST is being observed */
554 /* Get the UTC (GMT) time */
557 /* Convert UTC time to local time using the time zone info. If we are
558 observing DST, the calculated local time will include this.
560 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
562 /* Set the daylight bias to 0. The daylight bias is the amount of change
563 * in time that we use for daylight savings time. By setting this to 0
564 * we cause there to be no change in time during daylight savings time.
566 timeZoneInformation.DaylightBias = 0;
568 /* Convert the utc time to local time again, but this time without any
569 adjustment for daylight savings time.
571 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
573 /* If the two times are different, then it means that the localDST that
574 we calculated includes the daylight bias, and therefore we are
575 observing daylight savings time.
577 *pDST = localDST.wHour != local.wHour;
580 /* Determine if we are observing daylight savings time */
581 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
587 *pDstBias = -60; /* where can this be different? */
593 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
595 BOOL dst; /* Will be TRUE if observing DST */
596 LONG dstBias; /* Offset from local time if observing DST */
597 LONG bias; /* Offset from GMT for local time */
600 * This function will adjust the last write time to compensate
601 * for two bugs in the smb client:
603 * 1) During Daylight Savings Time, the LastWriteTime is ahead
604 * in time by the DaylightBias (ignoring the sign - the
605 * DaylightBias is always stored as a negative number). If
606 * the DaylightBias is -60, then the LastWriteTime will be
607 * ahead by 60 minutes.
609 * 2) If the local time zone is a positive offset from GMT, then
610 * the LastWriteTime will be the correct local time plus the
611 * Bias (ignoring the sign - a positive offset from GMT is
612 * always stored as a negative Bias). If the Bias is -120,
613 * then the LastWriteTime will be ahead by 120 minutes.
615 * These bugs can occur at the same time.
618 GetTimeZoneInfo(&dst, &dstBias, &bias);
620 /* First adjust for DST */
622 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
624 /* Now adjust for a positive offset from GMT (a negative bias). */
626 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
629 #ifndef USE_NUMERIC_TIME_CONV
631 * Calculate the difference (in seconds) between local time and GMT.
632 * This enables us to convert file times to kludge-GMT.
638 struct tm gmt_tm, local_tm;
639 int days, hours, minutes, seconds;
642 gmt_tm = *(gmtime(&t));
643 local_tm = *(localtime(&t));
645 days = local_tm.tm_yday - gmt_tm.tm_yday;
646 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
647 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
648 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
652 #endif /* USE_NUMERIC_TIME_CONV */
655 #ifdef USE_NUMERIC_TIME_CONV
656 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
658 // Note that LONGLONG is a 64-bit value
661 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
662 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
663 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
666 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
671 time_t ersatz_unixTime;
674 * Must use kludge-GMT instead of real GMT.
675 * kludge-GMT is computed by adding time zone difference to localtime.
678 * ltp = gmtime(&unixTime);
680 ersatz_unixTime = unixTime - smb_NowTZ;
681 ltp = localtime(&ersatz_unixTime);
683 /* if we fail, make up something */
686 localJunk.tm_year = 89 - 20;
687 localJunk.tm_mon = 4;
688 localJunk.tm_mday = 12;
689 localJunk.tm_hour = 0;
690 localJunk.tm_min = 0;
691 localJunk.tm_sec = 0;
694 stm.wYear = ltp->tm_year + 1900;
695 stm.wMonth = ltp->tm_mon + 1;
696 stm.wDayOfWeek = ltp->tm_wday;
697 stm.wDay = ltp->tm_mday;
698 stm.wHour = ltp->tm_hour;
699 stm.wMinute = ltp->tm_min;
700 stm.wSecond = ltp->tm_sec;
701 stm.wMilliseconds = 0;
703 SystemTimeToFileTime(&stm, largeTimep);
705 #endif /* USE_NUMERIC_TIME_CONV */
707 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
709 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
710 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
711 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
713 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
715 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
716 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
718 *ft = LargeIntegerMultiplyByLong(*ft, 60);
719 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
722 ut = ConvertLongToLargeInteger(unixTime);
723 ut = LargeIntegerMultiplyByLong(ut, 10000000);
724 *ft = LargeIntegerAdd(*ft, ut);
729 #ifdef USE_NUMERIC_TIME_CONV
730 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
732 // Note that LONGLONG is a 64-bit value
735 ll = largeTimep->dwHighDateTime;
737 ll += largeTimep->dwLowDateTime;
739 ll -= 116444736000000000;
742 *unixTimep = (DWORD)ll;
744 #else /* USE_NUMERIC_TIME_CONV */
745 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
751 FileTimeToSystemTime(largeTimep, &stm);
753 lt.tm_year = stm.wYear - 1900;
754 lt.tm_mon = stm.wMonth - 1;
755 lt.tm_wday = stm.wDayOfWeek;
756 lt.tm_mday = stm.wDay;
757 lt.tm_hour = stm.wHour;
758 lt.tm_min = stm.wMinute;
759 lt.tm_sec = stm.wSecond;
762 save_timezone = _timezone;
763 _timezone += smb_NowTZ;
764 *unixTimep = mktime(<);
765 _timezone = save_timezone;
767 #endif /* USE_NUMERIC_TIME_CONV */
769 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
771 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
772 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
773 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
777 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
778 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
779 a = LargeIntegerMultiplyByLong(a, 60);
780 a = LargeIntegerMultiplyByLong(a, 10000000);
782 /* subtract it from ft */
783 a = LargeIntegerSubtract(*ft, a);
785 /* divide down to seconds */
786 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
790 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
798 ltp = localtime((time_t*) &t);
800 /* if we fail, make up something */
803 localJunk.tm_year = 89 - 20;
804 localJunk.tm_mon = 4;
805 localJunk.tm_mday = 12;
806 localJunk.tm_hour = 0;
807 localJunk.tm_min = 0;
808 localJunk.tm_sec = 0;
811 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
812 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
813 *searchTimep = (dosDate<<16) | dosTime;
816 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
818 unsigned short dosDate;
819 unsigned short dosTime;
822 dosDate = (unsigned short) (searchTime & 0xffff);
823 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
825 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
826 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
827 localTm.tm_mday = (dosDate) & 0x1f;
828 localTm.tm_hour = (dosTime>>11) & 0x1f;
829 localTm.tm_min = (dosTime >> 5) & 0x3f;
830 localTm.tm_sec = (dosTime & 0x1f) * 2;
831 localTm.tm_isdst = -1; /* compute whether DST in effect */
833 *unixTimep = mktime(&localTm);
836 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
838 time_t diff_t = unixTime - smb_localZero;
839 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
840 osi_assert(diff_t < _UI32_MAX);
842 *dosUTimep = (afs_uint32)diff_t;
845 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
848 *unixTimep = dosTime + smb_localZero;
850 /* dosTime seems to be already adjusted for GMT */
851 *unixTimep = dosTime;
855 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
859 lock_ObtainWrite(&smb_rctLock);
860 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
861 if (lsn == vcp->lsn && lana == vcp->lana) {
862 smb_HoldVCNoLock(vcp);
866 if (!vcp && (flags & SMB_FLAG_CREATE)) {
867 vcp = malloc(sizeof(*vcp));
868 memset(vcp, 0, sizeof(*vcp));
869 lock_ObtainWrite(&smb_globalLock);
870 vcp->vcID = ++numVCs;
871 lock_ReleaseWrite(&smb_globalLock);
872 vcp->refCount = 2; /* smb_allVCsp and caller */
875 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
876 vcp->nextp = smb_allVCsp;
878 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
883 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
884 /* We must obtain a challenge for extended auth
885 * in case the client negotiates smb v3
887 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
888 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
889 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
890 ULONG lsaRespSize = 0;
892 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
894 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
901 if (nts != STATUS_SUCCESS)
902 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
903 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
904 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
906 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
907 LsaFreeReturnBuffer(lsaResp);
910 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
912 if (numVCs >= CM_SESSION_RESERVED) {
913 lock_ObtainWrite(&smb_globalLock);
915 lock_ReleaseWrite(&smb_globalLock);
916 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
919 lock_ReleaseWrite(&smb_rctLock);
923 int smb_IsStarMask(char *maskp)
928 for(i=0; i<11; i++) {
930 if (tc == '?' || tc == '*' || tc == '>')
936 void smb_ReleaseVCInternal(smb_vc_t *vcp)
941 osi_assert(vcp->refCount-- != 0);
946 if (vcp->refCount == 0) {
947 /* remove VCP from smb_deadVCsp */
948 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
954 lock_FinalizeMutex(&vcp->mx);
955 memset(vcp,0,sizeof(smb_vc_t));
960 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
962 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
963 smb_ReleaseVCInternal(vcp);
966 void smb_ReleaseVC(smb_vc_t *vcp)
968 lock_ObtainWrite(&smb_rctLock);
969 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
970 smb_ReleaseVCInternal(vcp);
971 lock_ReleaseWrite(&smb_rctLock);
974 void smb_HoldVCNoLock(smb_vc_t *vcp)
977 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
980 void smb_HoldVC(smb_vc_t *vcp)
982 lock_ObtainWrite(&smb_rctLock);
984 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
985 lock_ReleaseWrite(&smb_rctLock);
988 void smb_CleanupDeadVC(smb_vc_t *vcp)
996 smb_user_t *uidpIter;
997 smb_user_t *uidpNext;
1000 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1002 lock_ObtainWrite(&smb_rctLock);
1003 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1004 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1006 if (fidpIter->delete)
1009 fid = fidpIter->fid;
1010 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1012 smb_HoldFIDNoLock(fidpIter);
1013 lock_ReleaseWrite(&smb_rctLock);
1015 smb_CloseFID(vcp, fidpIter, NULL, 0);
1016 smb_ReleaseFID(fidpIter);
1018 lock_ObtainWrite(&smb_rctLock);
1019 fidpNext = vcp->fidsp;
1022 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1023 tidpNext = tidpIter->nextp;
1024 if (tidpIter->delete)
1026 tidpIter->delete = 1;
1028 tid = tidpIter->tid;
1029 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1031 smb_HoldTIDNoLock(tidpIter);
1032 lock_ReleaseWrite(&smb_rctLock);
1034 smb_ReleaseTID(tidpIter);
1036 lock_ObtainWrite(&smb_rctLock);
1037 tidpNext = vcp->tidsp;
1040 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1041 uidpNext = uidpIter->nextp;
1042 if (uidpIter->delete)
1044 uidpIter->delete = 1;
1046 /* do not add an additional reference count for the smb_user_t
1047 * as the smb_vc_t already is holding a reference */
1048 lock_ReleaseWrite(&smb_rctLock);
1050 smb_ReleaseUID(uidpIter);
1052 lock_ObtainWrite(&smb_rctLock);
1053 uidpNext = vcp->usersp;
1056 /* remove VCP from smb_allVCsp */
1057 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1060 vcp->nextp = smb_deadVCsp;
1062 /* We intentionally do not keep a reference to the
1063 * vcp once it is placed on the deadVCsp list. This
1064 * allows the refcount to reach 0 so we can delete
1066 smb_ReleaseVCNoLock(vcp);
1070 lock_ReleaseWrite(&smb_rctLock);
1071 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1074 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1078 lock_ObtainWrite(&smb_rctLock);
1079 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1080 if (tid == tidp->tid) {
1085 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1086 tidp = malloc(sizeof(*tidp));
1087 memset(tidp, 0, sizeof(*tidp));
1088 tidp->nextp = vcp->tidsp;
1091 smb_HoldVCNoLock(vcp);
1093 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1096 lock_ReleaseWrite(&smb_rctLock);
1100 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1105 void smb_ReleaseTID(smb_tid_t *tidp)
1112 lock_ObtainWrite(&smb_rctLock);
1113 osi_assert(tidp->refCount-- > 0);
1114 if (tidp->refCount == 0 && (tidp->delete)) {
1115 ltpp = &tidp->vcp->tidsp;
1116 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1120 osi_assert(tp != NULL);
1122 lock_FinalizeMutex(&tidp->mx);
1123 userp = tidp->userp; /* remember to drop ref later */
1125 smb_ReleaseVCNoLock(tidp->vcp);
1128 lock_ReleaseWrite(&smb_rctLock);
1130 cm_ReleaseUser(userp);
1133 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1135 smb_user_t *uidp = NULL;
1137 lock_ObtainWrite(&smb_rctLock);
1138 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1139 if (uid == uidp->userID) {
1141 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1143 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1147 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1148 uidp = malloc(sizeof(*uidp));
1149 memset(uidp, 0, sizeof(*uidp));
1150 uidp->nextp = vcp->usersp;
1151 uidp->refCount = 2; /* one for the vcp and one for the caller */
1153 smb_HoldVCNoLock(vcp);
1155 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1157 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1159 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1161 lock_ReleaseWrite(&smb_rctLock);
1165 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1167 smb_username_t *unp= NULL;
1169 lock_ObtainWrite(&smb_rctLock);
1170 for(unp = usernamesp; unp; unp = unp->nextp) {
1171 if (stricmp(unp->name, usern) == 0 &&
1172 stricmp(unp->machine, machine) == 0) {
1177 if (!unp && (flags & SMB_FLAG_CREATE)) {
1178 unp = malloc(sizeof(*unp));
1179 memset(unp, 0, sizeof(*unp));
1181 unp->nextp = usernamesp;
1182 unp->name = strdup(usern);
1183 unp->machine = strdup(machine);
1185 lock_InitializeMutex(&unp->mx, "username_t mutex");
1186 if (flags & SMB_FLAG_AFSLOGON)
1187 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1190 lock_ReleaseWrite(&smb_rctLock);
1194 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1196 smb_user_t *uidp= NULL;
1198 lock_ObtainWrite(&smb_rctLock);
1199 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1202 if (stricmp(uidp->unp->name, usern) == 0) {
1204 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1205 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1210 lock_ReleaseWrite(&smb_rctLock);
1214 void smb_ReleaseUsername(smb_username_t *unp)
1217 smb_username_t **lupp;
1218 cm_user_t *userp = NULL;
1219 time_t now = osi_Time();
1221 lock_ObtainWrite(&smb_rctLock);
1222 osi_assert(unp->refCount-- > 0);
1223 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1224 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1226 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1230 osi_assert(up != NULL);
1232 up->nextp = NULL; /* do not remove this */
1233 lock_FinalizeMutex(&unp->mx);
1239 lock_ReleaseWrite(&smb_rctLock);
1242 cm_ReleaseUser(userp);
1246 void smb_HoldUIDNoLock(smb_user_t *uidp)
1251 void smb_ReleaseUID(smb_user_t *uidp)
1255 smb_username_t *unp = NULL;
1257 lock_ObtainWrite(&smb_rctLock);
1258 osi_assert(uidp->refCount-- > 0);
1259 if (uidp->refCount == 0) {
1260 lupp = &uidp->vcp->usersp;
1261 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1265 osi_assert(up != NULL);
1267 lock_FinalizeMutex(&uidp->mx);
1269 smb_ReleaseVCNoLock(uidp->vcp);
1273 lock_ReleaseWrite(&smb_rctLock);
1277 cm_ReleaseUserVCRef(unp->userp);
1278 smb_ReleaseUsername(unp);
1282 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1284 cm_user_t *up = NULL;
1289 lock_ObtainMutex(&uidp->mx);
1291 up = uidp->unp->userp;
1294 lock_ReleaseMutex(&uidp->mx);
1300 /* retrieve a held reference to a user structure corresponding to an incoming
1302 * corresponding release function is cm_ReleaseUser.
1304 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1307 cm_user_t *up = NULL;
1310 smbp = (smb_t *) inp;
1311 uidp = smb_FindUID(vcp, smbp->uid, 0);
1315 up = smb_GetUserFromUID(uidp);
1317 smb_ReleaseUID(uidp);
1322 * Return a pointer to a pathname extracted from a TID structure. The
1323 * TID structure is not held; assume it won't go away.
1325 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1330 tidp = smb_FindTID(vcp, tid, 0);
1334 if (tidp->flags & SMB_TIDFLAG_IPC) {
1335 code = CM_ERROR_TIDIPC;
1336 /* tidp->pathname would be NULL, but that's fine */
1338 *treepath = tidp->pathname;
1339 smb_ReleaseTID(tidp);
1344 /* check to see if we have a chained fid, that is, a fid that comes from an
1345 * OpenAndX message that ran earlier in this packet. In this case, the fid
1346 * field in a read, for example, request, isn't set, since the value is
1347 * supposed to be inherited from the openAndX call.
1349 int smb_ChainFID(int fid, smb_packet_t *inp)
1351 if (inp->fid == 0 || inp->inCount == 0)
1357 /* are we a priv'd user? What does this mean on NT? */
1358 int smb_SUser(cm_user_t *userp)
1363 /* find a file ID. If we pass in 0 we select an unused File ID.
1364 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1365 * smb_fid_t data structure if desired File ID cannot be found.
1367 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1372 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1375 lock_ObtainWrite(&smb_rctLock);
1376 /* figure out if we need to allocate a new file ID */
1379 fid = vcp->fidCounter;
1383 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1384 if (fid == fidp->fid) {
1387 if (fid == 0xFFFF) {
1389 "New FID number wraps on vcp 0x%x", vcp);
1399 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1400 char eventName[MAX_PATH];
1402 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1403 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1404 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1405 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1406 thrd_CloseHandle(event);
1408 if (fid == 0xFFFF) {
1409 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1415 fidp = malloc(sizeof(*fidp));
1416 memset(fidp, 0, sizeof(*fidp));
1417 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1420 smb_HoldVCNoLock(vcp);
1421 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1423 fidp->curr_chunk = fidp->prev_chunk = -2;
1424 fidp->raw_write_event = event;
1426 vcp->fidCounter = fid+1;
1427 if (vcp->fidCounter == 0xFFFF) {
1428 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1430 vcp->fidCounter = 1;
1435 lock_ReleaseWrite(&smb_rctLock);
1439 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1444 void smb_ReleaseFID(smb_fid_t *fidp)
1446 cm_scache_t *scp = NULL;
1447 cm_user_t *userp = NULL;
1448 smb_vc_t *vcp = NULL;
1449 smb_ioctl_t *ioctlp;
1451 lock_ObtainWrite(&smb_rctLock);
1452 osi_assert(fidp->refCount-- > 0);
1453 lock_ObtainMutex(&fidp->mx);
1454 if (fidp->refCount == 0 && (fidp->delete)) {
1457 scp = fidp->scp; /* release after lock is released */
1459 userp = fidp->userp;
1463 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1464 thrd_CloseHandle(fidp->raw_write_event);
1466 /* and see if there is ioctl stuff to free */
1467 ioctlp = fidp->ioctlp;
1470 cm_FreeSpace(ioctlp->prefix);
1471 if (ioctlp->inAllocp)
1472 free(ioctlp->inAllocp);
1473 if (ioctlp->outAllocp)
1474 free(ioctlp->outAllocp);
1477 lock_ReleaseMutex(&fidp->mx);
1478 lock_FinalizeMutex(&fidp->mx);
1482 smb_ReleaseVCNoLock(vcp);
1484 lock_ReleaseMutex(&fidp->mx);
1486 lock_ReleaseWrite(&smb_rctLock);
1488 /* now release the scache structure */
1490 cm_ReleaseSCache(scp);
1493 cm_ReleaseUser(userp);
1497 * Case-insensitive search for one string in another;
1498 * used to find variable names in submount pathnames.
1500 static char *smb_stristr(char *str1, char *str2)
1504 for (cursor = str1; *cursor; cursor++)
1505 if (stricmp(cursor, str2) == 0)
1512 * Substitute a variable value for its name in a submount pathname. Variable
1513 * name has been identified by smb_stristr() and is in substr. Variable name
1514 * length (plus one) is in substr_size. Variable value is in newstr.
1516 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1521 strcpy(temp, substr + substr_size - 1);
1522 strcpy(substr, newstr);
1526 char VNUserName[] = "%USERNAME%";
1527 char VNLCUserName[] = "%LCUSERNAME%";
1528 char VNComputerName[] = "%COMPUTERNAME%";
1529 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1532 /* List available shares */
1533 int smb_ListShares()
1537 char shareBuf[4096];
1545 /*strcpy(shareNameList[num_shares], "all");
1546 strcpy(pathNameList[num_shares++], "/afs");*/
1547 fprintf(stderr, "The following shares are available:\n");
1548 fprintf(stderr, "Share Name (AFS Path)\n");
1549 fprintf(stderr, "---------------------\n");
1550 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1553 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1554 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1556 strcpy(sbmtpath, cm_confDir);
1558 strcat(sbmtpath, "/afsdsbmt.ini");
1559 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1560 shareBuf, sizeof(shareBuf),
1566 this_share = shareBuf;
1570 /*strcpy(shareNameList[num_shares], this_share);*/
1571 len = GetPrivateProfileString("AFS Submounts", this_share,
1578 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1581 if (*p == '\\') *p = '/'; /* change to / */
1585 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1586 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1589 while (*this_share != 0) this_share++; /* find next NUL */
1590 this_share++; /* skip past the NUL */
1591 } while (*this_share != 0); /* stop at final NUL */
1597 typedef struct smb_findShare_rock {
1601 } smb_findShare_rock_t;
1603 #define SMB_FINDSHARE_EXACT_MATCH 1
1604 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1606 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1610 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1611 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1612 if(!stricmp(dep->name, vrock->shareName))
1613 matchType = SMB_FINDSHARE_EXACT_MATCH;
1615 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1616 if(vrock->match) free(vrock->match);
1617 vrock->match = strdup(dep->name);
1618 vrock->matchType = matchType;
1620 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1621 return CM_ERROR_STOPNOW;
1627 /* find a shareName in the table of submounts */
1628 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1632 char pathName[1024];
1637 char sbmtpath[MAX_PATH];
1642 DWORD allSubmount = 1;
1644 /* if allSubmounts == 0, only return the //mountRoot/all share
1645 * if in fact it has been been created in the subMounts table.
1646 * This is to allow sites that want to restrict access to the
1649 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1650 0, KEY_QUERY_VALUE, &parmKey);
1651 if (code == ERROR_SUCCESS) {
1652 len = sizeof(allSubmount);
1653 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1654 (BYTE *) &allSubmount, &len);
1655 if (code != ERROR_SUCCESS) {
1658 RegCloseKey (parmKey);
1661 if (allSubmount && _stricmp(shareName, "all") == 0) {
1666 /* In case, the all share is disabled we need to still be able
1667 * to handle ioctl requests
1669 if (_stricmp(shareName, "ioctl$") == 0) {
1670 *pathNamep = strdup("/.__ioctl__");
1674 if (_stricmp(shareName, "IPC$") == 0 ||
1675 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1676 _stricmp(shareName, "DESKTOP.INI") == 0
1683 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1684 0, KEY_QUERY_VALUE, &parmKey);
1685 if (code == ERROR_SUCCESS) {
1686 len = sizeof(pathName);
1687 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1688 (BYTE *) pathName, &len);
1689 if (code != ERROR_SUCCESS)
1691 RegCloseKey (parmKey);
1696 strcpy(sbmtpath, cm_confDir);
1697 strcat(sbmtpath, "/afsdsbmt.ini");
1698 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1699 pathName, sizeof(pathName), sbmtpath);
1701 if (len != 0 && len != sizeof(pathName) - 1) {
1702 /* We can accept either unix or PC style AFS pathnames. Convert
1703 * Unix-style to PC style here for internal use.
1706 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1707 p += strlen(cm_mountRoot); /* skip mount path */
1710 if (*q == '/') *q = '\\'; /* change to \ */
1716 if (var = smb_stristr(p, VNUserName)) {
1717 if (uidp && uidp->unp)
1718 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1720 smb_subst(p, var, sizeof(VNUserName)," ");
1722 else if (var = smb_stristr(p, VNLCUserName))
1724 if (uidp && uidp->unp)
1725 strcpy(temp, uidp->unp->name);
1729 smb_subst(p, var, sizeof(VNLCUserName), temp);
1731 else if (var = smb_stristr(p, VNComputerName))
1733 sizeTemp = sizeof(temp);
1734 GetComputerName((LPTSTR)temp, &sizeTemp);
1735 smb_subst(p, var, sizeof(VNComputerName), temp);
1737 else if (var = smb_stristr(p, VNLCComputerName))
1739 sizeTemp = sizeof(temp);
1740 GetComputerName((LPTSTR)temp, &sizeTemp);
1742 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1747 *pathNamep = strdup(p);
1752 /* First lookup shareName in root.afs */
1754 smb_findShare_rock_t vrock;
1756 char * p = shareName;
1759 /* attempt to locate a partial match in root.afs. This is because
1760 when using the ANSI RAP calls, the share name is limited to 13 chars
1761 and hence is truncated. Of course we prefer exact matches. */
1763 thyper.HighPart = 0;
1766 vrock.shareName = shareName;
1768 vrock.matchType = 0;
1770 cm_HoldSCache(cm_data.rootSCachep);
1771 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1772 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1773 cm_ReleaseSCache(cm_data.rootSCachep);
1775 if (vrock.matchType) {
1776 sprintf(pathName,"/%s/",vrock.match);
1777 *pathNamep = strdup(strlwr(pathName));
1782 /* if we get here, there was no match for the share in root.afs */
1783 /* so try to create \\<netbiosName>\<cellname> */
1788 /* Get the full name for this cell */
1789 code = cm_SearchCellFile(p, temp, 0, 0);
1790 #ifdef AFS_AFSDB_ENV
1791 if (code && cm_dnsEnabled) {
1793 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1796 /* construct the path */
1798 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1799 *pathNamep = strdup(strlwr(pathName));
1808 /* Client-side offline caching policy types */
1809 #define CSC_POLICY_MANUAL 0
1810 #define CSC_POLICY_DOCUMENTS 1
1811 #define CSC_POLICY_PROGRAMS 2
1812 #define CSC_POLICY_DISABLE 3
1814 int smb_FindShareCSCPolicy(char *shareName)
1820 int retval = CSC_POLICY_MANUAL;
1822 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1823 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1826 REG_OPTION_NON_VOLATILE,
1832 len = sizeof(policy);
1833 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1835 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1837 else if (stricmp(policy, "documents") == 0)
1839 retval = CSC_POLICY_DOCUMENTS;
1841 else if (stricmp(policy, "programs") == 0)
1843 retval = CSC_POLICY_PROGRAMS;
1845 else if (stricmp(policy, "disable") == 0)
1847 retval = CSC_POLICY_DISABLE;
1850 RegCloseKey(hkCSCPolicy);
1854 /* find a dir search structure by cookie value, and return it held.
1855 * Must be called with smb_globalLock held.
1857 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1859 smb_dirSearch_t *dsp;
1861 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1862 if (dsp->cookie == cookie) {
1863 if (dsp != smb_firstDirSearchp) {
1864 /* move to head of LRU queue, too, if we're not already there */
1865 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1866 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1867 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1868 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1869 if (!smb_lastDirSearchp)
1870 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1872 lock_ObtainMutex(&dsp->mx);
1874 lock_ReleaseMutex(&dsp->mx);
1880 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1881 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1882 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1888 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1890 lock_ObtainWrite(&smb_globalLock);
1891 lock_ObtainMutex(&dsp->mx);
1892 dsp->flags |= SMB_DIRSEARCH_DELETE;
1893 if (dsp->scp != NULL) {
1894 lock_ObtainMutex(&dsp->scp->mx);
1895 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1896 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1897 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1898 dsp->scp->bulkStatProgress = hones;
1900 lock_ReleaseMutex(&dsp->scp->mx);
1902 lock_ReleaseMutex(&dsp->mx);
1903 lock_ReleaseWrite(&smb_globalLock);
1906 /* Must be called with the smb_globalLock held */
1907 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1909 cm_scache_t *scp = NULL;
1911 lock_ObtainMutex(&dsp->mx);
1912 osi_assert(dsp->refCount-- > 0);
1913 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1914 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1915 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1916 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1917 lock_ReleaseMutex(&dsp->mx);
1918 lock_FinalizeMutex(&dsp->mx);
1922 lock_ReleaseMutex(&dsp->mx);
1924 /* do this now to avoid spurious locking hierarchy creation */
1926 cm_ReleaseSCache(scp);
1929 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1931 lock_ObtainWrite(&smb_globalLock);
1932 smb_ReleaseDirSearchNoLock(dsp);
1933 lock_ReleaseWrite(&smb_globalLock);
1936 /* find a dir search structure by cookie value, and return it held */
1937 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1939 smb_dirSearch_t *dsp;
1941 lock_ObtainWrite(&smb_globalLock);
1942 dsp = smb_FindDirSearchNoLock(cookie);
1943 lock_ReleaseWrite(&smb_globalLock);
1947 /* GC some dir search entries, in the address space expected by the specific protocol.
1948 * Must be called with smb_globalLock held; release the lock temporarily.
1950 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1951 void smb_GCDirSearches(int isV3)
1953 smb_dirSearch_t *prevp;
1954 smb_dirSearch_t *tp;
1955 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1959 victimCount = 0; /* how many have we got so far */
1960 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1961 /* we'll move tp from queue, so
1964 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1965 /* if no one is using this guy, and we're either in the new protocol,
1966 * or we're in the old one and this is a small enough ID to be useful
1967 * to the old protocol, GC this guy.
1969 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1970 /* hold and delete */
1971 lock_ObtainMutex(&tp->mx);
1972 tp->flags |= SMB_DIRSEARCH_DELETE;
1973 lock_ReleaseMutex(&tp->mx);
1974 victimsp[victimCount++] = tp;
1978 /* don't do more than this */
1979 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1983 /* now release them */
1984 for (i = 0; i < victimCount; i++) {
1985 smb_ReleaseDirSearchNoLock(victimsp[i]);
1989 /* function for allocating a dir search entry. We need these to remember enough context
1990 * since we don't get passed the path from call to call during a directory search.
1992 * Returns a held dir search structure, and bumps the reference count on the vnode,
1993 * since it saves a pointer to the vnode.
1995 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1997 smb_dirSearch_t *dsp;
2003 lock_ObtainWrite(&smb_globalLock);
2006 /* what's the biggest ID allowed in this version of the protocol */
2007 maxAllowed = isV3 ? 65535 : 255;
2008 if (smb_dirSearchCounter > maxAllowed)
2009 smb_dirSearchCounter = 1;
2011 start = smb_dirSearchCounter;
2014 /* twice so we have enough tries to find guys we GC after one pass;
2015 * 10 extra is just in case I mis-counted.
2017 if (++counter > 2*maxAllowed+10)
2018 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2020 if (smb_dirSearchCounter > maxAllowed) {
2021 smb_dirSearchCounter = 1;
2023 if (smb_dirSearchCounter == start) {
2025 smb_GCDirSearches(isV3);
2028 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2030 /* don't need to watch for refcount zero and deleted, since
2031 * we haven't dropped the global lock.
2033 lock_ObtainMutex(&dsp->mx);
2035 lock_ReleaseMutex(&dsp->mx);
2036 ++smb_dirSearchCounter;
2040 dsp = malloc(sizeof(*dsp));
2041 memset(dsp, 0, sizeof(*dsp));
2042 dsp->cookie = smb_dirSearchCounter;
2043 ++smb_dirSearchCounter;
2045 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2046 dsp->lastTime = osi_Time();
2047 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2048 if (!smb_lastDirSearchp)
2049 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2052 lock_ReleaseWrite(&smb_globalLock);
2056 static smb_packet_t *GetPacket(void)
2060 unsigned int npar, seg, tb_sel;
2063 lock_ObtainWrite(&smb_globalLock);
2064 tbp = smb_packetFreeListp;
2066 smb_packetFreeListp = tbp->nextp;
2067 lock_ReleaseWrite(&smb_globalLock);
2070 tbp = calloc(65540,1);
2072 tbp = malloc(sizeof(smb_packet_t));
2074 tbp->magic = SMB_PACKETMAGIC;
2077 tbp->resumeCode = 0;
2083 tbp->ncb_length = 0;
2088 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
2091 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2093 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
2095 osi_panic("",__FILE__,__LINE__);
2098 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
2103 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
2104 tbp->dos_pkt_sel = tb_sel;
2107 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2112 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2116 memcpy(tbp, pkt, sizeof(smb_packet_t));
2117 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2119 smb_HoldVC(tbp->vcp);
2123 static NCB *GetNCB(void)
2128 unsigned int npar, seg, tb_sel;
2131 lock_ObtainWrite(&smb_globalLock);
2132 tbp = smb_ncbFreeListp;
2134 smb_ncbFreeListp = tbp->nextp;
2135 lock_ReleaseWrite(&smb_globalLock);
2138 tbp = calloc(sizeof(*tbp),1);
2140 tbp = malloc(sizeof(*tbp));
2141 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
2144 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2146 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2148 osi_panic("",__FILE__,__LINE__);
2150 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2155 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
2156 tbp->dos_ncb_sel = tb_sel;
2158 tbp->magic = SMB_NCBMAGIC;
2161 osi_assert(tbp->magic == SMB_NCBMAGIC);
2163 memset(&tbp->ncb, 0, sizeof(NCB));
2166 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2171 void smb_FreePacket(smb_packet_t *tbp)
2173 smb_vc_t * vcp = NULL;
2174 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2176 lock_ObtainWrite(&smb_globalLock);
2177 tbp->nextp = smb_packetFreeListp;
2178 smb_packetFreeListp = tbp;
2179 tbp->magic = SMB_PACKETMAGIC;
2183 tbp->resumeCode = 0;
2189 tbp->ncb_length = 0;
2191 lock_ReleaseWrite(&smb_globalLock);
2197 static void FreeNCB(NCB *bufferp)
2201 tbp = (smb_ncb_t *) bufferp;
2202 osi_assert(tbp->magic == SMB_NCBMAGIC);
2204 lock_ObtainWrite(&smb_globalLock);
2205 tbp->nextp = smb_ncbFreeListp;
2206 smb_ncbFreeListp = tbp;
2207 lock_ReleaseWrite(&smb_globalLock);
2210 /* get a ptr to the data part of a packet, and its count */
2211 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2215 unsigned char *afterParmsp;
2217 parmBytes = *smbp->wctp << 1;
2218 afterParmsp = smbp->wctp + parmBytes + 1;
2220 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2221 if (nbytesp) *nbytesp = dataBytes;
2223 /* don't forget to skip the data byte count, since it follows
2224 * the parameters; that's where the "2" comes from below.
2226 return (unsigned char *) (afterParmsp + 2);
2229 /* must set all the returned parameters before playing around with the
2230 * data region, since the data region is located past the end of the
2231 * variable number of parameters.
2233 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2235 unsigned char *afterParmsp;
2237 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2239 *afterParmsp++ = dsize & 0xff;
2240 *afterParmsp = (dsize>>8) & 0xff;
2243 /* return the parm'th parameter in the smbp packet */
2244 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2247 unsigned char *parmDatap;
2249 parmCount = *smbp->wctp;
2251 if (parm >= parmCount) {
2254 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2255 parm, parmCount, smbp->ncb_length);
2256 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2257 parm, parmCount, smbp->ncb_length);
2259 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2260 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2262 osi_panic(s, __FILE__, __LINE__);
2264 parmDatap = smbp->wctp + (2*parm) + 1;
2266 return parmDatap[0] + (parmDatap[1] << 8);
2269 /* return the parm'th parameter in the smbp packet */
2270 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2273 unsigned char *parmDatap;
2275 parmCount = *smbp->wctp;
2277 if (parm * 2 + offset >= parmCount * 2) {
2280 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2281 parm, offset, parmCount, smbp->ncb_length);
2283 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2284 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2286 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2287 parm, offset, parmCount, smbp->ncb_length);
2288 osi_panic(s, __FILE__, __LINE__);
2290 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2292 return parmDatap[0] + (parmDatap[1] << 8);
2295 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2299 /* make sure we have enough slots */
2300 if (*smbp->wctp <= slot)
2301 *smbp->wctp = slot+1;
2303 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2304 *parmDatap++ = parmValue & 0xff;
2305 *parmDatap = (parmValue>>8) & 0xff;
2308 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2312 /* make sure we have enough slots */
2313 if (*smbp->wctp <= slot)
2314 *smbp->wctp = slot+2;
2316 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2317 *parmDatap++ = parmValue & 0xff;
2318 *parmDatap++ = (parmValue>>8) & 0xff;
2319 *parmDatap++ = (parmValue>>16) & 0xff;
2320 *parmDatap++ = (parmValue>>24) & 0xff;
2323 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2328 /* make sure we have enough slots */
2329 if (*smbp->wctp <= slot)
2330 *smbp->wctp = slot+4;
2332 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2334 *parmDatap++ = *parmValuep++;
2337 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2341 /* make sure we have enough slots */
2342 if (*smbp->wctp <= slot) {
2343 if (smbp->oddByte) {
2345 *smbp->wctp = slot+1;
2350 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2351 *parmDatap++ = parmValue & 0xff;
2354 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2358 lastSlashp = strrchr(inPathp, '\\');
2360 *lastComponentp = lastSlashp;
2363 if (inPathp == lastSlashp)
2365 *outPathp++ = *inPathp++;
2374 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2379 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2384 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2390 tlen = inp[0] + (inp[1]<<8);
2391 inp += 2; /* skip length field */
2394 *chainpp = inp + tlen;
2403 /* format a packet as a response */
2404 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2409 outp = (smb_t *) op;
2411 /* zero the basic structure through the smb_wct field, and zero the data
2412 * size field, assuming that wct stays zero; otherwise, you have to
2413 * explicitly set the data size field, too.
2415 inSmbp = (smb_t *) inp;
2416 memset(outp, 0, sizeof(smb_t)+2);
2422 outp->com = inSmbp->com;
2423 outp->tid = inSmbp->tid;
2424 outp->pid = inSmbp->pid;
2425 outp->uid = inSmbp->uid;
2426 outp->mid = inSmbp->mid;
2427 outp->res[0] = inSmbp->res[0];
2428 outp->res[1] = inSmbp->res[1];
2429 op->inCom = inSmbp->com;
2431 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2432 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2434 /* copy fields in generic packet area */
2435 op->wctp = &outp->wct;
2438 /* send a (probably response) packet; vcp tells us to whom to send it.
2439 * we compute the length by looking at wct and bcc fields.
2441 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2458 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2461 memset((char *)ncbp, 0, sizeof(NCB));
2463 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2464 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2465 extra += tp[0] + (tp[1]<<8);
2466 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2467 extra += 3; /* wct and length fields */
2469 ncbp->ncb_length = extra; /* bytes to send */
2470 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2471 ncbp->ncb_lana_num = vcp->lana;
2472 ncbp->ncb_command = NCBSEND; /* op means send data */
2474 ncbp->ncb_buffer = (char *) inp;/* packet */
2475 code = Netbios(ncbp);
2477 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2478 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2480 /* copy header information from virtual to DOS address space */
2481 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2482 code = Netbios(ncbp, dos_ncb);
2486 const char * s = ncb_error_string(code);
2487 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2489 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2492 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2495 lock_ObtainMutex(&vcp->mx);
2496 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2497 lock_ReleaseMutex(&vcp->mx);
2498 lock_ObtainWrite(&smb_globalLock);
2499 dead_sessions[vcp->session] = TRUE;
2500 lock_ReleaseWrite(&smb_globalLock);
2501 smb_CleanupDeadVC(vcp);
2508 void smb_MapNTError(long code, unsigned long *NTStatusp)
2510 unsigned long NTStatus;
2512 /* map CM_ERROR_* errors to NT 32-bit status codes */
2513 /* NT Status codes are listed in ntstatus.h not winerror.h */
2514 if (code == CM_ERROR_NOSUCHCELL) {
2515 NTStatus = 0xC000000FL; /* No such file */
2517 else if (code == CM_ERROR_NOSUCHVOLUME) {
2518 NTStatus = 0xC000000FL; /* No such file */
2520 else if (code == CM_ERROR_TIMEDOUT) {
2522 NTStatus = 0xC00000CFL; /* Sharing Paused */
2524 NTStatus = 0x00000102L; /* Timeout */
2527 else if (code == CM_ERROR_RETRY) {
2528 NTStatus = 0xC000022DL; /* Retry */
2530 else if (code == CM_ERROR_NOACCESS) {
2531 NTStatus = 0xC0000022L; /* Access denied */
2533 else if (code == CM_ERROR_READONLY) {
2534 NTStatus = 0xC00000A2L; /* Write protected */
2536 else if (code == CM_ERROR_NOSUCHFILE) {
2537 NTStatus = 0xC000000FL; /* No such file */
2539 else if (code == CM_ERROR_NOSUCHPATH) {
2540 NTStatus = 0xC000003AL; /* Object path not found */
2542 else if (code == CM_ERROR_TOOBIG) {
2543 NTStatus = 0xC000007BL; /* Invalid image format */
2545 else if (code == CM_ERROR_INVAL) {
2546 NTStatus = 0xC000000DL; /* Invalid parameter */
2548 else if (code == CM_ERROR_BADFD) {
2549 NTStatus = 0xC0000008L; /* Invalid handle */
2551 else if (code == CM_ERROR_BADFDOP) {
2552 NTStatus = 0xC0000022L; /* Access denied */
2554 else if (code == CM_ERROR_EXISTS) {
2555 NTStatus = 0xC0000035L; /* Object name collision */
2557 else if (code == CM_ERROR_NOTEMPTY) {
2558 NTStatus = 0xC0000101L; /* Directory not empty */
2560 else if (code == CM_ERROR_CROSSDEVLINK) {
2561 NTStatus = 0xC00000D4L; /* Not same device */
2563 else if (code == CM_ERROR_NOTDIR) {
2564 NTStatus = 0xC0000103L; /* Not a directory */
2566 else if (code == CM_ERROR_ISDIR) {
2567 NTStatus = 0xC00000BAL; /* File is a directory */
2569 else if (code == CM_ERROR_BADOP) {
2571 /* I have no idea where this comes from */
2572 NTStatus = 0xC09820FFL; /* SMB no support */
2574 NTStatus = 0xC00000BBL; /* Not supported */
2575 #endif /* COMMENT */
2577 else if (code == CM_ERROR_BADSHARENAME) {
2578 NTStatus = 0xC00000CCL; /* Bad network name */
2580 else if (code == CM_ERROR_NOIPC) {
2582 NTStatus = 0xC0000022L; /* Access Denied */
2584 NTStatus = 0xC000013DL; /* Remote Resources */
2587 else if (code == CM_ERROR_CLOCKSKEW) {
2588 NTStatus = 0xC0000133L; /* Time difference at DC */
2590 else if (code == CM_ERROR_BADTID) {
2591 NTStatus = 0xC0982005L; /* SMB bad TID */
2593 else if (code == CM_ERROR_USESTD) {
2594 NTStatus = 0xC09820FBL; /* SMB use standard */
2596 else if (code == CM_ERROR_QUOTA) {
2598 NTStatus = 0xC0000044L; /* Quota exceeded */
2600 NTStatus = 0xC000007FL; /* Disk full */
2603 else if (code == CM_ERROR_SPACE) {
2604 NTStatus = 0xC000007FL; /* Disk full */
2606 else if (code == CM_ERROR_ATSYS) {
2607 NTStatus = 0xC0000033L; /* Object name invalid */
2609 else if (code == CM_ERROR_BADNTFILENAME) {
2610 NTStatus = 0xC0000033L; /* Object name invalid */
2612 else if (code == CM_ERROR_WOULDBLOCK) {
2613 NTStatus = 0xC0000055L; /* Lock not granted */
2615 else if (code == CM_ERROR_SHARING_VIOLATION) {
2616 NTStatus = 0xC0000043L; /* Sharing violation */
2618 else if (code == CM_ERROR_LOCK_CONFLICT) {
2619 NTStatus = 0xC0000054L; /* Lock conflict */
2621 else if (code == CM_ERROR_PARTIALWRITE) {
2622 NTStatus = 0xC000007FL; /* Disk full */
2624 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2625 NTStatus = 0xC0000023L; /* Buffer too small */
2627 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2628 NTStatus = 0xC0000035L; /* Object name collision */
2630 else if (code == CM_ERROR_BADPASSWORD) {
2631 NTStatus = 0xC000006DL; /* unknown username or bad password */
2633 else if (code == CM_ERROR_BADLOGONTYPE) {
2634 NTStatus = 0xC000015BL; /* logon type not granted */
2636 else if (code == CM_ERROR_GSSCONTINUE) {
2637 NTStatus = 0xC0000016L; /* more processing required */
2639 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2641 NTStatus = 0xC0000280L; /* reparse point not resolved */
2643 NTStatus = 0xC0000022L; /* Access Denied */
2646 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2647 NTStatus = 0xC0000257L; /* Path Not Covered */
2650 else if (code == CM_ERROR_ALLBUSY) {
2651 NTStatus = 0xC00000BFL; /* Network Busy */
2653 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2654 NTStatus = 0xC0000350L; /* Remote Host Down */
2657 /* we do not want to be telling the SMB/CIFS client that
2658 * the AFS Client Service is busy or down.
2660 else if (code == CM_ERROR_ALLBUSY ||
2661 code == CM_ERROR_ALLOFFLINE ||
2662 code == CM_ERROR_ALLDOWN) {
2663 NTStatus = 0xC00000BEL; /* Bad Network Path */
2666 else if (code == RXKADUNKNOWNKEY) {
2667 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2669 NTStatus = 0xC0982001L; /* SMB non-specific error */
2672 *NTStatusp = NTStatus;
2673 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2676 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2677 unsigned char *classp)
2679 unsigned char class;
2680 unsigned short error;
2682 /* map CM_ERROR_* errors to SMB errors */
2683 if (code == CM_ERROR_NOSUCHCELL) {
2685 error = 3; /* bad path */
2687 else if (code == CM_ERROR_NOSUCHVOLUME) {
2689 error = 3; /* bad path */
2691 else if (code == CM_ERROR_TIMEDOUT) {
2693 error = 81; /* server is paused */
2695 else if (code == CM_ERROR_RETRY) {
2696 class = 2; /* shouldn't happen */
2699 else if (code == CM_ERROR_NOACCESS) {
2701 error = 4; /* bad access */
2703 else if (code == CM_ERROR_READONLY) {
2705 error = 19; /* read only */
2707 else if (code == CM_ERROR_NOSUCHFILE) {
2709 error = 2; /* ENOENT! */
2711 else if (code == CM_ERROR_NOSUCHPATH) {
2713 error = 3; /* Bad path */
2715 else if (code == CM_ERROR_TOOBIG) {
2717 error = 11; /* bad format */
2719 else if (code == CM_ERROR_INVAL) {
2720 class = 2; /* server non-specific error code */
2723 else if (code == CM_ERROR_BADFD) {
2725 error = 6; /* invalid file handle */
2727 else if (code == CM_ERROR_BADFDOP) {
2728 class = 1; /* invalid op on FD */
2731 else if (code == CM_ERROR_EXISTS) {
2733 error = 80; /* file already exists */
2735 else if (code == CM_ERROR_NOTEMPTY) {
2737 error = 5; /* delete directory not empty */
2739 else if (code == CM_ERROR_CROSSDEVLINK) {
2741 error = 17; /* EXDEV */
2743 else if (code == CM_ERROR_NOTDIR) {
2744 class = 1; /* bad path */
2747 else if (code == CM_ERROR_ISDIR) {
2748 class = 1; /* access denied; DOS doesn't have a good match */
2751 else if (code == CM_ERROR_BADOP) {
2755 else if (code == CM_ERROR_BADSHARENAME) {
2759 else if (code == CM_ERROR_NOIPC) {
2761 error = 4; /* bad access */
2763 else if (code == CM_ERROR_CLOCKSKEW) {
2764 class = 1; /* invalid function */
2767 else if (code == CM_ERROR_BADTID) {
2771 else if (code == CM_ERROR_USESTD) {
2775 else if (code == CM_ERROR_REMOTECONN) {
2779 else if (code == CM_ERROR_QUOTA) {
2780 if (vcp->flags & SMB_VCFLAG_USEV3) {
2782 error = 39; /* disk full */
2786 error = 5; /* access denied */
2789 else if (code == CM_ERROR_SPACE) {
2790 if (vcp->flags & SMB_VCFLAG_USEV3) {
2792 error = 39; /* disk full */
2796 error = 5; /* access denied */
2799 else if (code == CM_ERROR_PARTIALWRITE) {
2801 error = 39; /* disk full */
2803 else if (code == CM_ERROR_ATSYS) {
2805 error = 2; /* ENOENT */
2807 else if (code == CM_ERROR_WOULDBLOCK) {
2809 error = 33; /* lock conflict */
2811 else if (code == CM_ERROR_LOCK_CONFLICT) {
2813 error = 33; /* lock conflict */
2815 else if (code == CM_ERROR_SHARING_VIOLATION) {
2817 error = 33; /* lock conflict */
2819 else if (code == CM_ERROR_NOFILES) {
2821 error = 18; /* no files in search */
2823 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2825 error = 183; /* Samba uses this */
2827 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2828 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2830 error = 2; /* bad password */
2832 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2834 error = 3; /* bad path */
2843 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2846 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2848 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2849 return CM_ERROR_BADOP;
2852 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2854 unsigned short EchoCount, i;
2855 char *data, *outdata;
2858 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2860 for (i=1; i<=EchoCount; i++) {
2861 data = smb_GetSMBData(inp, &dataSize);
2862 smb_SetSMBParm(outp, 0, i);
2863 smb_SetSMBDataLength(outp, dataSize);
2864 outdata = smb_GetSMBData(outp, NULL);
2865 memcpy(outdata, data, dataSize);
2866 smb_SendPacket(vcp, outp);
2872 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2875 long count, minCount, finalCount;
2880 cm_user_t *userp = NULL;
2884 char *rawBuf = NULL;
2886 dos_ptr rawBuf = NULL;
2893 fd = smb_GetSMBParm(inp, 0);
2894 count = smb_GetSMBParm(inp, 3);
2895 minCount = smb_GetSMBParm(inp, 4);
2896 offset.HighPart = 0; /* too bad */
2897 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2899 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2900 fd, offset.LowPart, count);
2902 fidp = smb_FindFID(vcp, fd, 0);
2906 pid = ((smb_t *) inp)->pid;
2908 LARGE_INTEGER LOffset, LLength;
2911 key = cm_GenerateKey(vcp->vcID, pid, fd);
2913 LOffset.HighPart = 0;
2914 LOffset.LowPart = offset.LowPart;
2915 LLength.HighPart = 0;
2916 LLength.LowPart = count;
2918 lock_ObtainMutex(&fidp->scp->mx);
2919 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2920 lock_ReleaseMutex(&fidp->scp->mx);
2926 lock_ObtainMutex(&smb_RawBufLock);
2928 /* Get a raw buf, from head of list */
2929 rawBuf = smb_RawBufs;
2931 smb_RawBufs = *(char **)smb_RawBufs;
2933 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2936 lock_ReleaseMutex(&smb_RawBufLock);
2940 lock_ObtainMutex(&fidp->mx);
2941 if (fidp->flags & SMB_FID_IOCTL)
2943 lock_ReleaseMutex(&fidp->mx);
2945 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2947 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2950 /* Give back raw buffer */
2951 lock_ObtainMutex(&smb_RawBufLock);
2953 *((char **) rawBuf) = smb_RawBufs;
2955 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2958 smb_RawBufs = rawBuf;
2959 lock_ReleaseMutex(&smb_RawBufLock);
2962 smb_ReleaseFID(fidp);
2965 lock_ReleaseMutex(&fidp->mx);
2967 userp = smb_GetUserFromVCP(vcp, inp);
2970 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2972 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2973 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2974 userp, &finalCount, TRUE /* rawFlag */);
2981 cm_ReleaseUser(userp);
2984 smb_ReleaseFID(fidp);
2989 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2991 memset((char *)ncbp, 0, sizeof(NCB));
2993 ncbp->ncb_length = (unsigned short) finalCount;
2994 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2995 ncbp->ncb_lana_num = vcp->lana;
2996 ncbp->ncb_command = NCBSEND;
2997 ncbp->ncb_buffer = rawBuf;
3000 code = Netbios(ncbp);
3002 code = Netbios(ncbp, dos_ncb);
3005 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3008 /* Give back raw buffer */
3009 lock_ObtainMutex(&smb_RawBufLock);
3011 *((char **) rawBuf) = smb_RawBufs;
3013 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3016 smb_RawBufs = rawBuf;
3017 lock_ReleaseMutex(&smb_RawBufLock);
3023 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3025 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3030 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3032 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3037 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3044 int protoIndex; /* index we're using */
3049 char protocol_array[10][1024]; /* protocol signature of the client */
3050 int caps; /* capabilities */
3053 TIME_ZONE_INFORMATION tzi;
3055 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3058 namep = smb_GetSMBData(inp, &dbytes);
3061 coreProtoIndex = -1; /* not found */
3064 while(namex < dbytes) {
3065 osi_Log1(smb_logp, "Protocol %s",
3066 osi_LogSaveString(smb_logp, namep+1));
3067 strcpy(protocol_array[tcounter], namep+1);
3069 /* namep points at the first protocol, or really, a 0x02
3070 * byte preceding the null-terminated ASCII name.
3072 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3073 coreProtoIndex = tcounter;
3075 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3076 v3ProtoIndex = tcounter;
3078 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3079 NTProtoIndex = tcounter;
3082 /* compute size of protocol entry */
3083 entryLength = (int)strlen(namep+1);
3084 entryLength += 2; /* 0x02 bytes and null termination */
3086 /* advance over this protocol entry */
3087 namex += entryLength;
3088 namep += entryLength;
3089 tcounter++; /* which proto entry we're looking at */
3092 lock_ObtainMutex(&vcp->mx);
3093 if (NTProtoIndex != -1) {
3094 protoIndex = NTProtoIndex;
3095 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3097 else if (v3ProtoIndex != -1) {
3098 protoIndex = v3ProtoIndex;
3099 vcp->flags |= SMB_VCFLAG_USEV3;
3101 else if (coreProtoIndex != -1) {
3102 protoIndex = coreProtoIndex;
3103 vcp->flags |= SMB_VCFLAG_USECORE;
3105 else protoIndex = -1;
3106 lock_ReleaseMutex(&vcp->mx);
3108 if (protoIndex == -1)
3109 return CM_ERROR_INVAL;
3110 else if (NTProtoIndex != -1) {
3111 smb_SetSMBParm(outp, 0, protoIndex);
3112 if (smb_authType != SMB_AUTH_NONE) {
3113 smb_SetSMBParmByte(outp, 1,
3114 NEGOTIATE_SECURITY_USER_LEVEL |
3115 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3117 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3119 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3120 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3121 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3122 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3123 /* The session key is not a well documented field however most clients
3124 * will echo back the session key to the server. Currently we are using
3125 * the same value for all sessions. We should generate a random value
3126 * and store it into the vcp
3128 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3129 smb_SetSMBParm(outp, 8, 1);
3131 * Tried changing the capabilities to support for W2K - defect 117695
3132 * Maybe something else needs to be changed here?
3136 smb_SetSMBParmLong(outp, 9, 0x43fd);
3138 smb_SetSMBParmLong(outp, 9, 0x251);
3141 * 32-bit error codes *
3146 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3148 NTNEGOTIATE_CAPABILITY_DFS |
3150 NTNEGOTIATE_CAPABILITY_NTFIND |
3151 NTNEGOTIATE_CAPABILITY_RAWMODE |
3152 NTNEGOTIATE_CAPABILITY_NTSMB;
3154 if ( smb_authType == SMB_AUTH_EXTENDED )
3155 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3157 smb_SetSMBParmLong(outp, 9, caps);
3159 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3160 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3161 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3163 GetTimeZoneInformation(&tzi);
3164 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3166 if (smb_authType == SMB_AUTH_NTLM) {
3167 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3168 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3169 /* paste in encryption key */
3170 datap = smb_GetSMBData(outp, NULL);
3171 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3172 /* and the faux domain name */
3173 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3174 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3178 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3180 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3182 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3184 datap = smb_GetSMBData(outp, NULL);
3185 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3188 datap += sizeof(smb_ServerGUID);
3189 memcpy(datap, secBlob, secBlobLength);
3193 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3194 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3197 else if (v3ProtoIndex != -1) {
3198 smb_SetSMBParm(outp, 0, protoIndex);
3200 /* NOTE: Extended authentication cannot be negotiated with v3
3201 * therefore we fail over to NTLM
3203 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3204 smb_SetSMBParm(outp, 1,
3205 NEGOTIATE_SECURITY_USER_LEVEL |
3206 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3208 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3210 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3211 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3212 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3213 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3214 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3215 smb_SetSMBParm(outp, 7, 1);
3217 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3218 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3219 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3221 GetTimeZoneInformation(&tzi);
3222 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3224 /* NOTE: Extended authentication cannot be negotiated with v3
3225 * therefore we fail over to NTLM
3227 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3228 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3229 smb_SetSMBParm(outp, 12, 0); /* resvd */
3230 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3231 datap = smb_GetSMBData(outp, NULL);
3232 /* paste in a new encryption key */
3233 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3234 /* and the faux domain name */
3235 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3237 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3238 smb_SetSMBParm(outp, 12, 0); /* resvd */
3239 smb_SetSMBDataLength(outp, 0);
3242 else if (coreProtoIndex != -1) { /* not really supported anymore */
3243 smb_SetSMBParm(outp, 0, protoIndex);
3244 smb_SetSMBDataLength(outp, 0);
3249 void smb_CheckVCs(void)
3251 smb_vc_t * vcp, *nextp;
3252 smb_packet_t * outp = GetPacket();
3255 lock_ObtainWrite(&smb_rctLock);
3256 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3260 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3263 smb_HoldVCNoLock(vcp);
3265 smb_HoldVCNoLock(nextp);
3266 smb_FormatResponsePacket(vcp, NULL, outp);
3267 smbp = (smb_t *)outp;
3268 outp->inCom = smbp->com = 0x2b /* Echo */;
3276 smb_SetSMBParm(outp, 0, 0);
3277 smb_SetSMBDataLength(outp, 0);
3278 lock_ReleaseWrite(&smb_rctLock);
3280 smb_SendPacket(vcp, outp);
3282 lock_ObtainWrite(&smb_rctLock);
3283 smb_ReleaseVCNoLock(vcp);
3285 smb_ReleaseVCNoLock(nextp);
3287 lock_ReleaseWrite(&smb_rctLock);
3288 smb_FreePacket(outp);
3291 void smb_Daemon(void *parmp)
3293 afs_uint32 count = 0;
3294 smb_username_t **unpp;
3297 while(smbShutdownFlag == 0) {
3301 if (smbShutdownFlag == 1)
3304 if ((count % 72) == 0) { /* every five minutes */
3306 time_t old_localZero = smb_localZero;
3308 /* Initialize smb_localZero */
3309 myTime.tm_isdst = -1; /* compute whether on DST or not */
3310 myTime.tm_year = 70;
3316 smb_localZero = mktime(&myTime);
3318 #ifndef USE_NUMERIC_TIME_CONV
3319 smb_CalculateNowTZ();
3320 #endif /* USE_NUMERIC_TIME_CONV */
3321 #ifdef AFS_FREELANCE
3322 if ( smb_localZero != old_localZero )
3323 cm_noteLocalMountPointChange();
3329 /* GC smb_username_t objects that will no longer be used */
3331 lock_ObtainWrite(&smb_rctLock);
3332 for ( unpp=&usernamesp; *unpp; ) {
3334 smb_username_t *unp;
3336 lock_ObtainMutex(&(*unpp)->mx);
3337 if ( (*unpp)->refCount > 0 ||
3338 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3339 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3341 else if (!smb_LogoffTokenTransfer ||
3342 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3344 lock_ReleaseMutex(&(*unpp)->mx);
3352 lock_FinalizeMutex(&unp->mx);
3358 lock_ReleaseWrite(&smb_rctLock);
3359 cm_ReleaseUser(userp);
3360 lock_ObtainWrite(&smb_rctLock);
3363 unpp = &(*unpp)->nextp;
3366 lock_ReleaseWrite(&smb_rctLock);
3368 /* XXX GC dir search entries */
3372 void smb_WaitingLocksDaemon()
3374 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3375 smb_waitingLock_t *wl, *wlNext;
3378 smb_packet_t *inp, *outp;
3382 while (smbShutdownFlag == 0) {
3383 lock_ObtainWrite(&smb_globalLock);
3384 nwlRequest = smb_allWaitingLocks;
3385 if (nwlRequest == NULL) {
3386 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3391 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3398 lock_ObtainWrite(&smb_globalLock);
3400 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3402 wlRequest = nwlRequest;
3403 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3404 lock_ReleaseWrite(&smb_globalLock);
3408 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3409 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3412 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3414 /* wl->state is either _DONE or _WAITING. _ERROR
3415 would no longer be on the queue. */
3416 code = cm_RetryLock( wl->lockp,
3417 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3420 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3421 } else if (code != CM_ERROR_WOULDBLOCK) {
3422 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3427 if (code == CM_ERROR_WOULDBLOCK) {
3430 if (wlRequest->timeRemaining != 0xffffffff
3431 && (wlRequest->timeRemaining -= 1000) < 0)
3443 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3446 scp = wlRequest->scp;
3450 lock_ObtainMutex(&scp->mx);
3452 for (wl = wlRequest->locks; wl; wl = wlNext) {
3453 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3455 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3456 wl->LLength, wl->key, NULL, &req);
3458 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3463 lock_ReleaseMutex(&scp->mx);
3467 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3470 for (wl = wlRequest->locks; wl; wl = wlNext) {
3471 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3472 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3477 vcp = wlRequest->vcp;
3478 inp = wlRequest->inp;
3479 outp = wlRequest->outp;
3481 ncbp->ncb_length = inp->ncb_length;
3482 inp->spacep = cm_GetSpace();
3484 /* Remove waitingLock from list */
3485 lock_ObtainWrite(&smb_globalLock);
3486 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3488 lock_ReleaseWrite(&smb_globalLock);
3490 /* Resume packet processing */
3492 smb_SetSMBDataLength(outp, 0);
3493 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3494 outp->resumeCode = code;
3496 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3499 cm_FreeSpace(inp->spacep);
3500 smb_FreePacket(inp);
3501 smb_FreePacket(outp);
3503 cm_ReleaseSCache(wlRequest->scp);
3506 } while (nwlRequest && smbShutdownFlag == 0);
3511 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3513 osi_Log0(smb_logp, "SMB receive get disk attributes");
3515 smb_SetSMBParm(outp, 0, 32000);
3516 smb_SetSMBParm(outp, 1, 64);
3517 smb_SetSMBParm(outp, 2, 1024);
3518 smb_SetSMBParm(outp, 3, 30000);
3519 smb_SetSMBParm(outp, 4, 0);
3520 smb_SetSMBDataLength(outp, 0);
3524 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3528 unsigned short newTid;
3529 char shareName[256];
3537 osi_Log0(smb_logp, "SMB receive tree connect");
3539 /* parse input parameters */
3540 tp = smb_GetSMBData(inp, NULL);
3541 pathp = smb_ParseASCIIBlock(tp, &tp);
3542 if (smb_StoreAnsiFilenames)
3543 OemToChar(pathp,pathp);
3544 passwordp = smb_ParseASCIIBlock(tp, &tp);
3545 tp = strrchr(pathp, '\\');
3547 return CM_ERROR_BADSMB;
3548 strcpy(shareName, tp+1);
3550 lock_ObtainMutex(&vcp->mx);
3551 newTid = vcp->tidCounter++;
3552 lock_ReleaseMutex(&vcp->mx);
3554 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3555 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3556 userp = smb_GetUserFromUID(uidp);
3557 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3559 smb_ReleaseUID(uidp);
3561 smb_ReleaseTID(tidp);
3562 return CM_ERROR_BADSHARENAME;
3564 lock_ObtainMutex(&tidp->mx);
3565 tidp->userp = userp;
3566 tidp->pathname = sharePath;
3567 lock_ReleaseMutex(&tidp->mx);
3568 smb_ReleaseTID(tidp);
3570 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3571 smb_SetSMBParm(rsp, 1, newTid);
3572 smb_SetSMBDataLength(rsp, 0);
3574 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3578 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3582 if (*inp++ != 0x1) return NULL;
3583 tlen = inp[0] + (inp[1]<<8);
3584 inp += 2; /* skip length field */
3587 *chainpp = inp + tlen;
3590 if (lengthp) *lengthp = tlen;
3595 /* set maskp to the mask part of the incoming path.
3596 * Mask is 11 bytes long (8.3 with the dot elided).
3597 * Returns true if succeeds with a valid name, otherwise it does
3598 * its best, but returns false.
3600 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3608 /* starts off valid */
3611 /* mask starts out all blanks */
3612 memset(maskp, ' ', 11);
3614 /* find last backslash, or use whole thing if there is none */
3615 tp = strrchr(pathp, '\\');
3616 if (!tp) tp = pathp;
3617 else tp++; /* skip slash */
3621 /* names starting with a dot are illegal */
3622 if (*tp == '.') valid8Dot3 = 0;
3626 if (tc == 0) return valid8Dot3;
3627 if (tc == '.' || tc == '"') break;
3628 if (i < 8) *up++ = tc;
3629 else valid8Dot3 = 0;
3632 /* if we get here, tp point after the dot */
3633 up = maskp+8; /* ext goes here */
3640 if (tc == '.' || tc == '"')
3643 /* copy extension if not too long */
3653 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3663 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3665 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3669 /* otherwise, we have a valid 8.3 name; see if we have a match,
3670 * treating '?' as a wildcard in maskp (but not in the file name).
3672 tp1 = umask; /* real name, in mask format */
3673 tp2 = maskp; /* mask, in mask format */
3674 for(i=0; i<11; i++) {
3675 tc1 = *tp1++; /* char from real name */
3676 tc2 = *tp2++; /* char from mask */
3677 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3678 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3681 if (tc2 == '?' && tc1 != ' ')
3688 /* we got a match */
3692 char *smb_FindMask(char *pathp)
3696 tp = strrchr(pathp, '\\'); /* find last slash */
3699 return tp+1; /* skip the slash */
3701 return pathp; /* no slash, return the entire path */
3704 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3706 unsigned char *pathp;
3708 unsigned char mask[11];
3709 unsigned char *statBlockp;
3710 unsigned char initStatBlock[21];
3713 osi_Log0(smb_logp, "SMB receive search volume");
3715 /* pull pathname and stat block out of request */
3716 tp = smb_GetSMBData(inp, NULL);
3717 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3718 osi_assert(pathp != NULL);
3719 if (smb_StoreAnsiFilenames)
3720 OemToChar(pathp,pathp);
3721 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3722 osi_assert(statBlockp != NULL);
3724 statBlockp = initStatBlock;
3728 /* for returning to caller */
3729 smb_Get8Dot3MaskFromPath(mask, pathp);
3731 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3732 tp = smb_GetSMBData(outp, NULL);
3734 *tp++ = 43; /* bytes in a dir entry */
3735 *tp++ = 0; /* high byte in counter */
3737 /* now marshall the dir entry, starting with the search status */
3738 *tp++ = statBlockp[0]; /* Reserved */
3739 memcpy(tp, mask, 11); tp += 11; /* FileName */
3741 /* now pass back server use info, with 1st byte non-zero */
3743 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3745 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3747 *tp++ = 0x8; /* attribute: volume */
3757 /* 4 byte file size */
3763 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3764 memset(tp, ' ', 13);
3767 /* set the length of the data part of the packet to 43 + 3, for the dir
3768 * entry plus the 5 and the length fields.
3770 smb_SetSMBDataLength(outp, 46);
3774 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3775 cm_user_t *userp, cm_req_t *reqp)
3783 smb_dirListPatch_t *patchp;
3784 smb_dirListPatch_t *npatchp;
3786 for (patchp = *dirPatchespp; patchp; patchp =
3787 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3789 dptr = patchp->dptr;
3791 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3793 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3794 *dptr++ = SMB_ATTR_HIDDEN;
3797 lock_ObtainMutex(&scp->mx);
3798 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3799 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3801 lock_ReleaseMutex(&scp->mx);
3802 cm_ReleaseSCache(scp);
3803 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3804 *dptr++ = SMB_ATTR_HIDDEN;
3808 attr = smb_Attributes(scp);
3809 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3810 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3811 attr |= SMB_ATTR_HIDDEN;
3815 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3818 shortTemp = (unsigned short) (dosTime & 0xffff);
3819 *((u_short *)dptr) = shortTemp;
3822 /* and copy out date */
3823 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3824 *((u_short *)dptr) = shortTemp;
3827 /* copy out file length */
3828 *((u_long *)dptr) = scp->length.LowPart;
3830 lock_ReleaseMutex(&scp->mx);
3831 cm_ReleaseSCache(scp);
3834 /* now free the patches */
3835 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3836 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3840 /* and mark the list as empty */
3841 *dirPatchespp = NULL;
3846 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3855 smb_dirListPatch_t *dirListPatchesp;
3856 smb_dirListPatch_t *curPatchp;
3860 osi_hyper_t dirLength;
3861 osi_hyper_t bufferOffset;
3862 osi_hyper_t curOffset;
3864 unsigned char *inCookiep;
3865 smb_dirSearch_t *dsp;
3869 unsigned long clientCookie;
3870 cm_pageHeader_t *pageHeaderp;
3871 cm_user_t *userp = NULL;
3878 long nextEntryCookie;
3879 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3880 char resByte; /* reserved byte from the cookie */
3881 char *op; /* output data ptr */
3882 char *origOp; /* original value of op */
3883 cm_space_t *spacep; /* for pathname buffer */
3894 maxCount = smb_GetSMBParm(inp, 0);
3896 dirListPatchesp = NULL;
3898 caseFold = CM_FLAG_CASEFOLD;
3900 tp = smb_GetSMBData(inp, NULL);
3901 pathp = smb_ParseASCIIBlock(tp, &tp);
3902 if (smb_StoreAnsiFilenames)
3903 OemToChar(pathp,pathp);
3904 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3906 /* bail out if request looks bad */
3907 if (!tp || !pathp) {
3908 return CM_ERROR_BADSMB;
3911 /* We can handle long names */
3912 if (vcp->flags & SMB_VCFLAG_USENT)
3913 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3915 /* make sure we got a whole search status */
3916 if (dataLength < 21) {
3917 nextCookie = 0; /* start at the beginning of the dir */
3920 attribute = smb_GetSMBParm(inp, 1);
3922 /* handle volume info in another function */
3923 if (attribute & 0x8)
3924 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3926 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3927 maxCount, osi_LogSaveString(smb_logp, pathp));
3929 if (*pathp == 0) { /* null pathp, treat as root dir */
3930 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3931 return CM_ERROR_NOFILES;
3935 dsp = smb_NewDirSearch(0);
3936 dsp->attribute = attribute;
3937 smb_Get8Dot3MaskFromPath(mask, pathp);
3938 memcpy(dsp->mask, mask, 11);
3940 /* track if this is likely to match a lot of entries */
3941 if (smb_IsStarMask(mask))
3946 /* pull the next cookie value out of the search status block */
3947 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3948 + (inCookiep[16]<<24);
3949 dsp = smb_FindDirSearch(inCookiep[12]);
3951 /* can't find dir search status; fatal error */
3952 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3953 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3954 return CM_ERROR_BADFD;
3956 attribute = dsp->attribute;
3957 resByte = inCookiep[0];
3959 /* copy out client cookie, in host byte order. Don't bother
3960 * interpreting it, since we're just passing it through, anyway.
3962 memcpy(&clientCookie, &inCookiep[17], 4);
3964 memcpy(mask, dsp->mask, 11);
3966 /* assume we're doing a star match if it has continued for more
3972 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3973 nextCookie, dsp->cookie, attribute);
3975 userp = smb_GetUserFromVCP(vcp, inp);
3977 /* try to get the vnode for the path name next */
3978 lock_ObtainMutex(&dsp->mx);
3984 spacep = inp->spacep;
3985 smb_StripLastComponent(spacep->data, NULL, pathp);
3986 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3988 lock_ReleaseMutex(&dsp->mx);
3989 cm_ReleaseUser(userp);
3990 smb_DeleteDirSearch(dsp);
3991 smb_ReleaseDirSearch(dsp);
3992 return CM_ERROR_NOFILES;
3994 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3995 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3998 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3999 cm_ReleaseSCache(scp);
4000 lock_ReleaseMutex(&dsp->mx);
4001 cm_ReleaseUser(userp);
4002 smb_DeleteDirSearch(dsp);
4003 smb_ReleaseDirSearch(dsp);
4004 if ( WANTS_DFS_PATHNAMES(inp) )
4005 return CM_ERROR_PATH_NOT_COVERED;
4007 return CM_ERROR_BADSHARENAME;
4009 #endif /* DFS_SUPPORT */
4012 /* we need one hold for the entry we just stored into,
4013 * and one for our own processing. When we're done with this
4014 * function, we'll drop the one for our own processing.
4015 * We held it once from the namei call, and so we do another hold
4019 lock_ObtainMutex(&scp->mx);
4020 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4021 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4022 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4023 dsp->flags |= SMB_DIRSEARCH_BULKST;
4025 lock_ReleaseMutex(&scp->mx);
4028 lock_ReleaseMutex(&dsp->mx);
4030 cm_ReleaseUser(userp);
4031 smb_DeleteDirSearch(dsp);
4032 smb_ReleaseDirSearch(dsp);
4036 /* reserves space for parameter; we'll adjust it again later to the
4037 * real count of the # of entries we returned once we've actually
4038 * assembled the directory listing.
4040 smb_SetSMBParm(outp, 0, 0);
4042 /* get the directory size */
4043 lock_ObtainMutex(&scp->mx);
4044 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4045 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4047 lock_ReleaseMutex(&scp->mx);
4048 cm_ReleaseSCache(scp);
4049 cm_ReleaseUser(userp);
4050 smb_DeleteDirSearch(dsp);
4051 smb_ReleaseDirSearch(dsp);
4055 dirLength = scp->length;
4057 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4058 curOffset.HighPart = 0;
4059 curOffset.LowPart = nextCookie;
4060 origOp = op = smb_GetSMBData(outp, NULL);
4061 /* and write out the basic header */
4062 *op++ = 5; /* variable block */
4063 op += 2; /* skip vbl block length; we'll fill it in later */
4067 /* make sure that curOffset.LowPart doesn't point to the first
4068 * 32 bytes in the 2nd through last dir page, and that it doesn't
4069 * point at the first 13 32-byte chunks in the first dir page,
4070 * since those are dir and page headers, and don't contain useful
4073 temp = curOffset.LowPart & (2048-1);
4074 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4075 /* we're in the first page */
4076 if (temp < 13*32) temp = 13*32;
4079 /* we're in a later dir page */
4080 if (temp < 32) temp = 32;
4083 /* make sure the low order 5 bits are zero */
4086 /* now put temp bits back ito curOffset.LowPart */
4087 curOffset.LowPart &= ~(2048-1);
4088 curOffset.LowPart |= temp;
4090 /* check if we've returned all the names that will fit in the
4093 if (returnedNames >= maxCount) {
4094 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4095 returnedNames, maxCount);
4099 /* check if we've passed the dir's EOF */
4100 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4102 /* see if we can use the bufferp we have now; compute in which page
4103 * the current offset would be, and check whether that's the offset
4104 * of the buffer we have. If not, get the buffer.
4106 thyper.HighPart = curOffset.HighPart;
4107 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4108 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4111 buf_Release(bufferp);
4114 lock_ReleaseMutex(&scp->mx);
4115 lock_ObtainRead(&scp->bufCreateLock);
4116 code = buf_Get(scp, &thyper, &bufferp);
4117 lock_ReleaseRead(&scp->bufCreateLock);
4118 lock_ObtainMutex(&dsp->mx);
4120 /* now, if we're doing a star match, do bulk fetching of all of
4121 * the status info for files in the dir.
4124 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4125 lock_ObtainMutex(&scp->mx);
4126 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4127 LargeIntegerGreaterThanOrEqualTo(thyper,
4128 scp->bulkStatProgress)) {
4129 /* Don't bulk stat if risking timeout */
4130 int now = GetTickCount();
4131 if (now - req.startTime > 5000) {
4132 scp->bulkStatProgress = thyper;
4133 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4134 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4136 cm_TryBulkStat(scp, &thyper, userp, &req);
4139 lock_ObtainMutex(&scp->mx);
4141 lock_ReleaseMutex(&dsp->mx);
4143 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4147 bufferOffset = thyper;
4149 /* now get the data in the cache */
4151 code = cm_SyncOp(scp, bufferp, userp, &req,
4153 CM_SCACHESYNC_NEEDCALLBACK |
4154 CM_SCACHESYNC_READ);
4156 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4160 if (cm_HaveBuffer(scp, bufferp, 0)) {
4161 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4165 /* otherwise, load the buffer and try again */
4166 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4168 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4169 scp, bufferp, code);
4174 buf_Release(bufferp);
4178 } /* if (wrong buffer) ... */
4180 /* now we have the buffer containing the entry we're interested in; copy
4181 * it out if it represents a non-deleted entry.
4183 entryInDir = curOffset.LowPart & (2048-1);
4184 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4186 /* page header will help tell us which entries are free. Page header
4187 * can change more often than once per buffer, since AFS 3 dir page size
4188 * may be less than (but not more than a buffer package buffer.
4190 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4191 temp &= ~(2048 - 1); /* turn off intra-page bits */
4192 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4194 /* now determine which entry we're looking at in the page. If it is
4195 * free (there's a free bitmap at the start of the dir), we should
4196 * skip these 32 bytes.
4198 slotInPage = (entryInDir & 0x7e0) >> 5;
4199 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4200 /* this entry is free */
4201 numDirChunks = 1; /* only skip this guy */
4205 tp = bufferp->datap + entryInBuffer;
4206 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4208 /* while we're here, compute the next entry's location, too,
4209 * since we'll need it when writing out the cookie into the dir
4212 * XXXX Probably should do more sanity checking.
4214 numDirChunks = cm_NameEntries(dep->name, NULL);
4216 /* compute the offset of the cookie representing the next entry */
4217 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4219 /* Compute 8.3 name if necessary */
4220 actualName = dep->name;
4221 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4222 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4223 actualName = shortName;
4226 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4227 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4228 osi_LogSaveString(smb_logp, actualName));
4230 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4231 /* this is one of the entries to use: it is not deleted
4232 * and it matches the star pattern we're looking for.
4235 /* Eliminate entries that don't match requested
4238 /* no hidden files */
4239 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4240 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4244 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4246 /* We have already done the cm_TryBulkStat above */
4247 fid.cell = scp->fid.cell;
4248 fid.volume = scp->fid.volume;
4249 fid.vnode = ntohl(dep->fid.vnode);
4250 fid.unique = ntohl(dep->fid.unique);
4251 fileType = cm_FindFileType(&fid);
4252 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4253 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4255 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4256 fileType == CM_SCACHETYPE_DFSLINK ||
4257 fileType == CM_SCACHETYPE_INVALID)
4258 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4263 memcpy(op, mask, 11); op += 11;
4264 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4265 *op++ = (char)(nextEntryCookie & 0xff);
4266 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4267 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4268 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4269 memcpy(op, &clientCookie, 4); op += 4;
4271 /* now we emit the attribute. This is sort of tricky,
4272 * since we need to really stat the file to find out
4273 * what type of entry we've got. Right now, we're
4274 * copying out data from a buffer, while holding the
4275 * scp locked, so it isn't really convenient to stat
4276 * something now. We'll put in a place holder now,
4277 * and make a second pass before returning this to get
4278 * the real attributes. So, we just skip the data for
4279 * now, and adjust it later. We allocate a patch
4280 * record to make it easy to find this point later.
4281 * The replay will happen at a time when it is safe to
4282 * unlock the directory.
4284 curPatchp = malloc(sizeof(*curPatchp));
4285 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4286 curPatchp->dptr = op;
4287 curPatchp->fid.cell = scp->fid.cell;
4288 curPatchp->fid.volume = scp->fid.volume;
4289 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4290 curPatchp->fid.unique = ntohl(dep->fid.unique);
4292 /* do hidden attribute here since name won't be around when applying
4296 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4297 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4299 curPatchp->flags = 0;
4301 op += 9; /* skip attr, time, date and size */
4303 /* zero out name area. The spec says to pad with
4304 * spaces, but Samba doesn't, and neither do we.
4308 /* finally, we get to copy out the name; we know that
4309 * it fits in 8.3 or the pattern wouldn't match, but it
4310 * never hurts to be sure.
4312 strncpy(op, actualName, 13);
4313 if (smb_StoreAnsiFilenames)
4316 /* Uppercase if requested by client */
4317 if (!KNOWS_LONG_NAMES(inp))
4322 /* now, adjust the # of entries copied */
4324 } /* if we're including this name */
4327 /* and adjust curOffset to be where the new cookie is */
4328 thyper.HighPart = 0;
4329 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4330 curOffset = LargeIntegerAdd(thyper, curOffset);
4331 } /* while copying data for dir listing */
4333 /* release the mutex */
4334 lock_ReleaseMutex(&scp->mx);
4335 if (bufferp) buf_Release(bufferp);
4337 /* apply and free last set of patches; if not doing a star match, this
4338 * will be empty, but better safe (and freeing everything) than sorry.
4340 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4342 /* special return code for unsuccessful search */
4343 if (code == 0 && dataLength < 21 && returnedNames == 0)
4344 code = CM_ERROR_NOFILES;
4346 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4347 returnedNames, code);
4350 smb_DeleteDirSearch(dsp);
4351 smb_ReleaseDirSearch(dsp);
4352 cm_ReleaseSCache(scp);
4353 cm_ReleaseUser(userp);
4357 /* finalize the output buffer */
4358 smb_SetSMBParm(outp, 0, returnedNames);
4359 temp = (long) (op - origOp);
4360 smb_SetSMBDataLength(outp, temp);
4362 /* the data area is a variable block, which has a 5 (already there)
4363 * followed by the length of the # of data bytes. We now know this to
4364 * be "temp," although that includes the 3 bytes of vbl block header.
4365 * Deduct for them and fill in the length field.
4367 temp -= 3; /* deduct vbl block info */
4368 osi_assert(temp == (43 * returnedNames));
4369 origOp[1] = (char)(temp & 0xff);
4370 origOp[2] = (char)((temp>>8) & 0xff);
4371 if (returnedNames == 0)
4372 smb_DeleteDirSearch(dsp);
4373 smb_ReleaseDirSearch(dsp);
4374 cm_ReleaseSCache(scp);
4375 cm_ReleaseUser(userp);
4379 /* verify that this is a valid path to a directory. I don't know why they
4380 * don't use the get file attributes call.
4382 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4386 cm_scache_t *rootScp;
4387 cm_scache_t *newScp;
4396 pathp = smb_GetSMBData(inp, NULL);
4397 pathp = smb_ParseASCIIBlock(pathp, NULL);
4399 return CM_ERROR_BADFD;
4400 if (smb_StoreAnsiFilenames)
4401 OemToChar(pathp,pathp);
4402 osi_Log1(smb_logp, "SMB receive check path %s",
4403 osi_LogSaveString(smb_logp, pathp));
4405 rootScp = cm_data.rootSCachep;
4407 userp = smb_GetUserFromVCP(vcp, inp);
4409 caseFold = CM_FLAG_CASEFOLD;
4411 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4413 cm_ReleaseUser(userp);
4414 return CM_ERROR_NOSUCHPATH;
4416 code = cm_NameI(rootScp, pathp,
4417 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4418 userp, tidPathp, &req, &newScp);
4421 cm_ReleaseUser(userp);
4426 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4427 cm_ReleaseSCache(newScp);
4428 cm_ReleaseUser(userp);
4429 if ( WANTS_DFS_PATHNAMES(inp) )
4430 return CM_ERROR_PATH_NOT_COVERED;
4432 return CM_ERROR_BADSHARENAME;
4434 #endif /* DFS_SUPPORT */
4436 /* now lock the vnode with a callback; returns with newScp locked */
4437 lock_ObtainMutex(&newScp->mx);
4438 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4439 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4440 if (code && code != CM_ERROR_NOACCESS) {
4441 lock_ReleaseMutex(&newScp->mx);
4442 cm_ReleaseSCache(newScp);
4443 cm_ReleaseUser(userp);
4447 attrs = smb_Attributes(newScp);
4449 if (!(attrs & SMB_ATTR_DIRECTORY))
4450 code = CM_ERROR_NOTDIR;
4452 lock_ReleaseMutex(&newScp->mx);
4454 cm_ReleaseSCache(newScp);
4455 cm_ReleaseUser(userp);
4459 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4463 cm_scache_t *rootScp;
4464 unsigned short attribute;
4466 cm_scache_t *newScp;
4475 /* decode basic attributes we're passed */
4476 attribute = smb_GetSMBParm(inp, 0);
4477 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4479 pathp = smb_GetSMBData(inp, NULL);
4480 pathp = smb_ParseASCIIBlock(pathp, NULL);
4482 return CM_ERROR_BADSMB;
4483 if (smb_StoreAnsiFilenames)
4484 OemToChar(pathp,pathp);
4486 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4487 dosTime, attribute);
4489 rootScp = cm_data.rootSCachep;
4491 userp = smb_GetUserFromVCP(vcp, inp);
4493 caseFold = CM_FLAG_CASEFOLD;
4495 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4497 cm_ReleaseUser(userp);
4498 return CM_ERROR_NOSUCHFILE;
4500 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4501 tidPathp, &req, &newScp);
4504 cm_ReleaseUser(userp);
4509 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4510 cm_ReleaseSCache(newScp);
4511 cm_ReleaseUser(userp);
4512 if ( WANTS_DFS_PATHNAMES(inp) )
4513 return CM_ERROR_PATH_NOT_COVERED;
4515 return CM_ERROR_BADSHARENAME;
4517 #endif /* DFS_SUPPORT */
4519 /* now lock the vnode with a callback; returns with newScp locked; we
4520 * need the current status to determine what the new status is, in some
4523 lock_ObtainMutex(&newScp->mx);
4524 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4525 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4527 lock_ReleaseMutex(&newScp->mx);
4528 cm_ReleaseSCache(newScp);
4529 cm_ReleaseUser(userp);
4533 /* Check for RO volume */
4534 if (newScp->flags & CM_SCACHEFLAG_RO) {
4535 lock_ReleaseMutex(&newScp->mx);
4536 cm_ReleaseSCache(newScp);
4537 cm_ReleaseUser(userp);
4538 return CM_ERROR_READONLY;
4541 /* prepare for setattr call */
4544 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4545 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4547 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4548 /* we're told to make a writable file read-only */
4549 attr.unixModeBits = newScp->unixModeBits & ~0222;
4550 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4552 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4553 /* we're told to make a read-only file writable */
4554 attr.unixModeBits = newScp->unixModeBits | 0222;
4555 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4557 lock_ReleaseMutex(&newScp->mx);
4559 /* now call setattr */
4561 code = cm_SetAttr(newScp, &attr, userp, &req);
4565 cm_ReleaseSCache(newScp);
4566 cm_ReleaseUser(userp);
4571 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4575 cm_scache_t *rootScp;
4576 cm_scache_t *newScp, *dscp;
4588 pathp = smb_GetSMBData(inp, NULL);
4589 pathp = smb_ParseASCIIBlock(pathp, NULL);
4591 return CM_ERROR_BADSMB;
4593 if (*pathp == 0) /* null path */
4596 if (smb_StoreAnsiFilenames)
4597 OemToChar(pathp,pathp);
4599 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4600 osi_LogSaveString(smb_logp, pathp));
4602 rootScp = cm_data.rootSCachep;
4604 userp = smb_GetUserFromVCP(vcp, inp);
4606 /* we shouldn't need this for V3 requests, but we seem to */
4607 caseFold = CM_FLAG_CASEFOLD;
4609 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4611 cm_ReleaseUser(userp);
4612 return CM_ERROR_NOSUCHFILE;
4616 * XXX Strange hack XXX
4618 * As of Patch 5 (16 July 97), we are having the following problem:
4619 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4620 * requests to look up "desktop.ini" in all the subdirectories.
4621 * This can cause zillions of timeouts looking up non-existent cells
4622 * and volumes, especially in the top-level directory.
4624 * We have not found any way to avoid this or work around it except
4625 * to explicitly ignore the requests for mount points that haven't
4626 * yet been evaluated and for directories that haven't yet been
4629 * We should modify this hack to provide a fake desktop.ini file
4630 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4632 spacep = inp->spacep;
4633 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4634 #ifndef SPECIAL_FOLDERS
4635 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4636 code = cm_NameI(rootScp, spacep->data,
4637 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4638 userp, tidPathp, &req, &dscp);
4641 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4642 if ( WANTS_DFS_PATHNAMES(inp) )
4643 return CM_ERROR_PATH_NOT_COVERED;
4645 return CM_ERROR_BADSHARENAME;
4647 #endif /* DFS_SUPPORT */
4648 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4649 code = CM_ERROR_NOSUCHFILE;
4650 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4651 cm_buf_t *bp = buf_Find(dscp, &hzero);
4655 code = CM_ERROR_NOSUCHFILE;
4657 cm_ReleaseSCache(dscp);
4659 cm_ReleaseUser(userp);
4664 #endif /* SPECIAL_FOLDERS */
4666 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4667 tidPathp, &req, &newScp);
4669 cm_ReleaseUser(userp);
4674 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4675 cm_ReleaseSCache(newScp);
4676 cm_ReleaseUser(userp);
4677 if ( WANTS_DFS_PATHNAMES(inp) )
4678 return CM_ERROR_PATH_NOT_COVERED;
4680 return CM_ERROR_BADSHARENAME;
4682 #endif /* DFS_SUPPORT */
4684 /* now lock the vnode with a callback; returns with newScp locked */
4685 lock_ObtainMutex(&newScp->mx);
4686 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4687 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4689 lock_ReleaseMutex(&newScp->mx);
4690 cm_ReleaseSCache(newScp);
4691 cm_ReleaseUser(userp);
4696 /* use smb_Attributes instead. Also the fact that a file is
4697 * in a readonly volume doesn't mean it shojuld be marked as RO
4699 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4700 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4701 attrs = SMB_ATTR_DIRECTORY;
4704 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4705 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4707 attrs = smb_Attributes(newScp);
4710 smb_SetSMBParm(outp, 0, attrs);
4712 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4713 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4714 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4715 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4716 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4717 smb_SetSMBParm(outp, 5, 0);
4718 smb_SetSMBParm(outp, 6, 0);
4719 smb_SetSMBParm(outp, 7, 0);
4720 smb_SetSMBParm(outp, 8, 0);
4721 smb_SetSMBParm(outp, 9, 0);
4722 smb_SetSMBDataLength(outp, 0);
4723 lock_ReleaseMutex(&newScp->mx);
4725 cm_ReleaseSCache(newScp);
4726 cm_ReleaseUser(userp);
4731 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4735 osi_Log0(smb_logp, "SMB receive tree disconnect");
4737 /* find the tree and free it */
4738 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4740 lock_ObtainWrite(&smb_rctLock);
4742 lock_ReleaseWrite(&smb_rctLock);
4743 smb_ReleaseTID(tidp);
4749 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4767 pathp = smb_GetSMBData(inp, NULL);
4768 pathp = smb_ParseASCIIBlock(pathp, NULL);
4769 if (smb_StoreAnsiFilenames)
4770 OemToChar(pathp,pathp);
4772 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4774 #ifdef DEBUG_VERBOSE
4778 hexpath = osi_HexifyString( pathp );
4779 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4784 share = smb_GetSMBParm(inp, 0);
4785 attribute = smb_GetSMBParm(inp, 1);
4787 spacep = inp->spacep;
4788 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4789 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4790 /* special case magic file name for receiving IOCTL requests
4791 * (since IOCTL calls themselves aren't getting through).
4793 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4794 smb_SetupIoctlFid(fidp, spacep);
4795 smb_SetSMBParm(outp, 0, fidp->fid);
4796 smb_SetSMBParm(outp, 1, 0); /* attrs */
4797 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4798 smb_SetSMBParm(outp, 3, 0);
4799 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4800 smb_SetSMBParm(outp, 5, 0x7fff);
4801 /* pass the open mode back */
4802 smb_SetSMBParm(outp, 6, (share & 0xf));
4803 smb_SetSMBDataLength(outp, 0);
4804 smb_ReleaseFID(fidp);
4808 userp = smb_GetUserFromVCP(vcp, inp);
4810 caseFold = CM_FLAG_CASEFOLD;
4812 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4814 cm_ReleaseUser(userp);
4815 return CM_ERROR_NOSUCHPATH;
4817 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4818 tidPathp, &req, &scp);
4821 cm_ReleaseUser(userp);
4826 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4827 cm_ReleaseSCache(scp);
4828 cm_ReleaseUser(userp);
4829 if ( WANTS_DFS_PATHNAMES(inp) )
4830 return CM_ERROR_PATH_NOT_COVERED;
4832 return CM_ERROR_BADSHARENAME;
4834 #endif /* DFS_SUPPORT */
4836 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4838 cm_ReleaseSCache(scp);
4839 cm_ReleaseUser(userp);
4843 /* don't need callback to check file type, since file types never
4844 * change, and namei and cm_Lookup all stat the object at least once on
4845 * a successful return.
4847 if (scp->fileType != CM_SCACHETYPE_FILE) {
4848 cm_ReleaseSCache(scp);
4849 cm_ReleaseUser(userp);
4850 return CM_ERROR_ISDIR;
4853 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4856 /* save a pointer to the vnode */
4860 fidp->userp = userp;
4862 lock_ObtainMutex(&fidp->mx);
4863 if ((share & 0xf) == 0)
4864 fidp->flags |= SMB_FID_OPENREAD;
4865 else if ((share & 0xf) == 1)
4866 fidp->flags |= SMB_FID_OPENWRITE;
4868 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4869 lock_ReleaseMutex(&fidp->mx);
4871 lock_ObtainMutex(&scp->mx);
4872 smb_SetSMBParm(outp, 0, fidp->fid);
4873 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4874 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4875 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4876 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4877 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4878 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4879 /* pass the open mode back; XXXX add access checks */
4880 smb_SetSMBParm(outp, 6, (share & 0xf));
4881 smb_SetSMBDataLength(outp, 0);
4882 lock_ReleaseMutex(&scp->mx);
4885 cm_Open(scp, 0, userp);
4887 /* send and free packet */
4888 smb_ReleaseFID(fidp);
4889 cm_ReleaseUser(userp);
4890 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4894 typedef struct smb_unlinkRock {
4899 char *maskp; /* pointer to the star pattern */
4904 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4907 smb_unlinkRock_t *rockp;
4915 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4916 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4917 caseFold |= CM_FLAG_8DOT3;
4919 matchName = dep->name;
4920 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4922 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4923 !cm_Is8Dot3(dep->name)) {
4924 cm_Gen8Dot3Name(dep, shortName, NULL);
4925 matchName = shortName;
4926 /* 8.3 matches are always case insensitive */
4927 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4930 osi_Log1(smb_logp, "Unlinking %s",
4931 osi_LogSaveString(smb_logp, matchName));
4932 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4933 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4934 smb_NotifyChange(FILE_ACTION_REMOVED,
4935 FILE_NOTIFY_CHANGE_FILE_NAME,
4936 dscp, dep->name, NULL, TRUE);
4940 /* If we made a case sensitive exact match, we might as well quit now. */
4941 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4942 code = CM_ERROR_STOPNOW;
4950 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4959 smb_unlinkRock_t rock;
4968 attribute = smb_GetSMBParm(inp, 0);
4970 tp = smb_GetSMBData(inp, NULL);
4971 pathp = smb_ParseASCIIBlock(tp, &tp);
4972 if (smb_StoreAnsiFilenames)
4973 OemToChar(pathp,pathp);
4975 osi_Log1(smb_logp, "SMB receive unlink %s",
4976 osi_LogSaveString(smb_logp, pathp));
4978 spacep = inp->spacep;
4979 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4981 userp = smb_GetUserFromVCP(vcp, inp);
4983 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4985 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4987 cm_ReleaseUser(userp);
4988 return CM_ERROR_NOSUCHPATH;
4990 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4993 cm_ReleaseUser(userp);
4998 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4999 cm_ReleaseSCache(dscp);
5000 cm_ReleaseUser(userp);
5001 if ( WANTS_DFS_PATHNAMES(inp) )
5002 return CM_ERROR_PATH_NOT_COVERED;
5004 return CM_ERROR_BADSHARENAME;
5006 #endif /* DFS_SUPPORT */
5008 /* otherwise, scp points to the parent directory. */
5015 rock.maskp = smb_FindMask(pathp);
5016 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5019 thyper.HighPart = 0;
5025 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5026 * match. If that fails, we do a case insensitve match.
5028 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5029 !smb_IsStarMask(rock.maskp)) {
5030 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5033 thyper.HighPart = 0;
5034 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5039 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5041 if (code == CM_ERROR_STOPNOW)
5044 cm_ReleaseUser(userp);
5046 cm_ReleaseSCache(dscp);
5048 if (code == 0 && !rock.any)
5049 code = CM_ERROR_NOSUCHFILE;
5053 typedef struct smb_renameRock {
5054 cm_scache_t *odscp; /* old dir */
5055 cm_scache_t *ndscp; /* new dir */
5056 cm_user_t *userp; /* user */
5057 cm_req_t *reqp; /* request struct */
5058 smb_vc_t *vcp; /* virtual circuit */
5059 char *maskp; /* pointer to star pattern of old file name */
5060 int flags; /* tilde, casefold, etc */
5061 char *newNamep; /* ptr to the new file's name */
5064 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5067 smb_renameRock_t *rockp;
5072 rockp = (smb_renameRock_t *) vrockp;
5074 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5075 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5076 caseFold |= CM_FLAG_8DOT3;
5078 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5080 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5081 !cm_Is8Dot3(dep->name)) {
5082 cm_Gen8Dot3Name(dep, shortName, NULL);
5083 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5086 code = cm_Rename(rockp->odscp, dep->name,
5087 rockp->ndscp, rockp->newNamep, rockp->userp,
5089 /* if the call worked, stop doing the search now, since we
5090 * really only want to rename one file.
5093 code = CM_ERROR_STOPNOW;
5102 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5105 cm_space_t *spacep = NULL;
5106 smb_renameRock_t rock;
5107 cm_scache_t *oldDscp = NULL;
5108 cm_scache_t *newDscp = NULL;
5109 cm_scache_t *tmpscp= NULL;
5110 cm_scache_t *tmpscp2 = NULL;
5120 userp = smb_GetUserFromVCP(vcp, inp);
5121 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5123 cm_ReleaseUser(userp);
5124 return CM_ERROR_NOSUCHPATH;
5128 spacep = inp->spacep;
5129 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5131 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5132 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5133 userp, tidPathp, &req, &oldDscp);
5135 cm_ReleaseUser(userp);
5140 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5141 cm_ReleaseSCache(oldDscp);
5142 cm_ReleaseUser(userp);
5143 if ( WANTS_DFS_PATHNAMES(inp) )
5144 return CM_ERROR_PATH_NOT_COVERED;
5146 return CM_ERROR_BADSHARENAME;
5148 #endif /* DFS_SUPPORT */
5150 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5151 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5152 userp, tidPathp, &req, &newDscp);
5155 cm_ReleaseSCache(oldDscp);
5156 cm_ReleaseUser(userp);
5161 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5162 cm_ReleaseSCache(oldDscp);
5163 cm_ReleaseSCache(newDscp);
5164 cm_ReleaseUser(userp);
5165 if ( WANTS_DFS_PATHNAMES(inp) )
5166 return CM_ERROR_PATH_NOT_COVERED;
5168 return CM_ERROR_BADSHARENAME;
5170 #endif /* DFS_SUPPORT */
5173 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5174 * next, get the component names, and lower case them.
5177 /* handle the old name first */
5179 oldLastNamep = oldPathp;
5183 /* and handle the new name, too */
5185 newLastNamep = newPathp;
5189 /* TODO: The old name could be a wildcard. The new name must not be */
5191 /* do the vnode call */
5192 rock.odscp = oldDscp;
5193 rock.ndscp = newDscp;
5197 rock.maskp = oldLastNamep;
5198 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5199 rock.newNamep = newLastNamep;
5201 /* Check if the file already exists; if so return error */
5202 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5203 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5204 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5205 osi_LogSaveString(afsd_logp, newLastNamep));
5207 /* Check if the old and the new names differ only in case. If so return
5208 * success, else return CM_ERROR_EXISTS
5210 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5212 /* This would be a success only if the old file is *as same as* the new file */
5213 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5215 if (tmpscp == tmpscp2)
5218 code = CM_ERROR_EXISTS;
5219 cm_ReleaseSCache(tmpscp2);
5222 code = CM_ERROR_NOSUCHFILE;
5225 /* file exist, do not rename, also fixes move */
5226 osi_Log0(smb_logp, "Can't rename. Target already exists");
5227 code = CM_ERROR_EXISTS;
5231 cm_ReleaseSCache(tmpscp);
5232 cm_ReleaseSCache(newDscp);
5233 cm_ReleaseSCache(oldDscp);
5234 cm_ReleaseUser(userp);
5238 /* Now search the directory for the pattern, and do the appropriate rename when found */
5239 thyper.LowPart = 0; /* search dir from here */
5240 thyper.HighPart = 0;
5242 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5243 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5245 if (code == CM_ERROR_STOPNOW)
5248 code = CM_ERROR_NOSUCHFILE;
5250 /* Handle Change Notification */
5252 * Being lazy, not distinguishing between files and dirs in this
5253 * filter, since we'd have to do a lookup.
5255 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5256 if (oldDscp == newDscp) {
5257 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5258 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5259 filter, oldDscp, oldLastNamep,
5260 newLastNamep, TRUE);
5262 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5263 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5264 filter, oldDscp, oldLastNamep,
5266 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5267 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5268 filter, newDscp, newLastNamep,
5273 cm_ReleaseSCache(tmpscp);
5274 cm_ReleaseUser(userp);
5275 cm_ReleaseSCache(oldDscp);
5276 cm_ReleaseSCache(newDscp);
5281 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5284 cm_space_t *spacep = NULL;
5285 cm_scache_t *oldDscp = NULL;
5286 cm_scache_t *newDscp = NULL;
5287 cm_scache_t *tmpscp= NULL;
5288 cm_scache_t *tmpscp2 = NULL;
5289 cm_scache_t *sscp = NULL;
5298 userp = smb_GetUserFromVCP(vcp, inp);
5300 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5302 cm_ReleaseUser(userp);
5303 return CM_ERROR_NOSUCHPATH;
5308 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5310 spacep = inp->spacep;
5311 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5313 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5314 userp, tidPathp, &req, &oldDscp);
5316 cm_ReleaseUser(userp);
5321 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5322 cm_ReleaseSCache(oldDscp);
5323 cm_ReleaseUser(userp);
5324 if ( WANTS_DFS_PATHNAMES(inp) )
5325 return CM_ERROR_PATH_NOT_COVERED;
5327 return CM_ERROR_BADSHARENAME;
5329 #endif /* DFS_SUPPORT */
5331 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5332 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5333 userp, tidPathp, &req, &newDscp);
5335 cm_ReleaseSCache(oldDscp);
5336 cm_ReleaseUser(userp);
5341 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5342 cm_ReleaseSCache(newDscp);
5343 cm_ReleaseSCache(oldDscp);
5344 cm_ReleaseUser(userp);
5345 if ( WANTS_DFS_PATHNAMES(inp) )
5346 return CM_ERROR_PATH_NOT_COVERED;
5348 return CM_ERROR_BADSHARENAME;
5350 #endif /* DFS_SUPPORT */
5352 /* Now, although we did two lookups for the two directories (because the same
5353 * directory can be referenced through different paths), we only allow hard links
5354 * within the same directory. */
5355 if (oldDscp != newDscp) {
5356 cm_ReleaseSCache(oldDscp);
5357 cm_ReleaseSCache(newDscp);
5358 cm_ReleaseUser(userp);
5359 return CM_ERROR_CROSSDEVLINK;
5362 /* handle the old name first */
5364 oldLastNamep = oldPathp;
5368 /* and handle the new name, too */
5370 newLastNamep = newPathp;
5374 /* now lookup the old name */
5375 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5376 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5378 cm_ReleaseSCache(oldDscp);
5379 cm_ReleaseSCache(newDscp);
5380 cm_ReleaseUser(userp);
5384 /* Check if the file already exists; if so return error */
5385 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5386 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5387 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5388 osi_LogSaveString(afsd_logp, newLastNamep));
5390 /* if the existing link is to the same file, then we return success */
5392 if(sscp == tmpscp) {
5395 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5396 code = CM_ERROR_EXISTS;
5401 cm_ReleaseSCache(tmpscp);
5402 cm_ReleaseSCache(sscp);
5403 cm_ReleaseSCache(newDscp);
5404 cm_ReleaseSCache(oldDscp);
5405 cm_ReleaseUser(userp);
5409 /* now create the hardlink */
5410 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5411 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5412 osi_Log1(smb_logp," Link returns %d", code);
5414 /* Handle Change Notification */
5416 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5417 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5418 smb_NotifyChange(FILE_ACTION_ADDED,
5419 filter, newDscp, newLastNamep,
5424 cm_ReleaseSCache(tmpscp);
5425 cm_ReleaseUser(userp);
5426 cm_ReleaseSCache(sscp);
5427 cm_ReleaseSCache(oldDscp);
5428 cm_ReleaseSCache(newDscp);
5433 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5439 tp = smb_GetSMBData(inp, NULL);
5440 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5441 if (smb_StoreAnsiFilenames)
5442 OemToChar(oldPathp,oldPathp);
5443 newPathp = smb_ParseASCIIBlock(tp, &tp);
5444 if (smb_StoreAnsiFilenames)
5445 OemToChar(newPathp,newPathp);
5447 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5448 osi_LogSaveString(smb_logp, oldPathp),
5449 osi_LogSaveString(smb_logp, newPathp));
5451 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5456 typedef struct smb_rmdirRock {
5460 char *maskp; /* pointer to the star pattern */
5465 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5468 smb_rmdirRock_t *rockp;
5473 rockp = (smb_rmdirRock_t *) vrockp;
5475 matchName = dep->name;
5476 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5477 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5479 match = (strcmp(matchName, rockp->maskp) == 0);
5481 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5482 !cm_Is8Dot3(dep->name)) {
5483 cm_Gen8Dot3Name(dep, shortName, NULL);
5484 matchName = shortName;
5485 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5488 osi_Log1(smb_logp, "Removing directory %s",
5489 osi_LogSaveString(smb_logp, matchName));
5490 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5491 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5492 smb_NotifyChange(FILE_ACTION_REMOVED,
5493 FILE_NOTIFY_CHANGE_DIR_NAME,
5494 dscp, dep->name, NULL, TRUE);
5503 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5511 smb_rmdirRock_t rock;
5520 tp = smb_GetSMBData(inp, NULL);
5521 pathp = smb_ParseASCIIBlock(tp, &tp);
5522 if (smb_StoreAnsiFilenames)
5523 OemToChar(pathp,pathp);
5525 spacep = inp->spacep;
5526 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5528 userp = smb_GetUserFromVCP(vcp, inp);
5530 caseFold = CM_FLAG_CASEFOLD;
5532 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5534 cm_ReleaseUser(userp);
5535 return CM_ERROR_NOSUCHPATH;
5537 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5538 userp, tidPathp, &req, &dscp);
5541 cm_ReleaseUser(userp);
5546 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5547 cm_ReleaseSCache(dscp);
5548 cm_ReleaseUser(userp);
5549 if ( WANTS_DFS_PATHNAMES(inp) )
5550 return CM_ERROR_PATH_NOT_COVERED;
5552 return CM_ERROR_BADSHARENAME;
5554 #endif /* DFS_SUPPORT */
5556 /* otherwise, scp points to the parent directory. */
5563 rock.maskp = lastNamep;
5564 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5567 thyper.HighPart = 0;
5571 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5572 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5573 if (code == 0 && !rock.any) {
5575 thyper.HighPart = 0;
5576 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5577 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5580 cm_ReleaseUser(userp);
5582 cm_ReleaseSCache(dscp);
5584 if (code == 0 && !rock.any)
5585 code = CM_ERROR_NOSUCHFILE;
5589 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5599 fid = smb_GetSMBParm(inp, 0);
5601 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5603 fid = smb_ChainFID(fid, inp);
5604 fidp = smb_FindFID(vcp, fid, 0);
5606 return CM_ERROR_BADFD;
5608 lock_ObtainMutex(&fidp->mx);
5609 if (fidp->flags & SMB_FID_IOCTL) {
5610 lock_ReleaseMutex(&fidp->mx);
5611 smb_ReleaseFID(fidp);
5612 return CM_ERROR_BADFD;
5614 lock_ReleaseMutex(&fidp->mx);
5616 userp = smb_GetUserFromVCP(vcp, inp);
5618 lock_ObtainMutex(&fidp->mx);
5619 if (fidp->flags & SMB_FID_OPENWRITE)
5620 code = cm_FSync(fidp->scp, userp, &req);
5623 lock_ReleaseMutex(&fidp->mx);
5625 smb_ReleaseFID(fidp);
5627 cm_ReleaseUser(userp);
5632 struct smb_FullNameRock {
5638 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5642 struct smb_FullNameRock *vrockp;
5644 vrockp = (struct smb_FullNameRock *)rockp;
5646 if (!cm_Is8Dot3(dep->name)) {
5647 cm_Gen8Dot3Name(dep, shortName, NULL);
5649 if (cm_stricmp(shortName, vrockp->name) == 0) {
5650 vrockp->fullName = strdup(dep->name);
5651 return CM_ERROR_STOPNOW;
5654 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5655 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5656 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5657 vrockp->fullName = strdup(dep->name);
5658 return CM_ERROR_STOPNOW;
5663 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5664 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5666 struct smb_FullNameRock rock;
5672 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5673 if (code == CM_ERROR_STOPNOW)
5674 *newPathp = rock.fullName;
5676 *newPathp = strdup(pathp);
5679 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5680 afs_uint32 dosTime) {
5683 cm_scache_t *dscp = fidp->NTopen_dscp;
5684 char *pathp = fidp->NTopen_pathp;
5686 osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
5687 fidp, fidp->fid, vcp);
5690 lock_ObtainMutex(&fidp->mx);
5691 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5692 lock_ReleaseMutex(&fidp->mx);
5693 osi_Log0(smb_logp, " No user specified. Not closing fid");
5694 return CM_ERROR_BADFD;
5697 userp = fidp->userp; /* no hold required since fidp is held
5698 throughout the function */
5699 lock_ReleaseMutex(&fidp->mx);
5704 lock_ObtainWrite(&smb_rctLock);
5706 osi_Log0(smb_logp, " Fid already closed.");
5707 lock_ReleaseWrite(&smb_rctLock);
5708 return CM_ERROR_BADFD;
5711 lock_ReleaseWrite(&smb_rctLock);
5713 lock_ObtainMutex(&fidp->mx);
5714 /* Don't jump the gun on an async raw write */
5715 while (fidp->raw_writers) {
5716 lock_ReleaseMutex(&fidp->mx);
5717 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5718 lock_ObtainMutex(&fidp->mx);
5721 /* watch for ioctl closes, and read-only opens */
5722 if (fidp->scp != NULL &&
5723 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5724 == SMB_FID_OPENWRITE) {
5725 if (dosTime != 0 && dosTime != -1) {
5726 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5727 /* This fixes defect 10958 */
5728 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5729 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5731 code = cm_FSync(fidp->scp, userp, &req);
5736 /* unlock any pending locks */
5737 if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
5738 fidp->scp->fileType == CM_SCACHETYPE_FILE) {
5743 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5745 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5748 lock_ObtainMutex(&scp->mx);
5750 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5751 CM_SCACHESYNC_NEEDCALLBACK
5752 | CM_SCACHESYNC_GETSTATUS
5753 | CM_SCACHESYNC_LOCK);
5757 "smb CoreClose SyncOp failure code 0x%x", tcode);
5758 goto post_syncopdone;
5761 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5763 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5767 lock_ReleaseMutex(&scp->mx);
5768 cm_ReleaseSCache(scp);
5771 if (fidp->flags & SMB_FID_DELONCLOSE) {
5774 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5775 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5776 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5777 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5778 smb_NotifyChange(FILE_ACTION_REMOVED,
5779 FILE_NOTIFY_CHANGE_DIR_NAME,
5780 dscp, fullPathp, NULL, TRUE);
5782 code = cm_Unlink(dscp, fullPathp, userp, &req);
5783 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5784 smb_NotifyChange(FILE_ACTION_REMOVED,
5785 FILE_NOTIFY_CHANGE_FILE_NAME,
5786 dscp, fullPathp, NULL, TRUE);
5789 fidp->flags &= ~SMB_FID_DELONCLOSE;
5792 if (fidp->flags & SMB_FID_NTOPEN) {
5793 fidp->NTopen_dscp = NULL;
5794 fidp->NTopen_pathp = NULL;
5795 fidp->flags &= ~SMB_FID_NTOPEN;
5797 if (fidp->NTopen_wholepathp) {
5798 free(fidp->NTopen_wholepathp);
5799 fidp->NTopen_wholepathp = NULL;
5801 lock_ReleaseMutex(&fidp->mx);
5804 cm_ReleaseSCache(dscp);
5812 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5820 fid = smb_GetSMBParm(inp, 0);
5821 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5823 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5825 fid = smb_ChainFID(fid, inp);
5826 fidp = smb_FindFID(vcp, fid, 0);
5828 return CM_ERROR_BADFD;
5831 userp = smb_GetUserFromVCP(vcp, inp);
5833 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5835 smb_ReleaseFID(fidp);
5836 cm_ReleaseUser(userp);
5841 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5844 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5845 cm_user_t *userp, long *readp)
5847 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5848 cm_user_t *userp, long *readp, int dosflag)
5855 osi_hyper_t fileLength;
5857 osi_hyper_t lastByte;
5858 osi_hyper_t bufferOffset;
5859 long bufIndex, nbytes;
5869 lock_ObtainMutex(&fidp->mx);
5871 lock_ObtainMutex(&scp->mx);
5873 if (offset.HighPart == 0) {
5874 chunk = offset.LowPart >> cm_logChunkSize;
5875 if (chunk != fidp->curr_chunk) {
5876 fidp->prev_chunk = fidp->curr_chunk;
5877 fidp->curr_chunk = chunk;
5879 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5883 /* start by looking up the file's end */
5884 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5885 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5886 if (code) goto done;
5888 /* now we have the entry locked, look up the length */
5889 fileLength = scp->length;
5891 /* adjust count down so that it won't go past EOF */
5892 thyper.LowPart = count;
5893 thyper.HighPart = 0;
5894 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5896 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5897 /* we'd read past EOF, so just stop at fileLength bytes.
5898 * Start by computing how many bytes remain in the file.
5900 thyper = LargeIntegerSubtract(fileLength, offset);
5902 /* if we are past EOF, read 0 bytes */
5903 if (LargeIntegerLessThanZero(thyper))
5906 count = thyper.LowPart;
5911 /* now, copy the data one buffer at a time,
5912 * until we've filled the request packet
5915 /* if we've copied all the data requested, we're done */
5916 if (count <= 0) break;
5918 /* otherwise, load up a buffer of data */
5919 thyper.HighPart = offset.HighPart;
5920 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5921 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5924 buf_Release(bufferp);
5927 lock_ReleaseMutex(&scp->mx);
5929 lock_ObtainRead(&scp->bufCreateLock);
5930 code = buf_Get(scp, &thyper, &bufferp);
5931 lock_ReleaseRead(&scp->bufCreateLock);
5933 lock_ObtainMutex(&scp->mx);
5934 if (code) goto done;
5935 bufferOffset = thyper;
5937 /* now get the data in the cache */
5939 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5940 CM_SCACHESYNC_NEEDCALLBACK |
5941 CM_SCACHESYNC_READ);
5942 if (code) goto done;
5944 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5946 /* otherwise, load the buffer and try again */
5947 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5951 buf_Release(bufferp);
5955 } /* if (wrong buffer) ... */
5957 /* now we have the right buffer loaded. Copy out the
5958 * data from here to the user's buffer.
5960 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5962 /* and figure out how many bytes we want from this buffer */
5963 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5964 if (nbytes > count) nbytes = count; /* don't go past EOF */
5966 /* now copy the data */
5969 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5972 memcpy(op, bufferp->datap + bufIndex, nbytes);
5974 /* adjust counters, pointers, etc. */
5977 thyper.LowPart = nbytes;
5978 thyper.HighPart = 0;
5979 offset = LargeIntegerAdd(thyper, offset);
5983 lock_ReleaseMutex(&scp->mx);
5984 lock_ReleaseMutex(&fidp->mx);
5986 buf_Release(bufferp);
5988 if (code == 0 && sequential)
5989 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5995 * smb_WriteData -- common code for Write and Raw Write
5998 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5999 cm_user_t *userp, long *writtenp)
6001 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6002 cm_user_t *userp, long *writtenp, int dosflag)
6009 osi_hyper_t fileLength; /* file's length at start of write */
6010 osi_hyper_t minLength; /* don't read past this */
6011 long nbytes; /* # of bytes to transfer this iteration */
6013 osi_hyper_t thyper; /* hyper tmp variable */
6014 osi_hyper_t bufferOffset;
6015 long bufIndex; /* index in buffer where our data is */
6017 osi_hyper_t writeBackOffset;/* offset of region to write back when
6022 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6023 fidp->fid, offsetp->LowPart, count);
6033 lock_ObtainMutex(&fidp->mx);
6035 lock_ObtainMutex(&scp->mx);
6037 /* start by looking up the file's end */
6038 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6039 CM_SCACHESYNC_NEEDCALLBACK
6040 | CM_SCACHESYNC_SETSTATUS
6041 | CM_SCACHESYNC_GETSTATUS);
6045 /* make sure we have a writable FD */
6046 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6047 lock_ReleaseMutex(&fidp->mx);
6048 code = CM_ERROR_BADFDOP;
6052 /* now we have the entry locked, look up the length */
6053 fileLength = scp->length;
6054 minLength = fileLength;
6055 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6056 minLength = scp->serverLength;
6058 /* adjust file length if we extend past EOF */
6059 thyper.LowPart = count;
6060 thyper.HighPart = 0;
6061 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6062 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6063 /* we'd write past EOF, so extend the file */
6064 scp->mask |= CM_SCACHEMASK_LENGTH;
6065 scp->length = thyper;
6066 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6068 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6070 /* now, if the new position (thyper) and the old (offset) are in
6071 * different storeback windows, remember to store back the previous
6072 * storeback window when we're done with the write.
6074 if ((thyper.LowPart & (-cm_chunkSize)) !=
6075 (offset.LowPart & (-cm_chunkSize))) {
6076 /* they're different */
6078 writeBackOffset.HighPart = offset.HighPart;
6079 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6084 /* now, copy the data one buffer at a time, until we've filled the
6087 /* if we've copied all the data requested, we're done */
6091 /* handle over quota or out of space */
6092 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6093 *writtenp = written;
6094 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6098 /* otherwise, load up a buffer of data */
6099 thyper.HighPart = offset.HighPart;
6100 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6101 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6104 lock_ReleaseMutex(&bufferp->mx);
6105 buf_Release(bufferp);
6108 lock_ReleaseMutex(&scp->mx);
6110 lock_ObtainRead(&scp->bufCreateLock);
6111 code = buf_Get(scp, &thyper, &bufferp);
6112 lock_ReleaseRead(&scp->bufCreateLock);
6114 lock_ObtainMutex(&bufferp->mx);
6115 lock_ObtainMutex(&scp->mx);
6116 if (code) goto done;
6118 bufferOffset = thyper;
6120 /* now get the data in the cache */
6122 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6123 CM_SCACHESYNC_NEEDCALLBACK
6124 | CM_SCACHESYNC_WRITE
6125 | CM_SCACHESYNC_BUFLOCKED);
6129 /* If we're overwriting the entire buffer, or
6130 * if we're writing at or past EOF, mark the
6131 * buffer as current so we don't call
6132 * cm_GetBuffer. This skips the fetch from the
6133 * server in those cases where we're going to
6134 * obliterate all the data in the buffer anyway,
6135 * or in those cases where there is no useful
6136 * data at the server to start with.
6138 * Use minLength instead of scp->length, since
6139 * the latter has already been updated by this
6142 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6143 || LargeIntegerEqualTo(offset, bufferp->offset)
6144 && (count >= cm_data.buf_blockSize
6145 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6146 ConvertLongToLargeInteger(count)),
6148 if (count < cm_data.buf_blockSize
6149 && bufferp->dataVersion == -1)
6150 memset(bufferp->datap, 0,
6151 cm_data.buf_blockSize);
6152 bufferp->dataVersion = scp->dataVersion;
6155 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6157 /* otherwise, load the buffer and try again */
6158 lock_ReleaseMutex(&bufferp->mx);
6159 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6161 lock_ReleaseMutex(&scp->mx);
6162 lock_ObtainMutex(&bufferp->mx);
6163 lock_ObtainMutex(&scp->mx);
6167 lock_ReleaseMutex(&bufferp->mx);
6168 buf_Release(bufferp);
6172 } /* if (wrong buffer) ... */
6174 /* now we have the right buffer loaded. Copy out the
6175 * data from here to the user's buffer.
6177 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6179 /* and figure out how many bytes we want from this buffer */
6180 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6182 nbytes = count; /* don't go past end of request */
6184 /* now copy the data */
6187 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
6190 memcpy(bufferp->datap + bufIndex, op, nbytes);
6191 buf_SetDirty(bufferp);
6193 /* and record the last writer */
6194 if (bufferp->userp != userp) {
6197 cm_ReleaseUser(bufferp->userp);
6198 bufferp->userp = userp;
6201 /* adjust counters, pointers, etc. */
6205 thyper.LowPart = nbytes;
6206 thyper.HighPart = 0;
6207 offset = LargeIntegerAdd(thyper, offset);
6211 lock_ReleaseMutex(&scp->mx);
6214 lock_ReleaseMutex(&bufferp->mx);
6215 buf_Release(bufferp);
6218 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6219 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6220 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6221 fidp->NTopen_dscp, fidp->NTopen_pathp,
6224 lock_ReleaseMutex(&fidp->mx);
6226 if (code == 0 && doWriteBack) {
6228 lock_ObtainMutex(&scp->mx);
6229 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6231 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6232 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
6234 lock_ReleaseMutex(&scp->mx);
6235 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6236 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6239 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
6240 fidp->fid, code, *writtenp);
6244 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6247 long count, written = 0, total_written = 0;
6253 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6255 int inDataBlockCount;
6257 fd = smb_GetSMBParm(inp, 0);
6258 count = smb_GetSMBParm(inp, 1);
6259 offset.HighPart = 0; /* too bad */
6260 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6262 op = smb_GetSMBData(inp, NULL);
6263 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6265 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6266 fd, offset.LowPart, count);
6268 fd = smb_ChainFID(fd, inp);
6269 fidp = smb_FindFID(vcp, fd, 0);
6271 return CM_ERROR_BADFD;
6273 lock_ObtainMutex(&fidp->mx);
6274 if (fidp->flags & SMB_FID_IOCTL) {
6275 lock_ReleaseMutex(&fidp->mx);
6276 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6277 smb_ReleaseFID(fidp);
6280 lock_ReleaseMutex(&fidp->mx);
6281 userp = smb_GetUserFromVCP(vcp, inp);
6283 /* special case: 0 bytes transferred means truncate to this position */
6289 truncAttr.mask = CM_ATTRMASK_LENGTH;
6290 truncAttr.length.LowPart = offset.LowPart;
6291 truncAttr.length.HighPart = 0;
6292 lock_ObtainMutex(&fidp->mx);
6293 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6294 fidp->flags |= SMB_FID_LENGTHSETDONE;
6295 lock_ReleaseMutex(&fidp->mx);
6296 smb_SetSMBParm(outp, 0, /* count */ 0);
6297 smb_SetSMBDataLength(outp, 0);
6303 LARGE_INTEGER LOffset;
6304 LARGE_INTEGER LLength;
6306 pid = ((smb_t *) inp)->pid;
6307 key = cm_GenerateKey(vcp->vcID, pid, fd);
6309 LOffset.HighPart = offset.HighPart;
6310 LOffset.LowPart = offset.LowPart;
6311 LLength.HighPart = 0;
6312 LLength.LowPart = count;
6314 lock_ObtainMutex(&fidp->scp->mx);
6315 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6316 lock_ReleaseMutex(&fidp->scp->mx);
6323 * Work around bug in NT client
6325 * When copying a file, the NT client should first copy the data,
6326 * then copy the last write time. But sometimes the NT client does
6327 * these in the wrong order, so the data copies would inadvertently
6328 * cause the last write time to be overwritten. We try to detect this,
6329 * and don't set client mod time if we think that would go against the
6332 lock_ObtainMutex(&fidp->mx);
6333 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6334 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6335 fidp->scp->clientModTime = time(NULL);
6337 lock_ReleaseMutex(&fidp->mx);
6340 while ( code == 0 && count > 0 ) {
6342 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6344 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6346 if (code == 0 && written == 0)
6347 code = CM_ERROR_PARTIALWRITE;
6349 offset.LowPart += written;
6351 total_written += written;
6355 /* set the packet data length to 3 bytes for the data block header,
6356 * plus the size of the data.
6358 smb_SetSMBParm(outp, 0, total_written);
6359 smb_SetSMBDataLength(outp, 0);
6362 smb_ReleaseFID(fidp);
6363 cm_ReleaseUser(userp);
6368 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6369 NCB *ncbp, raw_write_cont_t *rwcp)
6382 fd = smb_GetSMBParm(inp, 0);
6383 fidp = smb_FindFID(vcp, fd, 0);
6385 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
6386 rwcp->offset.LowPart, rwcp->count);
6388 userp = smb_GetUserFromVCP(vcp, inp);
6392 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6395 rawBuf = (dos_ptr) rwcp->buf;
6396 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6397 (unsigned char *) rawBuf, userp,
6401 if (rwcp->writeMode & 0x1) { /* synchronous */
6404 smb_FormatResponsePacket(vcp, inp, outp);
6405 op = (smb_t *) outp;
6406 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6407 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6408 smb_SetSMBDataLength(outp, 0);
6409 smb_SendPacket(vcp, outp);
6410 smb_FreePacket(outp);
6412 else { /* asynchronous */
6413 lock_ObtainMutex(&fidp->mx);
6414 fidp->raw_writers--;
6415 if (fidp->raw_writers == 0)
6416 thrd_SetEvent(fidp->raw_write_event);
6417 lock_ReleaseMutex(&fidp->mx);
6420 /* Give back raw buffer */
6421 lock_ObtainMutex(&smb_RawBufLock);
6423 *((char **)rawBuf) = smb_RawBufs;
6425 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6427 smb_RawBufs = rawBuf;
6428 lock_ReleaseMutex(&smb_RawBufLock);
6430 smb_ReleaseFID(fidp);
6431 cm_ReleaseUser(userp);
6434 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6439 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6442 long count, written = 0, total_written = 0;
6449 unsigned short writeMode;
6456 fd = smb_GetSMBParm(inp, 0);
6457 totalCount = smb_GetSMBParm(inp, 1);
6458 count = smb_GetSMBParm(inp, 10);
6459 offset.HighPart = 0; /* too bad */
6460 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6461 writeMode = smb_GetSMBParm(inp, 7);
6463 op = (char *) inp->data;
6464 op += smb_GetSMBParm(inp, 11);
6467 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
6468 fd, offset.LowPart, count, writeMode);
6470 fd = smb_ChainFID(fd, inp);
6471 fidp = smb_FindFID(vcp, fd, 0);
6473 return CM_ERROR_BADFD;
6479 LARGE_INTEGER LOffset;
6480 LARGE_INTEGER LLength;
6482 pid = ((smb_t *) inp)->pid;
6483 key = cm_GenerateKey(vcp->vcID, pid, fd);
6485 LOffset.HighPart = offset.HighPart;
6486 LOffset.LowPart = offset.LowPart;
6487 LLength.HighPart = 0;
6488 LLength.LowPart = count;
6490 lock_ObtainMutex(&fidp->scp->mx);
6491 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6492 lock_ReleaseMutex(&fidp->scp->mx);
6495 smb_ReleaseFID(fidp);
6500 userp = smb_GetUserFromVCP(vcp, inp);
6503 * Work around bug in NT client
6505 * When copying a file, the NT client should first copy the data,
6506 * then copy the last write time. But sometimes the NT client does
6507 * these in the wrong order, so the data copies would inadvertently
6508 * cause the last write time to be overwritten. We try to detect this,
6509 * and don't set client mod time if we think that would go against the
6512 lock_ObtainMutex(&fidp->mx);
6513 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6514 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6515 fidp->scp->clientModTime = time(NULL);
6517 lock_ReleaseMutex(&fidp->mx);
6520 while ( code == 0 && count > 0 ) {
6522 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6524 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6526 if (code == 0 && written == 0)
6527 code = CM_ERROR_PARTIALWRITE;
6529 offset.LowPart += written;
6531 total_written += written;
6535 /* Get a raw buffer */
6538 lock_ObtainMutex(&smb_RawBufLock);
6540 /* Get a raw buf, from head of list */
6541 rawBuf = smb_RawBufs;
6543 smb_RawBufs = *(char **)smb_RawBufs;
6545 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6549 code = CM_ERROR_USESTD;
6551 lock_ReleaseMutex(&smb_RawBufLock);
6554 /* Don't allow a premature Close */
6555 if (code == 0 && (writeMode & 1) == 0) {
6556 lock_ObtainMutex(&fidp->mx);
6557 fidp->raw_writers++;
6558 thrd_ResetEvent(fidp->raw_write_event);
6559 lock_ReleaseMutex(&fidp->mx);
6562 smb_ReleaseFID(fidp);
6563 cm_ReleaseUser(userp);
6566 smb_SetSMBParm(outp, 0, total_written);
6567 smb_SetSMBDataLength(outp, 0);
6568 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6575 rwcp->offset.HighPart = 0;
6576 rwcp->offset.LowPart = offset.LowPart + count;
6577 rwcp->count = totalCount - count;
6578 rwcp->writeMode = writeMode;
6579 rwcp->alreadyWritten = total_written;
6581 /* set the packet data length to 3 bytes for the data block header,
6582 * plus the size of the data.
6584 smb_SetSMBParm(outp, 0, 0xffff);
6585 smb_SetSMBDataLength(outp, 0);
6590 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6593 long count, finalCount;
6601 fd = smb_GetSMBParm(inp, 0);
6602 count = smb_GetSMBParm(inp, 1);
6603 offset.HighPart = 0; /* too bad */
6604 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6606 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6607 fd, offset.LowPart, count);
6609 fd = smb_ChainFID(fd, inp);
6610 fidp = smb_FindFID(vcp, fd, 0);
6612 return CM_ERROR_BADFD;
6614 lock_ObtainMutex(&fidp->mx);
6615 if (fidp->flags & SMB_FID_IOCTL) {
6616 lock_ReleaseMutex(&fidp->mx);
6617 code = smb_IoctlRead(fidp, vcp, inp, outp);
6618 smb_ReleaseFID(fidp);
6621 lock_ReleaseMutex(&fidp->mx);
6624 LARGE_INTEGER LOffset, LLength;
6627 pid = ((smb_t *) inp)->pid;
6628 key = cm_GenerateKey(vcp->vcID, pid, fd);
6630 LOffset.HighPart = 0;
6631 LOffset.LowPart = offset.LowPart;
6632 LLength.HighPart = 0;
6633 LLength.LowPart = count;
6635 lock_ObtainMutex(&fidp->scp->mx);
6636 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6637 lock_ReleaseMutex(&fidp->scp->mx);
6640 smb_ReleaseFID(fidp);
6644 userp = smb_GetUserFromVCP(vcp, inp);
6646 /* remember this for final results */
6647 smb_SetSMBParm(outp, 0, count);
6648 smb_SetSMBParm(outp, 1, 0);
6649 smb_SetSMBParm(outp, 2, 0);
6650 smb_SetSMBParm(outp, 3, 0);
6651 smb_SetSMBParm(outp, 4, 0);
6653 /* set the packet data length to 3 bytes for the data block header,
6654 * plus the size of the data.
6656 smb_SetSMBDataLength(outp, count+3);
6658 /* get op ptr after putting in the parms, since otherwise we don't
6659 * know where the data really is.
6661 op = smb_GetSMBData(outp, NULL);
6663 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6664 *op++ = 1; /* data block marker */
6665 *op++ = (unsigned char) (count & 0xff);
6666 *op++ = (unsigned char) ((count >> 8) & 0xff);
6669 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6671 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6674 /* fix some things up */
6675 smb_SetSMBParm(outp, 0, finalCount);
6676 smb_SetSMBDataLength(outp, finalCount+3);
6678 smb_ReleaseFID(fidp);
6680 cm_ReleaseUser(userp);
6684 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6691 cm_scache_t *dscp; /* dir we're dealing with */
6692 cm_scache_t *scp; /* file we're creating */
6694 int initialModeBits;
6704 /* compute initial mode bits based on read-only flag in attributes */
6705 initialModeBits = 0777;
6707 tp = smb_GetSMBData(inp, NULL);
6708 pathp = smb_ParseASCIIBlock(tp, &tp);
6709 if (smb_StoreAnsiFilenames)
6710 OemToChar(pathp,pathp);
6712 if (strcmp(pathp, "\\") == 0)
6713 return CM_ERROR_EXISTS;
6715 spacep = inp->spacep;
6716 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6718 userp = smb_GetUserFromVCP(vcp, inp);
6720 caseFold = CM_FLAG_CASEFOLD;
6722 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6724 cm_ReleaseUser(userp);
6725 return CM_ERROR_NOSUCHPATH;
6728 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6729 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6730 userp, tidPathp, &req, &dscp);
6733 cm_ReleaseUser(userp);
6738 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6739 cm_ReleaseSCache(dscp);
6740 cm_ReleaseUser(userp);
6741 if ( WANTS_DFS_PATHNAMES(inp) )
6742 return CM_ERROR_PATH_NOT_COVERED;
6744 return CM_ERROR_BADSHARENAME;
6746 #endif /* DFS_SUPPORT */
6748 /* otherwise, scp points to the parent directory. Do a lookup, and
6749 * fail if we find it. Otherwise, we do the create.
6755 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6756 if (scp) cm_ReleaseSCache(scp);
6757 if (code != CM_ERROR_NOSUCHFILE) {
6758 if (code == 0) code = CM_ERROR_EXISTS;
6759 cm_ReleaseSCache(dscp);
6760 cm_ReleaseUser(userp);
6764 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6765 setAttr.clientModTime = time(NULL);
6766 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6767 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6768 smb_NotifyChange(FILE_ACTION_ADDED,
6769 FILE_NOTIFY_CHANGE_DIR_NAME,
6770 dscp, lastNamep, NULL, TRUE);
6772 /* we don't need this any longer */
6773 cm_ReleaseSCache(dscp);
6776 /* something went wrong creating or truncating the file */
6777 cm_ReleaseUser(userp);
6781 /* otherwise we succeeded */
6782 smb_SetSMBDataLength(outp, 0);
6783 cm_ReleaseUser(userp);
6788 BOOL smb_IsLegalFilename(char *filename)
6791 * Find the longest substring of filename that does not contain
6792 * any of the chars in illegalChars. If that substring is less
6793 * than the length of the whole string, then one or more of the
6794 * illegal chars is in filename.
6796 if (strcspn(filename, illegalChars) < strlen(filename))
6802 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6810 cm_scache_t *dscp; /* dir we're dealing with */
6811 cm_scache_t *scp; /* file we're creating */
6813 int initialModeBits;
6825 excl = (inp->inCom == 0x03)? 0 : 1;
6827 attributes = smb_GetSMBParm(inp, 0);
6828 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6830 /* compute initial mode bits based on read-only flag in attributes */
6831 initialModeBits = 0666;
6832 if (attributes & 1) initialModeBits &= ~0222;
6834 tp = smb_GetSMBData(inp, NULL);
6835 pathp = smb_ParseASCIIBlock(tp, &tp);
6836 if (smb_StoreAnsiFilenames)
6837 OemToChar(pathp,pathp);
6839 spacep = inp->spacep;
6840 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6842 userp = smb_GetUserFromVCP(vcp, inp);
6844 caseFold = CM_FLAG_CASEFOLD;
6846 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6848 cm_ReleaseUser(userp);
6849 return CM_ERROR_NOSUCHPATH;
6851 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6852 userp, tidPathp, &req, &dscp);
6855 cm_ReleaseUser(userp);
6860 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6861 cm_ReleaseSCache(dscp);
6862 cm_ReleaseUser(userp);
6863 if ( WANTS_DFS_PATHNAMES(inp) )
6864 return CM_ERROR_PATH_NOT_COVERED;
6866 return CM_ERROR_BADSHARENAME;
6868 #endif /* DFS_SUPPORT */
6870 /* otherwise, scp points to the parent directory. Do a lookup, and
6871 * truncate the file if we find it, otherwise we create the file.
6878 if (!smb_IsLegalFilename(lastNamep))
6879 return CM_ERROR_BADNTFILENAME;
6881 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6882 #ifdef DEBUG_VERBOSE
6885 hexp = osi_HexifyString( lastNamep );
6886 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6891 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6892 if (code && code != CM_ERROR_NOSUCHFILE) {
6893 cm_ReleaseSCache(dscp);
6894 cm_ReleaseUser(userp);
6898 /* if we get here, if code is 0, the file exists and is represented by
6899 * scp. Otherwise, we have to create it.
6903 /* oops, file shouldn't be there */
6904 cm_ReleaseSCache(dscp);
6905 cm_ReleaseSCache(scp);
6906 cm_ReleaseUser(userp);
6907 return CM_ERROR_EXISTS;
6910 setAttr.mask = CM_ATTRMASK_LENGTH;
6911 setAttr.length.LowPart = 0;
6912 setAttr.length.HighPart = 0;
6913 code = cm_SetAttr(scp, &setAttr, userp, &req);
6916 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6917 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6918 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6920 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6921 smb_NotifyChange(FILE_ACTION_ADDED,
6922 FILE_NOTIFY_CHANGE_FILE_NAME,
6923 dscp, lastNamep, NULL, TRUE);
6924 if (!excl && code == CM_ERROR_EXISTS) {
6925 /* not an exclusive create, and someone else tried
6926 * creating it already, then we open it anyway. We
6927 * don't bother retrying after this, since if this next
6928 * fails, that means that the file was deleted after
6929 * we started this call.
6931 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6934 setAttr.mask = CM_ATTRMASK_LENGTH;
6935 setAttr.length.LowPart = 0;
6936 setAttr.length.HighPart = 0;
6937 code = cm_SetAttr(scp, &setAttr, userp, &req);
6942 /* we don't need this any longer */
6943 cm_ReleaseSCache(dscp);
6946 /* something went wrong creating or truncating the file */
6947 if (scp) cm_ReleaseSCache(scp);
6948 cm_ReleaseUser(userp);
6952 /* make sure we only open files */
6953 if (scp->fileType != CM_SCACHETYPE_FILE) {
6954 cm_ReleaseSCache(scp);
6955 cm_ReleaseUser(userp);
6956 return CM_ERROR_ISDIR;
6959 /* now all we have to do is open the file itself */
6960 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6965 lock_ObtainMutex(&fidp->mx);
6966 /* always create it open for read/write */
6967 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6969 /* save a pointer to the vnode */
6972 fidp->userp = userp;
6973 lock_ReleaseMutex(&fidp->mx);
6975 smb_SetSMBParm(outp, 0, fidp->fid);
6976 smb_SetSMBDataLength(outp, 0);
6978 cm_Open(scp, 0, userp);
6980 smb_ReleaseFID(fidp);
6981 cm_ReleaseUser(userp);
6982 /* leave scp held since we put it in fidp->scp */
6986 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6999 fd = smb_GetSMBParm(inp, 0);
7000 whence = smb_GetSMBParm(inp, 1);
7001 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7003 /* try to find the file descriptor */
7004 fd = smb_ChainFID(fd, inp);
7005 fidp = smb_FindFID(vcp, fd, 0);
7008 return CM_ERROR_BADFD;
7010 lock_ObtainMutex(&fidp->mx);
7011 if (fidp->flags & SMB_FID_IOCTL) {
7012 lock_ReleaseMutex(&fidp->mx);
7013 smb_ReleaseFID(fidp);
7014 return CM_ERROR_BADFD;
7016 lock_ReleaseMutex(&fidp->mx);
7018 userp = smb_GetUserFromVCP(vcp, inp);
7020 lock_ObtainMutex(&fidp->mx);
7022 lock_ObtainMutex(&scp->mx);
7023 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7024 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7027 /* offset from current offset */
7028 offset += fidp->offset;
7030 else if (whence == 2) {
7031 /* offset from current EOF */
7032 offset += scp->length.LowPart;
7034 fidp->offset = offset;
7035 smb_SetSMBParm(outp, 0, offset & 0xffff);
7036 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
7037 smb_SetSMBDataLength(outp, 0);
7039 lock_ReleaseMutex(&scp->mx);
7040 lock_ReleaseMutex(&fidp->mx);
7041 smb_ReleaseFID(fidp);
7042 cm_ReleaseUser(userp);
7046 /* dispatch all of the requests received in a packet. Due to chaining, this may
7047 * be more than one request.
7049 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7050 NCB *ncbp, raw_write_cont_t *rwcp)
7054 unsigned long code = 0;
7055 unsigned char *outWctp;
7056 int nparms; /* # of bytes of parameters */
7058 int nbytes; /* bytes of data, excluding count */
7061 unsigned short errCode;
7062 unsigned long NTStatus;
7064 unsigned char errClass;
7065 unsigned int oldGen;
7066 DWORD oldTime, newTime;
7068 /* get easy pointer to the data */
7069 smbp = (smb_t *) inp->data;
7071 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7072 /* setup the basic parms for the initial request in the packet */
7073 inp->inCom = smbp->com;
7074 inp->wctp = &smbp->wct;
7076 inp->ncb_length = ncbp->ncb_length;
7081 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7082 /* log it and discard it */
7084 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7085 __FILE__, __LINE__, ncbp->ncb_length);
7087 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7091 /* We are an ongoing op */
7092 thrd_Increment(&ongoingOps);
7094 /* set up response packet for receiving output */
7095 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7096 smb_FormatResponsePacket(vcp, inp, outp);
7097 outWctp = outp->wctp;
7099 /* Remember session generation number and time */
7100 oldGen = sessionGen;
7101 oldTime = GetTickCount();
7103 while (inp->inCom != 0xff) {
7104 dp = &smb_dispatchTable[inp->inCom];
7106 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7107 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7108 code = outp->resumeCode;
7112 /* process each request in the packet; inCom, wctp and inCount
7113 * are already set up.
7115 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7118 /* now do the dispatch */
7119 /* start by formatting the response record a little, as a default */
7120 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7122 outWctp[1] = 0xff; /* no operation */
7123 outWctp[2] = 0; /* padding */
7128 /* not a chained request, this is a more reasonable default */
7129 outWctp[0] = 0; /* wct of zero */
7130 outWctp[1] = 0; /* and bcc (word) of zero */
7134 /* once set, stays set. Doesn't matter, since we never chain
7135 * "no response" calls.
7137 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7141 /* we have a recognized operation */
7143 if (inp->inCom == 0x1d)
7145 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7147 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7148 code = (*(dp->procp)) (vcp, inp, outp);
7149 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7151 if ( code == CM_ERROR_BADSMB ||
7152 code == CM_ERROR_BADOP )
7154 #endif /* LOG_PACKET */
7157 if (oldGen != sessionGen) {
7158 newTime = GetTickCount();
7160 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7161 newTime - oldTime, ncbp->ncb_length);
7163 osi_Log2(smb_logp, "Pkt straddled session startup, "
7164 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7168 /* bad opcode, fail the request, after displaying it */
7169 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7172 #endif /* LOG_PACKET */
7176 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7177 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7178 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7179 if (code == IDCANCEL)
7183 code = CM_ERROR_BADOP;
7186 /* catastrophic failure: log as much as possible */
7187 if (code == CM_ERROR_BADSMB) {
7189 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7194 #endif /* LOG_PACKET */
7195 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7198 code = CM_ERROR_INVAL;
7201 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7202 thrd_Decrement(&ongoingOps);
7207 /* now, if we failed, turn the current response into an empty
7208 * one, and fill in the response packet's error code.
7211 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7212 smb_MapNTError(code, &NTStatus);
7213 outWctp = outp->wctp;
7214 smbp = (smb_t *) &outp->data;
7215 if (code != CM_ERROR_PARTIALWRITE
7216 && code != CM_ERROR_BUFFERTOOSMALL
7217 && code != CM_ERROR_GSSCONTINUE) {
7218 /* nuke wct and bcc. For a partial
7219 * write or an in-process authentication handshake,
7220 * assume they're OK.
7226 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7227 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7228 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7229 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7230 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7234 smb_MapCoreError(code, vcp, &errCode, &errClass);
7235 outWctp = outp->wctp;
7236 smbp = (smb_t *) &outp->data;
7237 if (code != CM_ERROR_PARTIALWRITE) {
7238 /* nuke wct and bcc. For a partial
7239 * write, assume they're OK.
7245 smbp->errLow = (unsigned char) (errCode & 0xff);
7246 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7247 smbp->rcls = errClass;
7250 } /* error occurred */
7252 /* if we're here, we've finished one request. Look to see if
7253 * this is a chained opcode. If it is, setup things to process
7254 * the chained request, and setup the output buffer to hold the
7255 * chained response. Start by finding the next input record.
7257 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7258 break; /* not a chained req */
7259 tp = inp->wctp; /* points to start of last request */
7260 /* in a chained request, the first two
7261 * parm fields are required, and are
7262 * AndXCommand/AndXReserved and
7264 if (tp[0] < 2) break;
7265 if (tp[1] == 0xff) break; /* no more chained opcodes */
7267 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7270 /* and now append the next output request to the end of this
7271 * last request. Begin by finding out where the last response
7272 * ends, since that's where we'll put our new response.
7274 outWctp = outp->wctp; /* ptr to out parameters */
7275 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7276 nparms = outWctp[0] << 1;
7277 tp = outWctp + nparms + 1; /* now points to bcc field */
7278 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7279 tp += 2 /* for the count itself */ + nbytes;
7280 /* tp now points to the new output record; go back and patch the
7281 * second parameter (off2) to point to the new record.
7283 temp = (unsigned int)(tp - outp->data);
7284 outWctp[3] = (unsigned char) (temp & 0xff);
7285 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7286 outWctp[2] = 0; /* padding */
7287 outWctp[1] = inp->inCom; /* next opcode */
7289 /* finally, setup for the next iteration */
7292 } /* while loop over all requests in the packet */
7294 /* now send the output packet, and return */
7296 smb_SendPacket(vcp, outp);
7297 thrd_Decrement(&ongoingOps);
7299 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7300 if (active_vcp != vcp) {
7303 "Replacing active_vcp %x with %x", active_vcp, vcp);
7304 smb_ReleaseVC(active_vcp);
7307 lock_ObtainWrite(&smb_globalLock);
7309 lock_ReleaseWrite(&smb_globalLock);
7311 last_msg_time = GetTickCount();
7312 } else if (active_vcp == vcp) { /* the vcp is dead */
7313 smb_ReleaseVC(active_vcp);
7314 lock_ObtainWrite(&smb_globalLock);
7316 lock_ReleaseWrite(&smb_globalLock);
7322 /* Wait for Netbios() calls to return, and make the results available to server
7323 * threads. Note that server threads can't wait on the NCBevents array
7324 * themselves, because NCB events are manual-reset, and the servers would race
7325 * each other to reset them.
7327 void smb_ClientWaiter(void *parmp)
7332 while (smbShutdownFlag == 0) {
7333 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7335 if (code == WAIT_OBJECT_0)
7338 /* error checking */
7339 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7341 int abandonIdx = code - WAIT_ABANDONED_0;
7342 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7345 if (code == WAIT_IO_COMPLETION)
7347 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7351 if (code == WAIT_TIMEOUT)
7353 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7356 if (code == WAIT_FAILED)
7358 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7361 idx = code - WAIT_OBJECT_0;
7363 /* check idx range! */
7364 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7366 /* this is fatal - log as much as possible */
7367 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7371 thrd_ResetEvent(NCBevents[idx]);
7372 thrd_SetEvent(NCBreturns[0][idx]);
7378 * Try to have one NCBRECV request waiting for every live session. Not more
7379 * than one, because if there is more than one, it's hard to handle Write Raw.
7381 void smb_ServerWaiter(void *parmp)
7384 int idx_session, idx_NCB;
7390 while (smbShutdownFlag == 0) {
7392 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7394 if (code == WAIT_OBJECT_0)
7397 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7399 int abandonIdx = code - WAIT_ABANDONED_0;
7400 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7403 if (code == WAIT_IO_COMPLETION)
7405 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7409 if (code == WAIT_TIMEOUT)
7411 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7414 if (code == WAIT_FAILED)
7416 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7419 idx_session = code - WAIT_OBJECT_0;
7421 /* check idx range! */
7422 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7424 /* this is fatal - log as much as possible */
7425 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7431 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7433 if (code == WAIT_OBJECT_0) {
7434 if (smbShutdownFlag == 1)
7440 /* error checking */
7441 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7443 int abandonIdx = code - WAIT_ABANDONED_0;
7444 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7447 if (code == WAIT_IO_COMPLETION)
7449 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7453 if (code == WAIT_TIMEOUT)
7455 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7458 if (code == WAIT_FAILED)
7460 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7463 idx_NCB = code - WAIT_OBJECT_0;
7465 /* check idx range! */
7466 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7468 /* this is fatal - log as much as possible */
7469 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7473 /* Link them together */
7474 NCBsessions[idx_NCB] = idx_session;
7477 ncbp = NCBs[idx_NCB];
7478 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7479 ncbp->ncb_command = NCBRECV | ASYNCH;
7480 ncbp->ncb_lana_num = lanas[idx_session];
7482 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7483 ncbp->ncb_event = NCBevents[idx_NCB];
7484 ncbp->ncb_length = SMB_PACKETSIZE;
7487 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7488 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7489 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7490 ncbp->ncb_length = SMB_PACKETSIZE;
7491 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7492 Netbios(ncbp, dos_ncb);
7498 * The top level loop for handling SMB request messages. Each server thread
7499 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7500 * NCB and buffer for the incoming request are loaned to us.
7502 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7503 * to immediately send a request for the rest of the data. This must come
7504 * before any other traffic for that session, so we delay setting the session
7505 * event until that data has come in.
7507 void smb_Server(VOID *parmp)
7509 INT_PTR myIdx = (INT_PTR) parmp;
7513 smb_packet_t *outbufp;
7515 int idx_NCB, idx_session;
7517 smb_vc_t *vcp = NULL;
7523 rx_StartClientThread();
7526 outbufp = GetPacket();
7527 outbufp->ncbp = outncbp;
7534 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7537 /* terminate silently if shutdown flag is set */
7538 if (code == WAIT_OBJECT_0) {
7539 if (smbShutdownFlag == 1) {
7540 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7546 /* error checking */
7547 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7549 int abandonIdx = code - WAIT_ABANDONED_0;
7550 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7553 if (code == WAIT_IO_COMPLETION)
7555 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7559 if (code == WAIT_TIMEOUT)
7561 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7564 if (code == WAIT_FAILED)
7566 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7569 idx_NCB = code - WAIT_OBJECT_0;
7571 /* check idx range! */
7572 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7574 /* this is fatal - log as much as possible */
7575 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7579 ncbp = NCBs[idx_NCB];
7581 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7583 idx_session = NCBsessions[idx_NCB];
7584 rc = ncbp->ncb_retcode;
7586 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7587 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7591 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7595 /* Can this happen? Or is it just my UNIX paranoia? */
7596 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7602 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7606 /* Client closed session */
7607 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7609 lock_ObtainMutex(&vcp->mx);
7610 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7611 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7613 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7614 lock_ReleaseMutex(&vcp->mx);
7615 lock_ObtainWrite(&smb_globalLock);
7616 dead_sessions[vcp->session] = TRUE;
7617 lock_ReleaseWrite(&smb_globalLock);
7618 smb_CleanupDeadVC(vcp);
7622 lock_ReleaseMutex(&vcp->mx);
7628 /* Treat as transient error */
7630 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7634 "dispatch smb recv failed, message incomplete, ncb_length %d",
7637 "SMB message incomplete, "
7638 "length %d", ncbp->ncb_length);
7641 * We used to discard the packet.
7642 * Instead, try handling it normally.
7646 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7650 /* A weird error code. Log it, sleep, and continue. */
7651 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7653 lock_ObtainMutex(&vcp->mx);
7654 if (vcp && vcp->errorCount++ > 3) {
7655 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7656 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7657 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7659 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7660 lock_ReleaseMutex(&vcp->mx);
7661 lock_ObtainWrite(&smb_globalLock);
7662 dead_sessions[vcp->session] = TRUE;
7663 lock_ReleaseWrite(&smb_globalLock);
7664 smb_CleanupDeadVC(vcp);
7668 lock_ReleaseMutex(&vcp->mx);
7674 lock_ReleaseMutex(&vcp->mx);
7676 thrd_SetEvent(SessionEvents[idx_session]);
7681 /* Success, so now dispatch on all the data in the packet */
7683 smb_concurrentCalls++;
7684 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7685 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7688 * If at this point vcp is NULL (implies that packet was invalid)
7689 * then we are in big trouble. This means either :
7690 * a) we have the wrong NCB.
7691 * b) Netbios screwed up the call.
7692 * Obviously this implies that
7693 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7694 * lanas[idx_session] != ncbp->ncb_lana_num )
7695 * Either way, we can't do anything with this packet.
7696 * Log, sleep and resume.
7699 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7703 ncbp->ncb_lana_num);
7705 /* Also log in the trace log. */
7706 osi_Log4(smb_logp, "Server: BAD VCP!"
7707 "LSNs[idx_session]=[%d],"
7708 "lanas[idx_session]=[%d],"
7709 "ncbp->ncb_lsn=[%d],"
7710 "ncbp->ncb_lana_num=[%d]",
7714 ncbp->ncb_lana_num);
7716 /* thrd_Sleep(1000); Don't bother sleeping */
7717 thrd_SetEvent(SessionEvents[idx_session]);
7718 smb_concurrentCalls--;
7722 vcp->errorCount = 0;
7723 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7725 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7726 /* copy whole packet to virtual memory */
7727 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7729 bufp->dos_pkt / 16, bufp);*/
7731 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7733 smbp = (smb_t *)bufp->data;
7736 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7740 if (smbp->com == 0x1d) {
7741 /* Special handling for Write Raw */
7742 raw_write_cont_t rwc;
7743 EVENT_HANDLE rwevent;
7744 char eventName[MAX_PATH];
7746 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7747 if (rwc.code == 0) {
7748 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7749 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7750 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7751 ncbp->ncb_command = NCBRECV | ASYNCH;
7752 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7753 ncbp->ncb_lana_num = vcp->lana;
7754 ncbp->ncb_buffer = rwc.buf;
7755 ncbp->ncb_length = 65535;
7756 ncbp->ncb_event = rwevent;
7760 Netbios(ncbp, dos_ncb);
7762 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7763 thrd_CloseHandle(rwevent);
7765 thrd_SetEvent(SessionEvents[idx_session]);
7767 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7769 else if (smbp->com == 0xa0) {
7771 * Serialize the handling for NT Transact
7774 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7775 thrd_SetEvent(SessionEvents[idx_session]);
7777 thrd_SetEvent(SessionEvents[idx_session]);
7778 /* TODO: what else needs to be serialized? */
7779 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7781 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7783 __except( smb_ServerExceptionFilter() ) {
7787 smb_concurrentCalls--;
7790 thrd_SetEvent(NCBavails[idx_NCB]);
7797 * Exception filter for the server threads. If an exception occurs in the
7798 * dispatch routines, which is where exceptions are most common, then do a
7799 * force trace and give control to upstream exception handlers. Useful for
7802 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7803 DWORD smb_ServerExceptionFilter(void) {
7804 /* While this is not the best time to do a trace, if it succeeds, then
7805 * we have a trace (assuming tracing was enabled). Otherwise, this should
7806 * throw a second exception.
7808 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7809 afsd_ForceTrace(TRUE);
7810 buf_ForceTrace(TRUE);
7811 return EXCEPTION_CONTINUE_SEARCH;
7816 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7817 * If the number of server threads is M, and the number of live sessions is
7818 * N, then the number of NCB's in use at any time either waiting for, or
7819 * holding, received messages is M + N, so that is how many NCB's get created.
7821 void InitNCBslot(int idx)
7823 struct smb_packet *bufp;
7824 EVENT_HANDLE retHandle;
7826 char eventName[MAX_PATH];
7828 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7830 NCBs[idx] = GetNCB();
7831 sprintf(eventName,"NCBavails[%d]", idx);
7832 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7833 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7834 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7836 sprintf(eventName,"NCBevents[%d]", idx);
7837 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7838 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7839 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7841 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7842 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7843 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7844 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7845 for (i=0; i<smb_NumServerThreads; i++)
7846 NCBreturns[i][idx] = retHandle;
7848 bufp->spacep = cm_GetSpace();
7852 /* listen for new connections */
7853 void smb_Listener(void *parmp)
7859 int session, thread;
7860 smb_vc_t *vcp = NULL;
7862 char rname[NCBNAMSZ+1];
7863 char cname[MAX_COMPUTERNAME_LENGTH+1];
7864 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7869 INT_PTR lana = (INT_PTR) parmp;
7873 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7876 /* retrieve computer name */
7877 GetComputerName(cname, &cnamelen);
7881 memset(ncbp, 0, sizeof(NCB));
7884 ncbp->ncb_command = NCBLISTEN;
7885 ncbp->ncb_rto = 0; /* No receive timeout */
7886 ncbp->ncb_sto = 0; /* No send timeout */
7888 /* pad out with spaces instead of null termination */
7889 len = (long)strlen(smb_localNamep);
7890 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7891 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7893 strcpy(ncbp->ncb_callname, "*");
7894 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7896 ncbp->ncb_lana_num = (UCHAR)lana;
7899 code = Netbios(ncbp);
7901 code = Netbios(ncbp, dos_ncb);
7910 /* terminate silently if shutdown flag is set */
7911 if (smbShutdownFlag == 1) {
7920 "NCBLISTEN lana=%d failed with code %d",
7921 ncbp->ncb_lana_num, code);
7923 "Client exiting due to network failure. Please restart client.\n");
7927 "Client exiting due to network failure. Please restart client.\n"
7928 "NCBLISTEN lana=%d failed with code %d",
7929 ncbp->ncb_lana_num, code);
7931 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7932 MB_OK|MB_SERVICE_NOTIFICATION);
7933 osi_assert(tbuffer);
7936 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7937 ncbp->ncb_lana_num, code);
7938 fprintf(stderr, "\nClient exiting due to network failure "
7939 "(possibly due to power-saving mode)\n");
7940 fprintf(stderr, "Please restart client.\n");
7941 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7945 /* check for remote conns */
7946 /* first get remote name and insert null terminator */
7947 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7948 for (i=NCBNAMSZ; i>0; i--) {
7949 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7955 /* compare with local name */
7957 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7958 flags |= SMB_VCFLAG_REMOTECONN;
7961 lock_ObtainMutex(&smb_ListenerLock);
7963 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7964 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
7966 /* now ncbp->ncb_lsn is the connection ID */
7967 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7968 if (vcp->session == 0) {
7969 /* New generation */
7970 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7973 /* Log session startup */
7975 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
7976 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7977 #endif /* NOTSERVICE */
7978 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7979 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7981 if (reportSessionStartups) {
7983 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7986 fprintf(stderr, "%s: New session %d starting from host %s\n",
7987 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7992 lock_ObtainMutex(&vcp->mx);
7993 strcpy(vcp->rname, rname);
7994 vcp->flags |= flags;
7995 lock_ReleaseMutex(&vcp->mx);
7997 /* Allocate slot in session arrays */
7998 /* Re-use dead session if possible, otherwise add one more */
7999 /* But don't look at session[0], it is reserved */
8000 lock_ObtainWrite(&smb_globalLock);
8001 for (session = 1; session < numSessions; session++) {
8002 if (dead_sessions[session]) {
8003 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8004 dead_sessions[session] = FALSE;
8008 lock_ReleaseWrite(&smb_globalLock);
8010 /* We are re-using an existing VC because the lsn and lana
8012 session = vcp->session;
8014 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8016 /* Log session startup */
8018 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8019 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8020 #endif /* NOTSERVICE */
8021 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8022 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8024 if (reportSessionStartups) {
8026 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8029 fprintf(stderr, "%s: Re-using session %d starting from host %s\n",
8030 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8036 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8037 unsigned long code = CM_ERROR_ALLBUSY;
8038 smb_packet_t * outp = GetPacket();
8039 unsigned char *outWctp;
8042 smb_FormatResponsePacket(vcp, NULL, outp);
8045 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8046 unsigned long NTStatus;
8047 smb_MapNTError(code, &NTStatus);
8048 outWctp = outp->wctp;
8049 smbp = (smb_t *) &outp->data;
8053 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8054 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8055 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8056 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8057 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8059 unsigned short errCode;
8060 unsigned char errClass;
8061 smb_MapCoreError(code, vcp, &errCode, &errClass);
8062 outWctp = outp->wctp;
8063 smbp = (smb_t *) &outp->data;
8067 smbp->errLow = (unsigned char) (errCode & 0xff);
8068 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8069 smbp->rcls = errClass;
8071 smb_SendPacket(vcp, outp);
8072 smb_FreePacket(outp);
8074 lock_ObtainMutex(&vcp->mx);
8075 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8076 lock_ReleaseMutex(&vcp->mx);
8077 smb_CleanupDeadVC(vcp);
8079 /* assert that we do not exceed the maximum number of sessions or NCBs.
8080 * we should probably want to wait for a session to be freed in case
8083 osi_assert(session < SESSION_MAX - 1);
8084 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8086 lock_ObtainMutex(&vcp->mx);
8087 vcp->session = session;
8088 lock_ReleaseMutex(&vcp->mx);
8089 lock_ObtainWrite(&smb_globalLock);
8090 LSNs[session] = ncbp->ncb_lsn;
8091 lanas[session] = ncbp->ncb_lana_num;
8092 lock_ReleaseWrite(&smb_globalLock);
8094 if (session == numSessions) {
8095 /* Add new NCB for new session */
8096 char eventName[MAX_PATH];
8098 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8100 InitNCBslot(numNCBs);
8101 lock_ObtainWrite(&smb_globalLock);
8103 lock_ReleaseWrite(&smb_globalLock);
8104 thrd_SetEvent(NCBavails[0]);
8105 thrd_SetEvent(NCBevents[0]);
8106 for (thread = 0; thread < smb_NumServerThreads; thread++)
8107 thrd_SetEvent(NCBreturns[thread][0]);
8108 /* Also add new session event */
8109 sprintf(eventName, "SessionEvents[%d]", session);
8110 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8111 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8112 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8113 lock_ObtainWrite(&smb_globalLock);
8115 lock_ReleaseWrite(&smb_globalLock);
8116 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8117 thrd_SetEvent(SessionEvents[0]);
8119 thrd_SetEvent(SessionEvents[session]);
8125 lock_ReleaseMutex(&smb_ListenerLock);
8126 } /* dispatch while loop */
8129 /* initialize Netbios */
8130 void smb_NetbiosInit()
8136 int i, lana, code, l;
8138 int delname_tried=0;
8141 OSVERSIONINFO Version;
8143 /* Get the version of Windows */
8144 memset(&Version, 0x00, sizeof(Version));
8145 Version.dwOSVersionInfoSize = sizeof(Version);
8146 GetVersionEx(&Version);
8148 /* setup the NCB system */
8151 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8155 if (smb_LANadapter == -1) {
8156 ncbp->ncb_command = NCBENUM;
8157 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8158 ncbp->ncb_length = sizeof(lana_list);
8159 code = Netbios(ncbp);
8161 afsi_log("Netbios NCBENUM error code %d", code);
8162 osi_panic(s, __FILE__, __LINE__);
8166 lana_list.length = 1;
8167 lana_list.lana[0] = smb_LANadapter;
8170 for (i = 0; i < lana_list.length; i++) {
8171 /* reset the adaptor: in Win32, this is required for every process, and
8172 * acts as an init call, not as a real hardware reset.
8174 ncbp->ncb_command = NCBRESET;
8175 ncbp->ncb_callname[0] = 100;
8176 ncbp->ncb_callname[2] = 100;
8177 ncbp->ncb_lana_num = lana_list.lana[i];
8178 code = Netbios(ncbp);
8180 code = ncbp->ncb_retcode;
8182 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8183 lana_list.lana[i] = 255; /* invalid lana */
8185 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8189 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
8190 we will just fake the LANA list */
8191 if (smb_LANadapter == -1) {
8192 for (i = 0; i < 8; i++)
8193 lana_list.lana[i] = i;
8194 lana_list.length = 8;
8197 lana_list.length = 1;
8198 lana_list.lana[0] = smb_LANadapter;
8202 /* and declare our name so we can receive connections */
8203 memset(ncbp, 0, sizeof(*ncbp));
8204 len=lstrlen(smb_localNamep);
8205 memset(smb_sharename,' ',NCBNAMSZ);
8206 memcpy(smb_sharename,smb_localNamep,len);
8207 afsi_log("lana_list.length %d", lana_list.length);
8209 /* Keep the name so we can unregister it later */
8210 for (l = 0; l < lana_list.length; l++) {
8211 lana = lana_list.lana[l];
8213 ncbp->ncb_command = NCBADDNAME;
8214 ncbp->ncb_lana_num = lana;
8215 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8217 code = Netbios(ncbp);
8219 code = Netbios(ncbp, dos_ncb);
8222 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8223 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8225 char name[NCBNAMSZ+1];
8227 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8228 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8231 if (code == 0) code = ncbp->ncb_retcode;
8233 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8235 /* we only use one LANA with djgpp */
8236 lana_list.lana[0] = lana;
8237 lana_list.length = 1;
8241 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8242 if (code == NRC_BRIDGE) { /* invalid LANA num */
8243 lana_list.lana[l] = 255;
8246 else if (code == NRC_DUPNAME) {
8247 afsi_log("Name already exists; try to delete it");
8248 memset(ncbp, 0, sizeof(*ncbp));
8249 ncbp->ncb_command = NCBDELNAME;
8250 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8251 ncbp->ncb_lana_num = lana;
8253 code = Netbios(ncbp);
8255 code = Netbios(ncbp, dos_ncb);
8258 code = ncbp->ncb_retcode;
8260 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8262 if (code != 0 || delname_tried) {
8263 lana_list.lana[l] = 255;
8265 else if (code == 0) {
8266 if (!delname_tried) {
8274 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8275 lana_list.lana[l] = 255; /* invalid lana */
8276 osi_panic(s, __FILE__, __LINE__);
8280 lana_found = 1; /* at least one worked */
8287 osi_assert(lana_list.length >= 0);
8289 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8292 /* we're done with the NCB now */
8296 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8313 EVENT_HANDLE retHandle;
8314 char eventName[MAX_PATH];
8317 smb_MBfunc = aMBfunc;
8321 smb_LANadapter = LANadapt;
8323 /* Initialize smb_localZero */
8324 myTime.tm_isdst = -1; /* compute whether on DST or not */
8325 myTime.tm_year = 70;
8331 smb_localZero = mktime(&myTime);
8333 #ifndef USE_NUMERIC_TIME_CONV
8334 /* Initialize kludge-GMT */
8335 smb_CalculateNowTZ();
8336 #endif /* USE_NUMERIC_TIME_CONV */
8337 #ifdef AFS_FREELANCE_CLIENT
8338 /* Make sure the root.afs volume has the correct time */
8339 cm_noteLocalMountPointChange();
8342 /* initialize the remote debugging log */
8345 /* remember the name */
8346 len = (int)strlen(snamep);
8347 smb_localNamep = malloc(len+1);
8348 strcpy(smb_localNamep, snamep);
8349 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8351 /* and the global lock */
8352 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8353 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8355 /* Raw I/O data structures */
8356 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8358 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8360 /* 4 Raw I/O buffers */
8362 smb_RawBufs = calloc(65536,1);
8363 *((char **)smb_RawBufs) = NULL;
8364 for (i=0; i<3; i++) {
8365 char *rawBuf = calloc(65536,1);
8366 *((char **)rawBuf) = smb_RawBufs;
8367 smb_RawBufs = rawBuf;
8370 npar = 65536 >> 4; /* number of paragraphs */
8371 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8373 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8375 osi_panic("",__FILE__,__LINE__);
8378 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8381 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8383 _farpokel(_dos_ds, smb_RawBufs, NULL);
8384 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8385 npar = 65536 >> 4; /* number of paragraphs */
8386 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8388 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8390 osi_panic("",__FILE__,__LINE__);
8393 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8396 rawBuf = (seg * 16) + 0; /* DOS physical address */
8397 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8398 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8399 smb_RawBufs = rawBuf;
8403 /* global free lists */
8404 smb_ncbFreeListp = NULL;
8405 smb_packetFreeListp = NULL;
8409 /* Initialize listener and server structures */
8411 memset(dead_sessions, 0, sizeof(dead_sessions));
8412 sprintf(eventName, "SessionEvents[0]");
8413 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8414 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8415 afsi_log("Event Object Already Exists: %s", eventName);
8417 smb_NumServerThreads = nThreads;
8418 sprintf(eventName, "NCBavails[0]");
8419 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8420 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8421 afsi_log("Event Object Already Exists: %s", eventName);
8422 sprintf(eventName, "NCBevents[0]");
8423 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8424 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8425 afsi_log("Event Object Already Exists: %s", eventName);
8426 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8427 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8428 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8429 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8430 afsi_log("Event Object Already Exists: %s", eventName);
8431 for (i = 0; i < smb_NumServerThreads; i++) {
8432 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8433 NCBreturns[i][0] = retHandle;
8436 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8437 for (i = 0; i < smb_NumServerThreads; i++) {
8438 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8439 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8440 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8441 afsi_log("Event Object Already Exists: %s", eventName);
8442 InitNCBslot((int)(i+1));
8444 numNCBs = smb_NumServerThreads + 1;
8446 /* Initialize dispatch table */
8447 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8448 /* Prepare the table for unknown operations */
8449 for(i=0; i<= SMB_NOPCODES; i++) {
8450 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8452 /* Fill in the ones we do know */
8453 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8454 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8455 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8456 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8457 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8458 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8459 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8460 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8461 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8462 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8463 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8464 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8465 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8466 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8467 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8468 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8469 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8470 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8471 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8472 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8473 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8474 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8475 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8476 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8477 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8478 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8479 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8480 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8481 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8482 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8483 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8484 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8485 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8486 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8487 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8488 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8489 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8490 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8491 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8492 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8493 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8494 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8495 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8496 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8497 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8498 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8499 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8500 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8501 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8502 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8503 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8504 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8505 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8506 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8507 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8508 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8509 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8510 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8511 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8512 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8513 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8514 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8515 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8516 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8517 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8518 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8519 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8520 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8521 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8522 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8523 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8524 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8526 /* setup tran 2 dispatch table */
8527 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8528 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8529 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8530 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8531 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8532 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8533 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8534 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8535 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8536 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8537 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8538 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8539 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8540 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8541 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8542 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8543 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8545 /* setup the rap dispatch table */
8546 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8547 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8548 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8549 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8550 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8554 /* if we are doing SMB authentication we have register outselves as a logon process */
8555 if (smb_authType != SMB_AUTH_NONE) {
8556 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8557 LSA_STRING afsProcessName;
8558 LSA_OPERATIONAL_MODE dummy; /*junk*/
8560 afsProcessName.Buffer = "OpenAFSClientDaemon";
8561 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8562 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8564 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8566 if (nts == STATUS_SUCCESS) {
8567 LSA_STRING packageName;
8568 /* we are registered. Find out the security package id */
8569 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8570 packageName.Length = (USHORT)strlen(packageName.Buffer);
8571 packageName.MaximumLength = packageName.Length + 1;
8572 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8573 if (nts == STATUS_SUCCESS) {
8575 * This code forces Windows to authenticate against the Logon Cache
8576 * first instead of attempting to authenticate against the Domain
8577 * Controller. When the Windows logon cache is enabled this improves
8578 * performance by removing the network access and works around a bug
8579 * seen at sites which are using a MIT Kerberos principal to login
8580 * to machines joined to a non-root domain in a multi-domain forest.
8582 PVOID pResponse = NULL;
8583 ULONG cbResponse = 0;
8584 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8586 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8587 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8588 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8589 OptionsRequest.DisableOptions = FALSE;
8591 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8594 sizeof(OptionsRequest),
8600 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8602 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8604 OutputDebugString(message);
8607 OutputDebugString("MsV1_0SetProcessOption success");
8608 afsi_log("MsV1_0SetProcessOption success");
8610 /* END - code from Larry */
8612 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8613 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8614 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8616 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8618 /* something went wrong. We report the error and revert back to no authentication
8619 because we can't perform any auth requests without a successful lsa handle
8620 or sec package id. */
8621 afsi_log("Reverting to NO SMB AUTH");
8622 smb_authType = SMB_AUTH_NONE;
8625 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8627 /* something went wrong. We report the error and revert back to no authentication
8628 because we can't perform any auth requests without a successful lsa handle
8629 or sec package id. */
8630 afsi_log("Reverting to NO SMB AUTH");
8631 smb_authType = SMB_AUTH_NONE;
8635 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8636 * time prevents the failure of authentication when logged into Windows with an
8637 * external Kerberos principal mapped to a local account.
8639 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8640 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8641 * then the only option is NTLMSSP anyway; so just fallback.
8646 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8647 if (secBlobLength == 0) {
8648 smb_authType = SMB_AUTH_NTLM;
8649 afsi_log("Reverting to SMB AUTH NTLM");
8658 /* Now get ourselves a domain name. */
8659 /* For now we are using the local computer name as the domain name.
8660 * It is actually the domain for local logins, and we are acting as
8661 * a local SMB server.
8663 bufsize = sizeof(smb_ServerDomainName) - 1;
8664 GetComputerName(smb_ServerDomainName, &bufsize);
8665 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8666 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8669 /* Start listeners, waiters, servers, and daemons */
8671 for (i = 0; i < lana_list.length; i++) {
8672 if (lana_list.lana[i] == 255)
8674 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8675 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8676 osi_assert(phandle != NULL);
8677 thrd_CloseHandle(phandle);
8681 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8682 NULL, 0, &lpid, "smb_ClientWaiter");
8683 osi_assert(phandle != NULL);
8684 thrd_CloseHandle(phandle);
8687 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8688 NULL, 0, &lpid, "smb_ServerWaiter");
8689 osi_assert(phandle != NULL);
8690 thrd_CloseHandle(phandle);
8692 for (i=0; i<smb_NumServerThreads; i++) {
8693 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8694 (void *) i, 0, &lpid, "smb_Server");
8695 osi_assert(phandle != NULL);
8696 thrd_CloseHandle(phandle);
8699 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8700 NULL, 0, &lpid, "smb_Daemon");
8701 osi_assert(phandle != NULL);
8702 thrd_CloseHandle(phandle);
8704 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8705 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8706 osi_assert(phandle != NULL);
8707 thrd_CloseHandle(phandle);
8716 void smb_Shutdown(void)
8726 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8728 /* setup the NCB system */
8731 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8734 /* Block new sessions by setting shutdown flag */
8735 smbShutdownFlag = 1;
8737 /* Hang up all sessions */
8738 memset((char *)ncbp, 0, sizeof(NCB));
8739 for (i = 1; i < numSessions; i++)
8741 if (dead_sessions[i])
8744 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8745 ncbp->ncb_command = NCBHANGUP;
8746 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8747 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8749 code = Netbios(ncbp);
8751 code = Netbios(ncbp, dos_ncb);
8753 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8754 if (code == 0) code = ncbp->ncb_retcode;
8756 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8757 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8761 /* Trigger the shutdown of all SMB threads */
8762 for (i = 0; i < smb_NumServerThreads; i++)
8763 thrd_SetEvent(NCBreturns[i][0]);
8765 thrd_SetEvent(NCBevents[0]);
8766 thrd_SetEvent(SessionEvents[0]);
8767 thrd_SetEvent(NCBavails[0]);
8769 for (i = 0;i < smb_NumServerThreads; i++) {
8770 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8771 if (code == WAIT_OBJECT_0) {
8774 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8775 thrd_SetEvent(NCBreturns[i--][0]);
8779 /* Delete Netbios name */
8780 memset((char *)ncbp, 0, sizeof(NCB));
8781 for (i = 0; i < lana_list.length; i++) {
8782 if (lana_list.lana[i] == 255) continue;
8783 ncbp->ncb_command = NCBDELNAME;
8784 ncbp->ncb_lana_num = lana_list.lana[i];
8785 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8787 code = Netbios(ncbp);
8789 code = Netbios(ncbp, dos_ncb);
8792 code = ncbp->ncb_retcode;
8794 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8795 ncbp->ncb_lana_num, code);
8800 /* Release the reference counts held by the VCs */
8801 lock_ObtainWrite(&smb_rctLock);
8802 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8807 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8809 if (fidp->scp != NULL) {
8812 lock_ObtainMutex(&fidp->mx);
8813 if (fidp->scp != NULL) {
8816 cm_ReleaseSCache(scp);
8818 lock_ReleaseMutex(&fidp->mx);
8822 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8824 smb_ReleaseVCNoLock(tidp->vcp);
8826 cm_user_t *userp = tidp->userp;
8828 lock_ReleaseWrite(&smb_rctLock);
8829 cm_ReleaseUser(userp);
8830 lock_ObtainWrite(&smb_rctLock);
8834 lock_ReleaseWrite(&smb_rctLock);
8837 /* Get the UNC \\<servername>\<sharename> prefix. */
8838 char *smb_GetSharename()
8842 /* Make sure we have been properly initialized. */
8843 if (smb_localNamep == NULL)
8846 /* Allocate space for \\<servername>\<sharename>, plus the
8849 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8850 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8856 void smb_LogPacket(smb_packet_t *packet)
8859 unsigned length, paramlen, datalen, i, j;
8861 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8863 if (!packet) return;
8865 osi_Log0(smb_logp, "*** SMB packet dump ***");
8867 vp = (BYTE *) packet->data;
8869 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8870 length = paramlen + 2 + datalen;
8873 for (i=0;i < length; i+=16)
8875 memset( buf, ' ', 80 );
8880 buf[strlen(buf)] = ' ';
8882 cp = (BYTE*) buf + 7;
8884 for (j=0;j < 16 && (i+j)<length; j++)
8886 *(cp++) = hex[vp[i+j] >> 4];
8887 *(cp++) = hex[vp[i+j] & 0xf];
8897 for (j=0;j < 16 && (i+j)<length;j++)
8899 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8910 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
8913 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8915 #endif /* LOG_PACKET */
8918 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8926 lock_ObtainRead(&smb_rctLock);
8928 sprintf(output, "begin dumping smb_vc_t\n");
8929 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8931 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8935 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8936 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8937 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8939 sprintf(output, "begin dumping smb_fid_t\n");
8940 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8942 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8944 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",
8945 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8946 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8947 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8948 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8951 sprintf(output, "done dumping smb_fid_t\n");
8952 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8955 sprintf(output, "done dumping smb_vc_t\n");
8956 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8958 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8959 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8961 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8965 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8966 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8967 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8969 sprintf(output, "begin dumping smb_fid_t\n");
8970 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8972 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8974 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",
8975 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8976 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8977 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8978 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8981 sprintf(output, "done dumping smb_fid_t\n");
8982 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8985 sprintf(output, "done dumping DEAD smb_vc_t\n");
8986 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8988 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8989 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8991 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8995 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8996 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8997 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8999 sprintf(output, "begin dumping smb_fid_t\n");
9000 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9002 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9004 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",
9005 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9006 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9007 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9008 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9011 sprintf(output, "done dumping smb_fid_t\n");
9012 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9015 sprintf(output, "done dumping DEAD smb_vc_t\n");
9016 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9019 lock_ReleaseRead(&smb_rctLock);