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)
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 (vcp->magic != SMB_VC_MAGIC)
862 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
865 if (lsn == vcp->lsn && lana == vcp->lana) {
866 smb_HoldVCNoLock(vcp);
870 if (!vcp && (flags & SMB_FLAG_CREATE)) {
871 vcp = malloc(sizeof(*vcp));
872 memset(vcp, 0, sizeof(*vcp));
873 lock_ObtainWrite(&smb_globalLock);
874 vcp->vcID = ++numVCs;
875 lock_ReleaseWrite(&smb_globalLock);
876 vcp->magic = SMB_VC_MAGIC;
877 vcp->refCount = 2; /* smb_allVCsp and caller */
880 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
881 vcp->nextp = smb_allVCsp;
883 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
888 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
889 /* We must obtain a challenge for extended auth
890 * in case the client negotiates smb v3
892 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
893 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
894 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
895 ULONG lsaRespSize = 0;
897 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
899 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
906 if (nts != STATUS_SUCCESS)
907 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
908 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
909 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
911 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
912 LsaFreeReturnBuffer(lsaResp);
915 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
917 if (numVCs >= CM_SESSION_RESERVED) {
918 lock_ObtainWrite(&smb_globalLock);
920 lock_ReleaseWrite(&smb_globalLock);
921 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
924 lock_ReleaseWrite(&smb_rctLock);
928 int smb_IsStarMask(char *maskp)
933 for(i=0; i<11; i++) {
935 if (tc == '?' || tc == '*' || tc == '>')
941 void smb_ReleaseVCInternal(smb_vc_t *vcp)
948 if (vcp->refCount == 0) {
949 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
950 /* remove VCP from smb_deadVCsp */
951 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
957 lock_FinalizeMutex(&vcp->mx);
958 memset(vcp,0,sizeof(smb_vc_t));
961 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
965 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
966 avcp?"not ":"",vcp, vcp->refCount);
968 GenerateMiniDump(NULL);
970 /* This is a wrong. However, I suspect that there is an undercount
971 * and I don't want to release 1.4.1 in a state that will allow
972 * smb_vc_t objects to be deallocated while still in the
973 * smb_allVCsp list. The list is supposed to keep a reference
974 * to the smb_vc_t. Put it back.
981 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
983 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
984 smb_ReleaseVCInternal(vcp);
987 void smb_ReleaseVC(smb_vc_t *vcp)
989 lock_ObtainWrite(&smb_rctLock);
990 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
991 smb_ReleaseVCInternal(vcp);
992 lock_ReleaseWrite(&smb_rctLock);
995 void smb_HoldVCNoLock(smb_vc_t *vcp)
998 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1001 void smb_HoldVC(smb_vc_t *vcp)
1003 lock_ObtainWrite(&smb_rctLock);
1005 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1006 lock_ReleaseWrite(&smb_rctLock);
1009 void smb_CleanupDeadVC(smb_vc_t *vcp)
1011 smb_fid_t *fidpIter;
1012 smb_fid_t *fidpNext;
1014 smb_tid_t *tidpIter;
1015 smb_tid_t *tidpNext;
1017 smb_user_t *uidpIter;
1018 smb_user_t *uidpNext;
1021 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1023 lock_ObtainWrite(&smb_rctLock);
1024 /* remove VCP from smb_allVCsp */
1025 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1026 if ((*vcpp)->magic != SMB_VC_MAGIC)
1027 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1028 __FILE__, __LINE__);
1031 vcp->nextp = smb_deadVCsp;
1033 /* Hold onto the reference until we are done with this function */
1038 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1039 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1041 if (fidpIter->delete)
1044 fid = fidpIter->fid;
1045 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1047 smb_HoldFIDNoLock(fidpIter);
1048 lock_ReleaseWrite(&smb_rctLock);
1050 smb_CloseFID(vcp, fidpIter, NULL, 0);
1051 smb_ReleaseFID(fidpIter);
1053 lock_ObtainWrite(&smb_rctLock);
1054 fidpNext = vcp->fidsp;
1057 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1058 tidpNext = tidpIter->nextp;
1059 if (tidpIter->delete)
1061 tidpIter->delete = 1;
1063 tid = tidpIter->tid;
1064 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1066 smb_HoldTIDNoLock(tidpIter);
1067 lock_ReleaseWrite(&smb_rctLock);
1069 smb_ReleaseTID(tidpIter);
1071 lock_ObtainWrite(&smb_rctLock);
1072 tidpNext = vcp->tidsp;
1075 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1076 uidpNext = uidpIter->nextp;
1077 if (uidpIter->delete)
1079 uidpIter->delete = 1;
1081 /* do not add an additional reference count for the smb_user_t
1082 * as the smb_vc_t already is holding a reference */
1083 lock_ReleaseWrite(&smb_rctLock);
1085 smb_ReleaseUID(uidpIter);
1087 lock_ObtainWrite(&smb_rctLock);
1088 uidpNext = vcp->usersp;
1092 /* The vcp is now on the deadVCsp list. We intentionally drop the
1093 * reference so that the refcount can reach 0 and we can delete it */
1094 smb_ReleaseVCNoLock(vcp);
1096 lock_ReleaseWrite(&smb_rctLock);
1097 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1100 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1104 lock_ObtainWrite(&smb_rctLock);
1105 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1106 if (tid == tidp->tid) {
1111 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1112 tidp = malloc(sizeof(*tidp));
1113 memset(tidp, 0, sizeof(*tidp));
1114 tidp->nextp = vcp->tidsp;
1117 smb_HoldVCNoLock(vcp);
1119 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1122 lock_ReleaseWrite(&smb_rctLock);
1126 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1131 void smb_ReleaseTID(smb_tid_t *tidp)
1138 lock_ObtainWrite(&smb_rctLock);
1139 osi_assert(tidp->refCount-- > 0);
1140 if (tidp->refCount == 0 && (tidp->delete)) {
1141 ltpp = &tidp->vcp->tidsp;
1142 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1146 osi_assert(tp != NULL);
1148 lock_FinalizeMutex(&tidp->mx);
1149 userp = tidp->userp; /* remember to drop ref later */
1151 smb_ReleaseVCNoLock(tidp->vcp);
1154 lock_ReleaseWrite(&smb_rctLock);
1156 cm_ReleaseUser(userp);
1159 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1161 smb_user_t *uidp = NULL;
1163 lock_ObtainWrite(&smb_rctLock);
1164 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1165 if (uid == uidp->userID) {
1167 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1169 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1173 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1174 uidp = malloc(sizeof(*uidp));
1175 memset(uidp, 0, sizeof(*uidp));
1176 uidp->nextp = vcp->usersp;
1177 uidp->refCount = 2; /* one for the vcp and one for the caller */
1179 smb_HoldVCNoLock(vcp);
1181 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1183 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1185 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1187 lock_ReleaseWrite(&smb_rctLock);
1191 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1193 smb_username_t *unp= NULL;
1195 lock_ObtainWrite(&smb_rctLock);
1196 for(unp = usernamesp; unp; unp = unp->nextp) {
1197 if (stricmp(unp->name, usern) == 0 &&
1198 stricmp(unp->machine, machine) == 0) {
1203 if (!unp && (flags & SMB_FLAG_CREATE)) {
1204 unp = malloc(sizeof(*unp));
1205 memset(unp, 0, sizeof(*unp));
1207 unp->nextp = usernamesp;
1208 unp->name = strdup(usern);
1209 unp->machine = strdup(machine);
1211 lock_InitializeMutex(&unp->mx, "username_t mutex");
1212 if (flags & SMB_FLAG_AFSLOGON)
1213 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1216 lock_ReleaseWrite(&smb_rctLock);
1220 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1222 smb_user_t *uidp= NULL;
1224 lock_ObtainWrite(&smb_rctLock);
1225 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1228 if (stricmp(uidp->unp->name, usern) == 0) {
1230 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1231 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1236 lock_ReleaseWrite(&smb_rctLock);
1240 void smb_ReleaseUsername(smb_username_t *unp)
1243 smb_username_t **lupp;
1244 cm_user_t *userp = NULL;
1245 time_t now = osi_Time();
1247 lock_ObtainWrite(&smb_rctLock);
1248 osi_assert(unp->refCount-- > 0);
1249 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1250 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1252 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1256 osi_assert(up != NULL);
1258 up->nextp = NULL; /* do not remove this */
1259 lock_FinalizeMutex(&unp->mx);
1265 lock_ReleaseWrite(&smb_rctLock);
1268 cm_ReleaseUser(userp);
1272 void smb_HoldUIDNoLock(smb_user_t *uidp)
1277 void smb_ReleaseUID(smb_user_t *uidp)
1281 smb_username_t *unp = NULL;
1283 lock_ObtainWrite(&smb_rctLock);
1284 osi_assert(uidp->refCount-- > 0);
1285 if (uidp->refCount == 0) {
1286 lupp = &uidp->vcp->usersp;
1287 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1291 osi_assert(up != NULL);
1293 lock_FinalizeMutex(&uidp->mx);
1295 smb_ReleaseVCNoLock(uidp->vcp);
1299 lock_ReleaseWrite(&smb_rctLock);
1303 cm_ReleaseUserVCRef(unp->userp);
1304 smb_ReleaseUsername(unp);
1308 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1310 cm_user_t *up = NULL;
1315 lock_ObtainMutex(&uidp->mx);
1317 up = uidp->unp->userp;
1320 lock_ReleaseMutex(&uidp->mx);
1326 /* retrieve a held reference to a user structure corresponding to an incoming
1328 * corresponding release function is cm_ReleaseUser.
1330 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1333 cm_user_t *up = NULL;
1336 smbp = (smb_t *) inp;
1337 uidp = smb_FindUID(vcp, smbp->uid, 0);
1341 up = smb_GetUserFromUID(uidp);
1343 smb_ReleaseUID(uidp);
1348 * Return a pointer to a pathname extracted from a TID structure. The
1349 * TID structure is not held; assume it won't go away.
1351 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1356 tidp = smb_FindTID(vcp, tid, 0);
1360 if (tidp->flags & SMB_TIDFLAG_IPC) {
1361 code = CM_ERROR_TIDIPC;
1362 /* tidp->pathname would be NULL, but that's fine */
1364 *treepath = tidp->pathname;
1365 smb_ReleaseTID(tidp);
1370 /* check to see if we have a chained fid, that is, a fid that comes from an
1371 * OpenAndX message that ran earlier in this packet. In this case, the fid
1372 * field in a read, for example, request, isn't set, since the value is
1373 * supposed to be inherited from the openAndX call.
1375 int smb_ChainFID(int fid, smb_packet_t *inp)
1377 if (inp->fid == 0 || inp->inCount == 0)
1383 /* are we a priv'd user? What does this mean on NT? */
1384 int smb_SUser(cm_user_t *userp)
1389 /* find a file ID. If we pass in 0 we select an unused File ID.
1390 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1391 * smb_fid_t data structure if desired File ID cannot be found.
1393 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1398 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1401 lock_ObtainWrite(&smb_rctLock);
1402 /* figure out if we need to allocate a new file ID */
1405 fid = vcp->fidCounter;
1409 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1410 if (fid == fidp->fid) {
1413 if (fid == 0xFFFF) {
1415 "New FID number wraps on vcp 0x%x", vcp);
1425 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1426 char eventName[MAX_PATH];
1428 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1429 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1430 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1431 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1432 thrd_CloseHandle(event);
1434 if (fid == 0xFFFF) {
1435 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1441 fidp = malloc(sizeof(*fidp));
1442 memset(fidp, 0, sizeof(*fidp));
1443 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1446 smb_HoldVCNoLock(vcp);
1447 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1449 fidp->curr_chunk = fidp->prev_chunk = -2;
1450 fidp->raw_write_event = event;
1452 vcp->fidCounter = fid+1;
1453 if (vcp->fidCounter == 0xFFFF) {
1454 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1456 vcp->fidCounter = 1;
1461 lock_ReleaseWrite(&smb_rctLock);
1465 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1470 void smb_ReleaseFID(smb_fid_t *fidp)
1472 cm_scache_t *scp = NULL;
1473 cm_user_t *userp = NULL;
1474 smb_vc_t *vcp = NULL;
1475 smb_ioctl_t *ioctlp;
1477 lock_ObtainWrite(&smb_rctLock);
1478 osi_assert(fidp->refCount-- > 0);
1479 lock_ObtainMutex(&fidp->mx);
1480 if (fidp->refCount == 0 && (fidp->delete)) {
1483 scp = fidp->scp; /* release after lock is released */
1485 userp = fidp->userp;
1489 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1490 thrd_CloseHandle(fidp->raw_write_event);
1492 /* and see if there is ioctl stuff to free */
1493 ioctlp = fidp->ioctlp;
1496 cm_FreeSpace(ioctlp->prefix);
1497 if (ioctlp->inAllocp)
1498 free(ioctlp->inAllocp);
1499 if (ioctlp->outAllocp)
1500 free(ioctlp->outAllocp);
1503 lock_ReleaseMutex(&fidp->mx);
1504 lock_FinalizeMutex(&fidp->mx);
1508 smb_ReleaseVCNoLock(vcp);
1510 lock_ReleaseMutex(&fidp->mx);
1512 lock_ReleaseWrite(&smb_rctLock);
1514 /* now release the scache structure */
1516 cm_ReleaseSCache(scp);
1519 cm_ReleaseUser(userp);
1523 * Case-insensitive search for one string in another;
1524 * used to find variable names in submount pathnames.
1526 static char *smb_stristr(char *str1, char *str2)
1530 for (cursor = str1; *cursor; cursor++)
1531 if (stricmp(cursor, str2) == 0)
1538 * Substitute a variable value for its name in a submount pathname. Variable
1539 * name has been identified by smb_stristr() and is in substr. Variable name
1540 * length (plus one) is in substr_size. Variable value is in newstr.
1542 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1547 strcpy(temp, substr + substr_size - 1);
1548 strcpy(substr, newstr);
1552 char VNUserName[] = "%USERNAME%";
1553 char VNLCUserName[] = "%LCUSERNAME%";
1554 char VNComputerName[] = "%COMPUTERNAME%";
1555 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1558 /* List available shares */
1559 int smb_ListShares()
1563 char shareBuf[4096];
1571 /*strcpy(shareNameList[num_shares], "all");
1572 strcpy(pathNameList[num_shares++], "/afs");*/
1573 fprintf(stderr, "The following shares are available:\n");
1574 fprintf(stderr, "Share Name (AFS Path)\n");
1575 fprintf(stderr, "---------------------\n");
1576 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1579 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1580 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1582 strcpy(sbmtpath, cm_confDir);
1584 strcat(sbmtpath, "/afsdsbmt.ini");
1585 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1586 shareBuf, sizeof(shareBuf),
1592 this_share = shareBuf;
1596 /*strcpy(shareNameList[num_shares], this_share);*/
1597 len = GetPrivateProfileString("AFS Submounts", this_share,
1604 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1607 if (*p == '\\') *p = '/'; /* change to / */
1611 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1612 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1615 while (*this_share != 0) this_share++; /* find next NUL */
1616 this_share++; /* skip past the NUL */
1617 } while (*this_share != 0); /* stop at final NUL */
1623 typedef struct smb_findShare_rock {
1627 } smb_findShare_rock_t;
1629 #define SMB_FINDSHARE_EXACT_MATCH 1
1630 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1632 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1636 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1637 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1638 if(!stricmp(dep->name, vrock->shareName))
1639 matchType = SMB_FINDSHARE_EXACT_MATCH;
1641 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1642 if(vrock->match) free(vrock->match);
1643 vrock->match = strdup(dep->name);
1644 vrock->matchType = matchType;
1646 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1647 return CM_ERROR_STOPNOW;
1653 /* find a shareName in the table of submounts */
1654 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1658 char pathName[1024];
1663 char sbmtpath[MAX_PATH];
1668 DWORD allSubmount = 1;
1670 /* if allSubmounts == 0, only return the //mountRoot/all share
1671 * if in fact it has been been created in the subMounts table.
1672 * This is to allow sites that want to restrict access to the
1675 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1676 0, KEY_QUERY_VALUE, &parmKey);
1677 if (code == ERROR_SUCCESS) {
1678 len = sizeof(allSubmount);
1679 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1680 (BYTE *) &allSubmount, &len);
1681 if (code != ERROR_SUCCESS) {
1684 RegCloseKey (parmKey);
1687 if (allSubmount && _stricmp(shareName, "all") == 0) {
1692 /* In case, the all share is disabled we need to still be able
1693 * to handle ioctl requests
1695 if (_stricmp(shareName, "ioctl$") == 0) {
1696 *pathNamep = strdup("/.__ioctl__");
1700 if (_stricmp(shareName, "IPC$") == 0 ||
1701 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1702 _stricmp(shareName, "DESKTOP.INI") == 0
1709 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1710 0, KEY_QUERY_VALUE, &parmKey);
1711 if (code == ERROR_SUCCESS) {
1712 len = sizeof(pathName);
1713 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1714 (BYTE *) pathName, &len);
1715 if (code != ERROR_SUCCESS)
1717 RegCloseKey (parmKey);
1722 strcpy(sbmtpath, cm_confDir);
1723 strcat(sbmtpath, "/afsdsbmt.ini");
1724 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1725 pathName, sizeof(pathName), sbmtpath);
1727 if (len != 0 && len != sizeof(pathName) - 1) {
1728 /* We can accept either unix or PC style AFS pathnames. Convert
1729 * Unix-style to PC style here for internal use.
1732 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1733 p += strlen(cm_mountRoot); /* skip mount path */
1736 if (*q == '/') *q = '\\'; /* change to \ */
1742 if (var = smb_stristr(p, VNUserName)) {
1743 if (uidp && uidp->unp)
1744 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1746 smb_subst(p, var, sizeof(VNUserName)," ");
1748 else if (var = smb_stristr(p, VNLCUserName))
1750 if (uidp && uidp->unp)
1751 strcpy(temp, uidp->unp->name);
1755 smb_subst(p, var, sizeof(VNLCUserName), temp);
1757 else if (var = smb_stristr(p, VNComputerName))
1759 sizeTemp = sizeof(temp);
1760 GetComputerName((LPTSTR)temp, &sizeTemp);
1761 smb_subst(p, var, sizeof(VNComputerName), temp);
1763 else if (var = smb_stristr(p, VNLCComputerName))
1765 sizeTemp = sizeof(temp);
1766 GetComputerName((LPTSTR)temp, &sizeTemp);
1768 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1773 *pathNamep = strdup(p);
1778 /* First lookup shareName in root.afs */
1780 smb_findShare_rock_t vrock;
1782 char * p = shareName;
1785 /* attempt to locate a partial match in root.afs. This is because
1786 when using the ANSI RAP calls, the share name is limited to 13 chars
1787 and hence is truncated. Of course we prefer exact matches. */
1789 thyper.HighPart = 0;
1792 vrock.shareName = shareName;
1794 vrock.matchType = 0;
1796 cm_HoldSCache(cm_data.rootSCachep);
1797 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1798 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1799 cm_ReleaseSCache(cm_data.rootSCachep);
1801 if (vrock.matchType) {
1802 sprintf(pathName,"/%s/",vrock.match);
1803 *pathNamep = strdup(strlwr(pathName));
1808 /* if we get here, there was no match for the share in root.afs */
1809 /* so try to create \\<netbiosName>\<cellname> */
1814 /* Get the full name for this cell */
1815 code = cm_SearchCellFile(p, temp, 0, 0);
1816 #ifdef AFS_AFSDB_ENV
1817 if (code && cm_dnsEnabled) {
1819 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1822 /* construct the path */
1824 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1825 *pathNamep = strdup(strlwr(pathName));
1834 /* Client-side offline caching policy types */
1835 #define CSC_POLICY_MANUAL 0
1836 #define CSC_POLICY_DOCUMENTS 1
1837 #define CSC_POLICY_PROGRAMS 2
1838 #define CSC_POLICY_DISABLE 3
1840 int smb_FindShareCSCPolicy(char *shareName)
1846 int retval = CSC_POLICY_MANUAL;
1848 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1849 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1852 REG_OPTION_NON_VOLATILE,
1858 len = sizeof(policy);
1859 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1861 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1863 else if (stricmp(policy, "documents") == 0)
1865 retval = CSC_POLICY_DOCUMENTS;
1867 else if (stricmp(policy, "programs") == 0)
1869 retval = CSC_POLICY_PROGRAMS;
1871 else if (stricmp(policy, "disable") == 0)
1873 retval = CSC_POLICY_DISABLE;
1876 RegCloseKey(hkCSCPolicy);
1880 /* find a dir search structure by cookie value, and return it held.
1881 * Must be called with smb_globalLock held.
1883 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1885 smb_dirSearch_t *dsp;
1887 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1888 if (dsp->cookie == cookie) {
1889 if (dsp != smb_firstDirSearchp) {
1890 /* move to head of LRU queue, too, if we're not already there */
1891 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1892 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1893 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1894 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1895 if (!smb_lastDirSearchp)
1896 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1898 lock_ObtainMutex(&dsp->mx);
1900 lock_ReleaseMutex(&dsp->mx);
1906 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1907 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1908 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1914 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1916 lock_ObtainWrite(&smb_globalLock);
1917 lock_ObtainMutex(&dsp->mx);
1918 dsp->flags |= SMB_DIRSEARCH_DELETE;
1919 if (dsp->scp != NULL) {
1920 lock_ObtainMutex(&dsp->scp->mx);
1921 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1922 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1923 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1924 dsp->scp->bulkStatProgress = hones;
1926 lock_ReleaseMutex(&dsp->scp->mx);
1928 lock_ReleaseMutex(&dsp->mx);
1929 lock_ReleaseWrite(&smb_globalLock);
1932 /* Must be called with the smb_globalLock held */
1933 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1935 cm_scache_t *scp = NULL;
1937 lock_ObtainMutex(&dsp->mx);
1938 osi_assert(dsp->refCount-- > 0);
1939 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1940 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1941 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1942 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1943 lock_ReleaseMutex(&dsp->mx);
1944 lock_FinalizeMutex(&dsp->mx);
1948 lock_ReleaseMutex(&dsp->mx);
1950 /* do this now to avoid spurious locking hierarchy creation */
1952 cm_ReleaseSCache(scp);
1955 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1957 lock_ObtainWrite(&smb_globalLock);
1958 smb_ReleaseDirSearchNoLock(dsp);
1959 lock_ReleaseWrite(&smb_globalLock);
1962 /* find a dir search structure by cookie value, and return it held */
1963 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1965 smb_dirSearch_t *dsp;
1967 lock_ObtainWrite(&smb_globalLock);
1968 dsp = smb_FindDirSearchNoLock(cookie);
1969 lock_ReleaseWrite(&smb_globalLock);
1973 /* GC some dir search entries, in the address space expected by the specific protocol.
1974 * Must be called with smb_globalLock held; release the lock temporarily.
1976 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1977 void smb_GCDirSearches(int isV3)
1979 smb_dirSearch_t *prevp;
1980 smb_dirSearch_t *tp;
1981 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1985 victimCount = 0; /* how many have we got so far */
1986 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1987 /* we'll move tp from queue, so
1990 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1991 /* if no one is using this guy, and we're either in the new protocol,
1992 * or we're in the old one and this is a small enough ID to be useful
1993 * to the old protocol, GC this guy.
1995 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1996 /* hold and delete */
1997 lock_ObtainMutex(&tp->mx);
1998 tp->flags |= SMB_DIRSEARCH_DELETE;
1999 lock_ReleaseMutex(&tp->mx);
2000 victimsp[victimCount++] = tp;
2004 /* don't do more than this */
2005 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2009 /* now release them */
2010 for (i = 0; i < victimCount; i++) {
2011 smb_ReleaseDirSearchNoLock(victimsp[i]);
2015 /* function for allocating a dir search entry. We need these to remember enough context
2016 * since we don't get passed the path from call to call during a directory search.
2018 * Returns a held dir search structure, and bumps the reference count on the vnode,
2019 * since it saves a pointer to the vnode.
2021 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2023 smb_dirSearch_t *dsp;
2029 lock_ObtainWrite(&smb_globalLock);
2032 /* what's the biggest ID allowed in this version of the protocol */
2033 maxAllowed = isV3 ? 65535 : 255;
2034 if (smb_dirSearchCounter > maxAllowed)
2035 smb_dirSearchCounter = 1;
2037 start = smb_dirSearchCounter;
2040 /* twice so we have enough tries to find guys we GC after one pass;
2041 * 10 extra is just in case I mis-counted.
2043 if (++counter > 2*maxAllowed+10)
2044 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2046 if (smb_dirSearchCounter > maxAllowed) {
2047 smb_dirSearchCounter = 1;
2049 if (smb_dirSearchCounter == start) {
2051 smb_GCDirSearches(isV3);
2054 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2056 /* don't need to watch for refcount zero and deleted, since
2057 * we haven't dropped the global lock.
2059 lock_ObtainMutex(&dsp->mx);
2061 lock_ReleaseMutex(&dsp->mx);
2062 ++smb_dirSearchCounter;
2066 dsp = malloc(sizeof(*dsp));
2067 memset(dsp, 0, sizeof(*dsp));
2068 dsp->cookie = smb_dirSearchCounter;
2069 ++smb_dirSearchCounter;
2071 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2072 dsp->lastTime = osi_Time();
2073 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2074 if (!smb_lastDirSearchp)
2075 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2078 lock_ReleaseWrite(&smb_globalLock);
2082 static smb_packet_t *GetPacket(void)
2086 unsigned int npar, seg, tb_sel;
2089 lock_ObtainWrite(&smb_globalLock);
2090 tbp = smb_packetFreeListp;
2092 smb_packetFreeListp = tbp->nextp;
2093 lock_ReleaseWrite(&smb_globalLock);
2096 tbp = calloc(65540,1);
2098 tbp = malloc(sizeof(smb_packet_t));
2100 tbp->magic = SMB_PACKETMAGIC;
2103 tbp->resumeCode = 0;
2109 tbp->ncb_length = 0;
2114 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
2117 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2119 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
2121 osi_panic("",__FILE__,__LINE__);
2124 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
2129 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
2130 tbp->dos_pkt_sel = tb_sel;
2133 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2138 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2142 memcpy(tbp, pkt, sizeof(smb_packet_t));
2143 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2145 smb_HoldVC(tbp->vcp);
2149 static NCB *GetNCB(void)
2154 unsigned int npar, seg, tb_sel;
2157 lock_ObtainWrite(&smb_globalLock);
2158 tbp = smb_ncbFreeListp;
2160 smb_ncbFreeListp = tbp->nextp;
2161 lock_ReleaseWrite(&smb_globalLock);
2164 tbp = calloc(sizeof(*tbp),1);
2166 tbp = malloc(sizeof(*tbp));
2167 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
2170 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2172 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2174 osi_panic("",__FILE__,__LINE__);
2176 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2181 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
2182 tbp->dos_ncb_sel = tb_sel;
2184 tbp->magic = SMB_NCBMAGIC;
2187 osi_assert(tbp->magic == SMB_NCBMAGIC);
2189 memset(&tbp->ncb, 0, sizeof(NCB));
2192 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2197 void smb_FreePacket(smb_packet_t *tbp)
2199 smb_vc_t * vcp = NULL;
2200 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2202 lock_ObtainWrite(&smb_globalLock);
2203 tbp->nextp = smb_packetFreeListp;
2204 smb_packetFreeListp = tbp;
2205 tbp->magic = SMB_PACKETMAGIC;
2209 tbp->resumeCode = 0;
2215 tbp->ncb_length = 0;
2217 lock_ReleaseWrite(&smb_globalLock);
2223 static void FreeNCB(NCB *bufferp)
2227 tbp = (smb_ncb_t *) bufferp;
2228 osi_assert(tbp->magic == SMB_NCBMAGIC);
2230 lock_ObtainWrite(&smb_globalLock);
2231 tbp->nextp = smb_ncbFreeListp;
2232 smb_ncbFreeListp = tbp;
2233 lock_ReleaseWrite(&smb_globalLock);
2236 /* get a ptr to the data part of a packet, and its count */
2237 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2241 unsigned char *afterParmsp;
2243 parmBytes = *smbp->wctp << 1;
2244 afterParmsp = smbp->wctp + parmBytes + 1;
2246 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2247 if (nbytesp) *nbytesp = dataBytes;
2249 /* don't forget to skip the data byte count, since it follows
2250 * the parameters; that's where the "2" comes from below.
2252 return (unsigned char *) (afterParmsp + 2);
2255 /* must set all the returned parameters before playing around with the
2256 * data region, since the data region is located past the end of the
2257 * variable number of parameters.
2259 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2261 unsigned char *afterParmsp;
2263 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2265 *afterParmsp++ = dsize & 0xff;
2266 *afterParmsp = (dsize>>8) & 0xff;
2269 /* return the parm'th parameter in the smbp packet */
2270 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2273 unsigned char *parmDatap;
2275 parmCount = *smbp->wctp;
2277 if (parm >= parmCount) {
2280 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2281 parm, parmCount, smbp->ncb_length);
2282 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2283 parm, parmCount, smbp->ncb_length);
2285 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2286 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2288 osi_panic(s, __FILE__, __LINE__);
2290 parmDatap = smbp->wctp + (2*parm) + 1;
2292 return parmDatap[0] + (parmDatap[1] << 8);
2295 /* return the parm'th parameter in the smbp packet */
2296 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2299 unsigned char *parmDatap;
2301 parmCount = *smbp->wctp;
2303 if (parm * 2 + offset >= parmCount * 2) {
2306 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2307 parm, offset, parmCount, smbp->ncb_length);
2309 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2310 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2312 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2313 parm, offset, parmCount, smbp->ncb_length);
2314 osi_panic(s, __FILE__, __LINE__);
2316 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2318 return parmDatap[0] + (parmDatap[1] << 8);
2321 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2325 /* make sure we have enough slots */
2326 if (*smbp->wctp <= slot)
2327 *smbp->wctp = slot+1;
2329 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2330 *parmDatap++ = parmValue & 0xff;
2331 *parmDatap = (parmValue>>8) & 0xff;
2334 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2338 /* make sure we have enough slots */
2339 if (*smbp->wctp <= slot)
2340 *smbp->wctp = slot+2;
2342 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2343 *parmDatap++ = parmValue & 0xff;
2344 *parmDatap++ = (parmValue>>8) & 0xff;
2345 *parmDatap++ = (parmValue>>16) & 0xff;
2346 *parmDatap++ = (parmValue>>24) & 0xff;
2349 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2354 /* make sure we have enough slots */
2355 if (*smbp->wctp <= slot)
2356 *smbp->wctp = slot+4;
2358 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2360 *parmDatap++ = *parmValuep++;
2363 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2367 /* make sure we have enough slots */
2368 if (*smbp->wctp <= slot) {
2369 if (smbp->oddByte) {
2371 *smbp->wctp = slot+1;
2376 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2377 *parmDatap++ = parmValue & 0xff;
2380 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2384 lastSlashp = strrchr(inPathp, '\\');
2386 *lastComponentp = lastSlashp;
2389 if (inPathp == lastSlashp)
2391 *outPathp++ = *inPathp++;
2400 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2405 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2410 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2416 tlen = inp[0] + (inp[1]<<8);
2417 inp += 2; /* skip length field */
2420 *chainpp = inp + tlen;
2429 /* format a packet as a response */
2430 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2435 outp = (smb_t *) op;
2437 /* zero the basic structure through the smb_wct field, and zero the data
2438 * size field, assuming that wct stays zero; otherwise, you have to
2439 * explicitly set the data size field, too.
2441 inSmbp = (smb_t *) inp;
2442 memset(outp, 0, sizeof(smb_t)+2);
2448 outp->com = inSmbp->com;
2449 outp->tid = inSmbp->tid;
2450 outp->pid = inSmbp->pid;
2451 outp->uid = inSmbp->uid;
2452 outp->mid = inSmbp->mid;
2453 outp->res[0] = inSmbp->res[0];
2454 outp->res[1] = inSmbp->res[1];
2455 op->inCom = inSmbp->com;
2457 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2458 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2460 /* copy fields in generic packet area */
2461 op->wctp = &outp->wct;
2464 /* send a (probably response) packet; vcp tells us to whom to send it.
2465 * we compute the length by looking at wct and bcc fields.
2467 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2484 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2487 memset((char *)ncbp, 0, sizeof(NCB));
2489 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2490 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2491 extra += tp[0] + (tp[1]<<8);
2492 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2493 extra += 3; /* wct and length fields */
2495 ncbp->ncb_length = extra; /* bytes to send */
2496 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2497 ncbp->ncb_lana_num = vcp->lana;
2498 ncbp->ncb_command = NCBSEND; /* op means send data */
2500 ncbp->ncb_buffer = (char *) inp;/* packet */
2501 code = Netbios(ncbp);
2503 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2504 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2506 /* copy header information from virtual to DOS address space */
2507 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2508 code = Netbios(ncbp, dos_ncb);
2512 const char * s = ncb_error_string(code);
2513 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2515 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2518 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2521 lock_ObtainMutex(&vcp->mx);
2522 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2523 lock_ReleaseMutex(&vcp->mx);
2524 lock_ObtainWrite(&smb_globalLock);
2525 dead_sessions[vcp->session] = TRUE;
2526 lock_ReleaseWrite(&smb_globalLock);
2527 smb_CleanupDeadVC(vcp);
2534 void smb_MapNTError(long code, unsigned long *NTStatusp)
2536 unsigned long NTStatus;
2538 /* map CM_ERROR_* errors to NT 32-bit status codes */
2539 /* NT Status codes are listed in ntstatus.h not winerror.h */
2540 if (code == CM_ERROR_NOSUCHCELL) {
2541 NTStatus = 0xC000000FL; /* No such file */
2543 else if (code == CM_ERROR_NOSUCHVOLUME) {
2544 NTStatus = 0xC000000FL; /* No such file */
2546 else if (code == CM_ERROR_TIMEDOUT) {
2548 NTStatus = 0xC00000CFL; /* Sharing Paused */
2550 NTStatus = 0x00000102L; /* Timeout */
2553 else if (code == CM_ERROR_RETRY) {
2554 NTStatus = 0xC000022DL; /* Retry */
2556 else if (code == CM_ERROR_NOACCESS) {
2557 NTStatus = 0xC0000022L; /* Access denied */
2559 else if (code == CM_ERROR_READONLY) {
2560 NTStatus = 0xC00000A2L; /* Write protected */
2562 else if (code == CM_ERROR_NOSUCHFILE) {
2563 NTStatus = 0xC000000FL; /* No such file */
2565 else if (code == CM_ERROR_NOSUCHPATH) {
2566 NTStatus = 0xC000003AL; /* Object path not found */
2568 else if (code == CM_ERROR_TOOBIG) {
2569 NTStatus = 0xC000007BL; /* Invalid image format */
2571 else if (code == CM_ERROR_INVAL) {
2572 NTStatus = 0xC000000DL; /* Invalid parameter */
2574 else if (code == CM_ERROR_BADFD) {
2575 NTStatus = 0xC0000008L; /* Invalid handle */
2577 else if (code == CM_ERROR_BADFDOP) {
2578 NTStatus = 0xC0000022L; /* Access denied */
2580 else if (code == CM_ERROR_EXISTS) {
2581 NTStatus = 0xC0000035L; /* Object name collision */
2583 else if (code == CM_ERROR_NOTEMPTY) {
2584 NTStatus = 0xC0000101L; /* Directory not empty */
2586 else if (code == CM_ERROR_CROSSDEVLINK) {
2587 NTStatus = 0xC00000D4L; /* Not same device */
2589 else if (code == CM_ERROR_NOTDIR) {
2590 NTStatus = 0xC0000103L; /* Not a directory */
2592 else if (code == CM_ERROR_ISDIR) {
2593 NTStatus = 0xC00000BAL; /* File is a directory */
2595 else if (code == CM_ERROR_BADOP) {
2597 /* I have no idea where this comes from */
2598 NTStatus = 0xC09820FFL; /* SMB no support */
2600 NTStatus = 0xC00000BBL; /* Not supported */
2601 #endif /* COMMENT */
2603 else if (code == CM_ERROR_BADSHARENAME) {
2604 NTStatus = 0xC00000CCL; /* Bad network name */
2606 else if (code == CM_ERROR_NOIPC) {
2608 NTStatus = 0xC0000022L; /* Access Denied */
2610 NTStatus = 0xC000013DL; /* Remote Resources */
2613 else if (code == CM_ERROR_CLOCKSKEW) {
2614 NTStatus = 0xC0000133L; /* Time difference at DC */
2616 else if (code == CM_ERROR_BADTID) {
2617 NTStatus = 0xC0982005L; /* SMB bad TID */
2619 else if (code == CM_ERROR_USESTD) {
2620 NTStatus = 0xC09820FBL; /* SMB use standard */
2622 else if (code == CM_ERROR_QUOTA) {
2624 NTStatus = 0xC0000044L; /* Quota exceeded */
2626 NTStatus = 0xC000007FL; /* Disk full */
2629 else if (code == CM_ERROR_SPACE) {
2630 NTStatus = 0xC000007FL; /* Disk full */
2632 else if (code == CM_ERROR_ATSYS) {
2633 NTStatus = 0xC0000033L; /* Object name invalid */
2635 else if (code == CM_ERROR_BADNTFILENAME) {
2636 NTStatus = 0xC0000033L; /* Object name invalid */
2638 else if (code == CM_ERROR_WOULDBLOCK) {
2639 NTStatus = 0xC0000055L; /* Lock not granted */
2641 else if (code == CM_ERROR_SHARING_VIOLATION) {
2642 NTStatus = 0xC0000043L; /* Sharing violation */
2644 else if (code == CM_ERROR_LOCK_CONFLICT) {
2645 NTStatus = 0xC0000054L; /* Lock conflict */
2647 else if (code == CM_ERROR_PARTIALWRITE) {
2648 NTStatus = 0xC000007FL; /* Disk full */
2650 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2651 NTStatus = 0xC0000023L; /* Buffer too small */
2653 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2654 NTStatus = 0xC0000035L; /* Object name collision */
2656 else if (code == CM_ERROR_BADPASSWORD) {
2657 NTStatus = 0xC000006DL; /* unknown username or bad password */
2659 else if (code == CM_ERROR_BADLOGONTYPE) {
2660 NTStatus = 0xC000015BL; /* logon type not granted */
2662 else if (code == CM_ERROR_GSSCONTINUE) {
2663 NTStatus = 0xC0000016L; /* more processing required */
2665 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2667 NTStatus = 0xC0000280L; /* reparse point not resolved */
2669 NTStatus = 0xC0000022L; /* Access Denied */
2672 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2673 NTStatus = 0xC0000257L; /* Path Not Covered */
2676 else if (code == CM_ERROR_ALLBUSY) {
2677 NTStatus = 0xC00000BFL; /* Network Busy */
2679 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2680 NTStatus = 0xC0000350L; /* Remote Host Down */
2683 /* we do not want to be telling the SMB/CIFS client that
2684 * the AFS Client Service is busy or down.
2686 else if (code == CM_ERROR_ALLBUSY ||
2687 code == CM_ERROR_ALLOFFLINE ||
2688 code == CM_ERROR_ALLDOWN) {
2689 NTStatus = 0xC00000BEL; /* Bad Network Path */
2692 else if (code == RXKADUNKNOWNKEY) {
2693 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2695 NTStatus = 0xC0982001L; /* SMB non-specific error */
2698 *NTStatusp = NTStatus;
2699 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2702 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2703 unsigned char *classp)
2705 unsigned char class;
2706 unsigned short error;
2708 /* map CM_ERROR_* errors to SMB errors */
2709 if (code == CM_ERROR_NOSUCHCELL) {
2711 error = 3; /* bad path */
2713 else if (code == CM_ERROR_NOSUCHVOLUME) {
2715 error = 3; /* bad path */
2717 else if (code == CM_ERROR_TIMEDOUT) {
2719 error = 81; /* server is paused */
2721 else if (code == CM_ERROR_RETRY) {
2722 class = 2; /* shouldn't happen */
2725 else if (code == CM_ERROR_NOACCESS) {
2727 error = 4; /* bad access */
2729 else if (code == CM_ERROR_READONLY) {
2731 error = 19; /* read only */
2733 else if (code == CM_ERROR_NOSUCHFILE) {
2735 error = 2; /* ENOENT! */
2737 else if (code == CM_ERROR_NOSUCHPATH) {
2739 error = 3; /* Bad path */
2741 else if (code == CM_ERROR_TOOBIG) {
2743 error = 11; /* bad format */
2745 else if (code == CM_ERROR_INVAL) {
2746 class = 2; /* server non-specific error code */
2749 else if (code == CM_ERROR_BADFD) {
2751 error = 6; /* invalid file handle */
2753 else if (code == CM_ERROR_BADFDOP) {
2754 class = 1; /* invalid op on FD */
2757 else if (code == CM_ERROR_EXISTS) {
2759 error = 80; /* file already exists */
2761 else if (code == CM_ERROR_NOTEMPTY) {
2763 error = 5; /* delete directory not empty */
2765 else if (code == CM_ERROR_CROSSDEVLINK) {
2767 error = 17; /* EXDEV */
2769 else if (code == CM_ERROR_NOTDIR) {
2770 class = 1; /* bad path */
2773 else if (code == CM_ERROR_ISDIR) {
2774 class = 1; /* access denied; DOS doesn't have a good match */
2777 else if (code == CM_ERROR_BADOP) {
2781 else if (code == CM_ERROR_BADSHARENAME) {
2785 else if (code == CM_ERROR_NOIPC) {
2787 error = 4; /* bad access */
2789 else if (code == CM_ERROR_CLOCKSKEW) {
2790 class = 1; /* invalid function */
2793 else if (code == CM_ERROR_BADTID) {
2797 else if (code == CM_ERROR_USESTD) {
2801 else if (code == CM_ERROR_REMOTECONN) {
2805 else if (code == CM_ERROR_QUOTA) {
2806 if (vcp->flags & SMB_VCFLAG_USEV3) {
2808 error = 39; /* disk full */
2812 error = 5; /* access denied */
2815 else if (code == CM_ERROR_SPACE) {
2816 if (vcp->flags & SMB_VCFLAG_USEV3) {
2818 error = 39; /* disk full */
2822 error = 5; /* access denied */
2825 else if (code == CM_ERROR_PARTIALWRITE) {
2827 error = 39; /* disk full */
2829 else if (code == CM_ERROR_ATSYS) {
2831 error = 2; /* ENOENT */
2833 else if (code == CM_ERROR_WOULDBLOCK) {
2835 error = 33; /* lock conflict */
2837 else if (code == CM_ERROR_LOCK_CONFLICT) {
2839 error = 33; /* lock conflict */
2841 else if (code == CM_ERROR_SHARING_VIOLATION) {
2843 error = 33; /* lock conflict */
2845 else if (code == CM_ERROR_NOFILES) {
2847 error = 18; /* no files in search */
2849 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2851 error = 183; /* Samba uses this */
2853 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2854 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2856 error = 2; /* bad password */
2858 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2860 error = 3; /* bad path */
2869 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2872 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2874 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2875 return CM_ERROR_BADOP;
2878 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2880 unsigned short EchoCount, i;
2881 char *data, *outdata;
2884 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2886 for (i=1; i<=EchoCount; i++) {
2887 data = smb_GetSMBData(inp, &dataSize);
2888 smb_SetSMBParm(outp, 0, i);
2889 smb_SetSMBDataLength(outp, dataSize);
2890 outdata = smb_GetSMBData(outp, NULL);
2891 memcpy(outdata, data, dataSize);
2892 smb_SendPacket(vcp, outp);
2898 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2901 long count, minCount, finalCount;
2906 cm_user_t *userp = NULL;
2910 char *rawBuf = NULL;
2912 dos_ptr rawBuf = NULL;
2919 fd = smb_GetSMBParm(inp, 0);
2920 count = smb_GetSMBParm(inp, 3);
2921 minCount = smb_GetSMBParm(inp, 4);
2922 offset.HighPart = 0; /* too bad */
2923 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2925 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2926 fd, offset.LowPart, count);
2928 fidp = smb_FindFID(vcp, fd, 0);
2932 pid = ((smb_t *) inp)->pid;
2934 LARGE_INTEGER LOffset, LLength;
2937 key = cm_GenerateKey(vcp->vcID, pid, fd);
2939 LOffset.HighPart = 0;
2940 LOffset.LowPart = offset.LowPart;
2941 LLength.HighPart = 0;
2942 LLength.LowPart = count;
2944 lock_ObtainMutex(&fidp->scp->mx);
2945 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2946 lock_ReleaseMutex(&fidp->scp->mx);
2952 lock_ObtainMutex(&smb_RawBufLock);
2954 /* Get a raw buf, from head of list */
2955 rawBuf = smb_RawBufs;
2957 smb_RawBufs = *(char **)smb_RawBufs;
2959 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2962 lock_ReleaseMutex(&smb_RawBufLock);
2966 lock_ObtainMutex(&fidp->mx);
2967 if (fidp->flags & SMB_FID_IOCTL)
2969 lock_ReleaseMutex(&fidp->mx);
2971 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2973 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2976 /* Give back raw buffer */
2977 lock_ObtainMutex(&smb_RawBufLock);
2979 *((char **) rawBuf) = smb_RawBufs;
2981 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2984 smb_RawBufs = rawBuf;
2985 lock_ReleaseMutex(&smb_RawBufLock);
2988 smb_ReleaseFID(fidp);
2991 lock_ReleaseMutex(&fidp->mx);
2993 userp = smb_GetUserFromVCP(vcp, inp);
2996 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2998 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2999 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
3000 userp, &finalCount, TRUE /* rawFlag */);
3007 cm_ReleaseUser(userp);
3010 smb_ReleaseFID(fidp);
3015 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
3017 memset((char *)ncbp, 0, sizeof(NCB));
3019 ncbp->ncb_length = (unsigned short) finalCount;
3020 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3021 ncbp->ncb_lana_num = vcp->lana;
3022 ncbp->ncb_command = NCBSEND;
3023 ncbp->ncb_buffer = rawBuf;
3026 code = Netbios(ncbp);
3028 code = Netbios(ncbp, dos_ncb);
3031 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3034 /* Give back raw buffer */
3035 lock_ObtainMutex(&smb_RawBufLock);
3037 *((char **) rawBuf) = smb_RawBufs;
3039 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3042 smb_RawBufs = rawBuf;
3043 lock_ReleaseMutex(&smb_RawBufLock);
3049 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3051 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3056 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3058 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3063 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3070 int protoIndex; /* index we're using */
3075 char protocol_array[10][1024]; /* protocol signature of the client */
3076 int caps; /* capabilities */
3079 TIME_ZONE_INFORMATION tzi;
3081 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3084 namep = smb_GetSMBData(inp, &dbytes);
3087 coreProtoIndex = -1; /* not found */
3090 while(namex < dbytes) {
3091 osi_Log1(smb_logp, "Protocol %s",
3092 osi_LogSaveString(smb_logp, namep+1));
3093 strcpy(protocol_array[tcounter], namep+1);
3095 /* namep points at the first protocol, or really, a 0x02
3096 * byte preceding the null-terminated ASCII name.
3098 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3099 coreProtoIndex = tcounter;
3101 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3102 v3ProtoIndex = tcounter;
3104 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3105 NTProtoIndex = tcounter;
3108 /* compute size of protocol entry */
3109 entryLength = (int)strlen(namep+1);
3110 entryLength += 2; /* 0x02 bytes and null termination */
3112 /* advance over this protocol entry */
3113 namex += entryLength;
3114 namep += entryLength;
3115 tcounter++; /* which proto entry we're looking at */
3118 lock_ObtainMutex(&vcp->mx);
3119 if (NTProtoIndex != -1) {
3120 protoIndex = NTProtoIndex;
3121 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3123 else if (v3ProtoIndex != -1) {
3124 protoIndex = v3ProtoIndex;
3125 vcp->flags |= SMB_VCFLAG_USEV3;
3127 else if (coreProtoIndex != -1) {
3128 protoIndex = coreProtoIndex;
3129 vcp->flags |= SMB_VCFLAG_USECORE;
3131 else protoIndex = -1;
3132 lock_ReleaseMutex(&vcp->mx);
3134 if (protoIndex == -1)
3135 return CM_ERROR_INVAL;
3136 else if (NTProtoIndex != -1) {
3137 smb_SetSMBParm(outp, 0, protoIndex);
3138 if (smb_authType != SMB_AUTH_NONE) {
3139 smb_SetSMBParmByte(outp, 1,
3140 NEGOTIATE_SECURITY_USER_LEVEL |
3141 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3143 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3145 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3146 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3147 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3148 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3149 /* The session key is not a well documented field however most clients
3150 * will echo back the session key to the server. Currently we are using
3151 * the same value for all sessions. We should generate a random value
3152 * and store it into the vcp
3154 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3155 smb_SetSMBParm(outp, 8, 1);
3157 * Tried changing the capabilities to support for W2K - defect 117695
3158 * Maybe something else needs to be changed here?
3162 smb_SetSMBParmLong(outp, 9, 0x43fd);
3164 smb_SetSMBParmLong(outp, 9, 0x251);
3167 * 32-bit error codes *
3172 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3174 NTNEGOTIATE_CAPABILITY_DFS |
3176 NTNEGOTIATE_CAPABILITY_NTFIND |
3177 NTNEGOTIATE_CAPABILITY_RAWMODE |
3178 NTNEGOTIATE_CAPABILITY_NTSMB;
3180 if ( smb_authType == SMB_AUTH_EXTENDED )
3181 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3183 smb_SetSMBParmLong(outp, 9, caps);
3185 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3186 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3187 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3189 GetTimeZoneInformation(&tzi);
3190 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3192 if (smb_authType == SMB_AUTH_NTLM) {
3193 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3194 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3195 /* paste in encryption key */
3196 datap = smb_GetSMBData(outp, NULL);
3197 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3198 /* and the faux domain name */
3199 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3200 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3204 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3206 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3208 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3210 datap = smb_GetSMBData(outp, NULL);
3211 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3214 datap += sizeof(smb_ServerGUID);
3215 memcpy(datap, secBlob, secBlobLength);
3219 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3220 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3223 else if (v3ProtoIndex != -1) {
3224 smb_SetSMBParm(outp, 0, protoIndex);
3226 /* NOTE: Extended authentication cannot be negotiated with v3
3227 * therefore we fail over to NTLM
3229 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3230 smb_SetSMBParm(outp, 1,
3231 NEGOTIATE_SECURITY_USER_LEVEL |
3232 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3234 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3236 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3237 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3238 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3239 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3240 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3241 smb_SetSMBParm(outp, 7, 1);
3243 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3244 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3245 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3247 GetTimeZoneInformation(&tzi);
3248 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3250 /* NOTE: Extended authentication cannot be negotiated with v3
3251 * therefore we fail over to NTLM
3253 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3254 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3255 smb_SetSMBParm(outp, 12, 0); /* resvd */
3256 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3257 datap = smb_GetSMBData(outp, NULL);
3258 /* paste in a new encryption key */
3259 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3260 /* and the faux domain name */
3261 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3263 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3264 smb_SetSMBParm(outp, 12, 0); /* resvd */
3265 smb_SetSMBDataLength(outp, 0);
3268 else if (coreProtoIndex != -1) { /* not really supported anymore */
3269 smb_SetSMBParm(outp, 0, protoIndex);
3270 smb_SetSMBDataLength(outp, 0);
3275 void smb_CheckVCs(void)
3277 smb_vc_t * vcp, *nextp;
3278 smb_packet_t * outp = GetPacket();
3281 lock_ObtainWrite(&smb_rctLock);
3282 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3284 if (vcp->magic != SMB_VC_MAGIC)
3285 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3286 __FILE__, __LINE__);
3290 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3293 smb_HoldVCNoLock(vcp);
3295 smb_HoldVCNoLock(nextp);
3296 smb_FormatResponsePacket(vcp, NULL, outp);
3297 smbp = (smb_t *)outp;
3298 outp->inCom = smbp->com = 0x2b /* Echo */;
3306 smb_SetSMBParm(outp, 0, 0);
3307 smb_SetSMBDataLength(outp, 0);
3308 lock_ReleaseWrite(&smb_rctLock);
3310 smb_SendPacket(vcp, outp);
3312 lock_ObtainWrite(&smb_rctLock);
3313 smb_ReleaseVCNoLock(vcp);
3315 smb_ReleaseVCNoLock(nextp);
3317 lock_ReleaseWrite(&smb_rctLock);
3318 smb_FreePacket(outp);
3321 void smb_Daemon(void *parmp)
3323 afs_uint32 count = 0;
3324 smb_username_t **unpp;
3327 while(smbShutdownFlag == 0) {
3331 if (smbShutdownFlag == 1)
3334 if ((count % 72) == 0) { /* every five minutes */
3336 time_t old_localZero = smb_localZero;
3338 /* Initialize smb_localZero */
3339 myTime.tm_isdst = -1; /* compute whether on DST or not */
3340 myTime.tm_year = 70;
3346 smb_localZero = mktime(&myTime);
3348 #ifndef USE_NUMERIC_TIME_CONV
3349 smb_CalculateNowTZ();
3350 #endif /* USE_NUMERIC_TIME_CONV */
3351 #ifdef AFS_FREELANCE
3352 if ( smb_localZero != old_localZero )
3353 cm_noteLocalMountPointChange();
3359 /* GC smb_username_t objects that will no longer be used */
3361 lock_ObtainWrite(&smb_rctLock);
3362 for ( unpp=&usernamesp; *unpp; ) {
3364 smb_username_t *unp;
3366 lock_ObtainMutex(&(*unpp)->mx);
3367 if ( (*unpp)->refCount > 0 ||
3368 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3369 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3371 else if (!smb_LogoffTokenTransfer ||
3372 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3374 lock_ReleaseMutex(&(*unpp)->mx);
3382 lock_FinalizeMutex(&unp->mx);
3388 lock_ReleaseWrite(&smb_rctLock);
3389 cm_ReleaseUser(userp);
3390 lock_ObtainWrite(&smb_rctLock);
3393 unpp = &(*unpp)->nextp;
3396 lock_ReleaseWrite(&smb_rctLock);
3398 /* XXX GC dir search entries */
3402 void smb_WaitingLocksDaemon()
3404 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3405 smb_waitingLock_t *wl, *wlNext;
3408 smb_packet_t *inp, *outp;
3412 while (smbShutdownFlag == 0) {
3413 lock_ObtainWrite(&smb_globalLock);
3414 nwlRequest = smb_allWaitingLocks;
3415 if (nwlRequest == NULL) {
3416 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3421 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3428 lock_ObtainWrite(&smb_globalLock);
3430 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3432 wlRequest = nwlRequest;
3433 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3434 lock_ReleaseWrite(&smb_globalLock);
3438 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3439 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3442 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3444 /* wl->state is either _DONE or _WAITING. _ERROR
3445 would no longer be on the queue. */
3446 code = cm_RetryLock( wl->lockp,
3447 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3450 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3451 } else if (code != CM_ERROR_WOULDBLOCK) {
3452 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3457 if (code == CM_ERROR_WOULDBLOCK) {
3460 if (wlRequest->timeRemaining != 0xffffffff
3461 && (wlRequest->timeRemaining -= 1000) < 0)
3473 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3476 scp = wlRequest->scp;
3480 lock_ObtainMutex(&scp->mx);
3482 for (wl = wlRequest->locks; wl; wl = wlNext) {
3483 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3485 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3486 wl->LLength, wl->key, NULL, &req);
3488 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3493 lock_ReleaseMutex(&scp->mx);
3497 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3500 for (wl = wlRequest->locks; wl; wl = wlNext) {
3501 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3502 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3507 vcp = wlRequest->vcp;
3508 inp = wlRequest->inp;
3509 outp = wlRequest->outp;
3511 ncbp->ncb_length = inp->ncb_length;
3512 inp->spacep = cm_GetSpace();
3514 /* Remove waitingLock from list */
3515 lock_ObtainWrite(&smb_globalLock);
3516 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3518 lock_ReleaseWrite(&smb_globalLock);
3520 /* Resume packet processing */
3522 smb_SetSMBDataLength(outp, 0);
3523 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3524 outp->resumeCode = code;
3526 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3529 cm_FreeSpace(inp->spacep);
3530 smb_FreePacket(inp);
3531 smb_FreePacket(outp);
3533 cm_ReleaseSCache(wlRequest->scp);
3536 } while (nwlRequest && smbShutdownFlag == 0);
3541 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3543 osi_Log0(smb_logp, "SMB receive get disk attributes");
3545 smb_SetSMBParm(outp, 0, 32000);
3546 smb_SetSMBParm(outp, 1, 64);
3547 smb_SetSMBParm(outp, 2, 1024);
3548 smb_SetSMBParm(outp, 3, 30000);
3549 smb_SetSMBParm(outp, 4, 0);
3550 smb_SetSMBDataLength(outp, 0);
3554 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3558 unsigned short newTid;
3559 char shareName[256];
3567 osi_Log0(smb_logp, "SMB receive tree connect");
3569 /* parse input parameters */
3570 tp = smb_GetSMBData(inp, NULL);
3571 pathp = smb_ParseASCIIBlock(tp, &tp);
3572 if (smb_StoreAnsiFilenames)
3573 OemToChar(pathp,pathp);
3574 passwordp = smb_ParseASCIIBlock(tp, &tp);
3575 tp = strrchr(pathp, '\\');
3577 return CM_ERROR_BADSMB;
3578 strcpy(shareName, tp+1);
3580 lock_ObtainMutex(&vcp->mx);
3581 newTid = vcp->tidCounter++;
3582 lock_ReleaseMutex(&vcp->mx);
3584 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3585 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3586 userp = smb_GetUserFromUID(uidp);
3587 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3589 smb_ReleaseUID(uidp);
3591 smb_ReleaseTID(tidp);
3592 return CM_ERROR_BADSHARENAME;
3594 lock_ObtainMutex(&tidp->mx);
3595 tidp->userp = userp;
3596 tidp->pathname = sharePath;
3597 lock_ReleaseMutex(&tidp->mx);
3598 smb_ReleaseTID(tidp);
3600 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3601 smb_SetSMBParm(rsp, 1, newTid);
3602 smb_SetSMBDataLength(rsp, 0);
3604 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3608 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3612 if (*inp++ != 0x1) return NULL;
3613 tlen = inp[0] + (inp[1]<<8);
3614 inp += 2; /* skip length field */
3617 *chainpp = inp + tlen;
3620 if (lengthp) *lengthp = tlen;
3625 /* set maskp to the mask part of the incoming path.
3626 * Mask is 11 bytes long (8.3 with the dot elided).
3627 * Returns true if succeeds with a valid name, otherwise it does
3628 * its best, but returns false.
3630 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3638 /* starts off valid */
3641 /* mask starts out all blanks */
3642 memset(maskp, ' ', 11);
3644 /* find last backslash, or use whole thing if there is none */
3645 tp = strrchr(pathp, '\\');
3646 if (!tp) tp = pathp;
3647 else tp++; /* skip slash */
3651 /* names starting with a dot are illegal */
3652 if (*tp == '.') valid8Dot3 = 0;
3656 if (tc == 0) return valid8Dot3;
3657 if (tc == '.' || tc == '"') break;
3658 if (i < 8) *up++ = tc;
3659 else valid8Dot3 = 0;
3662 /* if we get here, tp point after the dot */
3663 up = maskp+8; /* ext goes here */
3670 if (tc == '.' || tc == '"')
3673 /* copy extension if not too long */
3683 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3693 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3695 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3699 /* otherwise, we have a valid 8.3 name; see if we have a match,
3700 * treating '?' as a wildcard in maskp (but not in the file name).
3702 tp1 = umask; /* real name, in mask format */
3703 tp2 = maskp; /* mask, in mask format */
3704 for(i=0; i<11; i++) {
3705 tc1 = *tp1++; /* char from real name */
3706 tc2 = *tp2++; /* char from mask */
3707 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3708 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3711 if (tc2 == '?' && tc1 != ' ')
3718 /* we got a match */
3722 char *smb_FindMask(char *pathp)
3726 tp = strrchr(pathp, '\\'); /* find last slash */
3729 return tp+1; /* skip the slash */
3731 return pathp; /* no slash, return the entire path */
3734 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3736 unsigned char *pathp;
3738 unsigned char mask[11];
3739 unsigned char *statBlockp;
3740 unsigned char initStatBlock[21];
3743 osi_Log0(smb_logp, "SMB receive search volume");
3745 /* pull pathname and stat block out of request */
3746 tp = smb_GetSMBData(inp, NULL);
3747 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3748 osi_assert(pathp != NULL);
3749 if (smb_StoreAnsiFilenames)
3750 OemToChar(pathp,pathp);
3751 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3752 osi_assert(statBlockp != NULL);
3754 statBlockp = initStatBlock;
3758 /* for returning to caller */
3759 smb_Get8Dot3MaskFromPath(mask, pathp);
3761 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3762 tp = smb_GetSMBData(outp, NULL);
3764 *tp++ = 43; /* bytes in a dir entry */
3765 *tp++ = 0; /* high byte in counter */
3767 /* now marshall the dir entry, starting with the search status */
3768 *tp++ = statBlockp[0]; /* Reserved */
3769 memcpy(tp, mask, 11); tp += 11; /* FileName */
3771 /* now pass back server use info, with 1st byte non-zero */
3773 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3775 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3777 *tp++ = 0x8; /* attribute: volume */
3787 /* 4 byte file size */
3793 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3794 memset(tp, ' ', 13);
3797 /* set the length of the data part of the packet to 43 + 3, for the dir
3798 * entry plus the 5 and the length fields.
3800 smb_SetSMBDataLength(outp, 46);
3804 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3805 cm_user_t *userp, cm_req_t *reqp)
3813 smb_dirListPatch_t *patchp;
3814 smb_dirListPatch_t *npatchp;
3816 for (patchp = *dirPatchespp; patchp; patchp =
3817 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3819 dptr = patchp->dptr;
3821 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3823 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3824 *dptr++ = SMB_ATTR_HIDDEN;
3827 lock_ObtainMutex(&scp->mx);
3828 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3829 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3831 lock_ReleaseMutex(&scp->mx);
3832 cm_ReleaseSCache(scp);
3833 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3834 *dptr++ = SMB_ATTR_HIDDEN;
3838 attr = smb_Attributes(scp);
3839 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3840 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3841 attr |= SMB_ATTR_HIDDEN;
3845 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3848 shortTemp = (unsigned short) (dosTime & 0xffff);
3849 *((u_short *)dptr) = shortTemp;
3852 /* and copy out date */
3853 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3854 *((u_short *)dptr) = shortTemp;
3857 /* copy out file length */
3858 *((u_long *)dptr) = scp->length.LowPart;
3860 lock_ReleaseMutex(&scp->mx);
3861 cm_ReleaseSCache(scp);
3864 /* now free the patches */
3865 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3866 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3870 /* and mark the list as empty */
3871 *dirPatchespp = NULL;
3876 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3885 smb_dirListPatch_t *dirListPatchesp;
3886 smb_dirListPatch_t *curPatchp;
3890 osi_hyper_t dirLength;
3891 osi_hyper_t bufferOffset;
3892 osi_hyper_t curOffset;
3894 unsigned char *inCookiep;
3895 smb_dirSearch_t *dsp;
3899 unsigned long clientCookie;
3900 cm_pageHeader_t *pageHeaderp;
3901 cm_user_t *userp = NULL;
3908 long nextEntryCookie;
3909 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3910 char resByte; /* reserved byte from the cookie */
3911 char *op; /* output data ptr */
3912 char *origOp; /* original value of op */
3913 cm_space_t *spacep; /* for pathname buffer */
3924 maxCount = smb_GetSMBParm(inp, 0);
3926 dirListPatchesp = NULL;
3928 caseFold = CM_FLAG_CASEFOLD;
3930 tp = smb_GetSMBData(inp, NULL);
3931 pathp = smb_ParseASCIIBlock(tp, &tp);
3932 if (smb_StoreAnsiFilenames)
3933 OemToChar(pathp,pathp);
3934 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3936 /* bail out if request looks bad */
3937 if (!tp || !pathp) {
3938 return CM_ERROR_BADSMB;
3941 /* We can handle long names */
3942 if (vcp->flags & SMB_VCFLAG_USENT)
3943 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3945 /* make sure we got a whole search status */
3946 if (dataLength < 21) {
3947 nextCookie = 0; /* start at the beginning of the dir */
3950 attribute = smb_GetSMBParm(inp, 1);
3952 /* handle volume info in another function */
3953 if (attribute & 0x8)
3954 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3956 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3957 maxCount, osi_LogSaveString(smb_logp, pathp));
3959 if (*pathp == 0) { /* null pathp, treat as root dir */
3960 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3961 return CM_ERROR_NOFILES;
3965 dsp = smb_NewDirSearch(0);
3966 dsp->attribute = attribute;
3967 smb_Get8Dot3MaskFromPath(mask, pathp);
3968 memcpy(dsp->mask, mask, 11);
3970 /* track if this is likely to match a lot of entries */
3971 if (smb_IsStarMask(mask))
3976 /* pull the next cookie value out of the search status block */
3977 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3978 + (inCookiep[16]<<24);
3979 dsp = smb_FindDirSearch(inCookiep[12]);
3981 /* can't find dir search status; fatal error */
3982 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3983 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3984 return CM_ERROR_BADFD;
3986 attribute = dsp->attribute;
3987 resByte = inCookiep[0];
3989 /* copy out client cookie, in host byte order. Don't bother
3990 * interpreting it, since we're just passing it through, anyway.
3992 memcpy(&clientCookie, &inCookiep[17], 4);
3994 memcpy(mask, dsp->mask, 11);
3996 /* assume we're doing a star match if it has continued for more
4002 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4003 nextCookie, dsp->cookie, attribute);
4005 userp = smb_GetUserFromVCP(vcp, inp);
4007 /* try to get the vnode for the path name next */
4008 lock_ObtainMutex(&dsp->mx);
4014 spacep = inp->spacep;
4015 smb_StripLastComponent(spacep->data, NULL, pathp);
4016 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4018 lock_ReleaseMutex(&dsp->mx);
4019 cm_ReleaseUser(userp);
4020 smb_DeleteDirSearch(dsp);
4021 smb_ReleaseDirSearch(dsp);
4022 return CM_ERROR_NOFILES;
4024 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4025 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4028 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4029 cm_ReleaseSCache(scp);
4030 lock_ReleaseMutex(&dsp->mx);
4031 cm_ReleaseUser(userp);
4032 smb_DeleteDirSearch(dsp);
4033 smb_ReleaseDirSearch(dsp);
4034 if ( WANTS_DFS_PATHNAMES(inp) )
4035 return CM_ERROR_PATH_NOT_COVERED;
4037 return CM_ERROR_BADSHARENAME;
4039 #endif /* DFS_SUPPORT */
4042 /* we need one hold for the entry we just stored into,
4043 * and one for our own processing. When we're done with this
4044 * function, we'll drop the one for our own processing.
4045 * We held it once from the namei call, and so we do another hold
4049 lock_ObtainMutex(&scp->mx);
4050 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4051 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4052 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4053 dsp->flags |= SMB_DIRSEARCH_BULKST;
4055 lock_ReleaseMutex(&scp->mx);
4058 lock_ReleaseMutex(&dsp->mx);
4060 cm_ReleaseUser(userp);
4061 smb_DeleteDirSearch(dsp);
4062 smb_ReleaseDirSearch(dsp);
4066 /* reserves space for parameter; we'll adjust it again later to the
4067 * real count of the # of entries we returned once we've actually
4068 * assembled the directory listing.
4070 smb_SetSMBParm(outp, 0, 0);
4072 /* get the directory size */
4073 lock_ObtainMutex(&scp->mx);
4074 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4075 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4077 lock_ReleaseMutex(&scp->mx);
4078 cm_ReleaseSCache(scp);
4079 cm_ReleaseUser(userp);
4080 smb_DeleteDirSearch(dsp);
4081 smb_ReleaseDirSearch(dsp);
4085 dirLength = scp->length;
4087 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4088 curOffset.HighPart = 0;
4089 curOffset.LowPart = nextCookie;
4090 origOp = op = smb_GetSMBData(outp, NULL);
4091 /* and write out the basic header */
4092 *op++ = 5; /* variable block */
4093 op += 2; /* skip vbl block length; we'll fill it in later */
4097 /* make sure that curOffset.LowPart doesn't point to the first
4098 * 32 bytes in the 2nd through last dir page, and that it doesn't
4099 * point at the first 13 32-byte chunks in the first dir page,
4100 * since those are dir and page headers, and don't contain useful
4103 temp = curOffset.LowPart & (2048-1);
4104 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4105 /* we're in the first page */
4106 if (temp < 13*32) temp = 13*32;
4109 /* we're in a later dir page */
4110 if (temp < 32) temp = 32;
4113 /* make sure the low order 5 bits are zero */
4116 /* now put temp bits back ito curOffset.LowPart */
4117 curOffset.LowPart &= ~(2048-1);
4118 curOffset.LowPart |= temp;
4120 /* check if we've returned all the names that will fit in the
4123 if (returnedNames >= maxCount) {
4124 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4125 returnedNames, maxCount);
4129 /* check if we've passed the dir's EOF */
4130 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4132 /* see if we can use the bufferp we have now; compute in which page
4133 * the current offset would be, and check whether that's the offset
4134 * of the buffer we have. If not, get the buffer.
4136 thyper.HighPart = curOffset.HighPart;
4137 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4138 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4141 buf_Release(bufferp);
4144 lock_ReleaseMutex(&scp->mx);
4145 lock_ObtainRead(&scp->bufCreateLock);
4146 code = buf_Get(scp, &thyper, &bufferp);
4147 lock_ReleaseRead(&scp->bufCreateLock);
4148 lock_ObtainMutex(&dsp->mx);
4150 /* now, if we're doing a star match, do bulk fetching of all of
4151 * the status info for files in the dir.
4154 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4155 lock_ObtainMutex(&scp->mx);
4156 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4157 LargeIntegerGreaterThanOrEqualTo(thyper,
4158 scp->bulkStatProgress)) {
4159 /* Don't bulk stat if risking timeout */
4160 int now = GetTickCount();
4161 if (now - req.startTime > 5000) {
4162 scp->bulkStatProgress = thyper;
4163 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4164 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4166 cm_TryBulkStat(scp, &thyper, userp, &req);
4169 lock_ObtainMutex(&scp->mx);
4171 lock_ReleaseMutex(&dsp->mx);
4173 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4177 bufferOffset = thyper;
4179 /* now get the data in the cache */
4181 code = cm_SyncOp(scp, bufferp, userp, &req,
4183 CM_SCACHESYNC_NEEDCALLBACK |
4184 CM_SCACHESYNC_READ);
4186 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4190 if (cm_HaveBuffer(scp, bufferp, 0)) {
4191 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4195 /* otherwise, load the buffer and try again */
4196 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4198 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4199 scp, bufferp, code);
4204 buf_Release(bufferp);
4208 } /* if (wrong buffer) ... */
4210 /* now we have the buffer containing the entry we're interested in; copy
4211 * it out if it represents a non-deleted entry.
4213 entryInDir = curOffset.LowPart & (2048-1);
4214 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4216 /* page header will help tell us which entries are free. Page header
4217 * can change more often than once per buffer, since AFS 3 dir page size
4218 * may be less than (but not more than a buffer package buffer.
4220 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4221 temp &= ~(2048 - 1); /* turn off intra-page bits */
4222 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4224 /* now determine which entry we're looking at in the page. If it is
4225 * free (there's a free bitmap at the start of the dir), we should
4226 * skip these 32 bytes.
4228 slotInPage = (entryInDir & 0x7e0) >> 5;
4229 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4230 /* this entry is free */
4231 numDirChunks = 1; /* only skip this guy */
4235 tp = bufferp->datap + entryInBuffer;
4236 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4238 /* while we're here, compute the next entry's location, too,
4239 * since we'll need it when writing out the cookie into the dir
4242 * XXXX Probably should do more sanity checking.
4244 numDirChunks = cm_NameEntries(dep->name, NULL);
4246 /* compute the offset of the cookie representing the next entry */
4247 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4249 /* Compute 8.3 name if necessary */
4250 actualName = dep->name;
4251 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4252 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4253 actualName = shortName;
4256 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4257 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4258 osi_LogSaveString(smb_logp, actualName));
4260 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4261 /* this is one of the entries to use: it is not deleted
4262 * and it matches the star pattern we're looking for.
4265 /* Eliminate entries that don't match requested
4268 /* no hidden files */
4269 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4270 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4274 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4276 /* We have already done the cm_TryBulkStat above */
4277 fid.cell = scp->fid.cell;
4278 fid.volume = scp->fid.volume;
4279 fid.vnode = ntohl(dep->fid.vnode);
4280 fid.unique = ntohl(dep->fid.unique);
4281 fileType = cm_FindFileType(&fid);
4282 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4283 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4285 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4286 fileType == CM_SCACHETYPE_DFSLINK ||
4287 fileType == CM_SCACHETYPE_INVALID)
4288 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4293 memcpy(op, mask, 11); op += 11;
4294 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4295 *op++ = (char)(nextEntryCookie & 0xff);
4296 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4297 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4298 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4299 memcpy(op, &clientCookie, 4); op += 4;
4301 /* now we emit the attribute. This is sort of tricky,
4302 * since we need to really stat the file to find out
4303 * what type of entry we've got. Right now, we're
4304 * copying out data from a buffer, while holding the
4305 * scp locked, so it isn't really convenient to stat
4306 * something now. We'll put in a place holder now,
4307 * and make a second pass before returning this to get
4308 * the real attributes. So, we just skip the data for
4309 * now, and adjust it later. We allocate a patch
4310 * record to make it easy to find this point later.
4311 * The replay will happen at a time when it is safe to
4312 * unlock the directory.
4314 curPatchp = malloc(sizeof(*curPatchp));
4315 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4316 curPatchp->dptr = op;
4317 curPatchp->fid.cell = scp->fid.cell;
4318 curPatchp->fid.volume = scp->fid.volume;
4319 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4320 curPatchp->fid.unique = ntohl(dep->fid.unique);
4322 /* do hidden attribute here since name won't be around when applying
4326 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4327 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4329 curPatchp->flags = 0;
4331 op += 9; /* skip attr, time, date and size */
4333 /* zero out name area. The spec says to pad with
4334 * spaces, but Samba doesn't, and neither do we.
4338 /* finally, we get to copy out the name; we know that
4339 * it fits in 8.3 or the pattern wouldn't match, but it
4340 * never hurts to be sure.
4342 strncpy(op, actualName, 13);
4343 if (smb_StoreAnsiFilenames)
4346 /* Uppercase if requested by client */
4347 if (!KNOWS_LONG_NAMES(inp))
4352 /* now, adjust the # of entries copied */
4354 } /* if we're including this name */
4357 /* and adjust curOffset to be where the new cookie is */
4358 thyper.HighPart = 0;
4359 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4360 curOffset = LargeIntegerAdd(thyper, curOffset);
4361 } /* while copying data for dir listing */
4363 /* release the mutex */
4364 lock_ReleaseMutex(&scp->mx);
4365 if (bufferp) buf_Release(bufferp);
4367 /* apply and free last set of patches; if not doing a star match, this
4368 * will be empty, but better safe (and freeing everything) than sorry.
4370 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4372 /* special return code for unsuccessful search */
4373 if (code == 0 && dataLength < 21 && returnedNames == 0)
4374 code = CM_ERROR_NOFILES;
4376 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4377 returnedNames, code);
4380 smb_DeleteDirSearch(dsp);
4381 smb_ReleaseDirSearch(dsp);
4382 cm_ReleaseSCache(scp);
4383 cm_ReleaseUser(userp);
4387 /* finalize the output buffer */
4388 smb_SetSMBParm(outp, 0, returnedNames);
4389 temp = (long) (op - origOp);
4390 smb_SetSMBDataLength(outp, temp);
4392 /* the data area is a variable block, which has a 5 (already there)
4393 * followed by the length of the # of data bytes. We now know this to
4394 * be "temp," although that includes the 3 bytes of vbl block header.
4395 * Deduct for them and fill in the length field.
4397 temp -= 3; /* deduct vbl block info */
4398 osi_assert(temp == (43 * returnedNames));
4399 origOp[1] = (char)(temp & 0xff);
4400 origOp[2] = (char)((temp>>8) & 0xff);
4401 if (returnedNames == 0)
4402 smb_DeleteDirSearch(dsp);
4403 smb_ReleaseDirSearch(dsp);
4404 cm_ReleaseSCache(scp);
4405 cm_ReleaseUser(userp);
4409 /* verify that this is a valid path to a directory. I don't know why they
4410 * don't use the get file attributes call.
4412 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4416 cm_scache_t *rootScp;
4417 cm_scache_t *newScp;
4426 pathp = smb_GetSMBData(inp, NULL);
4427 pathp = smb_ParseASCIIBlock(pathp, NULL);
4429 return CM_ERROR_BADFD;
4430 if (smb_StoreAnsiFilenames)
4431 OemToChar(pathp,pathp);
4432 osi_Log1(smb_logp, "SMB receive check path %s",
4433 osi_LogSaveString(smb_logp, pathp));
4435 rootScp = cm_data.rootSCachep;
4437 userp = smb_GetUserFromVCP(vcp, inp);
4439 caseFold = CM_FLAG_CASEFOLD;
4441 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4443 cm_ReleaseUser(userp);
4444 return CM_ERROR_NOSUCHPATH;
4446 code = cm_NameI(rootScp, pathp,
4447 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4448 userp, tidPathp, &req, &newScp);
4451 cm_ReleaseUser(userp);
4456 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4457 cm_ReleaseSCache(newScp);
4458 cm_ReleaseUser(userp);
4459 if ( WANTS_DFS_PATHNAMES(inp) )
4460 return CM_ERROR_PATH_NOT_COVERED;
4462 return CM_ERROR_BADSHARENAME;
4464 #endif /* DFS_SUPPORT */
4466 /* now lock the vnode with a callback; returns with newScp locked */
4467 lock_ObtainMutex(&newScp->mx);
4468 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4469 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4470 if (code && code != CM_ERROR_NOACCESS) {
4471 lock_ReleaseMutex(&newScp->mx);
4472 cm_ReleaseSCache(newScp);
4473 cm_ReleaseUser(userp);
4477 attrs = smb_Attributes(newScp);
4479 if (!(attrs & SMB_ATTR_DIRECTORY))
4480 code = CM_ERROR_NOTDIR;
4482 lock_ReleaseMutex(&newScp->mx);
4484 cm_ReleaseSCache(newScp);
4485 cm_ReleaseUser(userp);
4489 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4493 cm_scache_t *rootScp;
4494 unsigned short attribute;
4496 cm_scache_t *newScp;
4505 /* decode basic attributes we're passed */
4506 attribute = smb_GetSMBParm(inp, 0);
4507 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4509 pathp = smb_GetSMBData(inp, NULL);
4510 pathp = smb_ParseASCIIBlock(pathp, NULL);
4512 return CM_ERROR_BADSMB;
4513 if (smb_StoreAnsiFilenames)
4514 OemToChar(pathp,pathp);
4516 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4517 dosTime, attribute);
4519 rootScp = cm_data.rootSCachep;
4521 userp = smb_GetUserFromVCP(vcp, inp);
4523 caseFold = CM_FLAG_CASEFOLD;
4525 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4527 cm_ReleaseUser(userp);
4528 return CM_ERROR_NOSUCHFILE;
4530 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4531 tidPathp, &req, &newScp);
4534 cm_ReleaseUser(userp);
4539 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4540 cm_ReleaseSCache(newScp);
4541 cm_ReleaseUser(userp);
4542 if ( WANTS_DFS_PATHNAMES(inp) )
4543 return CM_ERROR_PATH_NOT_COVERED;
4545 return CM_ERROR_BADSHARENAME;
4547 #endif /* DFS_SUPPORT */
4549 /* now lock the vnode with a callback; returns with newScp locked; we
4550 * need the current status to determine what the new status is, in some
4553 lock_ObtainMutex(&newScp->mx);
4554 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4555 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4557 lock_ReleaseMutex(&newScp->mx);
4558 cm_ReleaseSCache(newScp);
4559 cm_ReleaseUser(userp);
4563 /* Check for RO volume */
4564 if (newScp->flags & CM_SCACHEFLAG_RO) {
4565 lock_ReleaseMutex(&newScp->mx);
4566 cm_ReleaseSCache(newScp);
4567 cm_ReleaseUser(userp);
4568 return CM_ERROR_READONLY;
4571 /* prepare for setattr call */
4574 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4575 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4577 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4578 /* we're told to make a writable file read-only */
4579 attr.unixModeBits = newScp->unixModeBits & ~0222;
4580 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4582 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4583 /* we're told to make a read-only file writable */
4584 attr.unixModeBits = newScp->unixModeBits | 0222;
4585 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4587 lock_ReleaseMutex(&newScp->mx);
4589 /* now call setattr */
4591 code = cm_SetAttr(newScp, &attr, userp, &req);
4595 cm_ReleaseSCache(newScp);
4596 cm_ReleaseUser(userp);
4601 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4605 cm_scache_t *rootScp;
4606 cm_scache_t *newScp, *dscp;
4618 pathp = smb_GetSMBData(inp, NULL);
4619 pathp = smb_ParseASCIIBlock(pathp, NULL);
4621 return CM_ERROR_BADSMB;
4623 if (*pathp == 0) /* null path */
4626 if (smb_StoreAnsiFilenames)
4627 OemToChar(pathp,pathp);
4629 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4630 osi_LogSaveString(smb_logp, pathp));
4632 rootScp = cm_data.rootSCachep;
4634 userp = smb_GetUserFromVCP(vcp, inp);
4636 /* we shouldn't need this for V3 requests, but we seem to */
4637 caseFold = CM_FLAG_CASEFOLD;
4639 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4641 cm_ReleaseUser(userp);
4642 return CM_ERROR_NOSUCHFILE;
4646 * XXX Strange hack XXX
4648 * As of Patch 5 (16 July 97), we are having the following problem:
4649 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4650 * requests to look up "desktop.ini" in all the subdirectories.
4651 * This can cause zillions of timeouts looking up non-existent cells
4652 * and volumes, especially in the top-level directory.
4654 * We have not found any way to avoid this or work around it except
4655 * to explicitly ignore the requests for mount points that haven't
4656 * yet been evaluated and for directories that haven't yet been
4659 * We should modify this hack to provide a fake desktop.ini file
4660 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4662 spacep = inp->spacep;
4663 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4664 #ifndef SPECIAL_FOLDERS
4665 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4666 code = cm_NameI(rootScp, spacep->data,
4667 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4668 userp, tidPathp, &req, &dscp);
4671 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4672 if ( WANTS_DFS_PATHNAMES(inp) )
4673 return CM_ERROR_PATH_NOT_COVERED;
4675 return CM_ERROR_BADSHARENAME;
4677 #endif /* DFS_SUPPORT */
4678 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4679 code = CM_ERROR_NOSUCHFILE;
4680 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4681 cm_buf_t *bp = buf_Find(dscp, &hzero);
4685 code = CM_ERROR_NOSUCHFILE;
4687 cm_ReleaseSCache(dscp);
4689 cm_ReleaseUser(userp);
4694 #endif /* SPECIAL_FOLDERS */
4696 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4697 tidPathp, &req, &newScp);
4699 cm_ReleaseUser(userp);
4704 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4705 cm_ReleaseSCache(newScp);
4706 cm_ReleaseUser(userp);
4707 if ( WANTS_DFS_PATHNAMES(inp) )
4708 return CM_ERROR_PATH_NOT_COVERED;
4710 return CM_ERROR_BADSHARENAME;
4712 #endif /* DFS_SUPPORT */
4714 /* now lock the vnode with a callback; returns with newScp locked */
4715 lock_ObtainMutex(&newScp->mx);
4716 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4717 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4719 lock_ReleaseMutex(&newScp->mx);
4720 cm_ReleaseSCache(newScp);
4721 cm_ReleaseUser(userp);
4726 /* use smb_Attributes instead. Also the fact that a file is
4727 * in a readonly volume doesn't mean it shojuld be marked as RO
4729 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4730 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4731 attrs = SMB_ATTR_DIRECTORY;
4734 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4735 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4737 attrs = smb_Attributes(newScp);
4740 smb_SetSMBParm(outp, 0, attrs);
4742 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4743 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4744 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4745 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4746 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4747 smb_SetSMBParm(outp, 5, 0);
4748 smb_SetSMBParm(outp, 6, 0);
4749 smb_SetSMBParm(outp, 7, 0);
4750 smb_SetSMBParm(outp, 8, 0);
4751 smb_SetSMBParm(outp, 9, 0);
4752 smb_SetSMBDataLength(outp, 0);
4753 lock_ReleaseMutex(&newScp->mx);
4755 cm_ReleaseSCache(newScp);
4756 cm_ReleaseUser(userp);
4761 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4765 osi_Log0(smb_logp, "SMB receive tree disconnect");
4767 /* find the tree and free it */
4768 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4770 lock_ObtainWrite(&smb_rctLock);
4772 lock_ReleaseWrite(&smb_rctLock);
4773 smb_ReleaseTID(tidp);
4779 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4797 pathp = smb_GetSMBData(inp, NULL);
4798 pathp = smb_ParseASCIIBlock(pathp, NULL);
4799 if (smb_StoreAnsiFilenames)
4800 OemToChar(pathp,pathp);
4802 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4804 #ifdef DEBUG_VERBOSE
4808 hexpath = osi_HexifyString( pathp );
4809 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4814 share = smb_GetSMBParm(inp, 0);
4815 attribute = smb_GetSMBParm(inp, 1);
4817 spacep = inp->spacep;
4818 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4819 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4820 /* special case magic file name for receiving IOCTL requests
4821 * (since IOCTL calls themselves aren't getting through).
4823 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4824 smb_SetupIoctlFid(fidp, spacep);
4825 smb_SetSMBParm(outp, 0, fidp->fid);
4826 smb_SetSMBParm(outp, 1, 0); /* attrs */
4827 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4828 smb_SetSMBParm(outp, 3, 0);
4829 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4830 smb_SetSMBParm(outp, 5, 0x7fff);
4831 /* pass the open mode back */
4832 smb_SetSMBParm(outp, 6, (share & 0xf));
4833 smb_SetSMBDataLength(outp, 0);
4834 smb_ReleaseFID(fidp);
4838 userp = smb_GetUserFromVCP(vcp, inp);
4840 caseFold = CM_FLAG_CASEFOLD;
4842 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4844 cm_ReleaseUser(userp);
4845 return CM_ERROR_NOSUCHPATH;
4847 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4848 tidPathp, &req, &scp);
4851 cm_ReleaseUser(userp);
4856 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4857 cm_ReleaseSCache(scp);
4858 cm_ReleaseUser(userp);
4859 if ( WANTS_DFS_PATHNAMES(inp) )
4860 return CM_ERROR_PATH_NOT_COVERED;
4862 return CM_ERROR_BADSHARENAME;
4864 #endif /* DFS_SUPPORT */
4866 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4868 cm_ReleaseSCache(scp);
4869 cm_ReleaseUser(userp);
4873 /* don't need callback to check file type, since file types never
4874 * change, and namei and cm_Lookup all stat the object at least once on
4875 * a successful return.
4877 if (scp->fileType != CM_SCACHETYPE_FILE) {
4878 cm_ReleaseSCache(scp);
4879 cm_ReleaseUser(userp);
4880 return CM_ERROR_ISDIR;
4883 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4886 /* save a pointer to the vnode */
4890 fidp->userp = userp;
4892 lock_ObtainMutex(&fidp->mx);
4893 if ((share & 0xf) == 0)
4894 fidp->flags |= SMB_FID_OPENREAD;
4895 else if ((share & 0xf) == 1)
4896 fidp->flags |= SMB_FID_OPENWRITE;
4898 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4899 lock_ReleaseMutex(&fidp->mx);
4901 lock_ObtainMutex(&scp->mx);
4902 smb_SetSMBParm(outp, 0, fidp->fid);
4903 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4904 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4905 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4906 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4907 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4908 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4909 /* pass the open mode back; XXXX add access checks */
4910 smb_SetSMBParm(outp, 6, (share & 0xf));
4911 smb_SetSMBDataLength(outp, 0);
4912 lock_ReleaseMutex(&scp->mx);
4915 cm_Open(scp, 0, userp);
4917 /* send and free packet */
4918 smb_ReleaseFID(fidp);
4919 cm_ReleaseUser(userp);
4920 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4924 typedef struct smb_unlinkRock {
4929 char *maskp; /* pointer to the star pattern */
4934 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4937 smb_unlinkRock_t *rockp;
4945 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4946 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4947 caseFold |= CM_FLAG_8DOT3;
4949 matchName = dep->name;
4950 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4952 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4953 !cm_Is8Dot3(dep->name)) {
4954 cm_Gen8Dot3Name(dep, shortName, NULL);
4955 matchName = shortName;
4956 /* 8.3 matches are always case insensitive */
4957 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4960 osi_Log1(smb_logp, "Unlinking %s",
4961 osi_LogSaveString(smb_logp, matchName));
4962 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4963 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4964 smb_NotifyChange(FILE_ACTION_REMOVED,
4965 FILE_NOTIFY_CHANGE_FILE_NAME,
4966 dscp, dep->name, NULL, TRUE);
4970 /* If we made a case sensitive exact match, we might as well quit now. */
4971 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4972 code = CM_ERROR_STOPNOW;
4980 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4989 smb_unlinkRock_t rock;
4998 attribute = smb_GetSMBParm(inp, 0);
5000 tp = smb_GetSMBData(inp, NULL);
5001 pathp = smb_ParseASCIIBlock(tp, &tp);
5002 if (smb_StoreAnsiFilenames)
5003 OemToChar(pathp,pathp);
5005 osi_Log1(smb_logp, "SMB receive unlink %s",
5006 osi_LogSaveString(smb_logp, pathp));
5008 spacep = inp->spacep;
5009 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5011 userp = smb_GetUserFromVCP(vcp, inp);
5013 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5015 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5017 cm_ReleaseUser(userp);
5018 return CM_ERROR_NOSUCHPATH;
5020 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5023 cm_ReleaseUser(userp);
5028 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5029 cm_ReleaseSCache(dscp);
5030 cm_ReleaseUser(userp);
5031 if ( WANTS_DFS_PATHNAMES(inp) )
5032 return CM_ERROR_PATH_NOT_COVERED;
5034 return CM_ERROR_BADSHARENAME;
5036 #endif /* DFS_SUPPORT */
5038 /* otherwise, scp points to the parent directory. */
5045 rock.maskp = smb_FindMask(pathp);
5046 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5049 thyper.HighPart = 0;
5055 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5056 * match. If that fails, we do a case insensitve match.
5058 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5059 !smb_IsStarMask(rock.maskp)) {
5060 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5063 thyper.HighPart = 0;
5064 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5069 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5071 if (code == CM_ERROR_STOPNOW)
5074 cm_ReleaseUser(userp);
5076 cm_ReleaseSCache(dscp);
5078 if (code == 0 && !rock.any)
5079 code = CM_ERROR_NOSUCHFILE;
5083 typedef struct smb_renameRock {
5084 cm_scache_t *odscp; /* old dir */
5085 cm_scache_t *ndscp; /* new dir */
5086 cm_user_t *userp; /* user */
5087 cm_req_t *reqp; /* request struct */
5088 smb_vc_t *vcp; /* virtual circuit */
5089 char *maskp; /* pointer to star pattern of old file name */
5090 int flags; /* tilde, casefold, etc */
5091 char *newNamep; /* ptr to the new file's name */
5094 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5097 smb_renameRock_t *rockp;
5102 rockp = (smb_renameRock_t *) vrockp;
5104 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5105 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5106 caseFold |= CM_FLAG_8DOT3;
5108 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5110 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5111 !cm_Is8Dot3(dep->name)) {
5112 cm_Gen8Dot3Name(dep, shortName, NULL);
5113 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5116 code = cm_Rename(rockp->odscp, dep->name,
5117 rockp->ndscp, rockp->newNamep, rockp->userp,
5119 /* if the call worked, stop doing the search now, since we
5120 * really only want to rename one file.
5123 code = CM_ERROR_STOPNOW;
5132 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5135 cm_space_t *spacep = NULL;
5136 smb_renameRock_t rock;
5137 cm_scache_t *oldDscp = NULL;
5138 cm_scache_t *newDscp = NULL;
5139 cm_scache_t *tmpscp= NULL;
5140 cm_scache_t *tmpscp2 = NULL;
5150 userp = smb_GetUserFromVCP(vcp, inp);
5151 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5153 cm_ReleaseUser(userp);
5154 return CM_ERROR_NOSUCHPATH;
5158 spacep = inp->spacep;
5159 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5161 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5162 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5163 userp, tidPathp, &req, &oldDscp);
5165 cm_ReleaseUser(userp);
5170 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5171 cm_ReleaseSCache(oldDscp);
5172 cm_ReleaseUser(userp);
5173 if ( WANTS_DFS_PATHNAMES(inp) )
5174 return CM_ERROR_PATH_NOT_COVERED;
5176 return CM_ERROR_BADSHARENAME;
5178 #endif /* DFS_SUPPORT */
5180 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5181 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5182 userp, tidPathp, &req, &newDscp);
5185 cm_ReleaseSCache(oldDscp);
5186 cm_ReleaseUser(userp);
5191 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5192 cm_ReleaseSCache(oldDscp);
5193 cm_ReleaseSCache(newDscp);
5194 cm_ReleaseUser(userp);
5195 if ( WANTS_DFS_PATHNAMES(inp) )
5196 return CM_ERROR_PATH_NOT_COVERED;
5198 return CM_ERROR_BADSHARENAME;
5200 #endif /* DFS_SUPPORT */
5203 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5204 * next, get the component names, and lower case them.
5207 /* handle the old name first */
5209 oldLastNamep = oldPathp;
5213 /* and handle the new name, too */
5215 newLastNamep = newPathp;
5219 /* TODO: The old name could be a wildcard. The new name must not be */
5221 /* do the vnode call */
5222 rock.odscp = oldDscp;
5223 rock.ndscp = newDscp;
5227 rock.maskp = oldLastNamep;
5228 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5229 rock.newNamep = newLastNamep;
5231 /* Check if the file already exists; if so return error */
5232 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5233 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5234 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5235 osi_LogSaveString(afsd_logp, newLastNamep));
5237 /* Check if the old and the new names differ only in case. If so return
5238 * success, else return CM_ERROR_EXISTS
5240 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5242 /* This would be a success only if the old file is *as same as* the new file */
5243 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5245 if (tmpscp == tmpscp2)
5248 code = CM_ERROR_EXISTS;
5249 cm_ReleaseSCache(tmpscp2);
5252 code = CM_ERROR_NOSUCHFILE;
5255 /* file exist, do not rename, also fixes move */
5256 osi_Log0(smb_logp, "Can't rename. Target already exists");
5257 code = CM_ERROR_EXISTS;
5261 cm_ReleaseSCache(tmpscp);
5262 cm_ReleaseSCache(newDscp);
5263 cm_ReleaseSCache(oldDscp);
5264 cm_ReleaseUser(userp);
5268 /* Now search the directory for the pattern, and do the appropriate rename when found */
5269 thyper.LowPart = 0; /* search dir from here */
5270 thyper.HighPart = 0;
5272 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5273 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5275 if (code == CM_ERROR_STOPNOW)
5278 code = CM_ERROR_NOSUCHFILE;
5280 /* Handle Change Notification */
5282 * Being lazy, not distinguishing between files and dirs in this
5283 * filter, since we'd have to do a lookup.
5285 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5286 if (oldDscp == newDscp) {
5287 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5288 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5289 filter, oldDscp, oldLastNamep,
5290 newLastNamep, TRUE);
5292 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5293 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5294 filter, oldDscp, oldLastNamep,
5296 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5297 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5298 filter, newDscp, newLastNamep,
5303 cm_ReleaseSCache(tmpscp);
5304 cm_ReleaseUser(userp);
5305 cm_ReleaseSCache(oldDscp);
5306 cm_ReleaseSCache(newDscp);
5311 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5314 cm_space_t *spacep = NULL;
5315 cm_scache_t *oldDscp = NULL;
5316 cm_scache_t *newDscp = NULL;
5317 cm_scache_t *tmpscp= NULL;
5318 cm_scache_t *tmpscp2 = NULL;
5319 cm_scache_t *sscp = NULL;
5328 userp = smb_GetUserFromVCP(vcp, inp);
5330 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5332 cm_ReleaseUser(userp);
5333 return CM_ERROR_NOSUCHPATH;
5338 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5340 spacep = inp->spacep;
5341 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5343 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5344 userp, tidPathp, &req, &oldDscp);
5346 cm_ReleaseUser(userp);
5351 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5352 cm_ReleaseSCache(oldDscp);
5353 cm_ReleaseUser(userp);
5354 if ( WANTS_DFS_PATHNAMES(inp) )
5355 return CM_ERROR_PATH_NOT_COVERED;
5357 return CM_ERROR_BADSHARENAME;
5359 #endif /* DFS_SUPPORT */
5361 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5362 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5363 userp, tidPathp, &req, &newDscp);
5365 cm_ReleaseSCache(oldDscp);
5366 cm_ReleaseUser(userp);
5371 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5372 cm_ReleaseSCache(newDscp);
5373 cm_ReleaseSCache(oldDscp);
5374 cm_ReleaseUser(userp);
5375 if ( WANTS_DFS_PATHNAMES(inp) )
5376 return CM_ERROR_PATH_NOT_COVERED;
5378 return CM_ERROR_BADSHARENAME;
5380 #endif /* DFS_SUPPORT */
5382 /* Now, although we did two lookups for the two directories (because the same
5383 * directory can be referenced through different paths), we only allow hard links
5384 * within the same directory. */
5385 if (oldDscp != newDscp) {
5386 cm_ReleaseSCache(oldDscp);
5387 cm_ReleaseSCache(newDscp);
5388 cm_ReleaseUser(userp);
5389 return CM_ERROR_CROSSDEVLINK;
5392 /* handle the old name first */
5394 oldLastNamep = oldPathp;
5398 /* and handle the new name, too */
5400 newLastNamep = newPathp;
5404 /* now lookup the old name */
5405 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5406 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5408 cm_ReleaseSCache(oldDscp);
5409 cm_ReleaseSCache(newDscp);
5410 cm_ReleaseUser(userp);
5414 /* Check if the file already exists; if so return error */
5415 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5416 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5417 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5418 osi_LogSaveString(afsd_logp, newLastNamep));
5420 /* if the existing link is to the same file, then we return success */
5422 if(sscp == tmpscp) {
5425 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5426 code = CM_ERROR_EXISTS;
5431 cm_ReleaseSCache(tmpscp);
5432 cm_ReleaseSCache(sscp);
5433 cm_ReleaseSCache(newDscp);
5434 cm_ReleaseSCache(oldDscp);
5435 cm_ReleaseUser(userp);
5439 /* now create the hardlink */
5440 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5441 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5442 osi_Log1(smb_logp," Link returns %d", code);
5444 /* Handle Change Notification */
5446 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5447 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5448 smb_NotifyChange(FILE_ACTION_ADDED,
5449 filter, newDscp, newLastNamep,
5454 cm_ReleaseSCache(tmpscp);
5455 cm_ReleaseUser(userp);
5456 cm_ReleaseSCache(sscp);
5457 cm_ReleaseSCache(oldDscp);
5458 cm_ReleaseSCache(newDscp);
5463 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5469 tp = smb_GetSMBData(inp, NULL);
5470 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5471 if (smb_StoreAnsiFilenames)
5472 OemToChar(oldPathp,oldPathp);
5473 newPathp = smb_ParseASCIIBlock(tp, &tp);
5474 if (smb_StoreAnsiFilenames)
5475 OemToChar(newPathp,newPathp);
5477 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5478 osi_LogSaveString(smb_logp, oldPathp),
5479 osi_LogSaveString(smb_logp, newPathp));
5481 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5486 typedef struct smb_rmdirRock {
5490 char *maskp; /* pointer to the star pattern */
5495 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5498 smb_rmdirRock_t *rockp;
5503 rockp = (smb_rmdirRock_t *) vrockp;
5505 matchName = dep->name;
5506 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5507 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5509 match = (strcmp(matchName, rockp->maskp) == 0);
5511 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5512 !cm_Is8Dot3(dep->name)) {
5513 cm_Gen8Dot3Name(dep, shortName, NULL);
5514 matchName = shortName;
5515 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5518 osi_Log1(smb_logp, "Removing directory %s",
5519 osi_LogSaveString(smb_logp, matchName));
5520 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5521 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5522 smb_NotifyChange(FILE_ACTION_REMOVED,
5523 FILE_NOTIFY_CHANGE_DIR_NAME,
5524 dscp, dep->name, NULL, TRUE);
5533 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5541 smb_rmdirRock_t rock;
5550 tp = smb_GetSMBData(inp, NULL);
5551 pathp = smb_ParseASCIIBlock(tp, &tp);
5552 if (smb_StoreAnsiFilenames)
5553 OemToChar(pathp,pathp);
5555 spacep = inp->spacep;
5556 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5558 userp = smb_GetUserFromVCP(vcp, inp);
5560 caseFold = CM_FLAG_CASEFOLD;
5562 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5564 cm_ReleaseUser(userp);
5565 return CM_ERROR_NOSUCHPATH;
5567 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5568 userp, tidPathp, &req, &dscp);
5571 cm_ReleaseUser(userp);
5576 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5577 cm_ReleaseSCache(dscp);
5578 cm_ReleaseUser(userp);
5579 if ( WANTS_DFS_PATHNAMES(inp) )
5580 return CM_ERROR_PATH_NOT_COVERED;
5582 return CM_ERROR_BADSHARENAME;
5584 #endif /* DFS_SUPPORT */
5586 /* otherwise, scp points to the parent directory. */
5593 rock.maskp = lastNamep;
5594 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5597 thyper.HighPart = 0;
5601 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5602 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5603 if (code == 0 && !rock.any) {
5605 thyper.HighPart = 0;
5606 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5607 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5610 cm_ReleaseUser(userp);
5612 cm_ReleaseSCache(dscp);
5614 if (code == 0 && !rock.any)
5615 code = CM_ERROR_NOSUCHFILE;
5619 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5629 fid = smb_GetSMBParm(inp, 0);
5631 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5633 fid = smb_ChainFID(fid, inp);
5634 fidp = smb_FindFID(vcp, fid, 0);
5636 return CM_ERROR_BADFD;
5638 lock_ObtainMutex(&fidp->mx);
5639 if (fidp->flags & SMB_FID_IOCTL) {
5640 lock_ReleaseMutex(&fidp->mx);
5641 smb_ReleaseFID(fidp);
5642 return CM_ERROR_BADFD;
5644 lock_ReleaseMutex(&fidp->mx);
5646 userp = smb_GetUserFromVCP(vcp, inp);
5648 lock_ObtainMutex(&fidp->mx);
5649 if (fidp->flags & SMB_FID_OPENWRITE)
5650 code = cm_FSync(fidp->scp, userp, &req);
5653 lock_ReleaseMutex(&fidp->mx);
5655 smb_ReleaseFID(fidp);
5657 cm_ReleaseUser(userp);
5662 struct smb_FullNameRock {
5668 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5672 struct smb_FullNameRock *vrockp;
5674 vrockp = (struct smb_FullNameRock *)rockp;
5676 if (!cm_Is8Dot3(dep->name)) {
5677 cm_Gen8Dot3Name(dep, shortName, NULL);
5679 if (cm_stricmp(shortName, vrockp->name) == 0) {
5680 vrockp->fullName = strdup(dep->name);
5681 return CM_ERROR_STOPNOW;
5684 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5685 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5686 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5687 vrockp->fullName = strdup(dep->name);
5688 return CM_ERROR_STOPNOW;
5693 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5694 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5696 struct smb_FullNameRock rock;
5702 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5703 if (code == CM_ERROR_STOPNOW)
5704 *newPathp = rock.fullName;
5706 *newPathp = strdup(pathp);
5709 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5710 afs_uint32 dosTime) {
5713 cm_scache_t *dscp = fidp->NTopen_dscp;
5714 char *pathp = fidp->NTopen_pathp;
5716 osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
5717 fidp, fidp->fid, vcp);
5720 lock_ObtainMutex(&fidp->mx);
5721 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5722 lock_ReleaseMutex(&fidp->mx);
5723 osi_Log0(smb_logp, " No user specified. Not closing fid");
5724 return CM_ERROR_BADFD;
5727 userp = fidp->userp; /* no hold required since fidp is held
5728 throughout the function */
5729 lock_ReleaseMutex(&fidp->mx);
5734 lock_ObtainWrite(&smb_rctLock);
5736 osi_Log0(smb_logp, " Fid already closed.");
5737 lock_ReleaseWrite(&smb_rctLock);
5738 return CM_ERROR_BADFD;
5741 lock_ReleaseWrite(&smb_rctLock);
5743 lock_ObtainMutex(&fidp->mx);
5744 /* Don't jump the gun on an async raw write */
5745 while (fidp->raw_writers) {
5746 lock_ReleaseMutex(&fidp->mx);
5747 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5748 lock_ObtainMutex(&fidp->mx);
5751 /* watch for ioctl closes, and read-only opens */
5752 if (fidp->scp != NULL &&
5753 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5754 == SMB_FID_OPENWRITE) {
5755 if (dosTime != 0 && dosTime != -1) {
5756 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5757 /* This fixes defect 10958 */
5758 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5759 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5761 code = cm_FSync(fidp->scp, userp, &req);
5766 /* unlock any pending locks */
5767 if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
5768 fidp->scp->fileType == CM_SCACHETYPE_FILE) {
5773 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5775 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5778 lock_ObtainMutex(&scp->mx);
5780 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5781 CM_SCACHESYNC_NEEDCALLBACK
5782 | CM_SCACHESYNC_GETSTATUS
5783 | CM_SCACHESYNC_LOCK);
5787 "smb CoreClose SyncOp failure code 0x%x", tcode);
5788 goto post_syncopdone;
5791 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5793 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5797 lock_ReleaseMutex(&scp->mx);
5798 cm_ReleaseSCache(scp);
5801 if (fidp->flags & SMB_FID_DELONCLOSE) {
5804 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5805 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5806 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5807 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5808 smb_NotifyChange(FILE_ACTION_REMOVED,
5809 FILE_NOTIFY_CHANGE_DIR_NAME,
5810 dscp, fullPathp, NULL, TRUE);
5812 code = cm_Unlink(dscp, fullPathp, userp, &req);
5813 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5814 smb_NotifyChange(FILE_ACTION_REMOVED,
5815 FILE_NOTIFY_CHANGE_FILE_NAME,
5816 dscp, fullPathp, NULL, TRUE);
5819 fidp->flags &= ~SMB_FID_DELONCLOSE;
5822 if (fidp->flags & SMB_FID_NTOPEN) {
5823 fidp->NTopen_dscp = NULL;
5824 fidp->NTopen_pathp = NULL;
5825 fidp->flags &= ~SMB_FID_NTOPEN;
5827 if (fidp->NTopen_wholepathp) {
5828 free(fidp->NTopen_wholepathp);
5829 fidp->NTopen_wholepathp = NULL;
5831 lock_ReleaseMutex(&fidp->mx);
5834 cm_ReleaseSCache(dscp);
5842 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5850 fid = smb_GetSMBParm(inp, 0);
5851 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5853 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5855 fid = smb_ChainFID(fid, inp);
5856 fidp = smb_FindFID(vcp, fid, 0);
5858 return CM_ERROR_BADFD;
5861 userp = smb_GetUserFromVCP(vcp, inp);
5863 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5865 smb_ReleaseFID(fidp);
5866 cm_ReleaseUser(userp);
5871 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5874 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5875 cm_user_t *userp, long *readp)
5877 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5878 cm_user_t *userp, long *readp, int dosflag)
5885 osi_hyper_t fileLength;
5887 osi_hyper_t lastByte;
5888 osi_hyper_t bufferOffset;
5889 long bufIndex, nbytes;
5899 lock_ObtainMutex(&fidp->mx);
5901 lock_ObtainMutex(&scp->mx);
5903 if (offset.HighPart == 0) {
5904 chunk = offset.LowPart >> cm_logChunkSize;
5905 if (chunk != fidp->curr_chunk) {
5906 fidp->prev_chunk = fidp->curr_chunk;
5907 fidp->curr_chunk = chunk;
5909 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5913 /* start by looking up the file's end */
5914 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5915 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5916 if (code) goto done;
5918 /* now we have the entry locked, look up the length */
5919 fileLength = scp->length;
5921 /* adjust count down so that it won't go past EOF */
5922 thyper.LowPart = count;
5923 thyper.HighPart = 0;
5924 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5926 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5927 /* we'd read past EOF, so just stop at fileLength bytes.
5928 * Start by computing how many bytes remain in the file.
5930 thyper = LargeIntegerSubtract(fileLength, offset);
5932 /* if we are past EOF, read 0 bytes */
5933 if (LargeIntegerLessThanZero(thyper))
5936 count = thyper.LowPart;
5941 /* now, copy the data one buffer at a time,
5942 * until we've filled the request packet
5945 /* if we've copied all the data requested, we're done */
5946 if (count <= 0) break;
5948 /* otherwise, load up a buffer of data */
5949 thyper.HighPart = offset.HighPart;
5950 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5951 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5954 buf_Release(bufferp);
5957 lock_ReleaseMutex(&scp->mx);
5959 lock_ObtainRead(&scp->bufCreateLock);
5960 code = buf_Get(scp, &thyper, &bufferp);
5961 lock_ReleaseRead(&scp->bufCreateLock);
5963 lock_ObtainMutex(&scp->mx);
5964 if (code) goto done;
5965 bufferOffset = thyper;
5967 /* now get the data in the cache */
5969 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5970 CM_SCACHESYNC_NEEDCALLBACK |
5971 CM_SCACHESYNC_READ);
5972 if (code) goto done;
5974 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5976 /* otherwise, load the buffer and try again */
5977 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5981 buf_Release(bufferp);
5985 } /* if (wrong buffer) ... */
5987 /* now we have the right buffer loaded. Copy out the
5988 * data from here to the user's buffer.
5990 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5992 /* and figure out how many bytes we want from this buffer */
5993 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5994 if (nbytes > count) nbytes = count; /* don't go past EOF */
5996 /* now copy the data */
5999 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
6002 memcpy(op, bufferp->datap + bufIndex, nbytes);
6004 /* adjust counters, pointers, etc. */
6007 thyper.LowPart = nbytes;
6008 thyper.HighPart = 0;
6009 offset = LargeIntegerAdd(thyper, offset);
6013 lock_ReleaseMutex(&scp->mx);
6014 lock_ReleaseMutex(&fidp->mx);
6016 buf_Release(bufferp);
6018 if (code == 0 && sequential)
6019 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6025 * smb_WriteData -- common code for Write and Raw Write
6028 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6029 cm_user_t *userp, long *writtenp)
6031 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6032 cm_user_t *userp, long *writtenp, int dosflag)
6039 osi_hyper_t fileLength; /* file's length at start of write */
6040 osi_hyper_t minLength; /* don't read past this */
6041 long nbytes; /* # of bytes to transfer this iteration */
6043 osi_hyper_t thyper; /* hyper tmp variable */
6044 osi_hyper_t bufferOffset;
6045 long bufIndex; /* index in buffer where our data is */
6047 osi_hyper_t writeBackOffset;/* offset of region to write back when
6052 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6053 fidp->fid, offsetp->LowPart, count);
6063 lock_ObtainMutex(&fidp->mx);
6065 lock_ObtainMutex(&scp->mx);
6067 /* start by looking up the file's end */
6068 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6069 CM_SCACHESYNC_NEEDCALLBACK
6070 | CM_SCACHESYNC_SETSTATUS
6071 | CM_SCACHESYNC_GETSTATUS);
6075 /* make sure we have a writable FD */
6076 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6077 lock_ReleaseMutex(&fidp->mx);
6078 code = CM_ERROR_BADFDOP;
6082 /* now we have the entry locked, look up the length */
6083 fileLength = scp->length;
6084 minLength = fileLength;
6085 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6086 minLength = scp->serverLength;
6088 /* adjust file length if we extend past EOF */
6089 thyper.LowPart = count;
6090 thyper.HighPart = 0;
6091 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6092 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6093 /* we'd write past EOF, so extend the file */
6094 scp->mask |= CM_SCACHEMASK_LENGTH;
6095 scp->length = thyper;
6096 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6098 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6100 /* now, if the new position (thyper) and the old (offset) are in
6101 * different storeback windows, remember to store back the previous
6102 * storeback window when we're done with the write.
6104 if ((thyper.LowPart & (-cm_chunkSize)) !=
6105 (offset.LowPart & (-cm_chunkSize))) {
6106 /* they're different */
6108 writeBackOffset.HighPart = offset.HighPart;
6109 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6114 /* now, copy the data one buffer at a time, until we've filled the
6117 /* if we've copied all the data requested, we're done */
6121 /* handle over quota or out of space */
6122 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6123 *writtenp = written;
6124 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6128 /* otherwise, load up a buffer of data */
6129 thyper.HighPart = offset.HighPart;
6130 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6131 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6134 lock_ReleaseMutex(&bufferp->mx);
6135 buf_Release(bufferp);
6138 lock_ReleaseMutex(&scp->mx);
6140 lock_ObtainRead(&scp->bufCreateLock);
6141 code = buf_Get(scp, &thyper, &bufferp);
6142 lock_ReleaseRead(&scp->bufCreateLock);
6144 lock_ObtainMutex(&bufferp->mx);
6145 lock_ObtainMutex(&scp->mx);
6146 if (code) goto done;
6148 bufferOffset = thyper;
6150 /* now get the data in the cache */
6152 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6153 CM_SCACHESYNC_NEEDCALLBACK
6154 | CM_SCACHESYNC_WRITE
6155 | CM_SCACHESYNC_BUFLOCKED);
6159 /* If we're overwriting the entire buffer, or
6160 * if we're writing at or past EOF, mark the
6161 * buffer as current so we don't call
6162 * cm_GetBuffer. This skips the fetch from the
6163 * server in those cases where we're going to
6164 * obliterate all the data in the buffer anyway,
6165 * or in those cases where there is no useful
6166 * data at the server to start with.
6168 * Use minLength instead of scp->length, since
6169 * the latter has already been updated by this
6172 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6173 || LargeIntegerEqualTo(offset, bufferp->offset)
6174 && (count >= cm_data.buf_blockSize
6175 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6176 ConvertLongToLargeInteger(count)),
6178 if (count < cm_data.buf_blockSize
6179 && bufferp->dataVersion == -1)
6180 memset(bufferp->datap, 0,
6181 cm_data.buf_blockSize);
6182 bufferp->dataVersion = scp->dataVersion;
6185 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6187 /* otherwise, load the buffer and try again */
6188 lock_ReleaseMutex(&bufferp->mx);
6189 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6191 lock_ReleaseMutex(&scp->mx);
6192 lock_ObtainMutex(&bufferp->mx);
6193 lock_ObtainMutex(&scp->mx);
6197 lock_ReleaseMutex(&bufferp->mx);
6198 buf_Release(bufferp);
6202 } /* if (wrong buffer) ... */
6204 /* now we have the right buffer loaded. Copy out the
6205 * data from here to the user's buffer.
6207 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6209 /* and figure out how many bytes we want from this buffer */
6210 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6212 nbytes = count; /* don't go past end of request */
6214 /* now copy the data */
6217 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
6220 memcpy(bufferp->datap + bufIndex, op, nbytes);
6221 buf_SetDirty(bufferp);
6223 /* and record the last writer */
6224 if (bufferp->userp != userp) {
6227 cm_ReleaseUser(bufferp->userp);
6228 bufferp->userp = userp;
6231 /* adjust counters, pointers, etc. */
6235 thyper.LowPart = nbytes;
6236 thyper.HighPart = 0;
6237 offset = LargeIntegerAdd(thyper, offset);
6241 lock_ReleaseMutex(&scp->mx);
6244 lock_ReleaseMutex(&bufferp->mx);
6245 buf_Release(bufferp);
6248 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6249 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6250 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6251 fidp->NTopen_dscp, fidp->NTopen_pathp,
6254 lock_ReleaseMutex(&fidp->mx);
6256 if (code == 0 && doWriteBack) {
6258 lock_ObtainMutex(&scp->mx);
6259 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6261 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6262 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
6264 lock_ReleaseMutex(&scp->mx);
6265 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6266 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6269 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
6270 fidp->fid, code, *writtenp);
6274 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6277 long count, written = 0, total_written = 0;
6283 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6285 int inDataBlockCount;
6287 fd = smb_GetSMBParm(inp, 0);
6288 count = smb_GetSMBParm(inp, 1);
6289 offset.HighPart = 0; /* too bad */
6290 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6292 op = smb_GetSMBData(inp, NULL);
6293 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6295 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6296 fd, offset.LowPart, count);
6298 fd = smb_ChainFID(fd, inp);
6299 fidp = smb_FindFID(vcp, fd, 0);
6301 return CM_ERROR_BADFD;
6303 lock_ObtainMutex(&fidp->mx);
6304 if (fidp->flags & SMB_FID_IOCTL) {
6305 lock_ReleaseMutex(&fidp->mx);
6306 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6307 smb_ReleaseFID(fidp);
6310 lock_ReleaseMutex(&fidp->mx);
6311 userp = smb_GetUserFromVCP(vcp, inp);
6313 /* special case: 0 bytes transferred means truncate to this position */
6319 truncAttr.mask = CM_ATTRMASK_LENGTH;
6320 truncAttr.length.LowPart = offset.LowPart;
6321 truncAttr.length.HighPart = 0;
6322 lock_ObtainMutex(&fidp->mx);
6323 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6324 fidp->flags |= SMB_FID_LENGTHSETDONE;
6325 lock_ReleaseMutex(&fidp->mx);
6326 smb_SetSMBParm(outp, 0, /* count */ 0);
6327 smb_SetSMBDataLength(outp, 0);
6333 LARGE_INTEGER LOffset;
6334 LARGE_INTEGER LLength;
6336 pid = ((smb_t *) inp)->pid;
6337 key = cm_GenerateKey(vcp->vcID, pid, fd);
6339 LOffset.HighPart = offset.HighPart;
6340 LOffset.LowPart = offset.LowPart;
6341 LLength.HighPart = 0;
6342 LLength.LowPart = count;
6344 lock_ObtainMutex(&fidp->scp->mx);
6345 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6346 lock_ReleaseMutex(&fidp->scp->mx);
6353 * Work around bug in NT client
6355 * When copying a file, the NT client should first copy the data,
6356 * then copy the last write time. But sometimes the NT client does
6357 * these in the wrong order, so the data copies would inadvertently
6358 * cause the last write time to be overwritten. We try to detect this,
6359 * and don't set client mod time if we think that would go against the
6362 lock_ObtainMutex(&fidp->mx);
6363 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6364 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6365 fidp->scp->clientModTime = time(NULL);
6367 lock_ReleaseMutex(&fidp->mx);
6370 while ( code == 0 && count > 0 ) {
6372 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6374 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6376 if (code == 0 && written == 0)
6377 code = CM_ERROR_PARTIALWRITE;
6379 offset.LowPart += written;
6381 total_written += written;
6385 /* set the packet data length to 3 bytes for the data block header,
6386 * plus the size of the data.
6388 smb_SetSMBParm(outp, 0, total_written);
6389 smb_SetSMBDataLength(outp, 0);
6392 smb_ReleaseFID(fidp);
6393 cm_ReleaseUser(userp);
6398 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6399 NCB *ncbp, raw_write_cont_t *rwcp)
6412 fd = smb_GetSMBParm(inp, 0);
6413 fidp = smb_FindFID(vcp, fd, 0);
6415 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
6416 rwcp->offset.LowPart, rwcp->count);
6418 userp = smb_GetUserFromVCP(vcp, inp);
6422 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6425 rawBuf = (dos_ptr) rwcp->buf;
6426 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6427 (unsigned char *) rawBuf, userp,
6431 if (rwcp->writeMode & 0x1) { /* synchronous */
6434 smb_FormatResponsePacket(vcp, inp, outp);
6435 op = (smb_t *) outp;
6436 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6437 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6438 smb_SetSMBDataLength(outp, 0);
6439 smb_SendPacket(vcp, outp);
6440 smb_FreePacket(outp);
6442 else { /* asynchronous */
6443 lock_ObtainMutex(&fidp->mx);
6444 fidp->raw_writers--;
6445 if (fidp->raw_writers == 0)
6446 thrd_SetEvent(fidp->raw_write_event);
6447 lock_ReleaseMutex(&fidp->mx);
6450 /* Give back raw buffer */
6451 lock_ObtainMutex(&smb_RawBufLock);
6453 *((char **)rawBuf) = smb_RawBufs;
6455 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6457 smb_RawBufs = rawBuf;
6458 lock_ReleaseMutex(&smb_RawBufLock);
6460 smb_ReleaseFID(fidp);
6461 cm_ReleaseUser(userp);
6464 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6469 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6472 long count, written = 0, total_written = 0;
6479 unsigned short writeMode;
6486 fd = smb_GetSMBParm(inp, 0);
6487 totalCount = smb_GetSMBParm(inp, 1);
6488 count = smb_GetSMBParm(inp, 10);
6489 offset.HighPart = 0; /* too bad */
6490 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6491 writeMode = smb_GetSMBParm(inp, 7);
6493 op = (char *) inp->data;
6494 op += smb_GetSMBParm(inp, 11);
6497 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
6498 fd, offset.LowPart, count, writeMode);
6500 fd = smb_ChainFID(fd, inp);
6501 fidp = smb_FindFID(vcp, fd, 0);
6503 return CM_ERROR_BADFD;
6509 LARGE_INTEGER LOffset;
6510 LARGE_INTEGER LLength;
6512 pid = ((smb_t *) inp)->pid;
6513 key = cm_GenerateKey(vcp->vcID, pid, fd);
6515 LOffset.HighPart = offset.HighPart;
6516 LOffset.LowPart = offset.LowPart;
6517 LLength.HighPart = 0;
6518 LLength.LowPart = count;
6520 lock_ObtainMutex(&fidp->scp->mx);
6521 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6522 lock_ReleaseMutex(&fidp->scp->mx);
6525 smb_ReleaseFID(fidp);
6530 userp = smb_GetUserFromVCP(vcp, inp);
6533 * Work around bug in NT client
6535 * When copying a file, the NT client should first copy the data,
6536 * then copy the last write time. But sometimes the NT client does
6537 * these in the wrong order, so the data copies would inadvertently
6538 * cause the last write time to be overwritten. We try to detect this,
6539 * and don't set client mod time if we think that would go against the
6542 lock_ObtainMutex(&fidp->mx);
6543 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6544 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6545 fidp->scp->clientModTime = time(NULL);
6547 lock_ReleaseMutex(&fidp->mx);
6550 while ( code == 0 && count > 0 ) {
6552 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6554 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6556 if (code == 0 && written == 0)
6557 code = CM_ERROR_PARTIALWRITE;
6559 offset.LowPart += written;
6561 total_written += written;
6565 /* Get a raw buffer */
6568 lock_ObtainMutex(&smb_RawBufLock);
6570 /* Get a raw buf, from head of list */
6571 rawBuf = smb_RawBufs;
6573 smb_RawBufs = *(char **)smb_RawBufs;
6575 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6579 code = CM_ERROR_USESTD;
6581 lock_ReleaseMutex(&smb_RawBufLock);
6584 /* Don't allow a premature Close */
6585 if (code == 0 && (writeMode & 1) == 0) {
6586 lock_ObtainMutex(&fidp->mx);
6587 fidp->raw_writers++;
6588 thrd_ResetEvent(fidp->raw_write_event);
6589 lock_ReleaseMutex(&fidp->mx);
6592 smb_ReleaseFID(fidp);
6593 cm_ReleaseUser(userp);
6596 smb_SetSMBParm(outp, 0, total_written);
6597 smb_SetSMBDataLength(outp, 0);
6598 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6605 rwcp->offset.HighPart = 0;
6606 rwcp->offset.LowPart = offset.LowPart + count;
6607 rwcp->count = totalCount - count;
6608 rwcp->writeMode = writeMode;
6609 rwcp->alreadyWritten = total_written;
6611 /* set the packet data length to 3 bytes for the data block header,
6612 * plus the size of the data.
6614 smb_SetSMBParm(outp, 0, 0xffff);
6615 smb_SetSMBDataLength(outp, 0);
6620 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6623 long count, finalCount;
6631 fd = smb_GetSMBParm(inp, 0);
6632 count = smb_GetSMBParm(inp, 1);
6633 offset.HighPart = 0; /* too bad */
6634 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6636 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6637 fd, offset.LowPart, count);
6639 fd = smb_ChainFID(fd, inp);
6640 fidp = smb_FindFID(vcp, fd, 0);
6642 return CM_ERROR_BADFD;
6644 lock_ObtainMutex(&fidp->mx);
6645 if (fidp->flags & SMB_FID_IOCTL) {
6646 lock_ReleaseMutex(&fidp->mx);
6647 code = smb_IoctlRead(fidp, vcp, inp, outp);
6648 smb_ReleaseFID(fidp);
6651 lock_ReleaseMutex(&fidp->mx);
6654 LARGE_INTEGER LOffset, LLength;
6657 pid = ((smb_t *) inp)->pid;
6658 key = cm_GenerateKey(vcp->vcID, pid, fd);
6660 LOffset.HighPart = 0;
6661 LOffset.LowPart = offset.LowPart;
6662 LLength.HighPart = 0;
6663 LLength.LowPart = count;
6665 lock_ObtainMutex(&fidp->scp->mx);
6666 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6667 lock_ReleaseMutex(&fidp->scp->mx);
6670 smb_ReleaseFID(fidp);
6674 userp = smb_GetUserFromVCP(vcp, inp);
6676 /* remember this for final results */
6677 smb_SetSMBParm(outp, 0, count);
6678 smb_SetSMBParm(outp, 1, 0);
6679 smb_SetSMBParm(outp, 2, 0);
6680 smb_SetSMBParm(outp, 3, 0);
6681 smb_SetSMBParm(outp, 4, 0);
6683 /* set the packet data length to 3 bytes for the data block header,
6684 * plus the size of the data.
6686 smb_SetSMBDataLength(outp, count+3);
6688 /* get op ptr after putting in the parms, since otherwise we don't
6689 * know where the data really is.
6691 op = smb_GetSMBData(outp, NULL);
6693 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6694 *op++ = 1; /* data block marker */
6695 *op++ = (unsigned char) (count & 0xff);
6696 *op++ = (unsigned char) ((count >> 8) & 0xff);
6699 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6701 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6704 /* fix some things up */
6705 smb_SetSMBParm(outp, 0, finalCount);
6706 smb_SetSMBDataLength(outp, finalCount+3);
6708 smb_ReleaseFID(fidp);
6710 cm_ReleaseUser(userp);
6714 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6721 cm_scache_t *dscp; /* dir we're dealing with */
6722 cm_scache_t *scp; /* file we're creating */
6724 int initialModeBits;
6734 /* compute initial mode bits based on read-only flag in attributes */
6735 initialModeBits = 0777;
6737 tp = smb_GetSMBData(inp, NULL);
6738 pathp = smb_ParseASCIIBlock(tp, &tp);
6739 if (smb_StoreAnsiFilenames)
6740 OemToChar(pathp,pathp);
6742 if (strcmp(pathp, "\\") == 0)
6743 return CM_ERROR_EXISTS;
6745 spacep = inp->spacep;
6746 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6748 userp = smb_GetUserFromVCP(vcp, inp);
6750 caseFold = CM_FLAG_CASEFOLD;
6752 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6754 cm_ReleaseUser(userp);
6755 return CM_ERROR_NOSUCHPATH;
6758 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6759 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6760 userp, tidPathp, &req, &dscp);
6763 cm_ReleaseUser(userp);
6768 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6769 cm_ReleaseSCache(dscp);
6770 cm_ReleaseUser(userp);
6771 if ( WANTS_DFS_PATHNAMES(inp) )
6772 return CM_ERROR_PATH_NOT_COVERED;
6774 return CM_ERROR_BADSHARENAME;
6776 #endif /* DFS_SUPPORT */
6778 /* otherwise, scp points to the parent directory. Do a lookup, and
6779 * fail if we find it. Otherwise, we do the create.
6785 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6786 if (scp) cm_ReleaseSCache(scp);
6787 if (code != CM_ERROR_NOSUCHFILE) {
6788 if (code == 0) code = CM_ERROR_EXISTS;
6789 cm_ReleaseSCache(dscp);
6790 cm_ReleaseUser(userp);
6794 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6795 setAttr.clientModTime = time(NULL);
6796 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6797 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6798 smb_NotifyChange(FILE_ACTION_ADDED,
6799 FILE_NOTIFY_CHANGE_DIR_NAME,
6800 dscp, lastNamep, NULL, TRUE);
6802 /* we don't need this any longer */
6803 cm_ReleaseSCache(dscp);
6806 /* something went wrong creating or truncating the file */
6807 cm_ReleaseUser(userp);
6811 /* otherwise we succeeded */
6812 smb_SetSMBDataLength(outp, 0);
6813 cm_ReleaseUser(userp);
6818 BOOL smb_IsLegalFilename(char *filename)
6821 * Find the longest substring of filename that does not contain
6822 * any of the chars in illegalChars. If that substring is less
6823 * than the length of the whole string, then one or more of the
6824 * illegal chars is in filename.
6826 if (strcspn(filename, illegalChars) < strlen(filename))
6832 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6840 cm_scache_t *dscp; /* dir we're dealing with */
6841 cm_scache_t *scp; /* file we're creating */
6843 int initialModeBits;
6855 excl = (inp->inCom == 0x03)? 0 : 1;
6857 attributes = smb_GetSMBParm(inp, 0);
6858 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6860 /* compute initial mode bits based on read-only flag in attributes */
6861 initialModeBits = 0666;
6862 if (attributes & 1) initialModeBits &= ~0222;
6864 tp = smb_GetSMBData(inp, NULL);
6865 pathp = smb_ParseASCIIBlock(tp, &tp);
6866 if (smb_StoreAnsiFilenames)
6867 OemToChar(pathp,pathp);
6869 spacep = inp->spacep;
6870 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6872 userp = smb_GetUserFromVCP(vcp, inp);
6874 caseFold = CM_FLAG_CASEFOLD;
6876 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6878 cm_ReleaseUser(userp);
6879 return CM_ERROR_NOSUCHPATH;
6881 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6882 userp, tidPathp, &req, &dscp);
6885 cm_ReleaseUser(userp);
6890 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6891 cm_ReleaseSCache(dscp);
6892 cm_ReleaseUser(userp);
6893 if ( WANTS_DFS_PATHNAMES(inp) )
6894 return CM_ERROR_PATH_NOT_COVERED;
6896 return CM_ERROR_BADSHARENAME;
6898 #endif /* DFS_SUPPORT */
6900 /* otherwise, scp points to the parent directory. Do a lookup, and
6901 * truncate the file if we find it, otherwise we create the file.
6908 if (!smb_IsLegalFilename(lastNamep))
6909 return CM_ERROR_BADNTFILENAME;
6911 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6912 #ifdef DEBUG_VERBOSE
6915 hexp = osi_HexifyString( lastNamep );
6916 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6921 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6922 if (code && code != CM_ERROR_NOSUCHFILE) {
6923 cm_ReleaseSCache(dscp);
6924 cm_ReleaseUser(userp);
6928 /* if we get here, if code is 0, the file exists and is represented by
6929 * scp. Otherwise, we have to create it.
6933 /* oops, file shouldn't be there */
6934 cm_ReleaseSCache(dscp);
6935 cm_ReleaseSCache(scp);
6936 cm_ReleaseUser(userp);
6937 return CM_ERROR_EXISTS;
6940 setAttr.mask = CM_ATTRMASK_LENGTH;
6941 setAttr.length.LowPart = 0;
6942 setAttr.length.HighPart = 0;
6943 code = cm_SetAttr(scp, &setAttr, userp, &req);
6946 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6947 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6948 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6950 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6951 smb_NotifyChange(FILE_ACTION_ADDED,
6952 FILE_NOTIFY_CHANGE_FILE_NAME,
6953 dscp, lastNamep, NULL, TRUE);
6954 if (!excl && code == CM_ERROR_EXISTS) {
6955 /* not an exclusive create, and someone else tried
6956 * creating it already, then we open it anyway. We
6957 * don't bother retrying after this, since if this next
6958 * fails, that means that the file was deleted after
6959 * we started this call.
6961 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6964 setAttr.mask = CM_ATTRMASK_LENGTH;
6965 setAttr.length.LowPart = 0;
6966 setAttr.length.HighPart = 0;
6967 code = cm_SetAttr(scp, &setAttr, userp, &req);
6972 /* we don't need this any longer */
6973 cm_ReleaseSCache(dscp);
6976 /* something went wrong creating or truncating the file */
6977 if (scp) cm_ReleaseSCache(scp);
6978 cm_ReleaseUser(userp);
6982 /* make sure we only open files */
6983 if (scp->fileType != CM_SCACHETYPE_FILE) {
6984 cm_ReleaseSCache(scp);
6985 cm_ReleaseUser(userp);
6986 return CM_ERROR_ISDIR;
6989 /* now all we have to do is open the file itself */
6990 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6995 lock_ObtainMutex(&fidp->mx);
6996 /* always create it open for read/write */
6997 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6999 /* save a pointer to the vnode */
7002 fidp->userp = userp;
7003 lock_ReleaseMutex(&fidp->mx);
7005 smb_SetSMBParm(outp, 0, fidp->fid);
7006 smb_SetSMBDataLength(outp, 0);
7008 cm_Open(scp, 0, userp);
7010 smb_ReleaseFID(fidp);
7011 cm_ReleaseUser(userp);
7012 /* leave scp held since we put it in fidp->scp */
7016 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7029 fd = smb_GetSMBParm(inp, 0);
7030 whence = smb_GetSMBParm(inp, 1);
7031 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7033 /* try to find the file descriptor */
7034 fd = smb_ChainFID(fd, inp);
7035 fidp = smb_FindFID(vcp, fd, 0);
7038 return CM_ERROR_BADFD;
7040 lock_ObtainMutex(&fidp->mx);
7041 if (fidp->flags & SMB_FID_IOCTL) {
7042 lock_ReleaseMutex(&fidp->mx);
7043 smb_ReleaseFID(fidp);
7044 return CM_ERROR_BADFD;
7046 lock_ReleaseMutex(&fidp->mx);
7048 userp = smb_GetUserFromVCP(vcp, inp);
7050 lock_ObtainMutex(&fidp->mx);
7052 lock_ObtainMutex(&scp->mx);
7053 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7054 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7057 /* offset from current offset */
7058 offset += fidp->offset;
7060 else if (whence == 2) {
7061 /* offset from current EOF */
7062 offset += scp->length.LowPart;
7064 fidp->offset = offset;
7065 smb_SetSMBParm(outp, 0, offset & 0xffff);
7066 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
7067 smb_SetSMBDataLength(outp, 0);
7069 lock_ReleaseMutex(&scp->mx);
7070 lock_ReleaseMutex(&fidp->mx);
7071 smb_ReleaseFID(fidp);
7072 cm_ReleaseUser(userp);
7076 /* dispatch all of the requests received in a packet. Due to chaining, this may
7077 * be more than one request.
7079 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7080 NCB *ncbp, raw_write_cont_t *rwcp)
7084 unsigned long code = 0;
7085 unsigned char *outWctp;
7086 int nparms; /* # of bytes of parameters */
7088 int nbytes; /* bytes of data, excluding count */
7091 unsigned short errCode;
7092 unsigned long NTStatus;
7094 unsigned char errClass;
7095 unsigned int oldGen;
7096 DWORD oldTime, newTime;
7098 /* get easy pointer to the data */
7099 smbp = (smb_t *) inp->data;
7101 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7102 /* setup the basic parms for the initial request in the packet */
7103 inp->inCom = smbp->com;
7104 inp->wctp = &smbp->wct;
7106 inp->ncb_length = ncbp->ncb_length;
7111 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7112 /* log it and discard it */
7114 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7115 __FILE__, __LINE__, ncbp->ncb_length);
7117 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7121 /* We are an ongoing op */
7122 thrd_Increment(&ongoingOps);
7124 /* set up response packet for receiving output */
7125 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7126 smb_FormatResponsePacket(vcp, inp, outp);
7127 outWctp = outp->wctp;
7129 /* Remember session generation number and time */
7130 oldGen = sessionGen;
7131 oldTime = GetTickCount();
7133 while (inp->inCom != 0xff) {
7134 dp = &smb_dispatchTable[inp->inCom];
7136 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7137 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7138 code = outp->resumeCode;
7142 /* process each request in the packet; inCom, wctp and inCount
7143 * are already set up.
7145 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7148 /* now do the dispatch */
7149 /* start by formatting the response record a little, as a default */
7150 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7152 outWctp[1] = 0xff; /* no operation */
7153 outWctp[2] = 0; /* padding */
7158 /* not a chained request, this is a more reasonable default */
7159 outWctp[0] = 0; /* wct of zero */
7160 outWctp[1] = 0; /* and bcc (word) of zero */
7164 /* once set, stays set. Doesn't matter, since we never chain
7165 * "no response" calls.
7167 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7171 /* we have a recognized operation */
7173 if (inp->inCom == 0x1d)
7175 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7177 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7178 code = (*(dp->procp)) (vcp, inp, outp);
7179 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7181 if ( code == CM_ERROR_BADSMB ||
7182 code == CM_ERROR_BADOP )
7184 #endif /* LOG_PACKET */
7187 if (oldGen != sessionGen) {
7188 newTime = GetTickCount();
7190 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7191 newTime - oldTime, ncbp->ncb_length);
7193 osi_Log2(smb_logp, "Pkt straddled session startup, "
7194 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7198 /* bad opcode, fail the request, after displaying it */
7199 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7202 #endif /* LOG_PACKET */
7206 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7207 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7208 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7209 if (code == IDCANCEL)
7213 code = CM_ERROR_BADOP;
7216 /* catastrophic failure: log as much as possible */
7217 if (code == CM_ERROR_BADSMB) {
7219 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7224 #endif /* LOG_PACKET */
7225 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7228 code = CM_ERROR_INVAL;
7231 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7232 thrd_Decrement(&ongoingOps);
7237 /* now, if we failed, turn the current response into an empty
7238 * one, and fill in the response packet's error code.
7241 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7242 smb_MapNTError(code, &NTStatus);
7243 outWctp = outp->wctp;
7244 smbp = (smb_t *) &outp->data;
7245 if (code != CM_ERROR_PARTIALWRITE
7246 && code != CM_ERROR_BUFFERTOOSMALL
7247 && code != CM_ERROR_GSSCONTINUE) {
7248 /* nuke wct and bcc. For a partial
7249 * write or an in-process authentication handshake,
7250 * assume they're OK.
7256 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7257 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7258 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7259 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7260 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7264 smb_MapCoreError(code, vcp, &errCode, &errClass);
7265 outWctp = outp->wctp;
7266 smbp = (smb_t *) &outp->data;
7267 if (code != CM_ERROR_PARTIALWRITE) {
7268 /* nuke wct and bcc. For a partial
7269 * write, assume they're OK.
7275 smbp->errLow = (unsigned char) (errCode & 0xff);
7276 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7277 smbp->rcls = errClass;
7280 } /* error occurred */
7282 /* if we're here, we've finished one request. Look to see if
7283 * this is a chained opcode. If it is, setup things to process
7284 * the chained request, and setup the output buffer to hold the
7285 * chained response. Start by finding the next input record.
7287 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7288 break; /* not a chained req */
7289 tp = inp->wctp; /* points to start of last request */
7290 /* in a chained request, the first two
7291 * parm fields are required, and are
7292 * AndXCommand/AndXReserved and
7294 if (tp[0] < 2) break;
7295 if (tp[1] == 0xff) break; /* no more chained opcodes */
7297 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7300 /* and now append the next output request to the end of this
7301 * last request. Begin by finding out where the last response
7302 * ends, since that's where we'll put our new response.
7304 outWctp = outp->wctp; /* ptr to out parameters */
7305 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7306 nparms = outWctp[0] << 1;
7307 tp = outWctp + nparms + 1; /* now points to bcc field */
7308 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7309 tp += 2 /* for the count itself */ + nbytes;
7310 /* tp now points to the new output record; go back and patch the
7311 * second parameter (off2) to point to the new record.
7313 temp = (unsigned int)(tp - outp->data);
7314 outWctp[3] = (unsigned char) (temp & 0xff);
7315 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7316 outWctp[2] = 0; /* padding */
7317 outWctp[1] = inp->inCom; /* next opcode */
7319 /* finally, setup for the next iteration */
7322 } /* while loop over all requests in the packet */
7324 /* now send the output packet, and return */
7326 smb_SendPacket(vcp, outp);
7327 thrd_Decrement(&ongoingOps);
7329 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7330 if (active_vcp != vcp) {
7333 "Replacing active_vcp %x with %x", active_vcp, vcp);
7334 smb_ReleaseVC(active_vcp);
7337 lock_ObtainWrite(&smb_globalLock);
7339 lock_ReleaseWrite(&smb_globalLock);
7341 last_msg_time = GetTickCount();
7342 } else if (active_vcp == vcp) { /* the vcp is dead */
7343 smb_ReleaseVC(active_vcp);
7344 lock_ObtainWrite(&smb_globalLock);
7346 lock_ReleaseWrite(&smb_globalLock);
7352 /* Wait for Netbios() calls to return, and make the results available to server
7353 * threads. Note that server threads can't wait on the NCBevents array
7354 * themselves, because NCB events are manual-reset, and the servers would race
7355 * each other to reset them.
7357 void smb_ClientWaiter(void *parmp)
7362 while (smbShutdownFlag == 0) {
7363 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7365 if (code == WAIT_OBJECT_0)
7368 /* error checking */
7369 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7371 int abandonIdx = code - WAIT_ABANDONED_0;
7372 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7375 if (code == WAIT_IO_COMPLETION)
7377 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7381 if (code == WAIT_TIMEOUT)
7383 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7386 if (code == WAIT_FAILED)
7388 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7391 idx = code - WAIT_OBJECT_0;
7393 /* check idx range! */
7394 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7396 /* this is fatal - log as much as possible */
7397 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7401 thrd_ResetEvent(NCBevents[idx]);
7402 thrd_SetEvent(NCBreturns[0][idx]);
7408 * Try to have one NCBRECV request waiting for every live session. Not more
7409 * than one, because if there is more than one, it's hard to handle Write Raw.
7411 void smb_ServerWaiter(void *parmp)
7414 int idx_session, idx_NCB;
7420 while (smbShutdownFlag == 0) {
7422 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7424 if (code == WAIT_OBJECT_0)
7427 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7429 int abandonIdx = code - WAIT_ABANDONED_0;
7430 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7433 if (code == WAIT_IO_COMPLETION)
7435 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7439 if (code == WAIT_TIMEOUT)
7441 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7444 if (code == WAIT_FAILED)
7446 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7449 idx_session = code - WAIT_OBJECT_0;
7451 /* check idx range! */
7452 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7454 /* this is fatal - log as much as possible */
7455 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7461 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7463 if (code == WAIT_OBJECT_0) {
7464 if (smbShutdownFlag == 1)
7470 /* error checking */
7471 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7473 int abandonIdx = code - WAIT_ABANDONED_0;
7474 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7477 if (code == WAIT_IO_COMPLETION)
7479 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7483 if (code == WAIT_TIMEOUT)
7485 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7488 if (code == WAIT_FAILED)
7490 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7493 idx_NCB = code - WAIT_OBJECT_0;
7495 /* check idx range! */
7496 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7498 /* this is fatal - log as much as possible */
7499 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7503 /* Link them together */
7504 NCBsessions[idx_NCB] = idx_session;
7507 ncbp = NCBs[idx_NCB];
7508 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7509 ncbp->ncb_command = NCBRECV | ASYNCH;
7510 ncbp->ncb_lana_num = lanas[idx_session];
7512 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7513 ncbp->ncb_event = NCBevents[idx_NCB];
7514 ncbp->ncb_length = SMB_PACKETSIZE;
7517 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7518 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7519 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7520 ncbp->ncb_length = SMB_PACKETSIZE;
7521 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7522 Netbios(ncbp, dos_ncb);
7528 * The top level loop for handling SMB request messages. Each server thread
7529 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7530 * NCB and buffer for the incoming request are loaned to us.
7532 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7533 * to immediately send a request for the rest of the data. This must come
7534 * before any other traffic for that session, so we delay setting the session
7535 * event until that data has come in.
7537 void smb_Server(VOID *parmp)
7539 INT_PTR myIdx = (INT_PTR) parmp;
7543 smb_packet_t *outbufp;
7545 int idx_NCB, idx_session;
7547 smb_vc_t *vcp = NULL;
7553 rx_StartClientThread();
7556 outbufp = GetPacket();
7557 outbufp->ncbp = outncbp;
7564 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7567 /* terminate silently if shutdown flag is set */
7568 if (code == WAIT_OBJECT_0) {
7569 if (smbShutdownFlag == 1) {
7570 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7576 /* error checking */
7577 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7579 int abandonIdx = code - WAIT_ABANDONED_0;
7580 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7583 if (code == WAIT_IO_COMPLETION)
7585 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7589 if (code == WAIT_TIMEOUT)
7591 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7594 if (code == WAIT_FAILED)
7596 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7599 idx_NCB = code - WAIT_OBJECT_0;
7601 /* check idx range! */
7602 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7604 /* this is fatal - log as much as possible */
7605 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7609 ncbp = NCBs[idx_NCB];
7611 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7613 idx_session = NCBsessions[idx_NCB];
7614 rc = ncbp->ncb_retcode;
7616 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7617 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7621 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7625 /* Can this happen? Or is it just my UNIX paranoia? */
7626 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7632 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7636 /* Client closed session */
7637 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7639 lock_ObtainMutex(&vcp->mx);
7640 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7641 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7643 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7644 lock_ReleaseMutex(&vcp->mx);
7645 lock_ObtainWrite(&smb_globalLock);
7646 dead_sessions[vcp->session] = TRUE;
7647 lock_ReleaseWrite(&smb_globalLock);
7648 smb_CleanupDeadVC(vcp);
7652 lock_ReleaseMutex(&vcp->mx);
7658 /* Treat as transient error */
7660 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7664 "dispatch smb recv failed, message incomplete, ncb_length %d",
7667 "SMB message incomplete, "
7668 "length %d", ncbp->ncb_length);
7671 * We used to discard the packet.
7672 * Instead, try handling it normally.
7676 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7680 /* A weird error code. Log it, sleep, and continue. */
7681 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7683 lock_ObtainMutex(&vcp->mx);
7684 if (vcp && vcp->errorCount++ > 3) {
7685 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7686 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7687 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7689 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7690 lock_ReleaseMutex(&vcp->mx);
7691 lock_ObtainWrite(&smb_globalLock);
7692 dead_sessions[vcp->session] = TRUE;
7693 lock_ReleaseWrite(&smb_globalLock);
7694 smb_CleanupDeadVC(vcp);
7698 lock_ReleaseMutex(&vcp->mx);
7704 lock_ReleaseMutex(&vcp->mx);
7706 thrd_SetEvent(SessionEvents[idx_session]);
7711 /* Success, so now dispatch on all the data in the packet */
7713 smb_concurrentCalls++;
7714 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7715 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7718 * If at this point vcp is NULL (implies that packet was invalid)
7719 * then we are in big trouble. This means either :
7720 * a) we have the wrong NCB.
7721 * b) Netbios screwed up the call.
7722 * Obviously this implies that
7723 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7724 * lanas[idx_session] != ncbp->ncb_lana_num )
7725 * Either way, we can't do anything with this packet.
7726 * Log, sleep and resume.
7729 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7733 ncbp->ncb_lana_num);
7735 /* Also log in the trace log. */
7736 osi_Log4(smb_logp, "Server: BAD VCP!"
7737 "LSNs[idx_session]=[%d],"
7738 "lanas[idx_session]=[%d],"
7739 "ncbp->ncb_lsn=[%d],"
7740 "ncbp->ncb_lana_num=[%d]",
7744 ncbp->ncb_lana_num);
7746 /* thrd_Sleep(1000); Don't bother sleeping */
7747 thrd_SetEvent(SessionEvents[idx_session]);
7748 smb_concurrentCalls--;
7752 vcp->errorCount = 0;
7753 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7755 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7756 /* copy whole packet to virtual memory */
7757 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7759 bufp->dos_pkt / 16, bufp);*/
7761 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7763 smbp = (smb_t *)bufp->data;
7766 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7770 if (smbp->com == 0x1d) {
7771 /* Special handling for Write Raw */
7772 raw_write_cont_t rwc;
7773 EVENT_HANDLE rwevent;
7774 char eventName[MAX_PATH];
7776 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7777 if (rwc.code == 0) {
7778 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7779 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7780 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7781 ncbp->ncb_command = NCBRECV | ASYNCH;
7782 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7783 ncbp->ncb_lana_num = vcp->lana;
7784 ncbp->ncb_buffer = rwc.buf;
7785 ncbp->ncb_length = 65535;
7786 ncbp->ncb_event = rwevent;
7790 Netbios(ncbp, dos_ncb);
7792 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7793 thrd_CloseHandle(rwevent);
7795 thrd_SetEvent(SessionEvents[idx_session]);
7797 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7799 else if (smbp->com == 0xa0) {
7801 * Serialize the handling for NT Transact
7804 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7805 thrd_SetEvent(SessionEvents[idx_session]);
7807 thrd_SetEvent(SessionEvents[idx_session]);
7808 /* TODO: what else needs to be serialized? */
7809 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7811 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7813 __except( smb_ServerExceptionFilter() ) {
7817 smb_concurrentCalls--;
7820 thrd_SetEvent(NCBavails[idx_NCB]);
7827 * Exception filter for the server threads. If an exception occurs in the
7828 * dispatch routines, which is where exceptions are most common, then do a
7829 * force trace and give control to upstream exception handlers. Useful for
7832 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7833 DWORD smb_ServerExceptionFilter(void) {
7834 /* While this is not the best time to do a trace, if it succeeds, then
7835 * we have a trace (assuming tracing was enabled). Otherwise, this should
7836 * throw a second exception.
7838 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7839 afsd_ForceTrace(TRUE);
7840 buf_ForceTrace(TRUE);
7841 return EXCEPTION_CONTINUE_SEARCH;
7846 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7847 * If the number of server threads is M, and the number of live sessions is
7848 * N, then the number of NCB's in use at any time either waiting for, or
7849 * holding, received messages is M + N, so that is how many NCB's get created.
7851 void InitNCBslot(int idx)
7853 struct smb_packet *bufp;
7854 EVENT_HANDLE retHandle;
7856 char eventName[MAX_PATH];
7858 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7860 NCBs[idx] = GetNCB();
7861 sprintf(eventName,"NCBavails[%d]", idx);
7862 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7863 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7864 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7866 sprintf(eventName,"NCBevents[%d]", idx);
7867 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7868 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7869 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7871 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7872 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7873 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7874 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7875 for (i=0; i<smb_NumServerThreads; i++)
7876 NCBreturns[i][idx] = retHandle;
7878 bufp->spacep = cm_GetSpace();
7882 /* listen for new connections */
7883 void smb_Listener(void *parmp)
7889 int session, thread;
7890 smb_vc_t *vcp = NULL;
7892 char rname[NCBNAMSZ+1];
7893 char cname[MAX_COMPUTERNAME_LENGTH+1];
7894 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7899 INT_PTR lana = (INT_PTR) parmp;
7903 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7906 /* retrieve computer name */
7907 GetComputerName(cname, &cnamelen);
7911 memset(ncbp, 0, sizeof(NCB));
7914 ncbp->ncb_command = NCBLISTEN;
7915 ncbp->ncb_rto = 0; /* No receive timeout */
7916 ncbp->ncb_sto = 0; /* No send timeout */
7918 /* pad out with spaces instead of null termination */
7919 len = (long)strlen(smb_localNamep);
7920 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7921 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7923 strcpy(ncbp->ncb_callname, "*");
7924 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7926 ncbp->ncb_lana_num = (UCHAR)lana;
7929 code = Netbios(ncbp);
7931 code = Netbios(ncbp, dos_ncb);
7940 /* terminate silently if shutdown flag is set */
7941 if (smbShutdownFlag == 1) {
7950 "NCBLISTEN lana=%d failed with code %d",
7951 ncbp->ncb_lana_num, code);
7953 "Client exiting due to network failure. Please restart client.\n");
7957 "Client exiting due to network failure. Please restart client.\n"
7958 "NCBLISTEN lana=%d failed with code %d",
7959 ncbp->ncb_lana_num, code);
7961 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7962 MB_OK|MB_SERVICE_NOTIFICATION);
7963 osi_assert(tbuffer);
7966 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7967 ncbp->ncb_lana_num, code);
7968 fprintf(stderr, "\nClient exiting due to network failure "
7969 "(possibly due to power-saving mode)\n");
7970 fprintf(stderr, "Please restart client.\n");
7971 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7975 /* check for remote conns */
7976 /* first get remote name and insert null terminator */
7977 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7978 for (i=NCBNAMSZ; i>0; i--) {
7979 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7985 /* compare with local name */
7987 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7988 flags |= SMB_VCFLAG_REMOTECONN;
7991 lock_ObtainMutex(&smb_ListenerLock);
7993 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7994 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
7996 /* now ncbp->ncb_lsn is the connection ID */
7997 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7998 if (vcp->session == 0) {
7999 /* New generation */
8000 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8003 /* Log session startup */
8005 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8006 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8007 #endif /* NOTSERVICE */
8008 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8009 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8011 if (reportSessionStartups) {
8013 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8016 fprintf(stderr, "%s: New session %d starting from host %s\n",
8017 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8022 lock_ObtainMutex(&vcp->mx);
8023 strcpy(vcp->rname, rname);
8024 vcp->flags |= flags;
8025 lock_ReleaseMutex(&vcp->mx);
8027 /* Allocate slot in session arrays */
8028 /* Re-use dead session if possible, otherwise add one more */
8029 /* But don't look at session[0], it is reserved */
8030 lock_ObtainWrite(&smb_globalLock);
8031 for (session = 1; session < numSessions; session++) {
8032 if (dead_sessions[session]) {
8033 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8034 dead_sessions[session] = FALSE;
8038 lock_ReleaseWrite(&smb_globalLock);
8040 /* We are re-using an existing VC because the lsn and lana
8042 session = vcp->session;
8044 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8046 /* Log session startup */
8048 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8049 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8050 #endif /* NOTSERVICE */
8051 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8052 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8054 if (reportSessionStartups) {
8056 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8059 fprintf(stderr, "%s: Re-using session %d starting from host %s\n",
8060 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8066 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8067 unsigned long code = CM_ERROR_ALLBUSY;
8068 smb_packet_t * outp = GetPacket();
8069 unsigned char *outWctp;
8072 smb_FormatResponsePacket(vcp, NULL, outp);
8075 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8076 unsigned long NTStatus;
8077 smb_MapNTError(code, &NTStatus);
8078 outWctp = outp->wctp;
8079 smbp = (smb_t *) &outp->data;
8083 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8084 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8085 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8086 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8087 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8089 unsigned short errCode;
8090 unsigned char errClass;
8091 smb_MapCoreError(code, vcp, &errCode, &errClass);
8092 outWctp = outp->wctp;
8093 smbp = (smb_t *) &outp->data;
8097 smbp->errLow = (unsigned char) (errCode & 0xff);
8098 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8099 smbp->rcls = errClass;
8101 smb_SendPacket(vcp, outp);
8102 smb_FreePacket(outp);
8104 lock_ObtainMutex(&vcp->mx);
8105 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8106 lock_ReleaseMutex(&vcp->mx);
8107 smb_CleanupDeadVC(vcp);
8109 /* assert that we do not exceed the maximum number of sessions or NCBs.
8110 * we should probably want to wait for a session to be freed in case
8113 osi_assert(session < SESSION_MAX - 1);
8114 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8116 lock_ObtainMutex(&vcp->mx);
8117 vcp->session = session;
8118 lock_ReleaseMutex(&vcp->mx);
8119 lock_ObtainWrite(&smb_globalLock);
8120 LSNs[session] = ncbp->ncb_lsn;
8121 lanas[session] = ncbp->ncb_lana_num;
8122 lock_ReleaseWrite(&smb_globalLock);
8124 if (session == numSessions) {
8125 /* Add new NCB for new session */
8126 char eventName[MAX_PATH];
8128 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8130 InitNCBslot(numNCBs);
8131 lock_ObtainWrite(&smb_globalLock);
8133 lock_ReleaseWrite(&smb_globalLock);
8134 thrd_SetEvent(NCBavails[0]);
8135 thrd_SetEvent(NCBevents[0]);
8136 for (thread = 0; thread < smb_NumServerThreads; thread++)
8137 thrd_SetEvent(NCBreturns[thread][0]);
8138 /* Also add new session event */
8139 sprintf(eventName, "SessionEvents[%d]", session);
8140 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8141 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8142 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8143 lock_ObtainWrite(&smb_globalLock);
8145 lock_ReleaseWrite(&smb_globalLock);
8146 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8147 thrd_SetEvent(SessionEvents[0]);
8149 thrd_SetEvent(SessionEvents[session]);
8155 lock_ReleaseMutex(&smb_ListenerLock);
8156 } /* dispatch while loop */
8159 /* initialize Netbios */
8160 void smb_NetbiosInit()
8166 int i, lana, code, l;
8168 int delname_tried=0;
8171 OSVERSIONINFO Version;
8173 /* Get the version of Windows */
8174 memset(&Version, 0x00, sizeof(Version));
8175 Version.dwOSVersionInfoSize = sizeof(Version);
8176 GetVersionEx(&Version);
8178 /* setup the NCB system */
8181 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8185 if (smb_LANadapter == -1) {
8186 ncbp->ncb_command = NCBENUM;
8187 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8188 ncbp->ncb_length = sizeof(lana_list);
8189 code = Netbios(ncbp);
8191 afsi_log("Netbios NCBENUM error code %d", code);
8192 osi_panic(s, __FILE__, __LINE__);
8196 lana_list.length = 1;
8197 lana_list.lana[0] = smb_LANadapter;
8200 for (i = 0; i < lana_list.length; i++) {
8201 /* reset the adaptor: in Win32, this is required for every process, and
8202 * acts as an init call, not as a real hardware reset.
8204 ncbp->ncb_command = NCBRESET;
8205 ncbp->ncb_callname[0] = 100;
8206 ncbp->ncb_callname[2] = 100;
8207 ncbp->ncb_lana_num = lana_list.lana[i];
8208 code = Netbios(ncbp);
8210 code = ncbp->ncb_retcode;
8212 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8213 lana_list.lana[i] = 255; /* invalid lana */
8215 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8219 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
8220 we will just fake the LANA list */
8221 if (smb_LANadapter == -1) {
8222 for (i = 0; i < 8; i++)
8223 lana_list.lana[i] = i;
8224 lana_list.length = 8;
8227 lana_list.length = 1;
8228 lana_list.lana[0] = smb_LANadapter;
8232 /* and declare our name so we can receive connections */
8233 memset(ncbp, 0, sizeof(*ncbp));
8234 len=lstrlen(smb_localNamep);
8235 memset(smb_sharename,' ',NCBNAMSZ);
8236 memcpy(smb_sharename,smb_localNamep,len);
8237 afsi_log("lana_list.length %d", lana_list.length);
8239 /* Keep the name so we can unregister it later */
8240 for (l = 0; l < lana_list.length; l++) {
8241 lana = lana_list.lana[l];
8243 ncbp->ncb_command = NCBADDNAME;
8244 ncbp->ncb_lana_num = lana;
8245 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8247 code = Netbios(ncbp);
8249 code = Netbios(ncbp, dos_ncb);
8252 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8253 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8255 char name[NCBNAMSZ+1];
8257 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8258 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8261 if (code == 0) code = ncbp->ncb_retcode;
8263 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8265 /* we only use one LANA with djgpp */
8266 lana_list.lana[0] = lana;
8267 lana_list.length = 1;
8271 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8272 if (code == NRC_BRIDGE) { /* invalid LANA num */
8273 lana_list.lana[l] = 255;
8276 else if (code == NRC_DUPNAME) {
8277 afsi_log("Name already exists; try to delete it");
8278 memset(ncbp, 0, sizeof(*ncbp));
8279 ncbp->ncb_command = NCBDELNAME;
8280 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8281 ncbp->ncb_lana_num = lana;
8283 code = Netbios(ncbp);
8285 code = Netbios(ncbp, dos_ncb);
8288 code = ncbp->ncb_retcode;
8290 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8292 if (code != 0 || delname_tried) {
8293 lana_list.lana[l] = 255;
8295 else if (code == 0) {
8296 if (!delname_tried) {
8304 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8305 lana_list.lana[l] = 255; /* invalid lana */
8306 osi_panic(s, __FILE__, __LINE__);
8310 lana_found = 1; /* at least one worked */
8317 osi_assert(lana_list.length >= 0);
8319 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8322 /* we're done with the NCB now */
8326 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8343 EVENT_HANDLE retHandle;
8344 char eventName[MAX_PATH];
8347 smb_MBfunc = aMBfunc;
8351 smb_LANadapter = LANadapt;
8353 /* Initialize smb_localZero */
8354 myTime.tm_isdst = -1; /* compute whether on DST or not */
8355 myTime.tm_year = 70;
8361 smb_localZero = mktime(&myTime);
8363 #ifndef USE_NUMERIC_TIME_CONV
8364 /* Initialize kludge-GMT */
8365 smb_CalculateNowTZ();
8366 #endif /* USE_NUMERIC_TIME_CONV */
8367 #ifdef AFS_FREELANCE_CLIENT
8368 /* Make sure the root.afs volume has the correct time */
8369 cm_noteLocalMountPointChange();
8372 /* initialize the remote debugging log */
8375 /* remember the name */
8376 len = (int)strlen(snamep);
8377 smb_localNamep = malloc(len+1);
8378 strcpy(smb_localNamep, snamep);
8379 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8381 /* and the global lock */
8382 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8383 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8385 /* Raw I/O data structures */
8386 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8388 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8390 /* 4 Raw I/O buffers */
8392 smb_RawBufs = calloc(65536,1);
8393 *((char **)smb_RawBufs) = NULL;
8394 for (i=0; i<3; i++) {
8395 char *rawBuf = calloc(65536,1);
8396 *((char **)rawBuf) = smb_RawBufs;
8397 smb_RawBufs = rawBuf;
8400 npar = 65536 >> 4; /* number of paragraphs */
8401 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8403 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8405 osi_panic("",__FILE__,__LINE__);
8408 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8411 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8413 _farpokel(_dos_ds, smb_RawBufs, NULL);
8414 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8415 npar = 65536 >> 4; /* number of paragraphs */
8416 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8418 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8420 osi_panic("",__FILE__,__LINE__);
8423 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8426 rawBuf = (seg * 16) + 0; /* DOS physical address */
8427 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8428 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8429 smb_RawBufs = rawBuf;
8433 /* global free lists */
8434 smb_ncbFreeListp = NULL;
8435 smb_packetFreeListp = NULL;
8439 /* Initialize listener and server structures */
8441 memset(dead_sessions, 0, sizeof(dead_sessions));
8442 sprintf(eventName, "SessionEvents[0]");
8443 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8444 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8445 afsi_log("Event Object Already Exists: %s", eventName);
8447 smb_NumServerThreads = nThreads;
8448 sprintf(eventName, "NCBavails[0]");
8449 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8450 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8451 afsi_log("Event Object Already Exists: %s", eventName);
8452 sprintf(eventName, "NCBevents[0]");
8453 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8454 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8455 afsi_log("Event Object Already Exists: %s", eventName);
8456 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8457 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8458 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8459 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8460 afsi_log("Event Object Already Exists: %s", eventName);
8461 for (i = 0; i < smb_NumServerThreads; i++) {
8462 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8463 NCBreturns[i][0] = retHandle;
8466 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8467 for (i = 0; i < smb_NumServerThreads; i++) {
8468 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8469 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8470 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8471 afsi_log("Event Object Already Exists: %s", eventName);
8472 InitNCBslot((int)(i+1));
8474 numNCBs = smb_NumServerThreads + 1;
8476 /* Initialize dispatch table */
8477 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8478 /* Prepare the table for unknown operations */
8479 for(i=0; i<= SMB_NOPCODES; i++) {
8480 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8482 /* Fill in the ones we do know */
8483 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8484 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8485 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8486 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8487 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8488 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8489 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8490 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8491 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8492 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8493 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8494 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8495 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8496 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8497 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8498 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8499 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8500 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8501 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8502 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8503 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8504 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8505 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8506 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8507 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8508 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8509 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8510 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8511 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8512 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8513 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8514 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8515 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8516 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8517 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8518 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8519 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8520 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8521 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8522 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8523 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8524 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8525 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8526 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8527 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8528 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8529 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8530 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8531 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8532 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8533 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8534 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8535 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8536 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8537 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8538 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8539 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8540 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8541 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8542 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8543 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8544 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8545 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8546 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8547 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8548 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8549 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8550 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8551 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8552 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8553 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8554 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8556 /* setup tran 2 dispatch table */
8557 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8558 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8559 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8560 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8561 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8562 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8563 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8564 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8565 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8566 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8567 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8568 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8569 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8570 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8571 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8572 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8573 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8575 /* setup the rap dispatch table */
8576 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8577 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8578 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8579 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8580 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8584 /* if we are doing SMB authentication we have register outselves as a logon process */
8585 if (smb_authType != SMB_AUTH_NONE) {
8586 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8587 LSA_STRING afsProcessName;
8588 LSA_OPERATIONAL_MODE dummy; /*junk*/
8590 afsProcessName.Buffer = "OpenAFSClientDaemon";
8591 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8592 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8594 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8596 if (nts == STATUS_SUCCESS) {
8597 LSA_STRING packageName;
8598 /* we are registered. Find out the security package id */
8599 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8600 packageName.Length = (USHORT)strlen(packageName.Buffer);
8601 packageName.MaximumLength = packageName.Length + 1;
8602 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8603 if (nts == STATUS_SUCCESS) {
8605 * This code forces Windows to authenticate against the Logon Cache
8606 * first instead of attempting to authenticate against the Domain
8607 * Controller. When the Windows logon cache is enabled this improves
8608 * performance by removing the network access and works around a bug
8609 * seen at sites which are using a MIT Kerberos principal to login
8610 * to machines joined to a non-root domain in a multi-domain forest.
8612 PVOID pResponse = NULL;
8613 ULONG cbResponse = 0;
8614 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8616 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8617 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8618 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8619 OptionsRequest.DisableOptions = FALSE;
8621 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8624 sizeof(OptionsRequest),
8630 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8632 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8634 OutputDebugString(message);
8637 OutputDebugString("MsV1_0SetProcessOption success");
8638 afsi_log("MsV1_0SetProcessOption success");
8640 /* END - code from Larry */
8642 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8643 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8644 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8646 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8648 /* something went wrong. We report the error and revert back to no authentication
8649 because we can't perform any auth requests without a successful lsa handle
8650 or sec package id. */
8651 afsi_log("Reverting to NO SMB AUTH");
8652 smb_authType = SMB_AUTH_NONE;
8655 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8657 /* something went wrong. We report the error and revert back to no authentication
8658 because we can't perform any auth requests without a successful lsa handle
8659 or sec package id. */
8660 afsi_log("Reverting to NO SMB AUTH");
8661 smb_authType = SMB_AUTH_NONE;
8665 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8666 * time prevents the failure of authentication when logged into Windows with an
8667 * external Kerberos principal mapped to a local account.
8669 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8670 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8671 * then the only option is NTLMSSP anyway; so just fallback.
8676 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8677 if (secBlobLength == 0) {
8678 smb_authType = SMB_AUTH_NTLM;
8679 afsi_log("Reverting to SMB AUTH NTLM");
8688 /* Now get ourselves a domain name. */
8689 /* For now we are using the local computer name as the domain name.
8690 * It is actually the domain for local logins, and we are acting as
8691 * a local SMB server.
8693 bufsize = sizeof(smb_ServerDomainName) - 1;
8694 GetComputerName(smb_ServerDomainName, &bufsize);
8695 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8696 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8699 /* Start listeners, waiters, servers, and daemons */
8701 for (i = 0; i < lana_list.length; i++) {
8702 if (lana_list.lana[i] == 255)
8704 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8705 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8706 osi_assert(phandle != NULL);
8707 thrd_CloseHandle(phandle);
8711 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8712 NULL, 0, &lpid, "smb_ClientWaiter");
8713 osi_assert(phandle != NULL);
8714 thrd_CloseHandle(phandle);
8717 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8718 NULL, 0, &lpid, "smb_ServerWaiter");
8719 osi_assert(phandle != NULL);
8720 thrd_CloseHandle(phandle);
8722 for (i=0; i<smb_NumServerThreads; i++) {
8723 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8724 (void *) i, 0, &lpid, "smb_Server");
8725 osi_assert(phandle != NULL);
8726 thrd_CloseHandle(phandle);
8729 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8730 NULL, 0, &lpid, "smb_Daemon");
8731 osi_assert(phandle != NULL);
8732 thrd_CloseHandle(phandle);
8734 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8735 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8736 osi_assert(phandle != NULL);
8737 thrd_CloseHandle(phandle);
8746 void smb_Shutdown(void)
8756 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8758 /* setup the NCB system */
8761 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8764 /* Block new sessions by setting shutdown flag */
8765 smbShutdownFlag = 1;
8767 /* Hang up all sessions */
8768 memset((char *)ncbp, 0, sizeof(NCB));
8769 for (i = 1; i < numSessions; i++)
8771 if (dead_sessions[i])
8774 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8775 ncbp->ncb_command = NCBHANGUP;
8776 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8777 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8779 code = Netbios(ncbp);
8781 code = Netbios(ncbp, dos_ncb);
8783 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8784 if (code == 0) code = ncbp->ncb_retcode;
8786 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8787 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8791 /* Trigger the shutdown of all SMB threads */
8792 for (i = 0; i < smb_NumServerThreads; i++)
8793 thrd_SetEvent(NCBreturns[i][0]);
8795 thrd_SetEvent(NCBevents[0]);
8796 thrd_SetEvent(SessionEvents[0]);
8797 thrd_SetEvent(NCBavails[0]);
8799 for (i = 0;i < smb_NumServerThreads; i++) {
8800 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8801 if (code == WAIT_OBJECT_0) {
8804 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8805 thrd_SetEvent(NCBreturns[i--][0]);
8809 /* Delete Netbios name */
8810 memset((char *)ncbp, 0, sizeof(NCB));
8811 for (i = 0; i < lana_list.length; i++) {
8812 if (lana_list.lana[i] == 255) continue;
8813 ncbp->ncb_command = NCBDELNAME;
8814 ncbp->ncb_lana_num = lana_list.lana[i];
8815 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8817 code = Netbios(ncbp);
8819 code = Netbios(ncbp, dos_ncb);
8822 code = ncbp->ncb_retcode;
8824 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8825 ncbp->ncb_lana_num, code);
8830 /* Release the reference counts held by the VCs */
8831 lock_ObtainWrite(&smb_rctLock);
8832 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8837 if (vcp->magic != SMB_VC_MAGIC)
8838 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8839 __FILE__, __LINE__);
8841 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8843 if (fidp->scp != NULL) {
8846 lock_ObtainMutex(&fidp->mx);
8847 if (fidp->scp != NULL) {
8850 cm_ReleaseSCache(scp);
8852 lock_ReleaseMutex(&fidp->mx);
8856 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8858 smb_ReleaseVCNoLock(tidp->vcp);
8860 cm_user_t *userp = tidp->userp;
8862 lock_ReleaseWrite(&smb_rctLock);
8863 cm_ReleaseUser(userp);
8864 lock_ObtainWrite(&smb_rctLock);
8868 lock_ReleaseWrite(&smb_rctLock);
8871 /* Get the UNC \\<servername>\<sharename> prefix. */
8872 char *smb_GetSharename()
8876 /* Make sure we have been properly initialized. */
8877 if (smb_localNamep == NULL)
8880 /* Allocate space for \\<servername>\<sharename>, plus the
8883 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8884 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8890 void smb_LogPacket(smb_packet_t *packet)
8893 unsigned length, paramlen, datalen, i, j;
8895 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8897 if (!packet) return;
8899 osi_Log0(smb_logp, "*** SMB packet dump ***");
8901 vp = (BYTE *) packet->data;
8903 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8904 length = paramlen + 2 + datalen;
8907 for (i=0;i < length; i+=16)
8909 memset( buf, ' ', 80 );
8914 buf[strlen(buf)] = ' ';
8916 cp = (BYTE*) buf + 7;
8918 for (j=0;j < 16 && (i+j)<length; j++)
8920 *(cp++) = hex[vp[i+j] >> 4];
8921 *(cp++) = hex[vp[i+j] & 0xf];
8931 for (j=0;j < 16 && (i+j)<length;j++)
8933 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8944 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
8947 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8949 #endif /* LOG_PACKET */
8952 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8960 lock_ObtainRead(&smb_rctLock);
8962 sprintf(output, "begin dumping smb_vc_t\n");
8963 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8965 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8969 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8970 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8971 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8973 sprintf(output, "begin dumping smb_fid_t\n");
8974 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8976 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8978 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",
8979 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8980 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8981 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8982 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8985 sprintf(output, "done dumping smb_fid_t\n");
8986 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8989 sprintf(output, "done dumping smb_vc_t\n");
8990 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8992 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8993 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8995 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8999 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9000 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9001 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9003 sprintf(output, "begin dumping smb_fid_t\n");
9004 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9006 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9008 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",
9009 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9010 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9011 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9012 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9015 sprintf(output, "done dumping smb_fid_t\n");
9016 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9019 sprintf(output, "done dumping DEAD smb_vc_t\n");
9020 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9022 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9023 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9025 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9029 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9030 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9031 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9033 sprintf(output, "begin dumping smb_fid_t\n");
9034 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9036 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9038 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",
9039 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9040 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9041 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9042 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9045 sprintf(output, "done dumping smb_fid_t\n");
9046 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9049 sprintf(output, "done dumping DEAD smb_vc_t\n");
9050 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9053 lock_ReleaseRead(&smb_rctLock);