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>
30 #include <rx/rx_prototypes.h>
31 #include <WINNT\afsreg.h>
34 #include "lanahelper.h"
36 /* These characters are illegal in Windows filenames */
37 static char *illegalChars = "\\/:*?\"<>|";
38 BOOL isWindows2000 = FALSE;
40 int smbShutdownFlag = 0;
42 int smb_LogoffTokenTransfer;
43 time_t smb_LogoffTransferTimeout;
45 int smb_StoreAnsiFilenames = 0;
47 DWORD last_msg_time = 0;
51 unsigned int sessionGen = 0;
53 extern void afsi_log(char *pattern, ...);
54 extern HANDLE afsi_file;
56 osi_hyper_t hzero = {0, 0};
57 osi_hyper_t hones = {0xFFFFFFFF, -1};
60 osi_rwlock_t smb_globalLock;
61 osi_rwlock_t smb_rctLock;
62 osi_mutex_t smb_ListenerLock;
65 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
68 long smb_maxObsConcurrentCalls=0;
69 long smb_concurrentCalls=0;
71 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
73 smb_packet_t *smb_packetFreeListp;
74 smb_ncb_t *smb_ncbFreeListp;
76 int smb_NumServerThreads;
78 int numNCBs, numSessions, numVCs;
80 int smb_maxVCPerServer;
81 int smb_maxMpxRequests;
83 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
85 ULONG smb_lsaSecPackage;
86 LSA_STRING smb_lsaLogonOrigin;
88 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
89 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
90 EVENT_HANDLE **NCBreturns;
91 EVENT_HANDLE **NCBShutdown;
92 EVENT_HANDLE *smb_ServerShutdown;
93 DWORD NCBsessions[NCB_MAX];
95 struct smb_packet *bufs[NCB_MAX];
97 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
98 EVENT_HANDLE SessionEvents[SESSION_MAX];
99 unsigned short LSNs[SESSION_MAX];
100 int lanas[SESSION_MAX];
101 BOOL dead_sessions[SESSION_MAX];
105 osi_mutex_t smb_RawBufLock;
107 #define SMB_RAW_BUFS 4
109 int smb_RawBufSel[SMB_RAW_BUFS];
114 #define SMB_MASKFLAG_TILDE 1
115 #define SMB_MASKFLAG_CASEFOLD 2
117 #define RAWTIMEOUT INFINITE
120 typedef struct raw_write_cont {
133 /* dir search stuff */
134 long smb_dirSearchCounter = 1;
135 smb_dirSearch_t *smb_firstDirSearchp;
136 smb_dirSearch_t *smb_lastDirSearchp;
138 /* hide dot files? */
139 int smb_hideDotFiles;
141 /* global state about V3 protocols */
142 int smb_useV3; /* try to negotiate V3 */
145 static showErrors = 1;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
151 * Time in Unix format of midnight, 1/1/1970 local time.
152 * When added to dosUTime, gives Unix (AFS) time.
154 time_t smb_localZero = 0;
156 #define USE_NUMERIC_TIME_CONV 1
158 #ifndef USE_NUMERIC_TIME_CONV
159 /* Time difference for converting to kludge-GMT */
160 afs_uint32 smb_NowTZ;
161 #endif /* USE_NUMERIC_TIME_CONV */
163 char *smb_localNamep = NULL;
165 smb_vc_t *smb_allVCsp;
166 smb_vc_t *smb_deadVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLockRequest_t *smb_allWaitingLocks;
172 DWORD smb_TlsRequestSlot = -1;
175 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
176 NCB *ncbp, raw_write_cont_t *rwcp);
177 void smb_NetbiosInit();
179 #ifndef AFS_WIN95_ENV
180 DWORD smb_ServerExceptionFilter(void);
183 extern char cm_HostName[];
184 extern char cm_confDir[];
188 #define LPTSTR char *
189 #define GetComputerName(str, sizep) \
190 strcpy((str), cm_HostName); \
191 *(sizep) = strlen(cm_HostName)
195 void smb_LogPacket(smb_packet_t *packet);
196 #endif /* LOG_PACKET */
198 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
199 int smb_ServerDomainNameLength = 0;
200 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
201 int smb_ServerOSLength = sizeof(smb_ServerOS);
202 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
203 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
205 /* Faux server GUID. This is never checked. */
206 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
208 void smb_ResetServerPriority()
210 void * p = TlsGetValue(smb_TlsRequestSlot);
213 TlsSetValue(smb_TlsRequestSlot, NULL);
214 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
218 void smb_SetRequestStartTime()
220 time_t * tp = malloc(sizeof(time_t));
224 if (!TlsSetValue(smb_TlsRequestSlot, tp))
229 void smb_UpdateServerPriority()
231 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
234 time_t now = osi_Time();
236 /* Give one priority boost for each 15 seconds */
237 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
242 const char * ncb_error_string(int code)
246 case 0x01: s = "llegal buffer length"; break;
247 case 0x03: s = "illegal command"; break;
248 case 0x05: s = "command timed out"; break;
249 case 0x06: s = "message incomplete, issue another command"; break;
250 case 0x07: s = "illegal buffer address"; break;
251 case 0x08: s = "session number out of range"; break;
252 case 0x09: s = "no resource available"; break;
253 case 0x0a: s = "session closed"; break;
254 case 0x0b: s = "command cancelled"; break;
255 case 0x0d: s = "duplicate name"; break;
256 case 0x0e: s = "name table full"; break;
257 case 0x0f: s = "no deletions, name has active sessions"; break;
258 case 0x11: s = "local session table full"; break;
259 case 0x12: s = "remote session table full"; break;
260 case 0x13: s = "illegal name number"; break;
261 case 0x14: s = "no callname"; break;
262 case 0x15: s = "cannot put * in NCB_NAME"; break;
263 case 0x16: s = "name in use on remote adapter"; break;
264 case 0x17: s = "name deleted"; break;
265 case 0x18: s = "session ended abnormally"; break;
266 case 0x19: s = "name conflict detected"; break;
267 case 0x21: s = "interface busy, IRET before retrying"; break;
268 case 0x22: s = "too many commands outstanding, retry later";break;
269 case 0x23: s = "ncb_lana_num field invalid"; break;
270 case 0x24: s = "command completed while cancel occurring "; break;
271 case 0x26: s = "command not valid to cancel"; break;
272 case 0x30: s = "name defined by anther local process"; break;
273 case 0x34: s = "environment undefined. RESET required"; break;
274 case 0x35: s = "required OS resources exhausted"; break;
275 case 0x36: s = "max number of applications exceeded"; break;
276 case 0x37: s = "no saps available for netbios"; break;
277 case 0x38: s = "requested resources are not available"; break;
278 case 0x39: s = "invalid ncb address or length > segment"; break;
279 case 0x3B: s = "invalid NCB DDID"; break;
280 case 0x3C: s = "lock of user area failed"; break;
281 case 0x3f: s = "NETBIOS not loaded"; break;
282 case 0x40: s = "system error"; break;
283 default: s = "unknown error";
289 char * myCrt_Dispatch(int i)
294 return "(00)ReceiveCoreMakeDir";
296 return "(01)ReceiveCoreRemoveDir";
298 return "(02)ReceiveCoreOpen";
300 return "(03)ReceiveCoreCreate";
302 return "(04)ReceiveCoreClose";
304 return "(05)ReceiveCoreFlush";
306 return "(06)ReceiveCoreUnlink";
308 return "(07)ReceiveCoreRename";
310 return "(08)ReceiveCoreGetFileAttributes";
312 return "(09)ReceiveCoreSetFileAttributes";
314 return "(0a)ReceiveCoreRead";
316 return "(0b)ReceiveCoreWrite";
318 return "(0c)ReceiveCoreLockRecord";
320 return "(0d)ReceiveCoreUnlockRecord";
322 return "(0e)SendCoreBadOp";
324 return "(0f)ReceiveCoreCreate";
326 return "(10)ReceiveCoreCheckPath";
328 return "(11)SendCoreBadOp";
330 return "(12)ReceiveCoreSeek";
332 return "(1a)ReceiveCoreReadRaw";
334 return "(1d)ReceiveCoreWriteRawDummy";
336 return "(22)ReceiveV3SetAttributes";
338 return "(23)ReceiveV3GetAttributes";
340 return "(24)ReceiveV3LockingX";
342 return "(25)ReceiveV3Trans";
344 return "(26)ReceiveV3Trans[aux]";
346 return "(29)SendCoreBadOp";
348 return "(2b)ReceiveCoreEcho";
350 return "(2d)ReceiveV3OpenX";
352 return "(2e)ReceiveV3ReadX";
354 return "(2f)ReceiveV3WriteX";
356 return "(32)ReceiveV3Tran2A";
358 return "(33)ReceiveV3Tran2A[aux]";
360 return "(34)ReceiveV3FindClose";
362 return "(35)ReceiveV3FindNotifyClose";
364 return "(70)ReceiveCoreTreeConnect";
366 return "(71)ReceiveCoreTreeDisconnect";
368 return "(72)ReceiveNegotiate";
370 return "(73)ReceiveV3SessionSetupX";
372 return "(74)ReceiveV3UserLogoffX";
374 return "(75)ReceiveV3TreeConnectX";
376 return "(80)ReceiveCoreGetDiskAttributes";
378 return "(81)ReceiveCoreSearchDir";
382 return "(83)FindUnique";
384 return "(84)FindClose";
386 return "(A0)ReceiveNTTransact";
388 return "(A2)ReceiveNTCreateX";
390 return "(A4)ReceiveNTCancel";
392 return "(A5)ReceiveNTRename";
394 return "(C0)OpenPrintFile";
396 return "(C1)WritePrintFile";
398 return "(C2)ClosePrintFile";
400 return "(C3)GetPrintQueue";
402 return "(D8)ReadBulk";
404 return "(D9)WriteBulk";
406 return "(DA)WriteBulkData";
408 return "unknown SMB op";
412 char * myCrt_2Dispatch(int i)
417 return "unknown SMB op-2";
419 return "S(00)CreateFile";
421 return "S(01)FindFirst";
423 return "S(02)FindNext"; /* FindNext */
425 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
429 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
431 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
433 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
435 return "S(08)??_ReceiveTran2SetFileInfo";
437 return "S(09)??_ReceiveTran2FSCTL";
439 return "S(0a)_ReceiveTran2IOCTL";
441 return "S(0b)_ReceiveTran2FindNotifyFirst";
443 return "S(0c)_ReceiveTran2FindNotifyNext";
445 return "S(0d)_ReceiveTran2CreateDirectory";
447 return "S(0e)_ReceiveTran2SessionSetup";
449 return "S(10)_ReceiveTran2GetDfsReferral";
451 return "S(11)_ReceiveTran2ReportDfsInconsistency";
455 char * myCrt_RapDispatch(int i)
460 return "unknown RAP OP";
462 return "RAP(0)NetShareEnum";
464 return "RAP(1)NetShareGetInfo";
466 return "RAP(13)NetServerGetInfo";
468 return "RAP(63)NetWkStaGetInfo";
472 /* scache must be locked */
473 unsigned int smb_Attributes(cm_scache_t *scp)
477 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
478 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
479 scp->fileType == CM_SCACHETYPE_INVALID)
481 attrs = SMB_ATTR_DIRECTORY;
482 #ifdef SPECIAL_FOLDERS
483 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
484 #endif /* SPECIAL_FOLDERS */
485 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
486 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
491 * We used to mark a file RO if it was in an RO volume, but that
492 * turns out to be impolitic in NT. See defect 10007.
495 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
496 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
498 if ((scp->unixModeBits & 0222) == 0)
499 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
505 /* Check if the named file/dir is a dotfile/dotdir */
506 /* String pointed to by lastComp can have leading slashes, but otherwise should have
507 no other patch components */
508 unsigned int smb_IsDotFile(char *lastComp) {
511 /* skip over slashes */
512 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
517 /* nulls, curdir and parent dir doesn't count */
523 if(*(s+1) == '.' && !*(s + 2))
530 static int ExtractBits(WORD bits, short start, short len)
537 num = bits << (16 - end);
538 num = num >> ((16 - end) + start);
544 void ShowUnixTime(char *FuncName, time_t unixTime)
549 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
551 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
552 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
554 int day, month, year, sec, min, hour;
557 day = ExtractBits(wDate, 0, 5);
558 month = ExtractBits(wDate, 5, 4);
559 year = ExtractBits(wDate, 9, 7) + 1980;
561 sec = ExtractBits(wTime, 0, 5);
562 min = ExtractBits(wTime, 5, 6);
563 hour = ExtractBits(wTime, 11, 5);
565 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
566 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
572 /* Determine if we are observing daylight savings time */
573 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
575 TIME_ZONE_INFORMATION timeZoneInformation;
576 SYSTEMTIME utc, local, localDST;
578 /* Get the time zone info. NT uses this to calc if we are in DST. */
579 GetTimeZoneInformation(&timeZoneInformation);
581 /* Return the daylight bias */
582 *pDstBias = timeZoneInformation.DaylightBias;
584 /* Return the bias */
585 *pBias = timeZoneInformation.Bias;
587 /* Now determine if DST is being observed */
589 /* Get the UTC (GMT) time */
592 /* Convert UTC time to local time using the time zone info. If we are
593 observing DST, the calculated local time will include this.
595 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
597 /* Set the daylight bias to 0. The daylight bias is the amount of change
598 * in time that we use for daylight savings time. By setting this to 0
599 * we cause there to be no change in time during daylight savings time.
601 timeZoneInformation.DaylightBias = 0;
603 /* Convert the utc time to local time again, but this time without any
604 adjustment for daylight savings time.
606 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
608 /* If the two times are different, then it means that the localDST that
609 we calculated includes the daylight bias, and therefore we are
610 observing daylight savings time.
612 *pDST = localDST.wHour != local.wHour;
615 /* Determine if we are observing daylight savings time */
616 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
622 *pDstBias = -60; /* where can this be different? */
628 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
630 BOOL dst; /* Will be TRUE if observing DST */
631 LONG dstBias; /* Offset from local time if observing DST */
632 LONG bias; /* Offset from GMT for local time */
635 * This function will adjust the last write time to compensate
636 * for two bugs in the smb client:
638 * 1) During Daylight Savings Time, the LastWriteTime is ahead
639 * in time by the DaylightBias (ignoring the sign - the
640 * DaylightBias is always stored as a negative number). If
641 * the DaylightBias is -60, then the LastWriteTime will be
642 * ahead by 60 minutes.
644 * 2) If the local time zone is a positive offset from GMT, then
645 * the LastWriteTime will be the correct local time plus the
646 * Bias (ignoring the sign - a positive offset from GMT is
647 * always stored as a negative Bias). If the Bias is -120,
648 * then the LastWriteTime will be ahead by 120 minutes.
650 * These bugs can occur at the same time.
653 GetTimeZoneInfo(&dst, &dstBias, &bias);
655 /* First adjust for DST */
657 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
659 /* Now adjust for a positive offset from GMT (a negative bias). */
661 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
664 #ifndef USE_NUMERIC_TIME_CONV
666 * Calculate the difference (in seconds) between local time and GMT.
667 * This enables us to convert file times to kludge-GMT.
673 struct tm gmt_tm, local_tm;
674 int days, hours, minutes, seconds;
677 gmt_tm = *(gmtime(&t));
678 local_tm = *(localtime(&t));
680 days = local_tm.tm_yday - gmt_tm.tm_yday;
681 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
682 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
683 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
687 #endif /* USE_NUMERIC_TIME_CONV */
690 #ifdef USE_NUMERIC_TIME_CONV
691 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
693 // Note that LONGLONG is a 64-bit value
696 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
697 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
698 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
701 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
706 time_t ersatz_unixTime;
709 * Must use kludge-GMT instead of real GMT.
710 * kludge-GMT is computed by adding time zone difference to localtime.
713 * ltp = gmtime(&unixTime);
715 ersatz_unixTime = unixTime - smb_NowTZ;
716 ltp = localtime(&ersatz_unixTime);
718 /* if we fail, make up something */
721 localJunk.tm_year = 89 - 20;
722 localJunk.tm_mon = 4;
723 localJunk.tm_mday = 12;
724 localJunk.tm_hour = 0;
725 localJunk.tm_min = 0;
726 localJunk.tm_sec = 0;
729 stm.wYear = ltp->tm_year + 1900;
730 stm.wMonth = ltp->tm_mon + 1;
731 stm.wDayOfWeek = ltp->tm_wday;
732 stm.wDay = ltp->tm_mday;
733 stm.wHour = ltp->tm_hour;
734 stm.wMinute = ltp->tm_min;
735 stm.wSecond = ltp->tm_sec;
736 stm.wMilliseconds = 0;
738 SystemTimeToFileTime(&stm, largeTimep);
740 #endif /* USE_NUMERIC_TIME_CONV */
742 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
744 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
745 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
746 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
748 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
750 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
751 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
753 *ft = LargeIntegerMultiplyByLong(*ft, 60);
754 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
757 ut = ConvertLongToLargeInteger(unixTime);
758 ut = LargeIntegerMultiplyByLong(ut, 10000000);
759 *ft = LargeIntegerAdd(*ft, ut);
764 #ifdef USE_NUMERIC_TIME_CONV
765 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
767 // Note that LONGLONG is a 64-bit value
770 ll = largeTimep->dwHighDateTime;
772 ll += largeTimep->dwLowDateTime;
774 ll -= 116444736000000000;
777 *unixTimep = (DWORD)ll;
779 #else /* USE_NUMERIC_TIME_CONV */
780 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
786 FileTimeToSystemTime(largeTimep, &stm);
788 lt.tm_year = stm.wYear - 1900;
789 lt.tm_mon = stm.wMonth - 1;
790 lt.tm_wday = stm.wDayOfWeek;
791 lt.tm_mday = stm.wDay;
792 lt.tm_hour = stm.wHour;
793 lt.tm_min = stm.wMinute;
794 lt.tm_sec = stm.wSecond;
797 save_timezone = _timezone;
798 _timezone += smb_NowTZ;
799 *unixTimep = mktime(<);
800 _timezone = save_timezone;
802 #endif /* USE_NUMERIC_TIME_CONV */
804 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
806 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
807 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
808 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
812 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
813 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
814 a = LargeIntegerMultiplyByLong(a, 60);
815 a = LargeIntegerMultiplyByLong(a, 10000000);
817 /* subtract it from ft */
818 a = LargeIntegerSubtract(*ft, a);
820 /* divide down to seconds */
821 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
825 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
835 /* if we fail, make up something */
838 localJunk.tm_year = 89 - 20;
839 localJunk.tm_mon = 4;
840 localJunk.tm_mday = 12;
841 localJunk.tm_hour = 0;
842 localJunk.tm_min = 0;
843 localJunk.tm_sec = 0;
846 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
847 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
848 *searchTimep = (dosDate<<16) | dosTime;
851 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
853 unsigned short dosDate;
854 unsigned short dosTime;
857 dosDate = (unsigned short) (searchTime & 0xffff);
858 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
860 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
861 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
862 localTm.tm_mday = (dosDate) & 0x1f;
863 localTm.tm_hour = (dosTime>>11) & 0x1f;
864 localTm.tm_min = (dosTime >> 5) & 0x3f;
865 localTm.tm_sec = (dosTime & 0x1f) * 2;
866 localTm.tm_isdst = -1; /* compute whether DST in effect */
868 *unixTimep = mktime(&localTm);
871 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
873 time_t diff_t = unixTime - smb_localZero;
874 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
875 osi_assert(diff_t < _UI32_MAX);
877 *dosUTimep = (afs_uint32)diff_t;
880 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
883 *unixTimep = dosTime + smb_localZero;
885 /* dosTime seems to be already adjusted for GMT */
886 *unixTimep = dosTime;
890 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
894 lock_ObtainWrite(&smb_rctLock);
895 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
896 if (vcp->magic != SMB_VC_MAGIC)
897 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
900 if (lsn == vcp->lsn && lana == vcp->lana &&
901 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
902 smb_HoldVCNoLock(vcp);
906 if (!vcp && (flags & SMB_FLAG_CREATE)) {
907 vcp = malloc(sizeof(*vcp));
908 memset(vcp, 0, sizeof(*vcp));
909 lock_ObtainWrite(&smb_globalLock);
910 vcp->vcID = ++numVCs;
911 lock_ReleaseWrite(&smb_globalLock);
912 vcp->magic = SMB_VC_MAGIC;
913 vcp->refCount = 2; /* smb_allVCsp and caller */
916 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
917 vcp->nextp = smb_allVCsp;
919 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
924 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
925 /* We must obtain a challenge for extended auth
926 * in case the client negotiates smb v3
928 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
929 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
930 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
931 ULONG lsaRespSize = 0;
933 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
935 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
942 if (nts != STATUS_SUCCESS)
943 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
944 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
945 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
947 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
948 LsaFreeReturnBuffer(lsaResp);
951 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
953 if (numVCs >= CM_SESSION_RESERVED) {
954 lock_ObtainWrite(&smb_globalLock);
956 lock_ReleaseWrite(&smb_globalLock);
957 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
960 lock_ReleaseWrite(&smb_rctLock);
964 int smb_IsStarMask(char *maskp)
969 for(i=0; i<11; i++) {
971 if (tc == '?' || tc == '*' || tc == '>')
977 void smb_ReleaseVCInternal(smb_vc_t *vcp)
984 if (vcp->refCount == 0) {
985 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
986 /* remove VCP from smb_deadVCsp */
987 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
993 lock_FinalizeMutex(&vcp->mx);
994 memset(vcp,0,sizeof(smb_vc_t));
997 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
1001 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
1002 avcp?"not ":"",vcp, vcp->refCount);
1004 GenerateMiniDump(NULL);
1006 /* This is a wrong. However, I suspect that there is an undercount
1007 * and I don't want to release 1.4.1 in a state that will allow
1008 * smb_vc_t objects to be deallocated while still in the
1009 * smb_allVCsp list. The list is supposed to keep a reference
1010 * to the smb_vc_t. Put it back.
1017 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1019 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1020 smb_ReleaseVCInternal(vcp);
1023 void smb_ReleaseVC(smb_vc_t *vcp)
1025 lock_ObtainWrite(&smb_rctLock);
1026 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1027 smb_ReleaseVCInternal(vcp);
1028 lock_ReleaseWrite(&smb_rctLock);
1031 void smb_HoldVCNoLock(smb_vc_t *vcp)
1034 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1037 void smb_HoldVC(smb_vc_t *vcp)
1039 lock_ObtainWrite(&smb_rctLock);
1041 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1042 lock_ReleaseWrite(&smb_rctLock);
1045 void smb_CleanupDeadVC(smb_vc_t *vcp)
1047 smb_fid_t *fidpIter;
1048 smb_fid_t *fidpNext;
1050 smb_tid_t *tidpIter;
1051 smb_tid_t *tidpNext;
1053 smb_user_t *uidpIter;
1054 smb_user_t *uidpNext;
1058 lock_ObtainMutex(&vcp->mx);
1059 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1060 lock_ReleaseMutex(&vcp->mx);
1061 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1064 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1065 lock_ReleaseMutex(&vcp->mx);
1066 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1068 lock_ObtainWrite(&smb_rctLock);
1069 /* remove VCP from smb_allVCsp */
1070 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1071 if ((*vcpp)->magic != SMB_VC_MAGIC)
1072 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1073 __FILE__, __LINE__);
1076 vcp->nextp = smb_deadVCsp;
1078 /* Hold onto the reference until we are done with this function */
1083 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1084 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1086 if (fidpIter->delete)
1089 fid = fidpIter->fid;
1090 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1092 smb_HoldFIDNoLock(fidpIter);
1093 lock_ReleaseWrite(&smb_rctLock);
1095 smb_CloseFID(vcp, fidpIter, NULL, 0);
1096 smb_ReleaseFID(fidpIter);
1098 lock_ObtainWrite(&smb_rctLock);
1099 fidpNext = vcp->fidsp;
1102 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1103 tidpNext = tidpIter->nextp;
1104 if (tidpIter->delete)
1106 tidpIter->delete = 1;
1108 tid = tidpIter->tid;
1109 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1111 smb_HoldTIDNoLock(tidpIter);
1112 lock_ReleaseWrite(&smb_rctLock);
1114 smb_ReleaseTID(tidpIter);
1116 lock_ObtainWrite(&smb_rctLock);
1117 tidpNext = vcp->tidsp;
1120 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1121 uidpNext = uidpIter->nextp;
1122 if (uidpIter->delete)
1124 uidpIter->delete = 1;
1126 /* do not add an additional reference count for the smb_user_t
1127 * as the smb_vc_t already is holding a reference */
1128 lock_ReleaseWrite(&smb_rctLock);
1130 smb_ReleaseUID(uidpIter);
1132 lock_ObtainWrite(&smb_rctLock);
1133 uidpNext = vcp->usersp;
1136 /* The vcp is now on the deadVCsp list. We intentionally drop the
1137 * reference so that the refcount can reach 0 and we can delete it */
1138 smb_ReleaseVCNoLock(vcp);
1140 lock_ReleaseWrite(&smb_rctLock);
1141 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1144 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1148 lock_ObtainWrite(&smb_rctLock);
1149 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1150 if (tid == tidp->tid) {
1155 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1156 tidp = malloc(sizeof(*tidp));
1157 memset(tidp, 0, sizeof(*tidp));
1158 tidp->nextp = vcp->tidsp;
1161 smb_HoldVCNoLock(vcp);
1163 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1166 lock_ReleaseWrite(&smb_rctLock);
1170 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1175 void smb_ReleaseTID(smb_tid_t *tidp)
1182 lock_ObtainWrite(&smb_rctLock);
1183 osi_assert(tidp->refCount-- > 0);
1184 if (tidp->refCount == 0 && (tidp->delete)) {
1185 ltpp = &tidp->vcp->tidsp;
1186 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1190 osi_assert(tp != NULL);
1192 lock_FinalizeMutex(&tidp->mx);
1193 userp = tidp->userp; /* remember to drop ref later */
1195 smb_ReleaseVCNoLock(tidp->vcp);
1198 lock_ReleaseWrite(&smb_rctLock);
1200 cm_ReleaseUser(userp);
1203 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1205 smb_user_t *uidp = NULL;
1207 lock_ObtainWrite(&smb_rctLock);
1208 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1209 if (uid == uidp->userID) {
1211 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1213 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1217 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1218 uidp = malloc(sizeof(*uidp));
1219 memset(uidp, 0, sizeof(*uidp));
1220 uidp->nextp = vcp->usersp;
1221 uidp->refCount = 2; /* one for the vcp and one for the caller */
1223 smb_HoldVCNoLock(vcp);
1225 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1227 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1229 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1231 lock_ReleaseWrite(&smb_rctLock);
1235 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1237 smb_username_t *unp= NULL;
1239 lock_ObtainWrite(&smb_rctLock);
1240 for(unp = usernamesp; unp; unp = unp->nextp) {
1241 if (stricmp(unp->name, usern) == 0 &&
1242 stricmp(unp->machine, machine) == 0) {
1247 if (!unp && (flags & SMB_FLAG_CREATE)) {
1248 unp = malloc(sizeof(*unp));
1249 memset(unp, 0, sizeof(*unp));
1251 unp->nextp = usernamesp;
1252 unp->name = strdup(usern);
1253 unp->machine = strdup(machine);
1255 lock_InitializeMutex(&unp->mx, "username_t mutex");
1256 if (flags & SMB_FLAG_AFSLOGON)
1257 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1260 lock_ReleaseWrite(&smb_rctLock);
1264 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1266 smb_user_t *uidp= NULL;
1268 lock_ObtainWrite(&smb_rctLock);
1269 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1272 if (stricmp(uidp->unp->name, usern) == 0) {
1274 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1275 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1280 lock_ReleaseWrite(&smb_rctLock);
1284 void smb_ReleaseUsername(smb_username_t *unp)
1287 smb_username_t **lupp;
1288 cm_user_t *userp = NULL;
1289 time_t now = osi_Time();
1291 lock_ObtainWrite(&smb_rctLock);
1292 osi_assert(unp->refCount-- > 0);
1293 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1294 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1296 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1300 osi_assert(up != NULL);
1302 up->nextp = NULL; /* do not remove this */
1303 lock_FinalizeMutex(&unp->mx);
1309 lock_ReleaseWrite(&smb_rctLock);
1312 cm_ReleaseUser(userp);
1316 void smb_HoldUIDNoLock(smb_user_t *uidp)
1321 void smb_ReleaseUID(smb_user_t *uidp)
1325 smb_username_t *unp = NULL;
1327 lock_ObtainWrite(&smb_rctLock);
1328 osi_assert(uidp->refCount-- > 0);
1329 if (uidp->refCount == 0) {
1330 lupp = &uidp->vcp->usersp;
1331 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1335 osi_assert(up != NULL);
1337 lock_FinalizeMutex(&uidp->mx);
1339 smb_ReleaseVCNoLock(uidp->vcp);
1343 lock_ReleaseWrite(&smb_rctLock);
1347 cm_ReleaseUserVCRef(unp->userp);
1348 smb_ReleaseUsername(unp);
1352 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1354 cm_user_t *up = NULL;
1359 lock_ObtainMutex(&uidp->mx);
1361 up = uidp->unp->userp;
1364 lock_ReleaseMutex(&uidp->mx);
1370 /* retrieve a held reference to a user structure corresponding to an incoming
1372 * corresponding release function is cm_ReleaseUser.
1374 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1377 cm_user_t *up = NULL;
1380 smbp = (smb_t *) inp;
1381 uidp = smb_FindUID(vcp, smbp->uid, 0);
1385 up = smb_GetUserFromUID(uidp);
1387 smb_ReleaseUID(uidp);
1392 * Return a pointer to a pathname extracted from a TID structure. The
1393 * TID structure is not held; assume it won't go away.
1395 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1400 tidp = smb_FindTID(vcp, tid, 0);
1404 if (tidp->flags & SMB_TIDFLAG_IPC) {
1405 code = CM_ERROR_TIDIPC;
1406 /* tidp->pathname would be NULL, but that's fine */
1408 *treepath = tidp->pathname;
1409 smb_ReleaseTID(tidp);
1414 /* check to see if we have a chained fid, that is, a fid that comes from an
1415 * OpenAndX message that ran earlier in this packet. In this case, the fid
1416 * field in a read, for example, request, isn't set, since the value is
1417 * supposed to be inherited from the openAndX call.
1419 int smb_ChainFID(int fid, smb_packet_t *inp)
1421 if (inp->fid == 0 || inp->inCount == 0)
1427 /* are we a priv'd user? What does this mean on NT? */
1428 int smb_SUser(cm_user_t *userp)
1433 /* find a file ID. If we pass in 0 we select an unused File ID.
1434 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1435 * smb_fid_t data structure if desired File ID cannot be found.
1437 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1442 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1445 lock_ObtainWrite(&smb_rctLock);
1446 /* figure out if we need to allocate a new file ID */
1449 fid = vcp->fidCounter;
1453 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1454 if (fid == fidp->fid) {
1457 if (fid == 0xFFFF) {
1459 "New FID number wraps on vcp 0x%x", vcp);
1469 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1470 char eventName[MAX_PATH];
1472 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1473 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1474 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1475 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1476 thrd_CloseHandle(event);
1478 if (fid == 0xFFFF) {
1479 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1485 fidp = malloc(sizeof(*fidp));
1486 memset(fidp, 0, sizeof(*fidp));
1487 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1490 smb_HoldVCNoLock(vcp);
1491 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1493 fidp->curr_chunk = fidp->prev_chunk = -2;
1494 fidp->raw_write_event = event;
1496 vcp->fidCounter = fid+1;
1497 if (vcp->fidCounter == 0xFFFF) {
1498 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1500 vcp->fidCounter = 1;
1505 lock_ReleaseWrite(&smb_rctLock);
1509 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1514 void smb_ReleaseFID(smb_fid_t *fidp)
1516 cm_scache_t *scp = NULL;
1517 cm_user_t *userp = NULL;
1518 smb_vc_t *vcp = NULL;
1519 smb_ioctl_t *ioctlp;
1521 lock_ObtainMutex(&fidp->mx);
1522 lock_ObtainWrite(&smb_rctLock);
1523 osi_assert(fidp->refCount-- > 0);
1524 if (fidp->refCount == 0 && (fidp->delete)) {
1527 scp = fidp->scp; /* release after lock is released */
1529 userp = fidp->userp;
1533 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1534 thrd_CloseHandle(fidp->raw_write_event);
1536 /* and see if there is ioctl stuff to free */
1537 ioctlp = fidp->ioctlp;
1540 cm_FreeSpace(ioctlp->prefix);
1541 if (ioctlp->inAllocp)
1542 free(ioctlp->inAllocp);
1543 if (ioctlp->outAllocp)
1544 free(ioctlp->outAllocp);
1547 lock_ReleaseMutex(&fidp->mx);
1548 lock_FinalizeMutex(&fidp->mx);
1552 smb_ReleaseVCNoLock(vcp);
1554 lock_ReleaseMutex(&fidp->mx);
1556 lock_ReleaseWrite(&smb_rctLock);
1558 /* now release the scache structure */
1560 cm_ReleaseSCache(scp);
1563 cm_ReleaseUser(userp);
1567 * Case-insensitive search for one string in another;
1568 * used to find variable names in submount pathnames.
1570 static char *smb_stristr(char *str1, char *str2)
1574 for (cursor = str1; *cursor; cursor++)
1575 if (stricmp(cursor, str2) == 0)
1582 * Substitute a variable value for its name in a submount pathname. Variable
1583 * name has been identified by smb_stristr() and is in substr. Variable name
1584 * length (plus one) is in substr_size. Variable value is in newstr.
1586 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1591 strcpy(temp, substr + substr_size - 1);
1592 strcpy(substr, newstr);
1596 char VNUserName[] = "%USERNAME%";
1597 char VNLCUserName[] = "%LCUSERNAME%";
1598 char VNComputerName[] = "%COMPUTERNAME%";
1599 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1602 /* List available shares */
1603 int smb_ListShares()
1607 char shareBuf[4096];
1615 /*strcpy(shareNameList[num_shares], "all");
1616 strcpy(pathNameList[num_shares++], "/afs");*/
1617 fprintf(stderr, "The following shares are available:\n");
1618 fprintf(stderr, "Share Name (AFS Path)\n");
1619 fprintf(stderr, "---------------------\n");
1620 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1623 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1624 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1626 strcpy(sbmtpath, cm_confDir);
1628 strcat(sbmtpath, "/afsdsbmt.ini");
1629 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1630 shareBuf, sizeof(shareBuf),
1636 this_share = shareBuf;
1640 /*strcpy(shareNameList[num_shares], this_share);*/
1641 len = GetPrivateProfileString("AFS Submounts", this_share,
1648 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1651 if (*p == '\\') *p = '/'; /* change to / */
1655 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1656 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1659 while (*this_share != 0) this_share++; /* find next NUL */
1660 this_share++; /* skip past the NUL */
1661 } while (*this_share != 0); /* stop at final NUL */
1667 typedef struct smb_findShare_rock {
1671 } smb_findShare_rock_t;
1673 #define SMB_FINDSHARE_EXACT_MATCH 1
1674 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1676 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1680 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1681 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1682 if(!stricmp(dep->name, vrock->shareName))
1683 matchType = SMB_FINDSHARE_EXACT_MATCH;
1685 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1686 if(vrock->match) free(vrock->match);
1687 vrock->match = strdup(dep->name);
1688 vrock->matchType = matchType;
1690 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1691 return CM_ERROR_STOPNOW;
1697 /* find a shareName in the table of submounts */
1698 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1702 char pathName[1024];
1707 char sbmtpath[MAX_PATH];
1712 DWORD allSubmount = 1;
1714 /* if allSubmounts == 0, only return the //mountRoot/all share
1715 * if in fact it has been been created in the subMounts table.
1716 * This is to allow sites that want to restrict access to the
1719 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1720 0, KEY_QUERY_VALUE, &parmKey);
1721 if (code == ERROR_SUCCESS) {
1722 len = sizeof(allSubmount);
1723 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1724 (BYTE *) &allSubmount, &len);
1725 if (code != ERROR_SUCCESS) {
1728 RegCloseKey (parmKey);
1731 if (allSubmount && _stricmp(shareName, "all") == 0) {
1736 /* In case, the all share is disabled we need to still be able
1737 * to handle ioctl requests
1739 if (_stricmp(shareName, "ioctl$") == 0) {
1740 *pathNamep = strdup("/.__ioctl__");
1744 if (_stricmp(shareName, "IPC$") == 0 ||
1745 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1746 _stricmp(shareName, "DESKTOP.INI") == 0
1753 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1754 0, KEY_QUERY_VALUE, &parmKey);
1755 if (code == ERROR_SUCCESS) {
1756 len = sizeof(pathName);
1757 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1758 (BYTE *) pathName, &len);
1759 if (code != ERROR_SUCCESS)
1761 RegCloseKey (parmKey);
1766 strcpy(sbmtpath, cm_confDir);
1767 strcat(sbmtpath, "/afsdsbmt.ini");
1768 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1769 pathName, sizeof(pathName), sbmtpath);
1771 if (len != 0 && len != sizeof(pathName) - 1) {
1772 /* We can accept either unix or PC style AFS pathnames. Convert
1773 * Unix-style to PC style here for internal use.
1776 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1777 p += strlen(cm_mountRoot); /* skip mount path */
1780 if (*q == '/') *q = '\\'; /* change to \ */
1786 if (var = smb_stristr(p, VNUserName)) {
1787 if (uidp && uidp->unp)
1788 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1790 smb_subst(p, var, sizeof(VNUserName)," ");
1792 else if (var = smb_stristr(p, VNLCUserName))
1794 if (uidp && uidp->unp)
1795 strcpy(temp, uidp->unp->name);
1799 smb_subst(p, var, sizeof(VNLCUserName), temp);
1801 else if (var = smb_stristr(p, VNComputerName))
1803 sizeTemp = sizeof(temp);
1804 GetComputerName((LPTSTR)temp, &sizeTemp);
1805 smb_subst(p, var, sizeof(VNComputerName), temp);
1807 else if (var = smb_stristr(p, VNLCComputerName))
1809 sizeTemp = sizeof(temp);
1810 GetComputerName((LPTSTR)temp, &sizeTemp);
1812 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1817 *pathNamep = strdup(p);
1822 /* First lookup shareName in root.afs */
1824 smb_findShare_rock_t vrock;
1826 char * p = shareName;
1829 /* attempt to locate a partial match in root.afs. This is because
1830 when using the ANSI RAP calls, the share name is limited to 13 chars
1831 and hence is truncated. Of course we prefer exact matches. */
1833 thyper.HighPart = 0;
1836 vrock.shareName = shareName;
1838 vrock.matchType = 0;
1840 cm_HoldSCache(cm_data.rootSCachep);
1841 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1842 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1843 cm_ReleaseSCache(cm_data.rootSCachep);
1845 if (vrock.matchType) {
1846 sprintf(pathName,"/%s/",vrock.match);
1847 *pathNamep = strdup(strlwr(pathName));
1852 /* if we get here, there was no match for the share in root.afs */
1853 /* so try to create \\<netbiosName>\<cellname> */
1858 /* Get the full name for this cell */
1859 code = cm_SearchCellFile(p, temp, 0, 0);
1860 #ifdef AFS_AFSDB_ENV
1861 if (code && cm_dnsEnabled) {
1863 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1866 /* construct the path */
1868 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1869 *pathNamep = strdup(strlwr(pathName));
1878 /* Client-side offline caching policy types */
1879 #define CSC_POLICY_MANUAL 0
1880 #define CSC_POLICY_DOCUMENTS 1
1881 #define CSC_POLICY_PROGRAMS 2
1882 #define CSC_POLICY_DISABLE 3
1884 int smb_FindShareCSCPolicy(char *shareName)
1890 int retval = CSC_POLICY_MANUAL;
1892 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1893 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1896 REG_OPTION_NON_VOLATILE,
1902 len = sizeof(policy);
1903 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1905 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1907 else if (stricmp(policy, "documents") == 0)
1909 retval = CSC_POLICY_DOCUMENTS;
1911 else if (stricmp(policy, "programs") == 0)
1913 retval = CSC_POLICY_PROGRAMS;
1915 else if (stricmp(policy, "disable") == 0)
1917 retval = CSC_POLICY_DISABLE;
1920 RegCloseKey(hkCSCPolicy);
1924 /* find a dir search structure by cookie value, and return it held.
1925 * Must be called with smb_globalLock held.
1927 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1929 smb_dirSearch_t *dsp;
1931 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1932 if (dsp->cookie == cookie) {
1933 if (dsp != smb_firstDirSearchp) {
1934 /* move to head of LRU queue, too, if we're not already there */
1935 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1936 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1937 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1938 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1939 if (!smb_lastDirSearchp)
1940 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1942 lock_ObtainMutex(&dsp->mx);
1944 lock_ReleaseMutex(&dsp->mx);
1950 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1951 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1952 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1958 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1960 lock_ObtainWrite(&smb_globalLock);
1961 lock_ObtainMutex(&dsp->mx);
1962 dsp->flags |= SMB_DIRSEARCH_DELETE;
1963 if (dsp->scp != NULL) {
1964 lock_ObtainMutex(&dsp->scp->mx);
1965 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1966 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1967 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1968 dsp->scp->bulkStatProgress = hones;
1970 lock_ReleaseMutex(&dsp->scp->mx);
1972 lock_ReleaseMutex(&dsp->mx);
1973 lock_ReleaseWrite(&smb_globalLock);
1976 /* Must be called with the smb_globalLock held */
1977 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1979 cm_scache_t *scp = NULL;
1981 lock_ObtainMutex(&dsp->mx);
1982 osi_assert(dsp->refCount-- > 0);
1983 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1984 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1985 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1986 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1987 lock_ReleaseMutex(&dsp->mx);
1988 lock_FinalizeMutex(&dsp->mx);
1992 lock_ReleaseMutex(&dsp->mx);
1994 /* do this now to avoid spurious locking hierarchy creation */
1996 cm_ReleaseSCache(scp);
1999 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2001 lock_ObtainWrite(&smb_globalLock);
2002 smb_ReleaseDirSearchNoLock(dsp);
2003 lock_ReleaseWrite(&smb_globalLock);
2006 /* find a dir search structure by cookie value, and return it held */
2007 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2009 smb_dirSearch_t *dsp;
2011 lock_ObtainWrite(&smb_globalLock);
2012 dsp = smb_FindDirSearchNoLock(cookie);
2013 lock_ReleaseWrite(&smb_globalLock);
2017 /* GC some dir search entries, in the address space expected by the specific protocol.
2018 * Must be called with smb_globalLock held; release the lock temporarily.
2020 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2021 void smb_GCDirSearches(int isV3)
2023 smb_dirSearch_t *prevp;
2024 smb_dirSearch_t *tp;
2025 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2029 victimCount = 0; /* how many have we got so far */
2030 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
2031 /* we'll move tp from queue, so
2034 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
2035 /* if no one is using this guy, and we're either in the new protocol,
2036 * or we're in the old one and this is a small enough ID to be useful
2037 * to the old protocol, GC this guy.
2039 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2040 /* hold and delete */
2041 lock_ObtainMutex(&tp->mx);
2042 tp->flags |= SMB_DIRSEARCH_DELETE;
2043 lock_ReleaseMutex(&tp->mx);
2044 victimsp[victimCount++] = tp;
2048 /* don't do more than this */
2049 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2053 /* now release them */
2054 for (i = 0; i < victimCount; i++) {
2055 smb_ReleaseDirSearchNoLock(victimsp[i]);
2059 /* function for allocating a dir search entry. We need these to remember enough context
2060 * since we don't get passed the path from call to call during a directory search.
2062 * Returns a held dir search structure, and bumps the reference count on the vnode,
2063 * since it saves a pointer to the vnode.
2065 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2067 smb_dirSearch_t *dsp;
2073 lock_ObtainWrite(&smb_globalLock);
2076 /* what's the biggest ID allowed in this version of the protocol */
2077 maxAllowed = isV3 ? 65535 : 255;
2078 if (smb_dirSearchCounter > maxAllowed)
2079 smb_dirSearchCounter = 1;
2081 start = smb_dirSearchCounter;
2084 /* twice so we have enough tries to find guys we GC after one pass;
2085 * 10 extra is just in case I mis-counted.
2087 if (++counter > 2*maxAllowed+10)
2088 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2090 if (smb_dirSearchCounter > maxAllowed) {
2091 smb_dirSearchCounter = 1;
2093 if (smb_dirSearchCounter == start) {
2095 smb_GCDirSearches(isV3);
2098 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2100 /* don't need to watch for refcount zero and deleted, since
2101 * we haven't dropped the global lock.
2103 lock_ObtainMutex(&dsp->mx);
2105 lock_ReleaseMutex(&dsp->mx);
2106 ++smb_dirSearchCounter;
2110 dsp = malloc(sizeof(*dsp));
2111 memset(dsp, 0, sizeof(*dsp));
2112 dsp->cookie = smb_dirSearchCounter;
2113 ++smb_dirSearchCounter;
2115 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2116 dsp->lastTime = osi_Time();
2117 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2118 if (!smb_lastDirSearchp)
2119 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2122 lock_ReleaseWrite(&smb_globalLock);
2126 static smb_packet_t *GetPacket(void)
2130 unsigned int npar, seg, tb_sel;
2133 lock_ObtainWrite(&smb_globalLock);
2134 tbp = smb_packetFreeListp;
2136 smb_packetFreeListp = tbp->nextp;
2137 lock_ReleaseWrite(&smb_globalLock);
2140 tbp = calloc(65540,1);
2142 tbp = malloc(sizeof(smb_packet_t));
2144 tbp->magic = SMB_PACKETMAGIC;
2147 tbp->resumeCode = 0;
2153 tbp->ncb_length = 0;
2158 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
2161 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2163 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
2165 osi_panic("",__FILE__,__LINE__);
2168 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
2173 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
2174 tbp->dos_pkt_sel = tb_sel;
2177 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2182 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2186 memcpy(tbp, pkt, sizeof(smb_packet_t));
2187 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2189 smb_HoldVC(tbp->vcp);
2193 static NCB *GetNCB(void)
2198 unsigned int npar, seg, tb_sel;
2201 lock_ObtainWrite(&smb_globalLock);
2202 tbp = smb_ncbFreeListp;
2204 smb_ncbFreeListp = tbp->nextp;
2205 lock_ReleaseWrite(&smb_globalLock);
2208 tbp = calloc(sizeof(*tbp),1);
2210 tbp = malloc(sizeof(*tbp));
2211 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
2214 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2216 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2218 osi_panic("",__FILE__,__LINE__);
2220 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2225 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
2226 tbp->dos_ncb_sel = tb_sel;
2228 tbp->magic = SMB_NCBMAGIC;
2231 osi_assert(tbp->magic == SMB_NCBMAGIC);
2233 memset(&tbp->ncb, 0, sizeof(NCB));
2236 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2241 void smb_FreePacket(smb_packet_t *tbp)
2243 smb_vc_t * vcp = NULL;
2244 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2246 lock_ObtainWrite(&smb_globalLock);
2247 tbp->nextp = smb_packetFreeListp;
2248 smb_packetFreeListp = tbp;
2249 tbp->magic = SMB_PACKETMAGIC;
2253 tbp->resumeCode = 0;
2259 tbp->ncb_length = 0;
2261 lock_ReleaseWrite(&smb_globalLock);
2267 static void FreeNCB(NCB *bufferp)
2271 tbp = (smb_ncb_t *) bufferp;
2272 osi_assert(tbp->magic == SMB_NCBMAGIC);
2274 lock_ObtainWrite(&smb_globalLock);
2275 tbp->nextp = smb_ncbFreeListp;
2276 smb_ncbFreeListp = tbp;
2277 lock_ReleaseWrite(&smb_globalLock);
2280 /* get a ptr to the data part of a packet, and its count */
2281 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2285 unsigned char *afterParmsp;
2287 parmBytes = *smbp->wctp << 1;
2288 afterParmsp = smbp->wctp + parmBytes + 1;
2290 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2291 if (nbytesp) *nbytesp = dataBytes;
2293 /* don't forget to skip the data byte count, since it follows
2294 * the parameters; that's where the "2" comes from below.
2296 return (unsigned char *) (afterParmsp + 2);
2299 /* must set all the returned parameters before playing around with the
2300 * data region, since the data region is located past the end of the
2301 * variable number of parameters.
2303 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2305 unsigned char *afterParmsp;
2307 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2309 *afterParmsp++ = dsize & 0xff;
2310 *afterParmsp = (dsize>>8) & 0xff;
2313 /* return the parm'th parameter in the smbp packet */
2314 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2317 unsigned char *parmDatap;
2319 parmCount = *smbp->wctp;
2321 if (parm >= parmCount) {
2324 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2325 parm, parmCount, smbp->ncb_length);
2326 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2327 parm, parmCount, smbp->ncb_length);
2329 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2330 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2332 osi_panic(s, __FILE__, __LINE__);
2334 parmDatap = smbp->wctp + (2*parm) + 1;
2336 return parmDatap[0] + (parmDatap[1] << 8);
2339 /* return the parm'th parameter in the smbp packet */
2340 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2343 unsigned char *parmDatap;
2345 parmCount = *smbp->wctp;
2347 if (parm * 2 + offset >= parmCount * 2) {
2350 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2351 parm, offset, parmCount, smbp->ncb_length);
2353 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2354 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2356 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2357 parm, offset, parmCount, smbp->ncb_length);
2358 osi_panic(s, __FILE__, __LINE__);
2360 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2362 return parmDatap[0] + (parmDatap[1] << 8);
2365 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2369 /* make sure we have enough slots */
2370 if (*smbp->wctp <= slot)
2371 *smbp->wctp = slot+1;
2373 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2374 *parmDatap++ = parmValue & 0xff;
2375 *parmDatap = (parmValue>>8) & 0xff;
2378 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2382 /* make sure we have enough slots */
2383 if (*smbp->wctp <= slot)
2384 *smbp->wctp = slot+2;
2386 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2387 *parmDatap++ = parmValue & 0xff;
2388 *parmDatap++ = (parmValue>>8) & 0xff;
2389 *parmDatap++ = (parmValue>>16) & 0xff;
2390 *parmDatap++ = (parmValue>>24) & 0xff;
2393 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2398 /* make sure we have enough slots */
2399 if (*smbp->wctp <= slot)
2400 *smbp->wctp = slot+4;
2402 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2404 *parmDatap++ = *parmValuep++;
2407 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2411 /* make sure we have enough slots */
2412 if (*smbp->wctp <= slot) {
2413 if (smbp->oddByte) {
2415 *smbp->wctp = slot+1;
2420 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2421 *parmDatap++ = parmValue & 0xff;
2424 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2428 lastSlashp = strrchr(inPathp, '\\');
2430 *lastComponentp = lastSlashp;
2433 if (inPathp == lastSlashp)
2435 *outPathp++ = *inPathp++;
2444 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2449 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2454 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2460 tlen = inp[0] + (inp[1]<<8);
2461 inp += 2; /* skip length field */
2464 *chainpp = inp + tlen;
2473 /* format a packet as a response */
2474 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2479 outp = (smb_t *) op;
2481 /* zero the basic structure through the smb_wct field, and zero the data
2482 * size field, assuming that wct stays zero; otherwise, you have to
2483 * explicitly set the data size field, too.
2485 inSmbp = (smb_t *) inp;
2486 memset(outp, 0, sizeof(smb_t)+2);
2492 outp->com = inSmbp->com;
2493 outp->tid = inSmbp->tid;
2494 outp->pid = inSmbp->pid;
2495 outp->uid = inSmbp->uid;
2496 outp->mid = inSmbp->mid;
2497 outp->res[0] = inSmbp->res[0];
2498 outp->res[1] = inSmbp->res[1];
2499 op->inCom = inSmbp->com;
2501 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2502 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2504 /* copy fields in generic packet area */
2505 op->wctp = &outp->wct;
2508 /* send a (probably response) packet; vcp tells us to whom to send it.
2509 * we compute the length by looking at wct and bcc fields.
2511 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2528 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2531 memset((char *)ncbp, 0, sizeof(NCB));
2533 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2534 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2535 extra += tp[0] + (tp[1]<<8);
2536 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2537 extra += 3; /* wct and length fields */
2539 ncbp->ncb_length = extra; /* bytes to send */
2540 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2541 ncbp->ncb_lana_num = vcp->lana;
2542 ncbp->ncb_command = NCBSEND; /* op means send data */
2544 ncbp->ncb_buffer = (char *) inp;/* packet */
2545 code = Netbios(ncbp);
2547 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2548 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2550 /* copy header information from virtual to DOS address space */
2551 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2552 code = Netbios(ncbp, dos_ncb);
2556 const char * s = ncb_error_string(code);
2557 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2559 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2562 lock_ObtainMutex(&vcp->mx);
2563 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2564 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2566 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2567 lock_ReleaseMutex(&vcp->mx);
2568 lock_ObtainWrite(&smb_globalLock);
2569 dead_sessions[vcp->session] = TRUE;
2570 lock_ReleaseWrite(&smb_globalLock);
2571 smb_CleanupDeadVC(vcp);
2573 lock_ReleaseMutex(&vcp->mx);
2581 void smb_MapNTError(long code, unsigned long *NTStatusp)
2583 unsigned long NTStatus;
2585 /* map CM_ERROR_* errors to NT 32-bit status codes */
2586 /* NT Status codes are listed in ntstatus.h not winerror.h */
2587 if (code == CM_ERROR_NOSUCHCELL) {
2588 NTStatus = 0xC000000FL; /* No such file */
2590 else if (code == CM_ERROR_NOSUCHVOLUME) {
2591 NTStatus = 0xC000000FL; /* No such file */
2593 else if (code == CM_ERROR_TIMEDOUT) {
2595 NTStatus = 0xC00000CFL; /* Sharing Paused */
2597 NTStatus = 0x00000102L; /* Timeout */
2600 else if (code == CM_ERROR_RETRY) {
2601 NTStatus = 0xC000022DL; /* Retry */
2603 else if (code == CM_ERROR_NOACCESS) {
2604 NTStatus = 0xC0000022L; /* Access denied */
2606 else if (code == CM_ERROR_READONLY) {
2607 NTStatus = 0xC00000A2L; /* Write protected */
2609 else if (code == CM_ERROR_NOSUCHFILE) {
2610 NTStatus = 0xC000000FL; /* No such file */
2612 else if (code == CM_ERROR_NOSUCHPATH) {
2613 NTStatus = 0xC000003AL; /* Object path not found */
2615 else if (code == CM_ERROR_TOOBIG) {
2616 NTStatus = 0xC000007BL; /* Invalid image format */
2618 else if (code == CM_ERROR_INVAL) {
2619 NTStatus = 0xC000000DL; /* Invalid parameter */
2621 else if (code == CM_ERROR_BADFD) {
2622 NTStatus = 0xC0000008L; /* Invalid handle */
2624 else if (code == CM_ERROR_BADFDOP) {
2625 NTStatus = 0xC0000022L; /* Access denied */
2627 else if (code == CM_ERROR_EXISTS) {
2628 NTStatus = 0xC0000035L; /* Object name collision */
2630 else if (code == CM_ERROR_NOTEMPTY) {
2631 NTStatus = 0xC0000101L; /* Directory not empty */
2633 else if (code == CM_ERROR_CROSSDEVLINK) {
2634 NTStatus = 0xC00000D4L; /* Not same device */
2636 else if (code == CM_ERROR_NOTDIR) {
2637 NTStatus = 0xC0000103L; /* Not a directory */
2639 else if (code == CM_ERROR_ISDIR) {
2640 NTStatus = 0xC00000BAL; /* File is a directory */
2642 else if (code == CM_ERROR_BADOP) {
2644 /* I have no idea where this comes from */
2645 NTStatus = 0xC09820FFL; /* SMB no support */
2647 NTStatus = 0xC00000BBL; /* Not supported */
2648 #endif /* COMMENT */
2650 else if (code == CM_ERROR_BADSHARENAME) {
2651 NTStatus = 0xC00000CCL; /* Bad network name */
2653 else if (code == CM_ERROR_NOIPC) {
2655 NTStatus = 0xC0000022L; /* Access Denied */
2657 NTStatus = 0xC000013DL; /* Remote Resources */
2660 else if (code == CM_ERROR_CLOCKSKEW) {
2661 NTStatus = 0xC0000133L; /* Time difference at DC */
2663 else if (code == CM_ERROR_BADTID) {
2664 NTStatus = 0xC0982005L; /* SMB bad TID */
2666 else if (code == CM_ERROR_USESTD) {
2667 NTStatus = 0xC09820FBL; /* SMB use standard */
2669 else if (code == CM_ERROR_QUOTA) {
2671 NTStatus = 0xC0000044L; /* Quota exceeded */
2673 NTStatus = 0xC000007FL; /* Disk full */
2676 else if (code == CM_ERROR_SPACE) {
2677 NTStatus = 0xC000007FL; /* Disk full */
2679 else if (code == CM_ERROR_ATSYS) {
2680 NTStatus = 0xC0000033L; /* Object name invalid */
2682 else if (code == CM_ERROR_BADNTFILENAME) {
2683 NTStatus = 0xC0000033L; /* Object name invalid */
2685 else if (code == CM_ERROR_WOULDBLOCK) {
2686 NTStatus = 0xC0000055L; /* Lock not granted */
2688 else if (code == CM_ERROR_SHARING_VIOLATION) {
2689 NTStatus = 0xC0000043L; /* Sharing violation */
2691 else if (code == CM_ERROR_LOCK_CONFLICT) {
2692 NTStatus = 0xC0000054L; /* Lock conflict */
2694 else if (code == CM_ERROR_PARTIALWRITE) {
2695 NTStatus = 0xC000007FL; /* Disk full */
2697 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2698 NTStatus = 0xC0000023L; /* Buffer too small */
2700 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2701 NTStatus = 0xC0000035L; /* Object name collision */
2703 else if (code == CM_ERROR_BADPASSWORD) {
2704 NTStatus = 0xC000006DL; /* unknown username or bad password */
2706 else if (code == CM_ERROR_BADLOGONTYPE) {
2707 NTStatus = 0xC000015BL; /* logon type not granted */
2709 else if (code == CM_ERROR_GSSCONTINUE) {
2710 NTStatus = 0xC0000016L; /* more processing required */
2712 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2714 NTStatus = 0xC0000280L; /* reparse point not resolved */
2716 NTStatus = 0xC0000022L; /* Access Denied */
2719 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2720 NTStatus = 0xC0000257L; /* Path Not Covered */
2723 else if (code == CM_ERROR_ALLBUSY) {
2724 NTStatus = 0xC00000BFL; /* Network Busy */
2726 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2727 NTStatus = 0xC0000350L; /* Remote Host Down */
2730 /* we do not want to be telling the SMB/CIFS client that
2731 * the AFS Client Service is busy or down.
2733 else if (code == CM_ERROR_ALLBUSY ||
2734 code == CM_ERROR_ALLOFFLINE ||
2735 code == CM_ERROR_ALLDOWN) {
2736 NTStatus = 0xC00000BEL; /* Bad Network Path */
2739 else if (code == RXKADUNKNOWNKEY) {
2740 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2742 NTStatus = 0xC0982001L; /* SMB non-specific error */
2745 *NTStatusp = NTStatus;
2746 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2749 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2750 unsigned char *classp)
2752 unsigned char class;
2753 unsigned short error;
2755 /* map CM_ERROR_* errors to SMB errors */
2756 if (code == CM_ERROR_NOSUCHCELL) {
2758 error = 3; /* bad path */
2760 else if (code == CM_ERROR_NOSUCHVOLUME) {
2762 error = 3; /* bad path */
2764 else if (code == CM_ERROR_TIMEDOUT) {
2766 error = 81; /* server is paused */
2768 else if (code == CM_ERROR_RETRY) {
2769 class = 2; /* shouldn't happen */
2772 else if (code == CM_ERROR_NOACCESS) {
2774 error = 4; /* bad access */
2776 else if (code == CM_ERROR_READONLY) {
2778 error = 19; /* read only */
2780 else if (code == CM_ERROR_NOSUCHFILE) {
2782 error = 2; /* ENOENT! */
2784 else if (code == CM_ERROR_NOSUCHPATH) {
2786 error = 3; /* Bad path */
2788 else if (code == CM_ERROR_TOOBIG) {
2790 error = 11; /* bad format */
2792 else if (code == CM_ERROR_INVAL) {
2793 class = 2; /* server non-specific error code */
2796 else if (code == CM_ERROR_BADFD) {
2798 error = 6; /* invalid file handle */
2800 else if (code == CM_ERROR_BADFDOP) {
2801 class = 1; /* invalid op on FD */
2804 else if (code == CM_ERROR_EXISTS) {
2806 error = 80; /* file already exists */
2808 else if (code == CM_ERROR_NOTEMPTY) {
2810 error = 5; /* delete directory not empty */
2812 else if (code == CM_ERROR_CROSSDEVLINK) {
2814 error = 17; /* EXDEV */
2816 else if (code == CM_ERROR_NOTDIR) {
2817 class = 1; /* bad path */
2820 else if (code == CM_ERROR_ISDIR) {
2821 class = 1; /* access denied; DOS doesn't have a good match */
2824 else if (code == CM_ERROR_BADOP) {
2828 else if (code == CM_ERROR_BADSHARENAME) {
2832 else if (code == CM_ERROR_NOIPC) {
2834 error = 4; /* bad access */
2836 else if (code == CM_ERROR_CLOCKSKEW) {
2837 class = 1; /* invalid function */
2840 else if (code == CM_ERROR_BADTID) {
2844 else if (code == CM_ERROR_USESTD) {
2848 else if (code == CM_ERROR_REMOTECONN) {
2852 else if (code == CM_ERROR_QUOTA) {
2853 if (vcp->flags & SMB_VCFLAG_USEV3) {
2855 error = 39; /* disk full */
2859 error = 5; /* access denied */
2862 else if (code == CM_ERROR_SPACE) {
2863 if (vcp->flags & SMB_VCFLAG_USEV3) {
2865 error = 39; /* disk full */
2869 error = 5; /* access denied */
2872 else if (code == CM_ERROR_PARTIALWRITE) {
2874 error = 39; /* disk full */
2876 else if (code == CM_ERROR_ATSYS) {
2878 error = 2; /* ENOENT */
2880 else if (code == CM_ERROR_WOULDBLOCK) {
2882 error = 33; /* lock conflict */
2884 else if (code == CM_ERROR_LOCK_CONFLICT) {
2886 error = 33; /* lock conflict */
2888 else if (code == CM_ERROR_SHARING_VIOLATION) {
2890 error = 33; /* lock conflict */
2892 else if (code == CM_ERROR_NOFILES) {
2894 error = 18; /* no files in search */
2896 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2898 error = 183; /* Samba uses this */
2900 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2901 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2903 error = 2; /* bad password */
2905 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2907 error = 3; /* bad path */
2916 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2919 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2921 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2922 return CM_ERROR_BADOP;
2925 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2927 unsigned short EchoCount, i;
2928 char *data, *outdata;
2931 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2933 for (i=1; i<=EchoCount; i++) {
2934 data = smb_GetSMBData(inp, &dataSize);
2935 smb_SetSMBParm(outp, 0, i);
2936 smb_SetSMBDataLength(outp, dataSize);
2937 outdata = smb_GetSMBData(outp, NULL);
2938 memcpy(outdata, data, dataSize);
2939 smb_SendPacket(vcp, outp);
2945 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2948 long count, minCount, finalCount;
2953 cm_user_t *userp = NULL;
2957 char *rawBuf = NULL;
2959 dos_ptr rawBuf = NULL;
2966 fd = smb_GetSMBParm(inp, 0);
2967 count = smb_GetSMBParm(inp, 3);
2968 minCount = smb_GetSMBParm(inp, 4);
2969 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2971 if (*inp->wctp == 10) {
2972 /* we were sent a request with 64-bit file offsets */
2973 #ifdef AFS_LARGEFILES
2974 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2976 if (LargeIntegerLessThanZero(offset)) {
2977 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2981 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2982 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2985 offset.HighPart = 0;
2989 /* we were sent a request with 32-bit file offsets */
2990 offset.HighPart = 0;
2993 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2994 fd, offset.HighPart, offset.LowPart, count);
2996 fidp = smb_FindFID(vcp, fd, 0);
3000 pid = ((smb_t *) inp)->pid;
3002 LARGE_INTEGER LOffset, LLength;
3005 key = cm_GenerateKey(vcp->vcID, pid, fd);
3007 LOffset.HighPart = offset.HighPart;
3008 LOffset.LowPart = offset.LowPart;
3009 LLength.HighPart = 0;
3010 LLength.LowPart = count;
3012 lock_ObtainMutex(&fidp->scp->mx);
3013 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3014 lock_ReleaseMutex(&fidp->scp->mx);
3020 lock_ObtainMutex(&smb_RawBufLock);
3022 /* Get a raw buf, from head of list */
3023 rawBuf = smb_RawBufs;
3025 smb_RawBufs = *(char **)smb_RawBufs;
3027 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
3030 lock_ReleaseMutex(&smb_RawBufLock);
3034 lock_ObtainMutex(&fidp->mx);
3035 if (fidp->flags & SMB_FID_IOCTL)
3037 lock_ReleaseMutex(&fidp->mx);
3039 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3041 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
3044 /* Give back raw buffer */
3045 lock_ObtainMutex(&smb_RawBufLock);
3047 *((char **) rawBuf) = smb_RawBufs;
3049 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3052 smb_RawBufs = rawBuf;
3053 lock_ReleaseMutex(&smb_RawBufLock);
3056 smb_ReleaseFID(fidp);
3059 lock_ReleaseMutex(&fidp->mx);
3061 userp = smb_GetUserFromVCP(vcp, inp);
3064 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3066 /* have to give ReadData flag so it will treat buffer as DOS mem. */
3067 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
3068 userp, &finalCount, TRUE /* rawFlag */);
3075 cm_ReleaseUser(userp);
3078 smb_ReleaseFID(fidp);
3083 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
3085 memset((char *)ncbp, 0, sizeof(NCB));
3087 ncbp->ncb_length = (unsigned short) finalCount;
3088 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3089 ncbp->ncb_lana_num = vcp->lana;
3090 ncbp->ncb_command = NCBSEND;
3091 ncbp->ncb_buffer = rawBuf;
3094 code = Netbios(ncbp);
3096 code = Netbios(ncbp, dos_ncb);
3099 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3102 /* Give back raw buffer */
3103 lock_ObtainMutex(&smb_RawBufLock);
3105 *((char **) rawBuf) = smb_RawBufs;
3107 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3110 smb_RawBufs = rawBuf;
3111 lock_ReleaseMutex(&smb_RawBufLock);
3117 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3119 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3124 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3126 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3131 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3138 int protoIndex; /* index we're using */
3143 char protocol_array[10][1024]; /* protocol signature of the client */
3144 int caps; /* capabilities */
3147 TIME_ZONE_INFORMATION tzi;
3149 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3152 namep = smb_GetSMBData(inp, &dbytes);
3155 coreProtoIndex = -1; /* not found */
3158 while(namex < dbytes) {
3159 osi_Log1(smb_logp, "Protocol %s",
3160 osi_LogSaveString(smb_logp, namep+1));
3161 strcpy(protocol_array[tcounter], namep+1);
3163 /* namep points at the first protocol, or really, a 0x02
3164 * byte preceding the null-terminated ASCII name.
3166 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3167 coreProtoIndex = tcounter;
3169 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3170 v3ProtoIndex = tcounter;
3172 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3173 NTProtoIndex = tcounter;
3176 /* compute size of protocol entry */
3177 entryLength = (int)strlen(namep+1);
3178 entryLength += 2; /* 0x02 bytes and null termination */
3180 /* advance over this protocol entry */
3181 namex += entryLength;
3182 namep += entryLength;
3183 tcounter++; /* which proto entry we're looking at */
3186 lock_ObtainMutex(&vcp->mx);
3187 if (NTProtoIndex != -1) {
3188 protoIndex = NTProtoIndex;
3189 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3191 else if (v3ProtoIndex != -1) {
3192 protoIndex = v3ProtoIndex;
3193 vcp->flags |= SMB_VCFLAG_USEV3;
3195 else if (coreProtoIndex != -1) {
3196 protoIndex = coreProtoIndex;
3197 vcp->flags |= SMB_VCFLAG_USECORE;
3199 else protoIndex = -1;
3200 lock_ReleaseMutex(&vcp->mx);
3202 if (protoIndex == -1)
3203 return CM_ERROR_INVAL;
3204 else if (NTProtoIndex != -1) {
3205 smb_SetSMBParm(outp, 0, protoIndex);
3206 if (smb_authType != SMB_AUTH_NONE) {
3207 smb_SetSMBParmByte(outp, 1,
3208 NEGOTIATE_SECURITY_USER_LEVEL |
3209 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3211 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3213 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3214 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3215 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3216 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3217 /* The session key is not a well documented field however most clients
3218 * will echo back the session key to the server. Currently we are using
3219 * the same value for all sessions. We should generate a random value
3220 * and store it into the vcp
3222 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3223 smb_SetSMBParm(outp, 8, 1);
3225 * Tried changing the capabilities to support for W2K - defect 117695
3226 * Maybe something else needs to be changed here?
3230 smb_SetSMBParmLong(outp, 9, 0x43fd);
3232 smb_SetSMBParmLong(outp, 9, 0x251);
3235 * 32-bit error codes *
3240 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3242 NTNEGOTIATE_CAPABILITY_DFS |
3244 #ifdef AFS_LARGEFILES
3245 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3247 NTNEGOTIATE_CAPABILITY_NTFIND |
3248 NTNEGOTIATE_CAPABILITY_RAWMODE |
3249 NTNEGOTIATE_CAPABILITY_NTSMB;
3251 if ( smb_authType == SMB_AUTH_EXTENDED )
3252 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3254 smb_SetSMBParmLong(outp, 9, caps);
3256 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3257 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3258 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3260 GetTimeZoneInformation(&tzi);
3261 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3263 if (smb_authType == SMB_AUTH_NTLM) {
3264 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3265 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3266 /* paste in encryption key */
3267 datap = smb_GetSMBData(outp, NULL);
3268 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3269 /* and the faux domain name */
3270 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3271 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3275 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3277 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3279 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3281 datap = smb_GetSMBData(outp, NULL);
3282 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3285 datap += sizeof(smb_ServerGUID);
3286 memcpy(datap, secBlob, secBlobLength);
3290 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3291 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3294 else if (v3ProtoIndex != -1) {
3295 smb_SetSMBParm(outp, 0, protoIndex);
3297 /* NOTE: Extended authentication cannot be negotiated with v3
3298 * therefore we fail over to NTLM
3300 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3301 smb_SetSMBParm(outp, 1,
3302 NEGOTIATE_SECURITY_USER_LEVEL |
3303 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3305 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3307 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3308 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3309 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3310 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3311 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3312 smb_SetSMBParm(outp, 7, 1);
3314 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3315 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3316 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3318 GetTimeZoneInformation(&tzi);
3319 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3321 /* NOTE: Extended authentication cannot be negotiated with v3
3322 * therefore we fail over to NTLM
3324 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3325 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3326 smb_SetSMBParm(outp, 12, 0); /* resvd */
3327 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3328 datap = smb_GetSMBData(outp, NULL);
3329 /* paste in a new encryption key */
3330 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3331 /* and the faux domain name */
3332 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3334 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3335 smb_SetSMBParm(outp, 12, 0); /* resvd */
3336 smb_SetSMBDataLength(outp, 0);
3339 else if (coreProtoIndex != -1) { /* not really supported anymore */
3340 smb_SetSMBParm(outp, 0, protoIndex);
3341 smb_SetSMBDataLength(outp, 0);
3346 void smb_CheckVCs(void)
3348 smb_vc_t * vcp, *nextp;
3349 smb_packet_t * outp = GetPacket();
3352 lock_ObtainWrite(&smb_rctLock);
3353 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3355 if (vcp->magic != SMB_VC_MAGIC)
3356 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3357 __FILE__, __LINE__);
3361 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3364 smb_HoldVCNoLock(vcp);
3366 smb_HoldVCNoLock(nextp);
3367 smb_FormatResponsePacket(vcp, NULL, outp);
3368 smbp = (smb_t *)outp;
3369 outp->inCom = smbp->com = 0x2b /* Echo */;
3377 smb_SetSMBParm(outp, 0, 0);
3378 smb_SetSMBDataLength(outp, 0);
3379 lock_ReleaseWrite(&smb_rctLock);
3381 smb_SendPacket(vcp, outp);
3383 lock_ObtainWrite(&smb_rctLock);
3384 smb_ReleaseVCNoLock(vcp);
3386 smb_ReleaseVCNoLock(nextp);
3388 lock_ReleaseWrite(&smb_rctLock);
3389 smb_FreePacket(outp);
3392 void smb_Daemon(void *parmp)
3394 afs_uint32 count = 0;
3395 smb_username_t **unpp;
3398 while(smbShutdownFlag == 0) {
3402 if (smbShutdownFlag == 1)
3405 if ((count % 72) == 0) { /* every five minutes */
3407 time_t old_localZero = smb_localZero;
3409 /* Initialize smb_localZero */
3410 myTime.tm_isdst = -1; /* compute whether on DST or not */
3411 myTime.tm_year = 70;
3417 smb_localZero = mktime(&myTime);
3419 #ifndef USE_NUMERIC_TIME_CONV
3420 smb_CalculateNowTZ();
3421 #endif /* USE_NUMERIC_TIME_CONV */
3422 #ifdef AFS_FREELANCE
3423 if ( smb_localZero != old_localZero )
3424 cm_noteLocalMountPointChange();
3430 /* GC smb_username_t objects that will no longer be used */
3432 lock_ObtainWrite(&smb_rctLock);
3433 for ( unpp=&usernamesp; *unpp; ) {
3435 smb_username_t *unp;
3437 lock_ObtainMutex(&(*unpp)->mx);
3438 if ( (*unpp)->refCount > 0 ||
3439 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3440 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3442 else if (!smb_LogoffTokenTransfer ||
3443 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3445 lock_ReleaseMutex(&(*unpp)->mx);
3453 lock_FinalizeMutex(&unp->mx);
3459 lock_ReleaseWrite(&smb_rctLock);
3460 cm_ReleaseUser(userp);
3461 lock_ObtainWrite(&smb_rctLock);
3464 unpp = &(*unpp)->nextp;
3467 lock_ReleaseWrite(&smb_rctLock);
3469 /* XXX GC dir search entries */
3473 void smb_WaitingLocksDaemon()
3475 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3476 smb_waitingLock_t *wl, *wlNext;
3479 smb_packet_t *inp, *outp;
3483 while (smbShutdownFlag == 0) {
3484 lock_ObtainWrite(&smb_globalLock);
3485 nwlRequest = smb_allWaitingLocks;
3486 if (nwlRequest == NULL) {
3487 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3492 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3499 lock_ObtainWrite(&smb_globalLock);
3501 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3503 wlRequest = nwlRequest;
3504 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3505 lock_ReleaseWrite(&smb_globalLock);
3509 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3510 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3513 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3515 /* wl->state is either _DONE or _WAITING. _ERROR
3516 would no longer be on the queue. */
3517 code = cm_RetryLock( wl->lockp,
3518 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3521 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3522 } else if (code != CM_ERROR_WOULDBLOCK) {
3523 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3528 if (code == CM_ERROR_WOULDBLOCK) {
3531 if (wlRequest->timeRemaining != 0xffffffff
3532 && (wlRequest->timeRemaining -= 1000) < 0)
3544 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3547 scp = wlRequest->scp;
3551 lock_ObtainMutex(&scp->mx);
3553 for (wl = wlRequest->locks; wl; wl = wlNext) {
3554 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3556 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3557 wl->LLength, wl->key, NULL, &req);
3559 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3564 lock_ReleaseMutex(&scp->mx);
3568 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3571 for (wl = wlRequest->locks; wl; wl = wlNext) {
3572 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3573 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3578 vcp = wlRequest->vcp;
3579 inp = wlRequest->inp;
3580 outp = wlRequest->outp;
3582 ncbp->ncb_length = inp->ncb_length;
3583 inp->spacep = cm_GetSpace();
3585 /* Remove waitingLock from list */
3586 lock_ObtainWrite(&smb_globalLock);
3587 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3589 lock_ReleaseWrite(&smb_globalLock);
3591 /* Resume packet processing */
3593 smb_SetSMBDataLength(outp, 0);
3594 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3595 outp->resumeCode = code;
3597 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3600 cm_FreeSpace(inp->spacep);
3601 smb_FreePacket(inp);
3602 smb_FreePacket(outp);
3604 cm_ReleaseSCache(wlRequest->scp);
3607 } while (nwlRequest && smbShutdownFlag == 0);
3612 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3614 osi_Log0(smb_logp, "SMB receive get disk attributes");
3616 smb_SetSMBParm(outp, 0, 32000);
3617 smb_SetSMBParm(outp, 1, 64);
3618 smb_SetSMBParm(outp, 2, 1024);
3619 smb_SetSMBParm(outp, 3, 30000);
3620 smb_SetSMBParm(outp, 4, 0);
3621 smb_SetSMBDataLength(outp, 0);
3625 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3629 unsigned short newTid;
3630 char shareName[256];
3638 osi_Log0(smb_logp, "SMB receive tree connect");
3640 /* parse input parameters */
3641 tp = smb_GetSMBData(inp, NULL);
3642 pathp = smb_ParseASCIIBlock(tp, &tp);
3643 if (smb_StoreAnsiFilenames)
3644 OemToChar(pathp,pathp);
3645 passwordp = smb_ParseASCIIBlock(tp, &tp);
3646 tp = strrchr(pathp, '\\');
3648 return CM_ERROR_BADSMB;
3649 strcpy(shareName, tp+1);
3651 lock_ObtainMutex(&vcp->mx);
3652 newTid = vcp->tidCounter++;
3653 lock_ReleaseMutex(&vcp->mx);
3655 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3656 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3657 userp = smb_GetUserFromUID(uidp);
3658 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3660 smb_ReleaseUID(uidp);
3662 smb_ReleaseTID(tidp);
3663 return CM_ERROR_BADSHARENAME;
3665 lock_ObtainMutex(&tidp->mx);
3666 tidp->userp = userp;
3667 tidp->pathname = sharePath;
3668 lock_ReleaseMutex(&tidp->mx);
3669 smb_ReleaseTID(tidp);
3671 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3672 smb_SetSMBParm(rsp, 1, newTid);
3673 smb_SetSMBDataLength(rsp, 0);
3675 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3679 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3683 if (*inp++ != 0x1) return NULL;
3684 tlen = inp[0] + (inp[1]<<8);
3685 inp += 2; /* skip length field */
3688 *chainpp = inp + tlen;
3691 if (lengthp) *lengthp = tlen;
3696 /* set maskp to the mask part of the incoming path.
3697 * Mask is 11 bytes long (8.3 with the dot elided).
3698 * Returns true if succeeds with a valid name, otherwise it does
3699 * its best, but returns false.
3701 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3709 /* starts off valid */
3712 /* mask starts out all blanks */
3713 memset(maskp, ' ', 11);
3715 /* find last backslash, or use whole thing if there is none */
3716 tp = strrchr(pathp, '\\');
3717 if (!tp) tp = pathp;
3718 else tp++; /* skip slash */
3722 /* names starting with a dot are illegal */
3723 if (*tp == '.') valid8Dot3 = 0;
3727 if (tc == 0) return valid8Dot3;
3728 if (tc == '.' || tc == '"') break;
3729 if (i < 8) *up++ = tc;
3730 else valid8Dot3 = 0;
3733 /* if we get here, tp point after the dot */
3734 up = maskp+8; /* ext goes here */
3741 if (tc == '.' || tc == '"')
3744 /* copy extension if not too long */
3754 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3764 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3766 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3770 /* otherwise, we have a valid 8.3 name; see if we have a match,
3771 * treating '?' as a wildcard in maskp (but not in the file name).
3773 tp1 = umask; /* real name, in mask format */
3774 tp2 = maskp; /* mask, in mask format */
3775 for(i=0; i<11; i++) {
3776 tc1 = *tp1++; /* char from real name */
3777 tc2 = *tp2++; /* char from mask */
3778 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3779 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3782 if (tc2 == '?' && tc1 != ' ')
3789 /* we got a match */
3793 char *smb_FindMask(char *pathp)
3797 tp = strrchr(pathp, '\\'); /* find last slash */
3800 return tp+1; /* skip the slash */
3802 return pathp; /* no slash, return the entire path */
3805 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3807 unsigned char *pathp;
3809 unsigned char mask[11];
3810 unsigned char *statBlockp;
3811 unsigned char initStatBlock[21];
3814 osi_Log0(smb_logp, "SMB receive search volume");
3816 /* pull pathname and stat block out of request */
3817 tp = smb_GetSMBData(inp, NULL);
3818 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3819 osi_assert(pathp != NULL);
3820 if (smb_StoreAnsiFilenames)
3821 OemToChar(pathp,pathp);
3822 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3823 osi_assert(statBlockp != NULL);
3825 statBlockp = initStatBlock;
3829 /* for returning to caller */
3830 smb_Get8Dot3MaskFromPath(mask, pathp);
3832 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3833 tp = smb_GetSMBData(outp, NULL);
3835 *tp++ = 43; /* bytes in a dir entry */
3836 *tp++ = 0; /* high byte in counter */
3838 /* now marshall the dir entry, starting with the search status */
3839 *tp++ = statBlockp[0]; /* Reserved */
3840 memcpy(tp, mask, 11); tp += 11; /* FileName */
3842 /* now pass back server use info, with 1st byte non-zero */
3844 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3846 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3848 *tp++ = 0x8; /* attribute: volume */
3858 /* 4 byte file size */
3864 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3865 memset(tp, ' ', 13);
3868 /* set the length of the data part of the packet to 43 + 3, for the dir
3869 * entry plus the 5 and the length fields.
3871 smb_SetSMBDataLength(outp, 46);
3875 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3876 cm_user_t *userp, cm_req_t *reqp)
3884 smb_dirListPatch_t *patchp;
3885 smb_dirListPatch_t *npatchp;
3887 for (patchp = *dirPatchespp; patchp; patchp =
3888 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3890 dptr = patchp->dptr;
3892 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3894 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3895 *dptr++ = SMB_ATTR_HIDDEN;
3898 lock_ObtainMutex(&scp->mx);
3899 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3900 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3902 lock_ReleaseMutex(&scp->mx);
3903 cm_ReleaseSCache(scp);
3904 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3905 *dptr++ = SMB_ATTR_HIDDEN;
3909 attr = smb_Attributes(scp);
3910 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3911 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3912 attr |= SMB_ATTR_HIDDEN;
3916 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3919 shortTemp = (unsigned short) (dosTime & 0xffff);
3920 *((u_short *)dptr) = shortTemp;
3923 /* and copy out date */
3924 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3925 *((u_short *)dptr) = shortTemp;
3928 /* copy out file length */
3929 *((u_long *)dptr) = scp->length.LowPart;
3931 lock_ReleaseMutex(&scp->mx);
3932 cm_ReleaseSCache(scp);
3935 /* now free the patches */
3936 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3937 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3941 /* and mark the list as empty */
3942 *dirPatchespp = NULL;
3947 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3956 smb_dirListPatch_t *dirListPatchesp;
3957 smb_dirListPatch_t *curPatchp;
3961 osi_hyper_t dirLength;
3962 osi_hyper_t bufferOffset;
3963 osi_hyper_t curOffset;
3965 unsigned char *inCookiep;
3966 smb_dirSearch_t *dsp;
3970 unsigned long clientCookie;
3971 cm_pageHeader_t *pageHeaderp;
3972 cm_user_t *userp = NULL;
3979 long nextEntryCookie;
3980 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3981 char resByte; /* reserved byte from the cookie */
3982 char *op; /* output data ptr */
3983 char *origOp; /* original value of op */
3984 cm_space_t *spacep; /* for pathname buffer */
3995 maxCount = smb_GetSMBParm(inp, 0);
3997 dirListPatchesp = NULL;
3999 caseFold = CM_FLAG_CASEFOLD;
4001 tp = smb_GetSMBData(inp, NULL);
4002 pathp = smb_ParseASCIIBlock(tp, &tp);
4003 if (smb_StoreAnsiFilenames)
4004 OemToChar(pathp,pathp);
4005 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4007 /* bail out if request looks bad */
4008 if (!tp || !pathp) {
4009 return CM_ERROR_BADSMB;
4012 /* We can handle long names */
4013 if (vcp->flags & SMB_VCFLAG_USENT)
4014 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4016 /* make sure we got a whole search status */
4017 if (dataLength < 21) {
4018 nextCookie = 0; /* start at the beginning of the dir */
4021 attribute = smb_GetSMBParm(inp, 1);
4023 /* handle volume info in another function */
4024 if (attribute & 0x8)
4025 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4027 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
4028 maxCount, osi_LogSaveString(smb_logp, pathp));
4030 if (*pathp == 0) { /* null pathp, treat as root dir */
4031 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4032 return CM_ERROR_NOFILES;
4036 dsp = smb_NewDirSearch(0);
4037 dsp->attribute = attribute;
4038 smb_Get8Dot3MaskFromPath(mask, pathp);
4039 memcpy(dsp->mask, mask, 11);
4041 /* track if this is likely to match a lot of entries */
4042 if (smb_IsStarMask(mask))
4047 /* pull the next cookie value out of the search status block */
4048 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4049 + (inCookiep[16]<<24);
4050 dsp = smb_FindDirSearch(inCookiep[12]);
4052 /* can't find dir search status; fatal error */
4053 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
4054 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
4055 return CM_ERROR_BADFD;
4057 attribute = dsp->attribute;
4058 resByte = inCookiep[0];
4060 /* copy out client cookie, in host byte order. Don't bother
4061 * interpreting it, since we're just passing it through, anyway.
4063 memcpy(&clientCookie, &inCookiep[17], 4);
4065 memcpy(mask, dsp->mask, 11);
4067 /* assume we're doing a star match if it has continued for more
4073 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4074 nextCookie, dsp->cookie, attribute);
4076 userp = smb_GetUserFromVCP(vcp, inp);
4078 /* try to get the vnode for the path name next */
4079 lock_ObtainMutex(&dsp->mx);
4085 spacep = inp->spacep;
4086 smb_StripLastComponent(spacep->data, NULL, pathp);
4087 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4089 lock_ReleaseMutex(&dsp->mx);
4090 cm_ReleaseUser(userp);
4091 smb_DeleteDirSearch(dsp);
4092 smb_ReleaseDirSearch(dsp);
4093 return CM_ERROR_NOFILES;
4095 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4096 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4099 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4100 cm_ReleaseSCache(scp);
4101 lock_ReleaseMutex(&dsp->mx);
4102 cm_ReleaseUser(userp);
4103 smb_DeleteDirSearch(dsp);
4104 smb_ReleaseDirSearch(dsp);
4105 if ( WANTS_DFS_PATHNAMES(inp) )
4106 return CM_ERROR_PATH_NOT_COVERED;
4108 return CM_ERROR_BADSHARENAME;
4110 #endif /* DFS_SUPPORT */
4113 /* we need one hold for the entry we just stored into,
4114 * and one for our own processing. When we're done with this
4115 * function, we'll drop the one for our own processing.
4116 * We held it once from the namei call, and so we do another hold
4120 lock_ObtainMutex(&scp->mx);
4121 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4122 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4123 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4124 dsp->flags |= SMB_DIRSEARCH_BULKST;
4126 lock_ReleaseMutex(&scp->mx);
4129 lock_ReleaseMutex(&dsp->mx);
4131 cm_ReleaseUser(userp);
4132 smb_DeleteDirSearch(dsp);
4133 smb_ReleaseDirSearch(dsp);
4137 /* reserves space for parameter; we'll adjust it again later to the
4138 * real count of the # of entries we returned once we've actually
4139 * assembled the directory listing.
4141 smb_SetSMBParm(outp, 0, 0);
4143 /* get the directory size */
4144 lock_ObtainMutex(&scp->mx);
4145 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4146 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4148 lock_ReleaseMutex(&scp->mx);
4149 cm_ReleaseSCache(scp);
4150 cm_ReleaseUser(userp);
4151 smb_DeleteDirSearch(dsp);
4152 smb_ReleaseDirSearch(dsp);
4156 dirLength = scp->length;
4158 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4159 curOffset.HighPart = 0;
4160 curOffset.LowPart = nextCookie;
4161 origOp = op = smb_GetSMBData(outp, NULL);
4162 /* and write out the basic header */
4163 *op++ = 5; /* variable block */
4164 op += 2; /* skip vbl block length; we'll fill it in later */
4168 /* make sure that curOffset.LowPart doesn't point to the first
4169 * 32 bytes in the 2nd through last dir page, and that it doesn't
4170 * point at the first 13 32-byte chunks in the first dir page,
4171 * since those are dir and page headers, and don't contain useful
4174 temp = curOffset.LowPart & (2048-1);
4175 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4176 /* we're in the first page */
4177 if (temp < 13*32) temp = 13*32;
4180 /* we're in a later dir page */
4181 if (temp < 32) temp = 32;
4184 /* make sure the low order 5 bits are zero */
4187 /* now put temp bits back ito curOffset.LowPart */
4188 curOffset.LowPart &= ~(2048-1);
4189 curOffset.LowPart |= temp;
4191 /* check if we've returned all the names that will fit in the
4194 if (returnedNames >= maxCount) {
4195 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4196 returnedNames, maxCount);
4200 /* check if we've passed the dir's EOF */
4201 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4203 /* see if we can use the bufferp we have now; compute in which page
4204 * the current offset would be, and check whether that's the offset
4205 * of the buffer we have. If not, get the buffer.
4207 thyper.HighPart = curOffset.HighPart;
4208 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4209 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4212 buf_Release(bufferp);
4215 lock_ReleaseMutex(&scp->mx);
4216 lock_ObtainRead(&scp->bufCreateLock);
4217 code = buf_Get(scp, &thyper, &bufferp);
4218 lock_ReleaseRead(&scp->bufCreateLock);
4219 lock_ObtainMutex(&dsp->mx);
4221 /* now, if we're doing a star match, do bulk fetching of all of
4222 * the status info for files in the dir.
4225 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4226 lock_ObtainMutex(&scp->mx);
4227 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4228 LargeIntegerGreaterThanOrEqualTo(thyper,
4229 scp->bulkStatProgress)) {
4230 /* Don't bulk stat if risking timeout */
4231 int now = GetTickCount();
4232 if (now - req.startTime > 5000) {
4233 scp->bulkStatProgress = thyper;
4234 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4235 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4237 cm_TryBulkStat(scp, &thyper, userp, &req);
4240 lock_ObtainMutex(&scp->mx);
4242 lock_ReleaseMutex(&dsp->mx);
4244 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4248 bufferOffset = thyper;
4250 /* now get the data in the cache */
4252 code = cm_SyncOp(scp, bufferp, userp, &req,
4254 CM_SCACHESYNC_NEEDCALLBACK |
4255 CM_SCACHESYNC_READ);
4257 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4261 if (cm_HaveBuffer(scp, bufferp, 0)) {
4262 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4266 /* otherwise, load the buffer and try again */
4267 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4269 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4270 scp, bufferp, code);
4275 buf_Release(bufferp);
4279 } /* if (wrong buffer) ... */
4281 /* now we have the buffer containing the entry we're interested in; copy
4282 * it out if it represents a non-deleted entry.
4284 entryInDir = curOffset.LowPart & (2048-1);
4285 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4287 /* page header will help tell us which entries are free. Page header
4288 * can change more often than once per buffer, since AFS 3 dir page size
4289 * may be less than (but not more than a buffer package buffer.
4291 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4292 temp &= ~(2048 - 1); /* turn off intra-page bits */
4293 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4295 /* now determine which entry we're looking at in the page. If it is
4296 * free (there's a free bitmap at the start of the dir), we should
4297 * skip these 32 bytes.
4299 slotInPage = (entryInDir & 0x7e0) >> 5;
4300 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4301 /* this entry is free */
4302 numDirChunks = 1; /* only skip this guy */
4306 tp = bufferp->datap + entryInBuffer;
4307 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4309 /* while we're here, compute the next entry's location, too,
4310 * since we'll need it when writing out the cookie into the dir
4313 * XXXX Probably should do more sanity checking.
4315 numDirChunks = cm_NameEntries(dep->name, NULL);
4317 /* compute the offset of the cookie representing the next entry */
4318 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4320 /* Compute 8.3 name if necessary */
4321 actualName = dep->name;
4322 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4323 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4324 actualName = shortName;
4327 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4328 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4329 osi_LogSaveString(smb_logp, actualName));
4331 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4332 /* this is one of the entries to use: it is not deleted
4333 * and it matches the star pattern we're looking for.
4336 /* Eliminate entries that don't match requested
4339 /* no hidden files */
4340 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4341 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4345 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4347 /* We have already done the cm_TryBulkStat above */
4348 fid.cell = scp->fid.cell;
4349 fid.volume = scp->fid.volume;
4350 fid.vnode = ntohl(dep->fid.vnode);
4351 fid.unique = ntohl(dep->fid.unique);
4352 fileType = cm_FindFileType(&fid);
4353 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4354 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4356 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4357 fileType == CM_SCACHETYPE_DFSLINK ||
4358 fileType == CM_SCACHETYPE_INVALID)
4359 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4364 memcpy(op, mask, 11); op += 11;
4365 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4366 *op++ = (char)(nextEntryCookie & 0xff);
4367 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4368 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4369 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4370 memcpy(op, &clientCookie, 4); op += 4;
4372 /* now we emit the attribute. This is sort of tricky,
4373 * since we need to really stat the file to find out
4374 * what type of entry we've got. Right now, we're
4375 * copying out data from a buffer, while holding the
4376 * scp locked, so it isn't really convenient to stat
4377 * something now. We'll put in a place holder now,
4378 * and make a second pass before returning this to get
4379 * the real attributes. So, we just skip the data for
4380 * now, and adjust it later. We allocate a patch
4381 * record to make it easy to find this point later.
4382 * The replay will happen at a time when it is safe to
4383 * unlock the directory.
4385 curPatchp = malloc(sizeof(*curPatchp));
4386 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4387 curPatchp->dptr = op;
4388 curPatchp->fid.cell = scp->fid.cell;
4389 curPatchp->fid.volume = scp->fid.volume;
4390 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4391 curPatchp->fid.unique = ntohl(dep->fid.unique);
4393 /* do hidden attribute here since name won't be around when applying
4397 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4398 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4400 curPatchp->flags = 0;
4402 op += 9; /* skip attr, time, date and size */
4404 /* zero out name area. The spec says to pad with
4405 * spaces, but Samba doesn't, and neither do we.
4409 /* finally, we get to copy out the name; we know that
4410 * it fits in 8.3 or the pattern wouldn't match, but it
4411 * never hurts to be sure.
4413 strncpy(op, actualName, 13);
4414 if (smb_StoreAnsiFilenames)
4417 /* Uppercase if requested by client */
4418 if (!KNOWS_LONG_NAMES(inp))
4423 /* now, adjust the # of entries copied */
4425 } /* if we're including this name */
4428 /* and adjust curOffset to be where the new cookie is */
4429 thyper.HighPart = 0;
4430 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4431 curOffset = LargeIntegerAdd(thyper, curOffset);
4432 } /* while copying data for dir listing */
4434 /* release the mutex */
4435 lock_ReleaseMutex(&scp->mx);
4436 if (bufferp) buf_Release(bufferp);
4438 /* apply and free last set of patches; if not doing a star match, this
4439 * will be empty, but better safe (and freeing everything) than sorry.
4441 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4443 /* special return code for unsuccessful search */
4444 if (code == 0 && dataLength < 21 && returnedNames == 0)
4445 code = CM_ERROR_NOFILES;
4447 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4448 returnedNames, code);
4451 smb_DeleteDirSearch(dsp);
4452 smb_ReleaseDirSearch(dsp);
4453 cm_ReleaseSCache(scp);
4454 cm_ReleaseUser(userp);
4458 /* finalize the output buffer */
4459 smb_SetSMBParm(outp, 0, returnedNames);
4460 temp = (long) (op - origOp);
4461 smb_SetSMBDataLength(outp, temp);
4463 /* the data area is a variable block, which has a 5 (already there)
4464 * followed by the length of the # of data bytes. We now know this to
4465 * be "temp," although that includes the 3 bytes of vbl block header.
4466 * Deduct for them and fill in the length field.
4468 temp -= 3; /* deduct vbl block info */
4469 osi_assert(temp == (43 * returnedNames));
4470 origOp[1] = (char)(temp & 0xff);
4471 origOp[2] = (char)((temp>>8) & 0xff);
4472 if (returnedNames == 0)
4473 smb_DeleteDirSearch(dsp);
4474 smb_ReleaseDirSearch(dsp);
4475 cm_ReleaseSCache(scp);
4476 cm_ReleaseUser(userp);
4480 /* verify that this is a valid path to a directory. I don't know why they
4481 * don't use the get file attributes call.
4483 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4487 cm_scache_t *rootScp;
4488 cm_scache_t *newScp;
4497 pathp = smb_GetSMBData(inp, NULL);
4498 pathp = smb_ParseASCIIBlock(pathp, NULL);
4500 return CM_ERROR_BADFD;
4501 if (smb_StoreAnsiFilenames)
4502 OemToChar(pathp,pathp);
4503 osi_Log1(smb_logp, "SMB receive check path %s",
4504 osi_LogSaveString(smb_logp, pathp));
4506 rootScp = cm_data.rootSCachep;
4508 userp = smb_GetUserFromVCP(vcp, inp);
4510 caseFold = CM_FLAG_CASEFOLD;
4512 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4514 cm_ReleaseUser(userp);
4515 return CM_ERROR_NOSUCHPATH;
4517 code = cm_NameI(rootScp, pathp,
4518 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4519 userp, tidPathp, &req, &newScp);
4522 cm_ReleaseUser(userp);
4527 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4528 cm_ReleaseSCache(newScp);
4529 cm_ReleaseUser(userp);
4530 if ( WANTS_DFS_PATHNAMES(inp) )
4531 return CM_ERROR_PATH_NOT_COVERED;
4533 return CM_ERROR_BADSHARENAME;
4535 #endif /* DFS_SUPPORT */
4537 /* now lock the vnode with a callback; returns with newScp locked */
4538 lock_ObtainMutex(&newScp->mx);
4539 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4540 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4541 if (code && code != CM_ERROR_NOACCESS) {
4542 lock_ReleaseMutex(&newScp->mx);
4543 cm_ReleaseSCache(newScp);
4544 cm_ReleaseUser(userp);
4548 attrs = smb_Attributes(newScp);
4550 if (!(attrs & SMB_ATTR_DIRECTORY))
4551 code = CM_ERROR_NOTDIR;
4553 lock_ReleaseMutex(&newScp->mx);
4555 cm_ReleaseSCache(newScp);
4556 cm_ReleaseUser(userp);
4560 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4564 cm_scache_t *rootScp;
4565 unsigned short attribute;
4567 cm_scache_t *newScp;
4576 /* decode basic attributes we're passed */
4577 attribute = smb_GetSMBParm(inp, 0);
4578 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4580 pathp = smb_GetSMBData(inp, NULL);
4581 pathp = smb_ParseASCIIBlock(pathp, NULL);
4583 return CM_ERROR_BADSMB;
4584 if (smb_StoreAnsiFilenames)
4585 OemToChar(pathp,pathp);
4587 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4588 dosTime, attribute);
4590 rootScp = cm_data.rootSCachep;
4592 userp = smb_GetUserFromVCP(vcp, inp);
4594 caseFold = CM_FLAG_CASEFOLD;
4596 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4598 cm_ReleaseUser(userp);
4599 return CM_ERROR_NOSUCHFILE;
4601 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4602 tidPathp, &req, &newScp);
4605 cm_ReleaseUser(userp);
4610 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4611 cm_ReleaseSCache(newScp);
4612 cm_ReleaseUser(userp);
4613 if ( WANTS_DFS_PATHNAMES(inp) )
4614 return CM_ERROR_PATH_NOT_COVERED;
4616 return CM_ERROR_BADSHARENAME;
4618 #endif /* DFS_SUPPORT */
4620 /* now lock the vnode with a callback; returns with newScp locked; we
4621 * need the current status to determine what the new status is, in some
4624 lock_ObtainMutex(&newScp->mx);
4625 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4626 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4628 lock_ReleaseMutex(&newScp->mx);
4629 cm_ReleaseSCache(newScp);
4630 cm_ReleaseUser(userp);
4634 /* Check for RO volume */
4635 if (newScp->flags & CM_SCACHEFLAG_RO) {
4636 lock_ReleaseMutex(&newScp->mx);
4637 cm_ReleaseSCache(newScp);
4638 cm_ReleaseUser(userp);
4639 return CM_ERROR_READONLY;
4642 /* prepare for setattr call */
4645 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4646 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4648 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4649 /* we're told to make a writable file read-only */
4650 attr.unixModeBits = newScp->unixModeBits & ~0222;
4651 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4653 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4654 /* we're told to make a read-only file writable */
4655 attr.unixModeBits = newScp->unixModeBits | 0222;
4656 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4658 lock_ReleaseMutex(&newScp->mx);
4660 /* now call setattr */
4662 code = cm_SetAttr(newScp, &attr, userp, &req);
4666 cm_ReleaseSCache(newScp);
4667 cm_ReleaseUser(userp);
4672 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4676 cm_scache_t *rootScp;
4677 cm_scache_t *newScp, *dscp;
4689 pathp = smb_GetSMBData(inp, NULL);
4690 pathp = smb_ParseASCIIBlock(pathp, NULL);
4692 return CM_ERROR_BADSMB;
4694 if (*pathp == 0) /* null path */
4697 if (smb_StoreAnsiFilenames)
4698 OemToChar(pathp,pathp);
4700 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4701 osi_LogSaveString(smb_logp, pathp));
4703 rootScp = cm_data.rootSCachep;
4705 userp = smb_GetUserFromVCP(vcp, inp);
4707 /* we shouldn't need this for V3 requests, but we seem to */
4708 caseFold = CM_FLAG_CASEFOLD;
4710 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4712 cm_ReleaseUser(userp);
4713 return CM_ERROR_NOSUCHFILE;
4717 * XXX Strange hack XXX
4719 * As of Patch 5 (16 July 97), we are having the following problem:
4720 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4721 * requests to look up "desktop.ini" in all the subdirectories.
4722 * This can cause zillions of timeouts looking up non-existent cells
4723 * and volumes, especially in the top-level directory.
4725 * We have not found any way to avoid this or work around it except
4726 * to explicitly ignore the requests for mount points that haven't
4727 * yet been evaluated and for directories that haven't yet been
4730 * We should modify this hack to provide a fake desktop.ini file
4731 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4733 spacep = inp->spacep;
4734 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4735 #ifndef SPECIAL_FOLDERS
4736 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4737 code = cm_NameI(rootScp, spacep->data,
4738 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4739 userp, tidPathp, &req, &dscp);
4742 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4743 if ( WANTS_DFS_PATHNAMES(inp) )
4744 return CM_ERROR_PATH_NOT_COVERED;
4746 return CM_ERROR_BADSHARENAME;
4748 #endif /* DFS_SUPPORT */
4749 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4750 code = CM_ERROR_NOSUCHFILE;
4751 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4752 cm_buf_t *bp = buf_Find(dscp, &hzero);
4756 code = CM_ERROR_NOSUCHFILE;
4758 cm_ReleaseSCache(dscp);
4760 cm_ReleaseUser(userp);
4765 #endif /* SPECIAL_FOLDERS */
4767 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4768 tidPathp, &req, &newScp);
4770 cm_ReleaseUser(userp);
4775 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4776 cm_ReleaseSCache(newScp);
4777 cm_ReleaseUser(userp);
4778 if ( WANTS_DFS_PATHNAMES(inp) )
4779 return CM_ERROR_PATH_NOT_COVERED;
4781 return CM_ERROR_BADSHARENAME;
4783 #endif /* DFS_SUPPORT */
4785 /* now lock the vnode with a callback; returns with newScp locked */
4786 lock_ObtainMutex(&newScp->mx);
4787 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4788 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4790 lock_ReleaseMutex(&newScp->mx);
4791 cm_ReleaseSCache(newScp);
4792 cm_ReleaseUser(userp);
4797 /* use smb_Attributes instead. Also the fact that a file is
4798 * in a readonly volume doesn't mean it shojuld be marked as RO
4800 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4801 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4802 newScp->fileType == CM_SCACHETYPE_INVALID)
4803 attrs = SMB_ATTR_DIRECTORY;
4806 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4807 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4809 attrs = smb_Attributes(newScp);
4812 smb_SetSMBParm(outp, 0, attrs);
4814 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4815 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4816 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4817 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4818 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4819 smb_SetSMBParm(outp, 5, 0);
4820 smb_SetSMBParm(outp, 6, 0);
4821 smb_SetSMBParm(outp, 7, 0);
4822 smb_SetSMBParm(outp, 8, 0);
4823 smb_SetSMBParm(outp, 9, 0);
4824 smb_SetSMBDataLength(outp, 0);
4825 lock_ReleaseMutex(&newScp->mx);
4827 cm_ReleaseSCache(newScp);
4828 cm_ReleaseUser(userp);
4833 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4837 osi_Log0(smb_logp, "SMB receive tree disconnect");
4839 /* find the tree and free it */
4840 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4842 lock_ObtainWrite(&smb_rctLock);
4844 lock_ReleaseWrite(&smb_rctLock);
4845 smb_ReleaseTID(tidp);
4851 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4869 pathp = smb_GetSMBData(inp, NULL);
4870 pathp = smb_ParseASCIIBlock(pathp, NULL);
4871 if (smb_StoreAnsiFilenames)
4872 OemToChar(pathp,pathp);
4874 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4876 #ifdef DEBUG_VERBOSE
4880 hexpath = osi_HexifyString( pathp );
4881 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4886 share = smb_GetSMBParm(inp, 0);
4887 attribute = smb_GetSMBParm(inp, 1);
4889 spacep = inp->spacep;
4890 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4891 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4892 /* special case magic file name for receiving IOCTL requests
4893 * (since IOCTL calls themselves aren't getting through).
4895 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4896 smb_SetupIoctlFid(fidp, spacep);
4897 smb_SetSMBParm(outp, 0, fidp->fid);
4898 smb_SetSMBParm(outp, 1, 0); /* attrs */
4899 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4900 smb_SetSMBParm(outp, 3, 0);
4901 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4902 smb_SetSMBParm(outp, 5, 0x7fff);
4903 /* pass the open mode back */
4904 smb_SetSMBParm(outp, 6, (share & 0xf));
4905 smb_SetSMBDataLength(outp, 0);
4906 smb_ReleaseFID(fidp);
4910 userp = smb_GetUserFromVCP(vcp, inp);
4912 caseFold = CM_FLAG_CASEFOLD;
4914 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4916 cm_ReleaseUser(userp);
4917 return CM_ERROR_NOSUCHPATH;
4919 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4920 tidPathp, &req, &scp);
4923 cm_ReleaseUser(userp);
4928 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4929 cm_ReleaseSCache(scp);
4930 cm_ReleaseUser(userp);
4931 if ( WANTS_DFS_PATHNAMES(inp) )
4932 return CM_ERROR_PATH_NOT_COVERED;
4934 return CM_ERROR_BADSHARENAME;
4936 #endif /* DFS_SUPPORT */
4938 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4940 cm_ReleaseSCache(scp);
4941 cm_ReleaseUser(userp);
4945 /* don't need callback to check file type, since file types never
4946 * change, and namei and cm_Lookup all stat the object at least once on
4947 * a successful return.
4949 if (scp->fileType != CM_SCACHETYPE_FILE) {
4950 cm_ReleaseSCache(scp);
4951 cm_ReleaseUser(userp);
4952 return CM_ERROR_ISDIR;
4955 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4958 /* save a pointer to the vnode */
4962 fidp->userp = userp;
4964 lock_ObtainMutex(&fidp->mx);
4965 if ((share & 0xf) == 0)
4966 fidp->flags |= SMB_FID_OPENREAD;
4967 else if ((share & 0xf) == 1)
4968 fidp->flags |= SMB_FID_OPENWRITE;
4970 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4971 lock_ReleaseMutex(&fidp->mx);
4973 lock_ObtainMutex(&scp->mx);
4974 smb_SetSMBParm(outp, 0, fidp->fid);
4975 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4976 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4977 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4978 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4979 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4980 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4981 /* pass the open mode back; XXXX add access checks */
4982 smb_SetSMBParm(outp, 6, (share & 0xf));
4983 smb_SetSMBDataLength(outp, 0);
4984 lock_ReleaseMutex(&scp->mx);
4987 cm_Open(scp, 0, userp);
4989 /* send and free packet */
4990 smb_ReleaseFID(fidp);
4991 cm_ReleaseUser(userp);
4992 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4996 typedef struct smb_unlinkRock {
5001 char *maskp; /* pointer to the star pattern */
5006 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5009 smb_unlinkRock_t *rockp;
5017 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5018 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5019 caseFold |= CM_FLAG_8DOT3;
5021 matchName = dep->name;
5022 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
5024 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5025 !cm_Is8Dot3(dep->name)) {
5026 cm_Gen8Dot3Name(dep, shortName, NULL);
5027 matchName = shortName;
5028 /* 8.3 matches are always case insensitive */
5029 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5032 osi_Log1(smb_logp, "Unlinking %s",
5033 osi_LogSaveString(smb_logp, matchName));
5034 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
5035 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5036 smb_NotifyChange(FILE_ACTION_REMOVED,
5037 FILE_NOTIFY_CHANGE_FILE_NAME,
5038 dscp, dep->name, NULL, TRUE);
5042 /* If we made a case sensitive exact match, we might as well quit now. */
5043 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
5044 code = CM_ERROR_STOPNOW;
5052 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5061 smb_unlinkRock_t rock;
5070 attribute = smb_GetSMBParm(inp, 0);
5072 tp = smb_GetSMBData(inp, NULL);
5073 pathp = smb_ParseASCIIBlock(tp, &tp);
5074 if (smb_StoreAnsiFilenames)
5075 OemToChar(pathp,pathp);
5077 osi_Log1(smb_logp, "SMB receive unlink %s",
5078 osi_LogSaveString(smb_logp, pathp));
5080 spacep = inp->spacep;
5081 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5083 userp = smb_GetUserFromVCP(vcp, inp);
5085 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5087 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5089 cm_ReleaseUser(userp);
5090 return CM_ERROR_NOSUCHPATH;
5092 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5095 cm_ReleaseUser(userp);
5100 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5101 cm_ReleaseSCache(dscp);
5102 cm_ReleaseUser(userp);
5103 if ( WANTS_DFS_PATHNAMES(inp) )
5104 return CM_ERROR_PATH_NOT_COVERED;
5106 return CM_ERROR_BADSHARENAME;
5108 #endif /* DFS_SUPPORT */
5110 /* otherwise, scp points to the parent directory. */
5117 rock.maskp = smb_FindMask(pathp);
5118 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5121 thyper.HighPart = 0;
5127 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5128 * match. If that fails, we do a case insensitve match.
5130 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5131 !smb_IsStarMask(rock.maskp)) {
5132 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5135 thyper.HighPart = 0;
5136 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5141 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5143 if (code == CM_ERROR_STOPNOW)
5146 cm_ReleaseUser(userp);
5148 cm_ReleaseSCache(dscp);
5150 if (code == 0 && !rock.any)
5151 code = CM_ERROR_NOSUCHFILE;
5155 typedef struct smb_renameRock {
5156 cm_scache_t *odscp; /* old dir */
5157 cm_scache_t *ndscp; /* new dir */
5158 cm_user_t *userp; /* user */
5159 cm_req_t *reqp; /* request struct */
5160 smb_vc_t *vcp; /* virtual circuit */
5161 char *maskp; /* pointer to star pattern of old file name */
5162 int flags; /* tilde, casefold, etc */
5163 char *newNamep; /* ptr to the new file's name */
5166 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5169 smb_renameRock_t *rockp;
5174 rockp = (smb_renameRock_t *) vrockp;
5176 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5177 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5178 caseFold |= CM_FLAG_8DOT3;
5180 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5182 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5183 !cm_Is8Dot3(dep->name)) {
5184 cm_Gen8Dot3Name(dep, shortName, NULL);
5185 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5188 code = cm_Rename(rockp->odscp, dep->name,
5189 rockp->ndscp, rockp->newNamep, rockp->userp,
5191 /* if the call worked, stop doing the search now, since we
5192 * really only want to rename one file.
5195 code = CM_ERROR_STOPNOW;
5204 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5207 cm_space_t *spacep = NULL;
5208 smb_renameRock_t rock;
5209 cm_scache_t *oldDscp = NULL;
5210 cm_scache_t *newDscp = NULL;
5211 cm_scache_t *tmpscp= NULL;
5212 cm_scache_t *tmpscp2 = NULL;
5222 userp = smb_GetUserFromVCP(vcp, inp);
5223 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5225 cm_ReleaseUser(userp);
5226 return CM_ERROR_NOSUCHPATH;
5230 spacep = inp->spacep;
5231 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5233 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5234 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5235 userp, tidPathp, &req, &oldDscp);
5237 cm_ReleaseUser(userp);
5242 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5243 cm_ReleaseSCache(oldDscp);
5244 cm_ReleaseUser(userp);
5245 if ( WANTS_DFS_PATHNAMES(inp) )
5246 return CM_ERROR_PATH_NOT_COVERED;
5248 return CM_ERROR_BADSHARENAME;
5250 #endif /* DFS_SUPPORT */
5252 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5253 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5254 userp, tidPathp, &req, &newDscp);
5257 cm_ReleaseSCache(oldDscp);
5258 cm_ReleaseUser(userp);
5263 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5264 cm_ReleaseSCache(oldDscp);
5265 cm_ReleaseSCache(newDscp);
5266 cm_ReleaseUser(userp);
5267 if ( WANTS_DFS_PATHNAMES(inp) )
5268 return CM_ERROR_PATH_NOT_COVERED;
5270 return CM_ERROR_BADSHARENAME;
5272 #endif /* DFS_SUPPORT */
5275 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5276 * next, get the component names, and lower case them.
5279 /* handle the old name first */
5281 oldLastNamep = oldPathp;
5285 /* and handle the new name, too */
5287 newLastNamep = newPathp;
5291 /* TODO: The old name could be a wildcard. The new name must not be */
5293 /* do the vnode call */
5294 rock.odscp = oldDscp;
5295 rock.ndscp = newDscp;
5299 rock.maskp = oldLastNamep;
5300 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5301 rock.newNamep = newLastNamep;
5303 /* Check if the file already exists; if so return error */
5304 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5305 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5306 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5307 osi_LogSaveString(afsd_logp, newLastNamep));
5309 /* Check if the old and the new names differ only in case. If so return
5310 * success, else return CM_ERROR_EXISTS
5312 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5314 /* This would be a success only if the old file is *as same as* the new file */
5315 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5317 if (tmpscp == tmpscp2)
5320 code = CM_ERROR_EXISTS;
5321 cm_ReleaseSCache(tmpscp2);
5324 code = CM_ERROR_NOSUCHFILE;
5327 /* file exist, do not rename, also fixes move */
5328 osi_Log0(smb_logp, "Can't rename. Target already exists");
5329 code = CM_ERROR_EXISTS;
5333 cm_ReleaseSCache(tmpscp);
5334 cm_ReleaseSCache(newDscp);
5335 cm_ReleaseSCache(oldDscp);
5336 cm_ReleaseUser(userp);
5340 /* Now search the directory for the pattern, and do the appropriate rename when found */
5341 thyper.LowPart = 0; /* search dir from here */
5342 thyper.HighPart = 0;
5344 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5345 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5347 if (code == CM_ERROR_STOPNOW)
5350 code = CM_ERROR_NOSUCHFILE;
5352 /* Handle Change Notification */
5354 * Being lazy, not distinguishing between files and dirs in this
5355 * filter, since we'd have to do a lookup.
5357 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5358 if (oldDscp == newDscp) {
5359 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5360 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5361 filter, oldDscp, oldLastNamep,
5362 newLastNamep, TRUE);
5364 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5365 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5366 filter, oldDscp, oldLastNamep,
5368 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5369 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5370 filter, newDscp, newLastNamep,
5375 cm_ReleaseSCache(tmpscp);
5376 cm_ReleaseUser(userp);
5377 cm_ReleaseSCache(oldDscp);
5378 cm_ReleaseSCache(newDscp);
5383 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5386 cm_space_t *spacep = NULL;
5387 cm_scache_t *oldDscp = NULL;
5388 cm_scache_t *newDscp = NULL;
5389 cm_scache_t *tmpscp= NULL;
5390 cm_scache_t *tmpscp2 = NULL;
5391 cm_scache_t *sscp = NULL;
5400 userp = smb_GetUserFromVCP(vcp, inp);
5402 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5404 cm_ReleaseUser(userp);
5405 return CM_ERROR_NOSUCHPATH;
5410 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5412 spacep = inp->spacep;
5413 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5415 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5416 userp, tidPathp, &req, &oldDscp);
5418 cm_ReleaseUser(userp);
5423 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5424 cm_ReleaseSCache(oldDscp);
5425 cm_ReleaseUser(userp);
5426 if ( WANTS_DFS_PATHNAMES(inp) )
5427 return CM_ERROR_PATH_NOT_COVERED;
5429 return CM_ERROR_BADSHARENAME;
5431 #endif /* DFS_SUPPORT */
5433 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5434 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5435 userp, tidPathp, &req, &newDscp);
5437 cm_ReleaseSCache(oldDscp);
5438 cm_ReleaseUser(userp);
5443 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5444 cm_ReleaseSCache(newDscp);
5445 cm_ReleaseSCache(oldDscp);
5446 cm_ReleaseUser(userp);
5447 if ( WANTS_DFS_PATHNAMES(inp) )
5448 return CM_ERROR_PATH_NOT_COVERED;
5450 return CM_ERROR_BADSHARENAME;
5452 #endif /* DFS_SUPPORT */
5454 /* Now, although we did two lookups for the two directories (because the same
5455 * directory can be referenced through different paths), we only allow hard links
5456 * within the same directory. */
5457 if (oldDscp != newDscp) {
5458 cm_ReleaseSCache(oldDscp);
5459 cm_ReleaseSCache(newDscp);
5460 cm_ReleaseUser(userp);
5461 return CM_ERROR_CROSSDEVLINK;
5464 /* handle the old name first */
5466 oldLastNamep = oldPathp;
5470 /* and handle the new name, too */
5472 newLastNamep = newPathp;
5476 /* now lookup the old name */
5477 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5478 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5480 cm_ReleaseSCache(oldDscp);
5481 cm_ReleaseSCache(newDscp);
5482 cm_ReleaseUser(userp);
5486 /* Check if the file already exists; if so return error */
5487 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5488 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5489 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5490 osi_LogSaveString(afsd_logp, newLastNamep));
5492 /* if the existing link is to the same file, then we return success */
5494 if(sscp == tmpscp) {
5497 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5498 code = CM_ERROR_EXISTS;
5503 cm_ReleaseSCache(tmpscp);
5504 cm_ReleaseSCache(sscp);
5505 cm_ReleaseSCache(newDscp);
5506 cm_ReleaseSCache(oldDscp);
5507 cm_ReleaseUser(userp);
5511 /* now create the hardlink */
5512 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5513 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5514 osi_Log1(smb_logp," Link returns 0x%x", code);
5516 /* Handle Change Notification */
5518 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5519 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5520 smb_NotifyChange(FILE_ACTION_ADDED,
5521 filter, newDscp, newLastNamep,
5526 cm_ReleaseSCache(tmpscp);
5527 cm_ReleaseUser(userp);
5528 cm_ReleaseSCache(sscp);
5529 cm_ReleaseSCache(oldDscp);
5530 cm_ReleaseSCache(newDscp);
5535 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5541 tp = smb_GetSMBData(inp, NULL);
5542 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5543 if (smb_StoreAnsiFilenames)
5544 OemToChar(oldPathp,oldPathp);
5545 newPathp = smb_ParseASCIIBlock(tp, &tp);
5546 if (smb_StoreAnsiFilenames)
5547 OemToChar(newPathp,newPathp);
5549 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5550 osi_LogSaveString(smb_logp, oldPathp),
5551 osi_LogSaveString(smb_logp, newPathp));
5553 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5558 typedef struct smb_rmdirRock {
5562 char *maskp; /* pointer to the star pattern */
5567 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5570 smb_rmdirRock_t *rockp;
5575 rockp = (smb_rmdirRock_t *) vrockp;
5577 matchName = dep->name;
5578 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5579 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5581 match = (strcmp(matchName, rockp->maskp) == 0);
5583 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5584 !cm_Is8Dot3(dep->name)) {
5585 cm_Gen8Dot3Name(dep, shortName, NULL);
5586 matchName = shortName;
5587 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5590 osi_Log1(smb_logp, "Removing directory %s",
5591 osi_LogSaveString(smb_logp, matchName));
5592 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5593 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5594 smb_NotifyChange(FILE_ACTION_REMOVED,
5595 FILE_NOTIFY_CHANGE_DIR_NAME,
5596 dscp, dep->name, NULL, TRUE);
5605 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5613 smb_rmdirRock_t rock;
5622 tp = smb_GetSMBData(inp, NULL);
5623 pathp = smb_ParseASCIIBlock(tp, &tp);
5624 if (smb_StoreAnsiFilenames)
5625 OemToChar(pathp,pathp);
5627 spacep = inp->spacep;
5628 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5630 userp = smb_GetUserFromVCP(vcp, inp);
5632 caseFold = CM_FLAG_CASEFOLD;
5634 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5636 cm_ReleaseUser(userp);
5637 return CM_ERROR_NOSUCHPATH;
5639 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5640 userp, tidPathp, &req, &dscp);
5643 cm_ReleaseUser(userp);
5648 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5649 cm_ReleaseSCache(dscp);
5650 cm_ReleaseUser(userp);
5651 if ( WANTS_DFS_PATHNAMES(inp) )
5652 return CM_ERROR_PATH_NOT_COVERED;
5654 return CM_ERROR_BADSHARENAME;
5656 #endif /* DFS_SUPPORT */
5658 /* otherwise, scp points to the parent directory. */
5665 rock.maskp = lastNamep;
5666 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5669 thyper.HighPart = 0;
5673 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5674 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5675 if (code == 0 && !rock.any) {
5677 thyper.HighPart = 0;
5678 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5679 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5682 cm_ReleaseUser(userp);
5684 cm_ReleaseSCache(dscp);
5686 if (code == 0 && !rock.any)
5687 code = CM_ERROR_NOSUCHFILE;
5691 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5701 fid = smb_GetSMBParm(inp, 0);
5703 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5705 fid = smb_ChainFID(fid, inp);
5706 fidp = smb_FindFID(vcp, fid, 0);
5708 return CM_ERROR_BADFD;
5710 lock_ObtainMutex(&fidp->mx);
5711 if (fidp->flags & SMB_FID_IOCTL) {
5712 lock_ReleaseMutex(&fidp->mx);
5713 smb_ReleaseFID(fidp);
5714 return CM_ERROR_BADFD;
5716 lock_ReleaseMutex(&fidp->mx);
5718 userp = smb_GetUserFromVCP(vcp, inp);
5720 lock_ObtainMutex(&fidp->mx);
5721 if (fidp->flags & SMB_FID_OPENWRITE) {
5722 cm_scache_t * scp = fidp->scp;
5724 lock_ReleaseMutex(&fidp->mx);
5725 code = cm_FSync(scp, userp, &req);
5726 cm_ReleaseSCache(scp);
5729 lock_ReleaseMutex(&fidp->mx);
5732 smb_ReleaseFID(fidp);
5734 cm_ReleaseUser(userp);
5739 struct smb_FullNameRock {
5745 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5749 struct smb_FullNameRock *vrockp;
5751 vrockp = (struct smb_FullNameRock *)rockp;
5753 if (!cm_Is8Dot3(dep->name)) {
5754 cm_Gen8Dot3Name(dep, shortName, NULL);
5756 if (cm_stricmp(shortName, vrockp->name) == 0) {
5757 vrockp->fullName = strdup(dep->name);
5758 return CM_ERROR_STOPNOW;
5761 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5762 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5763 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5764 vrockp->fullName = strdup(dep->name);
5765 return CM_ERROR_STOPNOW;
5770 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5771 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5773 struct smb_FullNameRock rock;
5779 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5780 if (code == CM_ERROR_STOPNOW)
5781 *newPathp = rock.fullName;
5783 *newPathp = strdup(pathp);
5786 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5787 afs_uint32 dosTime) {
5790 cm_scache_t *dscp = fidp->NTopen_dscp;
5791 char *pathp = fidp->NTopen_pathp;
5794 osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
5795 fidp, fidp->fid, vcp);
5798 lock_ObtainMutex(&fidp->mx);
5799 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5800 lock_ReleaseMutex(&fidp->mx);
5801 osi_Log0(smb_logp, " No user specified. Not closing fid");
5802 return CM_ERROR_BADFD;
5805 userp = fidp->userp; /* no hold required since fidp is held
5806 throughout the function */
5807 lock_ReleaseMutex(&fidp->mx);
5812 lock_ObtainWrite(&smb_rctLock);
5814 osi_Log0(smb_logp, " Fid already closed.");
5815 lock_ReleaseWrite(&smb_rctLock);
5816 return CM_ERROR_BADFD;
5819 lock_ReleaseWrite(&smb_rctLock);
5821 lock_ObtainMutex(&fidp->mx);
5822 /* Don't jump the gun on an async raw write */
5823 while (fidp->raw_writers) {
5824 lock_ReleaseMutex(&fidp->mx);
5825 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5826 lock_ObtainMutex(&fidp->mx);
5833 /* watch for ioctl closes, and read-only opens */
5835 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5836 == SMB_FID_OPENWRITE) {
5837 if (dosTime != 0 && dosTime != -1) {
5838 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5839 /* This fixes defect 10958 */
5840 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5841 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5843 lock_ReleaseMutex(&fidp->mx);
5844 code = cm_FSync(scp, userp, &req);
5845 lock_ObtainMutex(&fidp->mx);
5850 /* unlock any pending locks */
5851 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5852 scp->fileType == CM_SCACHETYPE_FILE) {
5856 lock_ReleaseMutex(&fidp->mx);
5858 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5860 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5861 lock_ObtainMutex(&scp->mx);
5863 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5864 CM_SCACHESYNC_NEEDCALLBACK
5865 | CM_SCACHESYNC_GETSTATUS
5866 | CM_SCACHESYNC_LOCK);
5870 "smb CoreClose SyncOp failure code 0x%x", tcode);
5871 goto post_syncopdone;
5874 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5876 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5880 lock_ReleaseMutex(&scp->mx);
5881 lock_ObtainMutex(&fidp->mx);
5884 if (fidp->flags & SMB_FID_DELONCLOSE) {
5887 lock_ReleaseMutex(&fidp->mx);
5888 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5889 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5890 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5891 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5892 smb_NotifyChange(FILE_ACTION_REMOVED,
5893 FILE_NOTIFY_CHANGE_DIR_NAME,
5894 dscp, fullPathp, NULL, TRUE);
5896 code = cm_Unlink(dscp, fullPathp, userp, &req);
5897 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5898 smb_NotifyChange(FILE_ACTION_REMOVED,
5899 FILE_NOTIFY_CHANGE_FILE_NAME,
5900 dscp, fullPathp, NULL, TRUE);
5903 lock_ObtainMutex(&fidp->mx);
5904 fidp->flags &= ~SMB_FID_DELONCLOSE;
5907 /* if this was a newly created file, then clear the creator
5908 * in the stat cache entry. */
5909 if (fidp->flags & SMB_FID_CREATED) {
5910 lock_ObtainMutex(&scp->mx);
5911 if (scp->creator == userp)
5912 scp->creator = NULL;
5913 lock_ReleaseMutex(&scp->mx);
5914 fidp->flags &= ~SMB_FID_CREATED;
5917 if (fidp->flags & SMB_FID_NTOPEN) {
5918 fidp->NTopen_dscp = NULL;
5919 fidp->NTopen_pathp = NULL;
5920 fidp->flags &= ~SMB_FID_NTOPEN;
5922 if (fidp->NTopen_wholepathp) {
5923 free(fidp->NTopen_wholepathp);
5924 fidp->NTopen_wholepathp = NULL;
5926 lock_ReleaseMutex(&fidp->mx);
5929 cm_ReleaseSCache(dscp);
5932 cm_ReleaseSCache(scp);
5940 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5948 fid = smb_GetSMBParm(inp, 0);
5949 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5951 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5953 fid = smb_ChainFID(fid, inp);
5954 fidp = smb_FindFID(vcp, fid, 0);
5956 return CM_ERROR_BADFD;
5959 userp = smb_GetUserFromVCP(vcp, inp);
5961 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5963 smb_ReleaseFID(fidp);
5964 cm_ReleaseUser(userp);
5969 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5972 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5973 cm_user_t *userp, long *readp)
5975 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5976 cm_user_t *userp, long *readp, int dosflag)
5983 osi_hyper_t fileLength;
5985 osi_hyper_t lastByte;
5986 osi_hyper_t bufferOffset;
5987 long bufIndex, nbytes;
5997 lock_ObtainMutex(&fidp->mx);
5999 lock_ObtainMutex(&scp->mx);
6001 if (offset.HighPart == 0) {
6002 chunk = offset.LowPart >> cm_logChunkSize;
6003 if (chunk != fidp->curr_chunk) {
6004 fidp->prev_chunk = fidp->curr_chunk;
6005 fidp->curr_chunk = chunk;
6007 if (fidp->curr_chunk == fidp->prev_chunk + 1)
6010 lock_ReleaseMutex(&fidp->mx);
6012 /* start by looking up the file's end */
6013 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6014 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6015 if (code) goto done;
6017 /* now we have the entry locked, look up the length */
6018 fileLength = scp->length;
6020 /* adjust count down so that it won't go past EOF */
6021 thyper.LowPart = count;
6022 thyper.HighPart = 0;
6023 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6025 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6026 /* we'd read past EOF, so just stop at fileLength bytes.
6027 * Start by computing how many bytes remain in the file.
6029 thyper = LargeIntegerSubtract(fileLength, offset);
6031 /* if we are past EOF, read 0 bytes */
6032 if (LargeIntegerLessThanZero(thyper))
6035 count = thyper.LowPart;
6040 /* now, copy the data one buffer at a time,
6041 * until we've filled the request packet
6044 /* if we've copied all the data requested, we're done */
6045 if (count <= 0) break;
6047 /* otherwise, load up a buffer of data */
6048 thyper.HighPart = offset.HighPart;
6049 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6050 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6053 buf_Release(bufferp);
6056 lock_ReleaseMutex(&scp->mx);
6058 lock_ObtainRead(&scp->bufCreateLock);
6059 code = buf_Get(scp, &thyper, &bufferp);
6060 lock_ReleaseRead(&scp->bufCreateLock);
6062 lock_ObtainMutex(&scp->mx);
6063 if (code) goto done;
6064 bufferOffset = thyper;
6066 /* now get the data in the cache */
6068 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6069 CM_SCACHESYNC_NEEDCALLBACK |
6070 CM_SCACHESYNC_READ);
6071 if (code) goto done;
6073 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6075 /* otherwise, load the buffer and try again */
6076 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6080 buf_Release(bufferp);
6084 } /* if (wrong buffer) ... */
6086 /* now we have the right buffer loaded. Copy out the
6087 * data from here to the user's buffer.
6089 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6091 /* and figure out how many bytes we want from this buffer */
6092 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6093 if (nbytes > count) nbytes = count; /* don't go past EOF */
6095 /* now copy the data */
6098 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
6101 memcpy(op, bufferp->datap + bufIndex, nbytes);
6103 /* adjust counters, pointers, etc. */
6106 thyper.LowPart = nbytes;
6107 thyper.HighPart = 0;
6108 offset = LargeIntegerAdd(thyper, offset);
6112 lock_ReleaseMutex(&scp->mx);
6114 buf_Release(bufferp);
6116 if (code == 0 && sequential)
6117 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6123 * smb_WriteData -- common code for Write and Raw Write
6126 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6127 cm_user_t *userp, long *writtenp)
6129 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6130 cm_user_t *userp, long *writtenp, int dosflag)
6137 osi_hyper_t fileLength; /* file's length at start of write */
6138 osi_hyper_t minLength; /* don't read past this */
6139 long nbytes; /* # of bytes to transfer this iteration */
6141 osi_hyper_t thyper; /* hyper tmp variable */
6142 osi_hyper_t bufferOffset;
6143 long bufIndex; /* index in buffer where our data is */
6145 osi_hyper_t writeBackOffset;/* offset of region to write back when
6150 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6151 fidp->fid, offsetp->LowPart, count);
6161 lock_ObtainMutex(&fidp->mx);
6162 /* make sure we have a writable FD */
6163 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6164 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6165 fidp->fid, fidp->flags);
6166 lock_ReleaseMutex(&fidp->mx);
6167 code = CM_ERROR_BADFDOP;
6173 lock_ReleaseMutex(&fidp->mx);
6175 lock_ObtainMutex(&scp->mx);
6176 /* start by looking up the file's end */
6177 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6178 CM_SCACHESYNC_NEEDCALLBACK
6179 | CM_SCACHESYNC_SETSTATUS
6180 | CM_SCACHESYNC_GETSTATUS);
6184 /* now we have the entry locked, look up the length */
6185 fileLength = scp->length;
6186 minLength = fileLength;
6187 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6188 minLength = scp->serverLength;
6190 /* adjust file length if we extend past EOF */
6191 thyper.LowPart = count;
6192 thyper.HighPart = 0;
6193 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6194 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6195 /* we'd write past EOF, so extend the file */
6196 scp->mask |= CM_SCACHEMASK_LENGTH;
6197 scp->length = thyper;
6198 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6200 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6202 /* now, if the new position (thyper) and the old (offset) are in
6203 * different storeback windows, remember to store back the previous
6204 * storeback window when we're done with the write.
6206 if ((thyper.LowPart & (-cm_chunkSize)) !=
6207 (offset.LowPart & (-cm_chunkSize))) {
6208 /* they're different */
6210 writeBackOffset.HighPart = offset.HighPart;
6211 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6216 /* now, copy the data one buffer at a time, until we've filled the
6219 /* if we've copied all the data requested, we're done */
6223 /* handle over quota or out of space */
6224 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6225 *writtenp = written;
6226 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6230 /* otherwise, load up a buffer of data */
6231 thyper.HighPart = offset.HighPart;
6232 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6233 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6236 lock_ReleaseMutex(&bufferp->mx);
6237 buf_Release(bufferp);
6240 lock_ReleaseMutex(&scp->mx);
6242 lock_ObtainRead(&scp->bufCreateLock);
6243 code = buf_Get(scp, &thyper, &bufferp);
6244 lock_ReleaseRead(&scp->bufCreateLock);
6246 lock_ObtainMutex(&bufferp->mx);
6247 lock_ObtainMutex(&scp->mx);
6248 if (code) goto done;
6250 bufferOffset = thyper;
6252 /* now get the data in the cache */
6254 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6255 CM_SCACHESYNC_NEEDCALLBACK
6256 | CM_SCACHESYNC_WRITE
6257 | CM_SCACHESYNC_BUFLOCKED);
6261 /* If we're overwriting the entire buffer, or
6262 * if we're writing at or past EOF, mark the
6263 * buffer as current so we don't call
6264 * cm_GetBuffer. This skips the fetch from the
6265 * server in those cases where we're going to
6266 * obliterate all the data in the buffer anyway,
6267 * or in those cases where there is no useful
6268 * data at the server to start with.
6270 * Use minLength instead of scp->length, since
6271 * the latter has already been updated by this
6274 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6275 || LargeIntegerEqualTo(offset, bufferp->offset)
6276 && (count >= cm_data.buf_blockSize
6277 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6278 ConvertLongToLargeInteger(count)),
6280 if (count < cm_data.buf_blockSize
6281 && bufferp->dataVersion == -1)
6282 memset(bufferp->datap, 0,
6283 cm_data.buf_blockSize);
6284 bufferp->dataVersion = scp->dataVersion;
6287 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6289 /* otherwise, load the buffer and try again */
6290 lock_ReleaseMutex(&bufferp->mx);
6291 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6293 lock_ReleaseMutex(&scp->mx);
6294 lock_ObtainMutex(&bufferp->mx);
6295 lock_ObtainMutex(&scp->mx);
6299 lock_ReleaseMutex(&bufferp->mx);
6300 buf_Release(bufferp);
6304 } /* if (wrong buffer) ... */
6306 /* now we have the right buffer loaded. Copy out the
6307 * data from here to the user's buffer.
6309 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6311 /* and figure out how many bytes we want from this buffer */
6312 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6314 nbytes = count; /* don't go past end of request */
6316 /* now copy the data */
6319 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
6322 memcpy(bufferp->datap + bufIndex, op, nbytes);
6323 buf_SetDirty(bufferp);
6325 /* and record the last writer */
6326 if (bufferp->userp != userp) {
6329 cm_ReleaseUser(bufferp->userp);
6330 bufferp->userp = userp;
6333 /* adjust counters, pointers, etc. */
6337 thyper.LowPart = nbytes;
6338 thyper.HighPart = 0;
6339 offset = LargeIntegerAdd(thyper, offset);
6343 lock_ReleaseMutex(&scp->mx);
6346 lock_ReleaseMutex(&bufferp->mx);
6347 buf_Release(bufferp);
6350 lock_ObtainMutex(&fidp->mx);
6351 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6352 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6353 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6354 fidp->NTopen_dscp, fidp->NTopen_pathp,
6357 lock_ReleaseMutex(&fidp->mx);
6359 if (code == 0 && doWriteBack) {
6361 lock_ObtainMutex(&scp->mx);
6362 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6364 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6365 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6367 lock_ReleaseMutex(&scp->mx);
6368 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6369 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6372 cm_ReleaseSCache(scp);
6374 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6375 fidp->fid, code, *writtenp);
6379 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6382 long count, written = 0, total_written = 0;
6388 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6390 int inDataBlockCount;
6392 fd = smb_GetSMBParm(inp, 0);
6393 count = smb_GetSMBParm(inp, 1);
6394 offset.HighPart = 0; /* too bad */
6395 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6397 op = smb_GetSMBData(inp, NULL);
6398 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6400 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6401 fd, offset.LowPart, count);
6403 fd = smb_ChainFID(fd, inp);
6404 fidp = smb_FindFID(vcp, fd, 0);
6406 return CM_ERROR_BADFD;
6408 lock_ObtainMutex(&fidp->mx);
6409 if (fidp->flags & SMB_FID_IOCTL) {
6410 lock_ReleaseMutex(&fidp->mx);
6411 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6412 smb_ReleaseFID(fidp);
6415 lock_ReleaseMutex(&fidp->mx);
6416 userp = smb_GetUserFromVCP(vcp, inp);
6418 /* special case: 0 bytes transferred means truncate to this position */
6424 truncAttr.mask = CM_ATTRMASK_LENGTH;
6425 truncAttr.length.LowPart = offset.LowPart;
6426 truncAttr.length.HighPart = 0;
6427 lock_ObtainMutex(&fidp->mx);
6428 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6429 fidp->flags |= SMB_FID_LENGTHSETDONE;
6430 lock_ReleaseMutex(&fidp->mx);
6431 smb_SetSMBParm(outp, 0, /* count */ 0);
6432 smb_SetSMBDataLength(outp, 0);
6438 LARGE_INTEGER LOffset;
6439 LARGE_INTEGER LLength;
6441 pid = ((smb_t *) inp)->pid;
6442 key = cm_GenerateKey(vcp->vcID, pid, fd);
6444 LOffset.HighPart = offset.HighPart;
6445 LOffset.LowPart = offset.LowPart;
6446 LLength.HighPart = 0;
6447 LLength.LowPart = count;
6449 lock_ObtainMutex(&fidp->scp->mx);
6450 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6451 lock_ReleaseMutex(&fidp->scp->mx);
6458 * Work around bug in NT client
6460 * When copying a file, the NT client should first copy the data,
6461 * then copy the last write time. But sometimes the NT client does
6462 * these in the wrong order, so the data copies would inadvertently
6463 * cause the last write time to be overwritten. We try to detect this,
6464 * and don't set client mod time if we think that would go against the
6467 lock_ObtainMutex(&fidp->mx);
6468 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6469 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6470 fidp->scp->clientModTime = time(NULL);
6472 lock_ReleaseMutex(&fidp->mx);
6475 while ( code == 0 && count > 0 ) {
6477 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6479 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6481 if (code == 0 && written == 0)
6482 code = CM_ERROR_PARTIALWRITE;
6484 offset = LargeIntegerAdd(offset,
6485 ConvertLongToLargeInteger(written));
6487 total_written += written;
6491 /* set the packet data length to 3 bytes for the data block header,
6492 * plus the size of the data.
6494 smb_SetSMBParm(outp, 0, total_written);
6495 smb_SetSMBDataLength(outp, 0);
6498 smb_ReleaseFID(fidp);
6499 cm_ReleaseUser(userp);
6504 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6505 NCB *ncbp, raw_write_cont_t *rwcp)
6518 fd = smb_GetSMBParm(inp, 0);
6519 fidp = smb_FindFID(vcp, fd, 0);
6521 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6522 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6524 userp = smb_GetUserFromVCP(vcp, inp);
6528 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6531 rawBuf = (dos_ptr) rwcp->buf;
6532 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6533 (unsigned char *) rawBuf, userp,
6537 if (rwcp->writeMode & 0x1) { /* synchronous */
6540 smb_FormatResponsePacket(vcp, inp, outp);
6541 op = (smb_t *) outp;
6542 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6543 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6544 smb_SetSMBDataLength(outp, 0);
6545 smb_SendPacket(vcp, outp);
6546 smb_FreePacket(outp);
6548 else { /* asynchronous */
6549 lock_ObtainMutex(&fidp->mx);
6550 fidp->raw_writers--;
6551 if (fidp->raw_writers == 0)
6552 thrd_SetEvent(fidp->raw_write_event);
6553 lock_ReleaseMutex(&fidp->mx);
6556 /* Give back raw buffer */
6557 lock_ObtainMutex(&smb_RawBufLock);
6559 *((char **)rawBuf) = smb_RawBufs;
6561 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6563 smb_RawBufs = rawBuf;
6564 lock_ReleaseMutex(&smb_RawBufLock);
6566 smb_ReleaseFID(fidp);
6567 cm_ReleaseUser(userp);
6570 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6575 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6578 long count, written = 0, total_written = 0;
6585 unsigned short writeMode;
6592 fd = smb_GetSMBParm(inp, 0);
6593 totalCount = smb_GetSMBParm(inp, 1);
6594 count = smb_GetSMBParm(inp, 10);
6595 writeMode = smb_GetSMBParm(inp, 7);
6597 op = (char *) inp->data;
6598 op += smb_GetSMBParm(inp, 11);
6600 offset.HighPart = 0;
6601 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6603 if (*inp->wctp == 14) {
6604 /* we received a 64-bit file offset */
6605 #ifdef AFS_LARGEFILES
6606 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6608 if (LargeIntegerLessThanZero(offset)) {
6610 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6611 offset.HighPart, offset.LowPart);
6612 return CM_ERROR_BADSMB;
6615 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6617 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6618 return CM_ERROR_BADSMB;
6621 offset.HighPart = 0;
6624 offset.HighPart = 0; /* 32-bit file offset */
6628 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6629 fd, offset.HighPart, offset.LowPart, count);
6631 " WriteRaw WriteMode 0x%x",
6634 fd = smb_ChainFID(fd, inp);
6635 fidp = smb_FindFID(vcp, fd, 0);
6637 return CM_ERROR_BADFD;
6643 LARGE_INTEGER LOffset;
6644 LARGE_INTEGER LLength;
6646 pid = ((smb_t *) inp)->pid;
6647 key = cm_GenerateKey(vcp->vcID, pid, fd);
6649 LOffset.HighPart = offset.HighPart;
6650 LOffset.LowPart = offset.LowPart;
6651 LLength.HighPart = 0;
6652 LLength.LowPart = count;
6654 lock_ObtainMutex(&fidp->scp->mx);
6655 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6656 lock_ReleaseMutex(&fidp->scp->mx);
6659 smb_ReleaseFID(fidp);
6664 userp = smb_GetUserFromVCP(vcp, inp);
6667 * Work around bug in NT client
6669 * When copying a file, the NT client should first copy the data,
6670 * then copy the last write time. But sometimes the NT client does
6671 * these in the wrong order, so the data copies would inadvertently
6672 * cause the last write time to be overwritten. We try to detect this,
6673 * and don't set client mod time if we think that would go against the
6676 lock_ObtainMutex(&fidp->mx);
6677 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6678 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6679 fidp->scp->clientModTime = time(NULL);
6681 lock_ReleaseMutex(&fidp->mx);
6684 while ( code == 0 && count > 0 ) {
6686 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6688 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6690 if (code == 0 && written == 0)
6691 code = CM_ERROR_PARTIALWRITE;
6693 offset = LargeIntegerAdd(offset,
6694 ConvertLongToLargeInteger(written));
6697 total_written += written;
6701 /* Get a raw buffer */
6704 lock_ObtainMutex(&smb_RawBufLock);
6706 /* Get a raw buf, from head of list */
6707 rawBuf = smb_RawBufs;
6709 smb_RawBufs = *(char **)smb_RawBufs;
6711 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6715 code = CM_ERROR_USESTD;
6717 lock_ReleaseMutex(&smb_RawBufLock);
6720 /* Don't allow a premature Close */
6721 if (code == 0 && (writeMode & 1) == 0) {
6722 lock_ObtainMutex(&fidp->mx);
6723 fidp->raw_writers++;
6724 thrd_ResetEvent(fidp->raw_write_event);
6725 lock_ReleaseMutex(&fidp->mx);
6728 smb_ReleaseFID(fidp);
6729 cm_ReleaseUser(userp);
6732 smb_SetSMBParm(outp, 0, total_written);
6733 smb_SetSMBDataLength(outp, 0);
6734 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6739 offset = LargeIntegerAdd(offset,
6740 ConvertLongToLargeInteger(count));
6744 rwcp->offset.HighPart = offset.HighPart;
6745 rwcp->offset.LowPart = offset.LowPart;
6746 rwcp->count = totalCount - count;
6747 rwcp->writeMode = writeMode;
6748 rwcp->alreadyWritten = total_written;
6750 /* set the packet data length to 3 bytes for the data block header,
6751 * plus the size of the data.
6753 smb_SetSMBParm(outp, 0, 0xffff);
6754 smb_SetSMBDataLength(outp, 0);
6759 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6762 long count, finalCount;
6770 fd = smb_GetSMBParm(inp, 0);
6771 count = smb_GetSMBParm(inp, 1);
6772 offset.HighPart = 0; /* too bad */
6773 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6775 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6776 fd, offset.LowPart, count);
6778 fd = smb_ChainFID(fd, inp);
6779 fidp = smb_FindFID(vcp, fd, 0);
6781 return CM_ERROR_BADFD;
6783 lock_ObtainMutex(&fidp->mx);
6784 if (fidp->flags & SMB_FID_IOCTL) {
6785 lock_ReleaseMutex(&fidp->mx);
6786 code = smb_IoctlRead(fidp, vcp, inp, outp);
6787 smb_ReleaseFID(fidp);
6790 lock_ReleaseMutex(&fidp->mx);
6793 LARGE_INTEGER LOffset, LLength;
6796 pid = ((smb_t *) inp)->pid;
6797 key = cm_GenerateKey(vcp->vcID, pid, fd);
6799 LOffset.HighPart = 0;
6800 LOffset.LowPart = offset.LowPart;
6801 LLength.HighPart = 0;
6802 LLength.LowPart = count;
6804 lock_ObtainMutex(&fidp->scp->mx);
6805 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6806 lock_ReleaseMutex(&fidp->scp->mx);
6809 smb_ReleaseFID(fidp);
6813 userp = smb_GetUserFromVCP(vcp, inp);
6815 /* remember this for final results */
6816 smb_SetSMBParm(outp, 0, count);
6817 smb_SetSMBParm(outp, 1, 0);
6818 smb_SetSMBParm(outp, 2, 0);
6819 smb_SetSMBParm(outp, 3, 0);
6820 smb_SetSMBParm(outp, 4, 0);
6822 /* set the packet data length to 3 bytes for the data block header,
6823 * plus the size of the data.
6825 smb_SetSMBDataLength(outp, count+3);
6827 /* get op ptr after putting in the parms, since otherwise we don't
6828 * know where the data really is.
6830 op = smb_GetSMBData(outp, NULL);
6832 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6833 *op++ = 1; /* data block marker */
6834 *op++ = (unsigned char) (count & 0xff);
6835 *op++ = (unsigned char) ((count >> 8) & 0xff);
6838 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6840 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6843 /* fix some things up */
6844 smb_SetSMBParm(outp, 0, finalCount);
6845 smb_SetSMBDataLength(outp, finalCount+3);
6847 smb_ReleaseFID(fidp);
6849 cm_ReleaseUser(userp);
6853 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6860 cm_scache_t *dscp; /* dir we're dealing with */
6861 cm_scache_t *scp; /* file we're creating */
6863 int initialModeBits;
6873 /* compute initial mode bits based on read-only flag in attributes */
6874 initialModeBits = 0777;
6876 tp = smb_GetSMBData(inp, NULL);
6877 pathp = smb_ParseASCIIBlock(tp, &tp);
6878 if (smb_StoreAnsiFilenames)
6879 OemToChar(pathp,pathp);
6881 if (strcmp(pathp, "\\") == 0)
6882 return CM_ERROR_EXISTS;
6884 spacep = inp->spacep;
6885 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6887 userp = smb_GetUserFromVCP(vcp, inp);
6889 caseFold = CM_FLAG_CASEFOLD;
6891 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6893 cm_ReleaseUser(userp);
6894 return CM_ERROR_NOSUCHPATH;
6897 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6898 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6899 userp, tidPathp, &req, &dscp);
6902 cm_ReleaseUser(userp);
6907 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6908 cm_ReleaseSCache(dscp);
6909 cm_ReleaseUser(userp);
6910 if ( WANTS_DFS_PATHNAMES(inp) )
6911 return CM_ERROR_PATH_NOT_COVERED;
6913 return CM_ERROR_BADSHARENAME;
6915 #endif /* DFS_SUPPORT */
6917 /* otherwise, scp points to the parent directory. Do a lookup, and
6918 * fail if we find it. Otherwise, we do the create.
6924 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6925 if (scp) cm_ReleaseSCache(scp);
6926 if (code != CM_ERROR_NOSUCHFILE) {
6927 if (code == 0) code = CM_ERROR_EXISTS;
6928 cm_ReleaseSCache(dscp);
6929 cm_ReleaseUser(userp);
6933 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6934 setAttr.clientModTime = time(NULL);
6935 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6936 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6937 smb_NotifyChange(FILE_ACTION_ADDED,
6938 FILE_NOTIFY_CHANGE_DIR_NAME,
6939 dscp, lastNamep, NULL, TRUE);
6941 /* we don't need this any longer */
6942 cm_ReleaseSCache(dscp);
6945 /* something went wrong creating or truncating the file */
6946 cm_ReleaseUser(userp);
6950 /* otherwise we succeeded */
6951 smb_SetSMBDataLength(outp, 0);
6952 cm_ReleaseUser(userp);
6957 BOOL smb_IsLegalFilename(char *filename)
6960 * Find the longest substring of filename that does not contain
6961 * any of the chars in illegalChars. If that substring is less
6962 * than the length of the whole string, then one or more of the
6963 * illegal chars is in filename.
6965 if (strcspn(filename, illegalChars) < strlen(filename))
6971 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6979 cm_scache_t *dscp; /* dir we're dealing with */
6980 cm_scache_t *scp; /* file we're creating */
6982 int initialModeBits;
6990 int created = 0; /* the file was new */
6995 excl = (inp->inCom == 0x03)? 0 : 1;
6997 attributes = smb_GetSMBParm(inp, 0);
6998 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7000 /* compute initial mode bits based on read-only flag in attributes */
7001 initialModeBits = 0666;
7002 if (attributes & 1) initialModeBits &= ~0222;
7004 tp = smb_GetSMBData(inp, NULL);
7005 pathp = smb_ParseASCIIBlock(tp, &tp);
7006 if (smb_StoreAnsiFilenames)
7007 OemToChar(pathp,pathp);
7009 spacep = inp->spacep;
7010 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7012 userp = smb_GetUserFromVCP(vcp, inp);
7014 caseFold = CM_FLAG_CASEFOLD;
7016 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7018 cm_ReleaseUser(userp);
7019 return CM_ERROR_NOSUCHPATH;
7021 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7022 userp, tidPathp, &req, &dscp);
7025 cm_ReleaseUser(userp);
7030 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7031 cm_ReleaseSCache(dscp);
7032 cm_ReleaseUser(userp);
7033 if ( WANTS_DFS_PATHNAMES(inp) )
7034 return CM_ERROR_PATH_NOT_COVERED;
7036 return CM_ERROR_BADSHARENAME;
7038 #endif /* DFS_SUPPORT */
7040 /* otherwise, scp points to the parent directory. Do a lookup, and
7041 * truncate the file if we find it, otherwise we create the file.
7048 if (!smb_IsLegalFilename(lastNamep))
7049 return CM_ERROR_BADNTFILENAME;
7051 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7052 #ifdef DEBUG_VERBOSE
7055 hexp = osi_HexifyString( lastNamep );
7056 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7061 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7062 if (code && code != CM_ERROR_NOSUCHFILE) {
7063 cm_ReleaseSCache(dscp);
7064 cm_ReleaseUser(userp);
7068 /* if we get here, if code is 0, the file exists and is represented by
7069 * scp. Otherwise, we have to create it.
7073 /* oops, file shouldn't be there */
7074 cm_ReleaseSCache(dscp);
7075 cm_ReleaseSCache(scp);
7076 cm_ReleaseUser(userp);
7077 return CM_ERROR_EXISTS;
7080 setAttr.mask = CM_ATTRMASK_LENGTH;
7081 setAttr.length.LowPart = 0;
7082 setAttr.length.HighPart = 0;
7083 code = cm_SetAttr(scp, &setAttr, userp, &req);
7086 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7087 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7088 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7092 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7093 smb_NotifyChange(FILE_ACTION_ADDED,
7094 FILE_NOTIFY_CHANGE_FILE_NAME,
7095 dscp, lastNamep, NULL, TRUE);
7096 } else if (!excl && code == CM_ERROR_EXISTS) {
7097 /* not an exclusive create, and someone else tried
7098 * creating it already, then we open it anyway. We
7099 * don't bother retrying after this, since if this next
7100 * fails, that means that the file was deleted after
7101 * we started this call.
7103 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7106 setAttr.mask = CM_ATTRMASK_LENGTH;
7107 setAttr.length.LowPart = 0;
7108 setAttr.length.HighPart = 0;
7109 code = cm_SetAttr(scp, &setAttr, userp, &req);
7114 /* we don't need this any longer */
7115 cm_ReleaseSCache(dscp);
7118 /* something went wrong creating or truncating the file */
7119 if (scp) cm_ReleaseSCache(scp);
7120 cm_ReleaseUser(userp);
7124 /* make sure we only open files */
7125 if (scp->fileType != CM_SCACHETYPE_FILE) {
7126 cm_ReleaseSCache(scp);
7127 cm_ReleaseUser(userp);
7128 return CM_ERROR_ISDIR;
7131 /* now all we have to do is open the file itself */
7132 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7137 lock_ObtainMutex(&fidp->mx);
7138 /* always create it open for read/write */
7139 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
7141 /* remember that the file was newly created */
7143 fidp->flags |= SMB_FID_CREATED;
7145 /* save a pointer to the vnode */
7148 fidp->userp = userp;
7149 lock_ReleaseMutex(&fidp->mx);
7151 smb_SetSMBParm(outp, 0, fidp->fid);
7152 smb_SetSMBDataLength(outp, 0);
7154 cm_Open(scp, 0, userp);
7156 smb_ReleaseFID(fidp);
7157 cm_ReleaseUser(userp);
7158 /* leave scp held since we put it in fidp->scp */
7162 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7165 osi_hyper_t new_offset;
7176 fd = smb_GetSMBParm(inp, 0);
7177 whence = smb_GetSMBParm(inp, 1);
7178 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7180 /* try to find the file descriptor */
7181 fd = smb_ChainFID(fd, inp);
7182 fidp = smb_FindFID(vcp, fd, 0);
7185 return CM_ERROR_BADFD;
7187 lock_ObtainMutex(&fidp->mx);
7188 if (fidp->flags & SMB_FID_IOCTL) {
7189 lock_ReleaseMutex(&fidp->mx);
7190 smb_ReleaseFID(fidp);
7191 return CM_ERROR_BADFD;
7193 lock_ReleaseMutex(&fidp->mx);
7195 userp = smb_GetUserFromVCP(vcp, inp);
7197 lock_ObtainMutex(&fidp->mx);
7200 lock_ReleaseMutex(&fidp->mx);
7201 lock_ObtainMutex(&scp->mx);
7202 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7203 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7206 /* offset from current offset */
7207 new_offset = LargeIntegerAdd(fidp->offset,
7208 ConvertLongToLargeInteger(offset));
7210 else if (whence == 2) {
7211 /* offset from current EOF */
7212 new_offset = LargeIntegerAdd(scp->length,
7213 ConvertLongToLargeInteger(offset));
7215 new_offset = ConvertLongToLargeInteger(offset);
7218 fidp->offset = new_offset;
7219 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7220 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7221 smb_SetSMBDataLength(outp, 0);
7223 lock_ReleaseMutex(&scp->mx);
7224 smb_ReleaseFID(fidp);
7225 cm_ReleaseSCache(scp);
7226 cm_ReleaseUser(userp);
7230 /* dispatch all of the requests received in a packet. Due to chaining, this may
7231 * be more than one request.
7233 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7234 NCB *ncbp, raw_write_cont_t *rwcp)
7238 unsigned long code = 0;
7239 unsigned char *outWctp;
7240 int nparms; /* # of bytes of parameters */
7242 int nbytes; /* bytes of data, excluding count */
7245 unsigned short errCode;
7246 unsigned long NTStatus;
7248 unsigned char errClass;
7249 unsigned int oldGen;
7250 DWORD oldTime, newTime;
7252 /* get easy pointer to the data */
7253 smbp = (smb_t *) inp->data;
7255 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7256 /* setup the basic parms for the initial request in the packet */
7257 inp->inCom = smbp->com;
7258 inp->wctp = &smbp->wct;
7260 inp->ncb_length = ncbp->ncb_length;
7265 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7266 /* log it and discard it */
7268 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7269 __FILE__, __LINE__, ncbp->ncb_length);
7271 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7275 /* We are an ongoing op */
7276 thrd_Increment(&ongoingOps);
7278 /* set up response packet for receiving output */
7279 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7280 smb_FormatResponsePacket(vcp, inp, outp);
7281 outWctp = outp->wctp;
7283 /* Remember session generation number and time */
7284 oldGen = sessionGen;
7285 oldTime = GetTickCount();
7287 while (inp->inCom != 0xff) {
7288 dp = &smb_dispatchTable[inp->inCom];
7290 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7291 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7292 code = outp->resumeCode;
7296 /* process each request in the packet; inCom, wctp and inCount
7297 * are already set up.
7299 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7302 /* now do the dispatch */
7303 /* start by formatting the response record a little, as a default */
7304 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7306 outWctp[1] = 0xff; /* no operation */
7307 outWctp[2] = 0; /* padding */
7312 /* not a chained request, this is a more reasonable default */
7313 outWctp[0] = 0; /* wct of zero */
7314 outWctp[1] = 0; /* and bcc (word) of zero */
7318 /* once set, stays set. Doesn't matter, since we never chain
7319 * "no response" calls.
7321 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7325 /* we have a recognized operation */
7327 if (inp->inCom == 0x1d)
7329 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7331 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7332 code = (*(dp->procp)) (vcp, inp, outp);
7333 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7335 if ( code == CM_ERROR_BADSMB ||
7336 code == CM_ERROR_BADOP )
7338 #endif /* LOG_PACKET */
7341 if (oldGen != sessionGen) {
7342 newTime = GetTickCount();
7344 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7345 newTime - oldTime, ncbp->ncb_length);
7347 osi_Log2(smb_logp, "Pkt straddled session startup, "
7348 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7352 /* bad opcode, fail the request, after displaying it */
7353 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7356 #endif /* LOG_PACKET */
7360 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7361 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7362 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7363 if (code == IDCANCEL)
7367 code = CM_ERROR_BADOP;
7370 /* catastrophic failure: log as much as possible */
7371 if (code == CM_ERROR_BADSMB) {
7373 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7378 #endif /* LOG_PACKET */
7379 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7382 code = CM_ERROR_INVAL;
7385 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7386 thrd_Decrement(&ongoingOps);
7391 /* now, if we failed, turn the current response into an empty
7392 * one, and fill in the response packet's error code.
7395 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7396 smb_MapNTError(code, &NTStatus);
7397 outWctp = outp->wctp;
7398 smbp = (smb_t *) &outp->data;
7399 if (code != CM_ERROR_PARTIALWRITE
7400 && code != CM_ERROR_BUFFERTOOSMALL
7401 && code != CM_ERROR_GSSCONTINUE) {
7402 /* nuke wct and bcc. For a partial
7403 * write or an in-process authentication handshake,
7404 * assume they're OK.
7410 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7411 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7412 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7413 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7414 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7418 smb_MapCoreError(code, vcp, &errCode, &errClass);
7419 outWctp = outp->wctp;
7420 smbp = (smb_t *) &outp->data;
7421 if (code != CM_ERROR_PARTIALWRITE) {
7422 /* nuke wct and bcc. For a partial
7423 * write, assume they're OK.
7429 smbp->errLow = (unsigned char) (errCode & 0xff);
7430 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7431 smbp->rcls = errClass;
7434 } /* error occurred */
7436 /* if we're here, we've finished one request. Look to see if
7437 * this is a chained opcode. If it is, setup things to process
7438 * the chained request, and setup the output buffer to hold the
7439 * chained response. Start by finding the next input record.
7441 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7442 break; /* not a chained req */
7443 tp = inp->wctp; /* points to start of last request */
7444 /* in a chained request, the first two
7445 * parm fields are required, and are
7446 * AndXCommand/AndXReserved and
7448 if (tp[0] < 2) break;
7449 if (tp[1] == 0xff) break; /* no more chained opcodes */
7451 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7454 /* and now append the next output request to the end of this
7455 * last request. Begin by finding out where the last response
7456 * ends, since that's where we'll put our new response.
7458 outWctp = outp->wctp; /* ptr to out parameters */
7459 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7460 nparms = outWctp[0] << 1;
7461 tp = outWctp + nparms + 1; /* now points to bcc field */
7462 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7463 tp += 2 /* for the count itself */ + nbytes;
7464 /* tp now points to the new output record; go back and patch the
7465 * second parameter (off2) to point to the new record.
7467 temp = (unsigned int)(tp - outp->data);
7468 outWctp[3] = (unsigned char) (temp & 0xff);
7469 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7470 outWctp[2] = 0; /* padding */
7471 outWctp[1] = inp->inCom; /* next opcode */
7473 /* finally, setup for the next iteration */
7476 } /* while loop over all requests in the packet */
7478 /* now send the output packet, and return */
7480 smb_SendPacket(vcp, outp);
7481 thrd_Decrement(&ongoingOps);
7487 /* Wait for Netbios() calls to return, and make the results available to server
7488 * threads. Note that server threads can't wait on the NCBevents array
7489 * themselves, because NCB events are manual-reset, and the servers would race
7490 * each other to reset them.
7492 void smb_ClientWaiter(void *parmp)
7497 while (smbShutdownFlag == 0) {
7498 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7500 if (code == WAIT_OBJECT_0)
7503 /* error checking */
7504 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7506 int abandonIdx = code - WAIT_ABANDONED_0;
7507 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7510 if (code == WAIT_IO_COMPLETION)
7512 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7516 if (code == WAIT_TIMEOUT)
7518 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7521 if (code == WAIT_FAILED)
7523 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7526 idx = code - WAIT_OBJECT_0;
7528 /* check idx range! */
7529 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7531 /* this is fatal - log as much as possible */
7532 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7536 thrd_ResetEvent(NCBevents[idx]);
7537 thrd_SetEvent(NCBreturns[0][idx]);
7543 * Try to have one NCBRECV request waiting for every live session. Not more
7544 * than one, because if there is more than one, it's hard to handle Write Raw.
7546 void smb_ServerWaiter(void *parmp)
7549 int idx_session, idx_NCB;
7555 while (smbShutdownFlag == 0) {
7557 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7559 if (code == WAIT_OBJECT_0)
7562 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7564 int abandonIdx = code - WAIT_ABANDONED_0;
7565 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7568 if (code == WAIT_IO_COMPLETION)
7570 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7574 if (code == WAIT_TIMEOUT)
7576 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7579 if (code == WAIT_FAILED)
7581 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7584 idx_session = code - WAIT_OBJECT_0;
7586 /* check idx range! */
7587 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7589 /* this is fatal - log as much as possible */
7590 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7596 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7598 if (code == WAIT_OBJECT_0) {
7599 if (smbShutdownFlag == 1)
7605 /* error checking */
7606 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7608 int abandonIdx = code - WAIT_ABANDONED_0;
7609 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7612 if (code == WAIT_IO_COMPLETION)
7614 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7618 if (code == WAIT_TIMEOUT)
7620 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7623 if (code == WAIT_FAILED)
7625 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7628 idx_NCB = code - WAIT_OBJECT_0;
7630 /* check idx range! */
7631 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7633 /* this is fatal - log as much as possible */
7634 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7638 /* Link them together */
7639 NCBsessions[idx_NCB] = idx_session;
7642 ncbp = NCBs[idx_NCB];
7643 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7644 ncbp->ncb_command = NCBRECV | ASYNCH;
7645 ncbp->ncb_lana_num = lanas[idx_session];
7647 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7648 ncbp->ncb_event = NCBevents[idx_NCB];
7649 ncbp->ncb_length = SMB_PACKETSIZE;
7652 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7653 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7654 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7655 ncbp->ncb_length = SMB_PACKETSIZE;
7656 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7657 Netbios(ncbp, dos_ncb);
7663 * The top level loop for handling SMB request messages. Each server thread
7664 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7665 * NCB and buffer for the incoming request are loaned to us.
7667 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7668 * to immediately send a request for the rest of the data. This must come
7669 * before any other traffic for that session, so we delay setting the session
7670 * event until that data has come in.
7672 void smb_Server(VOID *parmp)
7674 INT_PTR myIdx = (INT_PTR) parmp;
7678 smb_packet_t *outbufp;
7680 int idx_NCB, idx_session;
7682 smb_vc_t *vcp = NULL;
7688 rx_StartClientThread();
7691 outbufp = GetPacket();
7692 outbufp->ncbp = outncbp;
7700 smb_ResetServerPriority();
7702 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7705 /* terminate silently if shutdown flag is set */
7706 if (code == WAIT_OBJECT_0) {
7707 if (smbShutdownFlag == 1) {
7708 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7714 /* error checking */
7715 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7717 int abandonIdx = code - WAIT_ABANDONED_0;
7718 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7721 if (code == WAIT_IO_COMPLETION)
7723 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7727 if (code == WAIT_TIMEOUT)
7729 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7732 if (code == WAIT_FAILED)
7734 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7737 idx_NCB = code - WAIT_OBJECT_0;
7739 /* check idx range! */
7740 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7742 /* this is fatal - log as much as possible */
7743 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7747 ncbp = NCBs[idx_NCB];
7749 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7751 idx_session = NCBsessions[idx_NCB];
7752 rc = ncbp->ncb_retcode;
7754 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7755 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7759 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7763 /* Can this happen? Or is it just my UNIX paranoia? */
7764 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7770 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7774 /* Client closed session */
7775 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7777 lock_ObtainMutex(&vcp->mx);
7778 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7779 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7781 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7782 lock_ReleaseMutex(&vcp->mx);
7783 lock_ObtainWrite(&smb_globalLock);
7784 dead_sessions[vcp->session] = TRUE;
7785 lock_ReleaseWrite(&smb_globalLock);
7786 smb_CleanupDeadVC(vcp);
7790 lock_ReleaseMutex(&vcp->mx);
7796 /* Treat as transient error */
7798 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7802 "dispatch smb recv failed, message incomplete, ncb_length %d",
7805 "SMB message incomplete, "
7806 "length %d", ncbp->ncb_length);
7809 * We used to discard the packet.
7810 * Instead, try handling it normally.
7814 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7818 /* A weird error code. Log it, sleep, and continue. */
7819 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7821 lock_ObtainMutex(&vcp->mx);
7822 if (vcp && vcp->errorCount++ > 3) {
7823 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7824 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7825 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7827 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7828 lock_ReleaseMutex(&vcp->mx);
7829 lock_ObtainWrite(&smb_globalLock);
7830 dead_sessions[vcp->session] = TRUE;
7831 lock_ReleaseWrite(&smb_globalLock);
7832 smb_CleanupDeadVC(vcp);
7836 lock_ReleaseMutex(&vcp->mx);
7842 lock_ReleaseMutex(&vcp->mx);
7844 thrd_SetEvent(SessionEvents[idx_session]);
7849 /* Success, so now dispatch on all the data in the packet */
7851 smb_concurrentCalls++;
7852 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7853 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7856 * If at this point vcp is NULL (implies that packet was invalid)
7857 * then we are in big trouble. This means either :
7858 * a) we have the wrong NCB.
7859 * b) Netbios screwed up the call.
7860 * c) The VC was already marked dead before we were able to
7862 * Obviously this implies that
7863 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7864 * lanas[idx_session] != ncbp->ncb_lana_num )
7865 * Either way, we can't do anything with this packet.
7866 * Log, sleep and resume.
7869 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7873 ncbp->ncb_lana_num);
7875 /* Also log in the trace log. */
7876 osi_Log4(smb_logp, "Server: VCP does not exist!"
7877 "LSNs[idx_session]=[%d],"
7878 "lanas[idx_session]=[%d],"
7879 "ncbp->ncb_lsn=[%d],"
7880 "ncbp->ncb_lana_num=[%d]",
7884 ncbp->ncb_lana_num);
7886 /* thrd_Sleep(1000); Don't bother sleeping */
7887 thrd_SetEvent(SessionEvents[idx_session]);
7888 smb_concurrentCalls--;
7892 smb_SetRequestStartTime();
7894 vcp->errorCount = 0;
7895 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7897 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7898 /* copy whole packet to virtual memory */
7899 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7901 bufp->dos_pkt / 16, bufp);*/
7903 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7905 smbp = (smb_t *)bufp->data;
7908 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7912 if (smbp->com == 0x1d) {
7913 /* Special handling for Write Raw */
7914 raw_write_cont_t rwc;
7915 EVENT_HANDLE rwevent;
7916 char eventName[MAX_PATH];
7918 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7919 if (rwc.code == 0) {
7920 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7921 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7922 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7923 ncbp->ncb_command = NCBRECV | ASYNCH;
7924 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7925 ncbp->ncb_lana_num = vcp->lana;
7926 ncbp->ncb_buffer = rwc.buf;
7927 ncbp->ncb_length = 65535;
7928 ncbp->ncb_event = rwevent;
7932 Netbios(ncbp, dos_ncb);
7934 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7935 thrd_CloseHandle(rwevent);
7937 thrd_SetEvent(SessionEvents[idx_session]);
7939 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7941 else if (smbp->com == 0xa0) {
7943 * Serialize the handling for NT Transact
7946 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7947 thrd_SetEvent(SessionEvents[idx_session]);
7949 thrd_SetEvent(SessionEvents[idx_session]);
7950 /* TODO: what else needs to be serialized? */
7951 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7953 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7955 __except( smb_ServerExceptionFilter() ) {
7959 smb_concurrentCalls--;
7962 thrd_SetEvent(NCBavails[idx_NCB]);
7969 * Exception filter for the server threads. If an exception occurs in the
7970 * dispatch routines, which is where exceptions are most common, then do a
7971 * force trace and give control to upstream exception handlers. Useful for
7974 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7975 DWORD smb_ServerExceptionFilter(void) {
7976 /* While this is not the best time to do a trace, if it succeeds, then
7977 * we have a trace (assuming tracing was enabled). Otherwise, this should
7978 * throw a second exception.
7980 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7981 afsd_ForceTrace(TRUE);
7982 buf_ForceTrace(TRUE);
7983 return EXCEPTION_CONTINUE_SEARCH;
7988 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7989 * If the number of server threads is M, and the number of live sessions is
7990 * N, then the number of NCB's in use at any time either waiting for, or
7991 * holding, received messages is M + N, so that is how many NCB's get created.
7993 void InitNCBslot(int idx)
7995 struct smb_packet *bufp;
7996 EVENT_HANDLE retHandle;
7998 char eventName[MAX_PATH];
8000 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
8002 NCBs[idx] = GetNCB();
8003 sprintf(eventName,"NCBavails[%d]", idx);
8004 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8005 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8006 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8008 sprintf(eventName,"NCBevents[%d]", idx);
8009 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8010 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8011 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8013 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8014 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8015 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8016 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8017 for (i=0; i<smb_NumServerThreads; i++)
8018 NCBreturns[i][idx] = retHandle;
8020 bufp->spacep = cm_GetSpace();
8024 /* listen for new connections */
8025 void smb_Listener(void *parmp)
8031 int session, thread;
8032 smb_vc_t *vcp = NULL;
8034 char rname[NCBNAMSZ+1];
8035 char cname[MAX_COMPUTERNAME_LENGTH+1];
8036 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8041 INT_PTR lana = (INT_PTR) parmp;
8045 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8048 /* retrieve computer name */
8049 GetComputerName(cname, &cnamelen);
8053 memset(ncbp, 0, sizeof(NCB));
8056 ncbp->ncb_command = NCBLISTEN;
8057 ncbp->ncb_rto = 0; /* No receive timeout */
8058 ncbp->ncb_sto = 0; /* No send timeout */
8060 /* pad out with spaces instead of null termination */
8061 len = (long)strlen(smb_localNamep);
8062 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8063 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8065 strcpy(ncbp->ncb_callname, "*");
8066 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8068 ncbp->ncb_lana_num = (UCHAR)lana;
8071 code = Netbios(ncbp);
8073 code = Netbios(ncbp, dos_ncb);
8082 /* terminate silently if shutdown flag is set */
8083 if (smbShutdownFlag == 1) {
8092 "NCBLISTEN lana=%d failed with code %d",
8093 ncbp->ncb_lana_num, code);
8095 "Client exiting due to network failure. Please restart client.\n");
8099 "Client exiting due to network failure. Please restart client.\n"
8100 "NCBLISTEN lana=%d failed with code %d",
8101 ncbp->ncb_lana_num, code);
8103 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8104 MB_OK|MB_SERVICE_NOTIFICATION);
8105 osi_assert(tbuffer);
8108 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
8109 ncbp->ncb_lana_num, code);
8110 fprintf(stderr, "\nClient exiting due to network failure "
8111 "(possibly due to power-saving mode)\n");
8112 fprintf(stderr, "Please restart client.\n");
8113 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
8117 /* check for remote conns */
8118 /* first get remote name and insert null terminator */
8119 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8120 for (i=NCBNAMSZ; i>0; i--) {
8121 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8127 /* compare with local name */
8129 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8130 flags |= SMB_VCFLAG_REMOTECONN;
8133 lock_ObtainMutex(&smb_ListenerLock);
8135 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8136 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8138 /* now ncbp->ncb_lsn is the connection ID */
8139 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8140 if (vcp->session == 0) {
8141 /* New generation */
8142 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8145 /* Log session startup */
8147 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8148 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8149 #endif /* NOTSERVICE */
8150 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8151 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8153 if (reportSessionStartups) {
8155 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8158 fprintf(stderr, "%s: New session %d starting from host %s\n",
8159 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8164 lock_ObtainMutex(&vcp->mx);
8165 strcpy(vcp->rname, rname);
8166 vcp->flags |= flags;
8167 lock_ReleaseMutex(&vcp->mx);
8169 /* Allocate slot in session arrays */
8170 /* Re-use dead session if possible, otherwise add one more */
8171 /* But don't look at session[0], it is reserved */
8172 lock_ObtainWrite(&smb_globalLock);
8173 for (session = 1; session < numSessions; session++) {
8174 if (dead_sessions[session]) {
8175 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8176 dead_sessions[session] = FALSE;
8180 lock_ReleaseWrite(&smb_globalLock);
8182 /* We are re-using an existing VC because the lsn and lana
8184 session = vcp->session;
8186 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8188 /* Log session startup */
8190 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8191 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8192 #endif /* NOTSERVICE */
8193 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8194 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8196 if (reportSessionStartups) {
8198 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8201 fprintf(stderr, "%s: Re-using session %d starting from host %s\n",
8202 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8208 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8209 unsigned long code = CM_ERROR_ALLBUSY;
8210 smb_packet_t * outp = GetPacket();
8211 unsigned char *outWctp;
8214 smb_FormatResponsePacket(vcp, NULL, outp);
8217 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8218 unsigned long NTStatus;
8219 smb_MapNTError(code, &NTStatus);
8220 outWctp = outp->wctp;
8221 smbp = (smb_t *) &outp->data;
8225 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8226 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8227 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8228 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8229 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8231 unsigned short errCode;
8232 unsigned char errClass;
8233 smb_MapCoreError(code, vcp, &errCode, &errClass);
8234 outWctp = outp->wctp;
8235 smbp = (smb_t *) &outp->data;
8239 smbp->errLow = (unsigned char) (errCode & 0xff);
8240 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8241 smbp->rcls = errClass;
8243 smb_SendPacket(vcp, outp);
8244 smb_FreePacket(outp);
8246 lock_ObtainMutex(&vcp->mx);
8247 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8248 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8250 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8251 lock_ReleaseMutex(&vcp->mx);
8252 lock_ObtainWrite(&smb_globalLock);
8253 dead_sessions[vcp->session] = TRUE;
8254 lock_ReleaseWrite(&smb_globalLock);
8255 smb_CleanupDeadVC(vcp);
8257 lock_ReleaseMutex(&vcp->mx);
8260 /* assert that we do not exceed the maximum number of sessions or NCBs.
8261 * we should probably want to wait for a session to be freed in case
8264 osi_assert(session < SESSION_MAX - 1);
8265 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8267 lock_ObtainMutex(&vcp->mx);
8268 vcp->session = session;
8269 lock_ReleaseMutex(&vcp->mx);
8270 lock_ObtainWrite(&smb_globalLock);
8271 LSNs[session] = ncbp->ncb_lsn;
8272 lanas[session] = ncbp->ncb_lana_num;
8273 lock_ReleaseWrite(&smb_globalLock);
8275 if (session == numSessions) {
8276 /* Add new NCB for new session */
8277 char eventName[MAX_PATH];
8279 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8281 InitNCBslot(numNCBs);
8282 lock_ObtainWrite(&smb_globalLock);
8284 lock_ReleaseWrite(&smb_globalLock);
8285 thrd_SetEvent(NCBavails[0]);
8286 thrd_SetEvent(NCBevents[0]);
8287 for (thread = 0; thread < smb_NumServerThreads; thread++)
8288 thrd_SetEvent(NCBreturns[thread][0]);
8289 /* Also add new session event */
8290 sprintf(eventName, "SessionEvents[%d]", session);
8291 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8292 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8293 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8294 lock_ObtainWrite(&smb_globalLock);
8296 lock_ReleaseWrite(&smb_globalLock);
8297 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8298 thrd_SetEvent(SessionEvents[0]);
8300 thrd_SetEvent(SessionEvents[session]);
8306 lock_ReleaseMutex(&smb_ListenerLock);
8307 } /* dispatch while loop */
8310 /* initialize Netbios */
8311 void smb_NetbiosInit()
8317 int i, lana, code, l;
8319 int delname_tried=0;
8322 OSVERSIONINFO Version;
8324 /* Get the version of Windows */
8325 memset(&Version, 0x00, sizeof(Version));
8326 Version.dwOSVersionInfoSize = sizeof(Version);
8327 GetVersionEx(&Version);
8329 /* setup the NCB system */
8332 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8336 if (smb_LANadapter == -1) {
8337 ncbp->ncb_command = NCBENUM;
8338 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8339 ncbp->ncb_length = sizeof(lana_list);
8340 code = Netbios(ncbp);
8342 afsi_log("Netbios NCBENUM error code %d", code);
8343 osi_panic(s, __FILE__, __LINE__);
8347 lana_list.length = 1;
8348 lana_list.lana[0] = smb_LANadapter;
8351 for (i = 0; i < lana_list.length; i++) {
8352 /* reset the adaptor: in Win32, this is required for every process, and
8353 * acts as an init call, not as a real hardware reset.
8355 ncbp->ncb_command = NCBRESET;
8356 ncbp->ncb_callname[0] = 100;
8357 ncbp->ncb_callname[2] = 100;
8358 ncbp->ncb_lana_num = lana_list.lana[i];
8359 code = Netbios(ncbp);
8361 code = ncbp->ncb_retcode;
8363 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8364 lana_list.lana[i] = 255; /* invalid lana */
8366 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8370 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
8371 we will just fake the LANA list */
8372 if (smb_LANadapter == -1) {
8373 for (i = 0; i < 8; i++)
8374 lana_list.lana[i] = i;
8375 lana_list.length = 8;
8378 lana_list.length = 1;
8379 lana_list.lana[0] = smb_LANadapter;
8383 /* and declare our name so we can receive connections */
8384 memset(ncbp, 0, sizeof(*ncbp));
8385 len=lstrlen(smb_localNamep);
8386 memset(smb_sharename,' ',NCBNAMSZ);
8387 memcpy(smb_sharename,smb_localNamep,len);
8388 afsi_log("lana_list.length %d", lana_list.length);
8390 /* Keep the name so we can unregister it later */
8391 for (l = 0; l < lana_list.length; l++) {
8392 lana = lana_list.lana[l];
8394 ncbp->ncb_command = NCBADDNAME;
8395 ncbp->ncb_lana_num = lana;
8396 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8398 code = Netbios(ncbp);
8400 code = Netbios(ncbp, dos_ncb);
8403 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8404 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8406 char name[NCBNAMSZ+1];
8408 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8409 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8412 if (code == 0) code = ncbp->ncb_retcode;
8414 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8416 /* we only use one LANA with djgpp */
8417 lana_list.lana[0] = lana;
8418 lana_list.length = 1;
8422 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8423 if (code == NRC_BRIDGE) { /* invalid LANA num */
8424 lana_list.lana[l] = 255;
8427 else if (code == NRC_DUPNAME) {
8428 afsi_log("Name already exists; try to delete it");
8429 memset(ncbp, 0, sizeof(*ncbp));
8430 ncbp->ncb_command = NCBDELNAME;
8431 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8432 ncbp->ncb_lana_num = lana;
8434 code = Netbios(ncbp);
8436 code = Netbios(ncbp, dos_ncb);
8439 code = ncbp->ncb_retcode;
8441 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8443 if (code != 0 || delname_tried) {
8444 lana_list.lana[l] = 255;
8446 else if (code == 0) {
8447 if (!delname_tried) {
8455 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8456 lana_list.lana[l] = 255; /* invalid lana */
8457 osi_panic(s, __FILE__, __LINE__);
8461 lana_found = 1; /* at least one worked */
8468 osi_assert(lana_list.length >= 0);
8470 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8473 /* we're done with the NCB now */
8477 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8494 EVENT_HANDLE retHandle;
8495 char eventName[MAX_PATH];
8497 smb_TlsRequestSlot = TlsAlloc();
8500 smb_MBfunc = aMBfunc;
8504 smb_LANadapter = LANadapt;
8506 /* Initialize smb_localZero */
8507 myTime.tm_isdst = -1; /* compute whether on DST or not */
8508 myTime.tm_year = 70;
8514 smb_localZero = mktime(&myTime);
8516 #ifndef USE_NUMERIC_TIME_CONV
8517 /* Initialize kludge-GMT */
8518 smb_CalculateNowTZ();
8519 #endif /* USE_NUMERIC_TIME_CONV */
8520 #ifdef AFS_FREELANCE_CLIENT
8521 /* Make sure the root.afs volume has the correct time */
8522 cm_noteLocalMountPointChange();
8525 /* initialize the remote debugging log */
8528 /* remember the name */
8529 len = (int)strlen(snamep);
8530 smb_localNamep = malloc(len+1);
8531 strcpy(smb_localNamep, snamep);
8532 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8534 /* and the global lock */
8535 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8536 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8538 /* Raw I/O data structures */
8539 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8541 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8543 /* 4 Raw I/O buffers */
8545 smb_RawBufs = calloc(65536,1);
8546 *((char **)smb_RawBufs) = NULL;
8547 for (i=0; i<3; i++) {
8548 char *rawBuf = calloc(65536,1);
8549 *((char **)rawBuf) = smb_RawBufs;
8550 smb_RawBufs = rawBuf;
8553 npar = 65536 >> 4; /* number of paragraphs */
8554 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8556 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8558 osi_panic("",__FILE__,__LINE__);
8561 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8564 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8566 _farpokel(_dos_ds, smb_RawBufs, NULL);
8567 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8568 npar = 65536 >> 4; /* number of paragraphs */
8569 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8571 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8573 osi_panic("",__FILE__,__LINE__);
8576 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8579 rawBuf = (seg * 16) + 0; /* DOS physical address */
8580 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8581 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8582 smb_RawBufs = rawBuf;
8586 /* global free lists */
8587 smb_ncbFreeListp = NULL;
8588 smb_packetFreeListp = NULL;
8592 /* Initialize listener and server structures */
8594 memset(dead_sessions, 0, sizeof(dead_sessions));
8595 sprintf(eventName, "SessionEvents[0]");
8596 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8597 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8598 afsi_log("Event Object Already Exists: %s", eventName);
8600 smb_NumServerThreads = nThreads;
8601 sprintf(eventName, "NCBavails[0]");
8602 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8603 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8604 afsi_log("Event Object Already Exists: %s", eventName);
8605 sprintf(eventName, "NCBevents[0]");
8606 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8607 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8608 afsi_log("Event Object Already Exists: %s", eventName);
8609 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8610 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8611 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8612 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8613 afsi_log("Event Object Already Exists: %s", eventName);
8614 for (i = 0; i < smb_NumServerThreads; i++) {
8615 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8616 NCBreturns[i][0] = retHandle;
8619 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8620 for (i = 0; i < smb_NumServerThreads; i++) {
8621 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8622 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8623 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8624 afsi_log("Event Object Already Exists: %s", eventName);
8625 InitNCBslot((int)(i+1));
8627 numNCBs = smb_NumServerThreads + 1;
8629 /* Initialize dispatch table */
8630 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8631 /* Prepare the table for unknown operations */
8632 for(i=0; i<= SMB_NOPCODES; i++) {
8633 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8635 /* Fill in the ones we do know */
8636 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8637 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8638 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8639 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8640 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8641 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8642 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8643 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8644 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8645 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8646 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8647 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8648 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8649 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8650 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8651 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8652 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8653 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8654 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8655 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8656 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8657 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8658 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8659 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8660 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8661 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8662 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8663 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8664 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8665 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8666 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8667 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8668 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8669 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8670 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8671 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8672 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8673 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8674 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8675 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8676 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8677 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8678 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8679 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8680 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8681 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8682 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8683 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8684 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8685 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8686 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8687 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8688 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8689 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8690 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8691 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8692 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8693 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8694 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8695 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8696 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8697 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8698 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8699 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8700 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8701 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8702 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8703 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8704 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8705 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8706 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8707 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8708 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8709 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8711 /* setup tran 2 dispatch table */
8712 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8713 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8714 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8715 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8716 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8717 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8718 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8719 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8720 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8721 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8722 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8723 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8724 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8725 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8726 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8727 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8728 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8730 /* setup the rap dispatch table */
8731 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8732 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8733 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8734 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8735 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8739 /* if we are doing SMB authentication we have register outselves as a logon process */
8740 if (smb_authType != SMB_AUTH_NONE) {
8741 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8742 LSA_STRING afsProcessName;
8743 LSA_OPERATIONAL_MODE dummy; /*junk*/
8745 afsProcessName.Buffer = "OpenAFSClientDaemon";
8746 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8747 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8749 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8751 if (nts == STATUS_SUCCESS) {
8752 LSA_STRING packageName;
8753 /* we are registered. Find out the security package id */
8754 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8755 packageName.Length = (USHORT)strlen(packageName.Buffer);
8756 packageName.MaximumLength = packageName.Length + 1;
8757 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8758 if (nts == STATUS_SUCCESS) {
8760 * This code forces Windows to authenticate against the Logon Cache
8761 * first instead of attempting to authenticate against the Domain
8762 * Controller. When the Windows logon cache is enabled this improves
8763 * performance by removing the network access and works around a bug
8764 * seen at sites which are using a MIT Kerberos principal to login
8765 * to machines joined to a non-root domain in a multi-domain forest.
8767 PVOID pResponse = NULL;
8768 ULONG cbResponse = 0;
8769 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8771 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8772 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8773 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8774 OptionsRequest.DisableOptions = FALSE;
8776 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8779 sizeof(OptionsRequest),
8785 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8787 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8789 OutputDebugString(message);
8792 OutputDebugString("MsV1_0SetProcessOption success");
8793 afsi_log("MsV1_0SetProcessOption success");
8795 /* END - code from Larry */
8797 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8798 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8799 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8801 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8803 /* something went wrong. We report the error and revert back to no authentication
8804 because we can't perform any auth requests without a successful lsa handle
8805 or sec package id. */
8806 afsi_log("Reverting to NO SMB AUTH");
8807 smb_authType = SMB_AUTH_NONE;
8810 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8812 /* something went wrong. We report the error and revert back to no authentication
8813 because we can't perform any auth requests without a successful lsa handle
8814 or sec package id. */
8815 afsi_log("Reverting to NO SMB AUTH");
8816 smb_authType = SMB_AUTH_NONE;
8820 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8821 * time prevents the failure of authentication when logged into Windows with an
8822 * external Kerberos principal mapped to a local account.
8824 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8825 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8826 * then the only option is NTLMSSP anyway; so just fallback.
8831 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8832 if (secBlobLength == 0) {
8833 smb_authType = SMB_AUTH_NTLM;
8834 afsi_log("Reverting to SMB AUTH NTLM");
8843 /* Now get ourselves a domain name. */
8844 /* For now we are using the local computer name as the domain name.
8845 * It is actually the domain for local logins, and we are acting as
8846 * a local SMB server.
8848 bufsize = sizeof(smb_ServerDomainName) - 1;
8849 GetComputerName(smb_ServerDomainName, &bufsize);
8850 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8851 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8854 /* Start listeners, waiters, servers, and daemons */
8856 for (i = 0; i < lana_list.length; i++) {
8857 if (lana_list.lana[i] == 255)
8859 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8860 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8861 osi_assert(phandle != NULL);
8862 thrd_CloseHandle(phandle);
8866 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8867 NULL, 0, &lpid, "smb_ClientWaiter");
8868 osi_assert(phandle != NULL);
8869 thrd_CloseHandle(phandle);
8872 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8873 NULL, 0, &lpid, "smb_ServerWaiter");
8874 osi_assert(phandle != NULL);
8875 thrd_CloseHandle(phandle);
8877 for (i=0; i<smb_NumServerThreads; i++) {
8878 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8879 (void *) i, 0, &lpid, "smb_Server");
8880 osi_assert(phandle != NULL);
8881 thrd_CloseHandle(phandle);
8884 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8885 NULL, 0, &lpid, "smb_Daemon");
8886 osi_assert(phandle != NULL);
8887 thrd_CloseHandle(phandle);
8889 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8890 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8891 osi_assert(phandle != NULL);
8892 thrd_CloseHandle(phandle);
8901 void smb_Shutdown(void)
8911 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8913 /* setup the NCB system */
8916 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8919 /* Block new sessions by setting shutdown flag */
8920 smbShutdownFlag = 1;
8922 /* Hang up all sessions */
8923 memset((char *)ncbp, 0, sizeof(NCB));
8924 for (i = 1; i < numSessions; i++)
8926 if (dead_sessions[i])
8929 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8930 ncbp->ncb_command = NCBHANGUP;
8931 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8932 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8934 code = Netbios(ncbp);
8936 code = Netbios(ncbp, dos_ncb);
8938 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8939 if (code == 0) code = ncbp->ncb_retcode;
8941 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8942 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8946 /* Trigger the shutdown of all SMB threads */
8947 for (i = 0; i < smb_NumServerThreads; i++)
8948 thrd_SetEvent(NCBreturns[i][0]);
8950 thrd_SetEvent(NCBevents[0]);
8951 thrd_SetEvent(SessionEvents[0]);
8952 thrd_SetEvent(NCBavails[0]);
8954 for (i = 0;i < smb_NumServerThreads; i++) {
8955 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8956 if (code == WAIT_OBJECT_0) {
8959 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8960 thrd_SetEvent(NCBreturns[i--][0]);
8964 /* Delete Netbios name */
8965 memset((char *)ncbp, 0, sizeof(NCB));
8966 for (i = 0; i < lana_list.length; i++) {
8967 if (lana_list.lana[i] == 255) continue;
8968 ncbp->ncb_command = NCBDELNAME;
8969 ncbp->ncb_lana_num = lana_list.lana[i];
8970 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8972 code = Netbios(ncbp);
8974 code = Netbios(ncbp, dos_ncb);
8977 code = ncbp->ncb_retcode;
8979 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8980 ncbp->ncb_lana_num, code);
8985 /* Release the reference counts held by the VCs */
8986 lock_ObtainWrite(&smb_rctLock);
8987 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8992 if (vcp->magic != SMB_VC_MAGIC)
8993 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8994 __FILE__, __LINE__);
8996 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8998 if (fidp->scp != NULL) {
9001 lock_ObtainMutex(&fidp->mx);
9002 if (fidp->scp != NULL) {
9005 cm_ReleaseSCache(scp);
9007 lock_ReleaseMutex(&fidp->mx);
9011 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9013 smb_ReleaseVCNoLock(tidp->vcp);
9015 cm_user_t *userp = tidp->userp;
9017 lock_ReleaseWrite(&smb_rctLock);
9018 cm_ReleaseUser(userp);
9019 lock_ObtainWrite(&smb_rctLock);
9023 lock_ReleaseWrite(&smb_rctLock);
9025 TlsFree(smb_TlsRequestSlot);
9028 /* Get the UNC \\<servername>\<sharename> prefix. */
9029 char *smb_GetSharename()
9033 /* Make sure we have been properly initialized. */
9034 if (smb_localNamep == NULL)
9037 /* Allocate space for \\<servername>\<sharename>, plus the
9040 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9041 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9047 void smb_LogPacket(smb_packet_t *packet)
9050 unsigned length, paramlen, datalen, i, j;
9052 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9054 if (!packet) return;
9056 osi_Log0(smb_logp, "*** SMB packet dump ***");
9058 vp = (BYTE *) packet->data;
9060 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9061 length = paramlen + 2 + datalen;
9064 for (i=0;i < length; i+=16)
9066 memset( buf, ' ', 80 );
9071 buf[strlen(buf)] = ' ';
9073 cp = (BYTE*) buf + 7;
9075 for (j=0;j < 16 && (i+j)<length; j++)
9077 *(cp++) = hex[vp[i+j] >> 4];
9078 *(cp++) = hex[vp[i+j] & 0xf];
9088 for (j=0;j < 16 && (i+j)<length;j++)
9090 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9101 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9104 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9106 #endif /* LOG_PACKET */
9109 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9117 lock_ObtainRead(&smb_rctLock);
9119 sprintf(output, "begin dumping smb_vc_t\n");
9120 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9122 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9126 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9127 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9128 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9130 sprintf(output, "begin dumping smb_fid_t\n");
9131 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9133 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9135 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",
9136 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9137 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9138 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9139 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9142 sprintf(output, "done dumping smb_fid_t\n");
9143 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9146 sprintf(output, "done dumping smb_vc_t\n");
9147 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9149 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9150 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9152 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9156 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9157 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9158 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9160 sprintf(output, "begin dumping smb_fid_t\n");
9161 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9163 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9165 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",
9166 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9167 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9168 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9169 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9172 sprintf(output, "done dumping smb_fid_t\n");
9173 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9176 sprintf(output, "done dumping DEAD smb_vc_t\n");
9177 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9179 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9180 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9182 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9186 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9187 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9188 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9190 sprintf(output, "begin dumping smb_fid_t\n");
9191 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9193 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9195 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",
9196 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9197 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9198 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9199 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9202 sprintf(output, "done dumping smb_fid_t\n");
9203 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9206 sprintf(output, "done dumping DEAD smb_vc_t\n");
9207 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9210 lock_ReleaseRead(&smb_rctLock);