2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
17 #include <sys/timeb.h>
29 #include <rx/rx_prototypes.h>
32 #include <WINNT\afsreg.h>
35 #include "lanahelper.h"
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
49 int smbShutdownFlag = 0;
51 int smb_LogoffTokenTransfer;
52 time_t smb_LogoffTransferTimeout;
54 int smb_StoreAnsiFilenames = 0;
56 DWORD last_msg_time = 0;
60 unsigned int sessionGen = 0;
62 extern void afsi_log(char *pattern, ...);
63 extern HANDLE afsi_file;
65 osi_hyper_t hzero = {0, 0};
66 osi_hyper_t hones = {0xFFFFFFFF, -1};
69 osi_rwlock_t smb_globalLock;
70 osi_rwlock_t smb_rctLock;
71 osi_mutex_t smb_ListenerLock;
74 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
85 int smb_NumServerThreads;
87 int numNCBs, numSessions, numVCs;
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
92 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
94 ULONG smb_lsaSecPackage;
95 LSA_STRING smb_lsaLogonOrigin;
97 #define NCBmax MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
99 EVENT_HANDLE **NCBreturns;
100 EVENT_HANDLE **NCBShutdown;
101 EVENT_HANDLE *smb_ServerShutdown;
102 DWORD NCBsessions[NCBmax];
104 struct smb_packet *bufs[NCBmax];
106 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
107 EVENT_HANDLE SessionEvents[Sessionmax];
108 unsigned short LSNs[Sessionmax];
109 int lanas[Sessionmax];
110 BOOL dead_sessions[Sessionmax];
114 osi_mutex_t smb_RawBufLock;
116 #define SMB_RAW_BUFS 4
118 int smb_RawBufSel[SMB_RAW_BUFS];
123 #define SMB_MASKFLAG_TILDE 1
124 #define SMB_MASKFLAG_CASEFOLD 2
126 #define RAWTIMEOUT INFINITE
129 typedef struct raw_write_cont {
142 /* dir search stuff */
143 long smb_dirSearchCounter = 1;
144 smb_dirSearch_t *smb_firstDirSearchp;
145 smb_dirSearch_t *smb_lastDirSearchp;
147 /* hide dot files? */
148 int smb_hideDotFiles;
150 /* global state about V3 protocols */
151 int smb_useV3; /* try to negotiate V3 */
154 static showErrors = 1;
155 /* MessageBox or something like it */
156 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
160 * Time in Unix format of midnight, 1/1/1970 local time.
161 * When added to dosUTime, gives Unix (AFS) time.
163 time_t smb_localZero = 0;
165 #define USE_NUMERIC_TIME_CONV 1
167 #ifndef USE_NUMERIC_TIME_CONV
168 /* Time difference for converting to kludge-GMT */
169 afs_uint32 smb_NowTZ;
170 #endif /* USE_NUMERIC_TIME_CONV */
172 char *smb_localNamep = NULL;
174 smb_vc_t *smb_allVCsp;
176 smb_username_t *usernamesp = NULL;
178 smb_waitingLockRequest_t *smb_allWaitingLocks;
181 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
182 NCB *ncbp, raw_write_cont_t *rwcp);
183 void smb_NetbiosInit();
185 #ifndef AFS_WIN95_ENV
186 DWORD smb_ServerExceptionFilter(void);
189 extern char cm_HostName[];
190 extern char cm_confDir[];
194 #define LPTSTR char *
195 #define GetComputerName(str, sizep) \
196 strcpy((str), cm_HostName); \
197 *(sizep) = strlen(cm_HostName)
201 void smb_LogPacket(smb_packet_t *packet);
202 #endif /* LOG_PACKET */
204 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
205 int smb_ServerDomainNameLength = 0;
206 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
207 int smb_ServerOSLength = sizeof(smb_ServerOS);
208 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
209 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
211 /* Faux server GUID. This is never checked. */
212 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
214 char * myCrt_Dispatch(int i)
219 return "(00)ReceiveCoreMakeDir";
221 return "(01)ReceiveCoreRemoveDir";
223 return "(02)ReceiveCoreOpen";
225 return "(03)ReceiveCoreCreate";
227 return "(04)ReceiveCoreClose";
229 return "(05)ReceiveCoreFlush";
231 return "(06)ReceiveCoreUnlink";
233 return "(07)ReceiveCoreRename";
235 return "(08)ReceiveCoreGetFileAttributes";
237 return "(09)ReceiveCoreSetFileAttributes";
239 return "(0a)ReceiveCoreRead";
241 return "(0b)ReceiveCoreWrite";
243 return "(0c)ReceiveCoreLockRecord";
245 return "(0d)ReceiveCoreUnlockRecord";
247 return "(0e)SendCoreBadOp";
249 return "(0f)ReceiveCoreCreate";
251 return "(10)ReceiveCoreCheckPath";
253 return "(11)SendCoreBadOp";
255 return "(12)ReceiveCoreSeek";
257 return "(1a)ReceiveCoreReadRaw";
259 return "(1d)ReceiveCoreWriteRawDummy";
261 return "(22)ReceiveV3SetAttributes";
263 return "(23)ReceiveV3GetAttributes";
265 return "(24)ReceiveV3LockingX";
267 return "(25)ReceiveV3Trans";
269 return "(26)ReceiveV3Trans[aux]";
271 return "(29)SendCoreBadOp";
273 return "(2b)ReceiveCoreEcho";
275 return "(2d)ReceiveV3OpenX";
277 return "(2e)ReceiveV3ReadX";
279 return "(32)ReceiveV3Tran2A";
281 return "(33)ReceiveV3Tran2A[aux]";
283 return "(34)ReceiveV3FindClose";
285 return "(35)ReceiveV3FindNotifyClose";
287 return "(70)ReceiveCoreTreeConnect";
289 return "(71)ReceiveCoreTreeDisconnect";
291 return "(72)ReceiveNegotiate";
293 return "(73)ReceiveV3SessionSetupX";
295 return "(74)ReceiveV3UserLogoffX";
297 return "(75)ReceiveV3TreeConnectX";
299 return "(80)ReceiveCoreGetDiskAttributes";
301 return "(81)ReceiveCoreSearchDir";
305 return "(83)FindUnique";
307 return "(84)FindClose";
309 return "(A0)ReceiveNTTransact";
311 return "(A2)ReceiveNTCreateX";
313 return "(A4)ReceiveNTCancel";
315 return "(A5)ReceiveNTRename";
317 return "(C0)OpenPrintFile";
319 return "(C1)WritePrintFile";
321 return "(C2)ClosePrintFile";
323 return "(C3)GetPrintQueue";
325 return "(D8)ReadBulk";
327 return "(D9)WriteBulk";
329 return "(DA)WriteBulkData";
331 return "unknown SMB op";
335 char * myCrt_2Dispatch(int i)
340 return "unknown SMB op-2";
342 return "S(00)CreateFile";
344 return "S(01)FindFirst";
346 return "S(02)FindNext"; /* FindNext */
348 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
352 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
354 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
356 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
358 return "S(08)??_ReceiveTran2SetFileInfo";
360 return "S(09)??_ReceiveTran2FSCTL";
362 return "S(0a)_ReceiveTran2IOCTL";
364 return "S(0b)_ReceiveTran2FindNotifyFirst";
366 return "S(0c)_ReceiveTran2FindNotifyNext";
368 return "S(0d)_ReceiveTran2CreateDirectory";
370 return "S(0e)_ReceiveTran2SessionSetup";
372 return "S(10)_ReceiveTran2GetDfsReferral";
374 return "S(11)_ReceiveTran2ReportDfsInconsistency";
378 char * myCrt_RapDispatch(int i)
383 return "unknown RAP OP";
385 return "RAP(0)NetShareEnum";
387 return "RAP(1)NetShareGetInfo";
389 return "RAP(13)NetServerGetInfo";
391 return "RAP(63)NetWkStaGetInfo";
395 /* scache must be locked */
396 unsigned int smb_Attributes(cm_scache_t *scp)
400 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
401 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
402 scp->fileType == CM_SCACHETYPE_INVALID)
404 attrs = SMB_ATTR_DIRECTORY;
405 #ifdef SPECIAL_FOLDERS
406 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
407 #endif /* SPECIAL_FOLDERS */
408 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
409 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
414 * We used to mark a file RO if it was in an RO volume, but that
415 * turns out to be impolitic in NT. See defect 10007.
418 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
419 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
421 if ((scp->unixModeBits & 0222) == 0)
422 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
428 /* Check if the named file/dir is a dotfile/dotdir */
429 /* String pointed to by lastComp can have leading slashes, but otherwise should have
430 no other patch components */
431 unsigned int smb_IsDotFile(char *lastComp) {
434 /* skip over slashes */
435 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
440 /* nulls, curdir and parent dir doesn't count */
446 if(*(s+1) == '.' && !*(s + 2))
453 static int ExtractBits(WORD bits, short start, short len)
460 num = bits << (16 - end);
461 num = num >> ((16 - end) + start);
467 void ShowUnixTime(char *FuncName, time_t unixTime)
472 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
474 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
475 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
477 int day, month, year, sec, min, hour;
480 day = ExtractBits(wDate, 0, 5);
481 month = ExtractBits(wDate, 5, 4);
482 year = ExtractBits(wDate, 9, 7) + 1980;
484 sec = ExtractBits(wTime, 0, 5);
485 min = ExtractBits(wTime, 5, 6);
486 hour = ExtractBits(wTime, 11, 5);
488 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
489 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
495 /* Determine if we are observing daylight savings time */
496 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
498 TIME_ZONE_INFORMATION timeZoneInformation;
499 SYSTEMTIME utc, local, localDST;
501 /* Get the time zone info. NT uses this to calc if we are in DST. */
502 GetTimeZoneInformation(&timeZoneInformation);
504 /* Return the daylight bias */
505 *pDstBias = timeZoneInformation.DaylightBias;
507 /* Return the bias */
508 *pBias = timeZoneInformation.Bias;
510 /* Now determine if DST is being observed */
512 /* Get the UTC (GMT) time */
515 /* Convert UTC time to local time using the time zone info. If we are
516 observing DST, the calculated local time will include this.
518 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
520 /* Set the daylight bias to 0. The daylight bias is the amount of change
521 * in time that we use for daylight savings time. By setting this to 0
522 * we cause there to be no change in time during daylight savings time.
524 timeZoneInformation.DaylightBias = 0;
526 /* Convert the utc time to local time again, but this time without any
527 adjustment for daylight savings time.
529 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
531 /* If the two times are different, then it means that the localDST that
532 we calculated includes the daylight bias, and therefore we are
533 observing daylight savings time.
535 *pDST = localDST.wHour != local.wHour;
538 /* Determine if we are observing daylight savings time */
539 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
545 *pDstBias = -60; /* where can this be different? */
551 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
553 BOOL dst; /* Will be TRUE if observing DST */
554 LONG dstBias; /* Offset from local time if observing DST */
555 LONG bias; /* Offset from GMT for local time */
558 * This function will adjust the last write time to compensate
559 * for two bugs in the smb client:
561 * 1) During Daylight Savings Time, the LastWriteTime is ahead
562 * in time by the DaylightBias (ignoring the sign - the
563 * DaylightBias is always stored as a negative number). If
564 * the DaylightBias is -60, then the LastWriteTime will be
565 * ahead by 60 minutes.
567 * 2) If the local time zone is a positive offset from GMT, then
568 * the LastWriteTime will be the correct local time plus the
569 * Bias (ignoring the sign - a positive offset from GMT is
570 * always stored as a negative Bias). If the Bias is -120,
571 * then the LastWriteTime will be ahead by 120 minutes.
573 * These bugs can occur at the same time.
576 GetTimeZoneInfo(&dst, &dstBias, &bias);
578 /* First adjust for DST */
580 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
582 /* Now adjust for a positive offset from GMT (a negative bias). */
584 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
587 #ifndef USE_NUMERIC_TIME_CONV
589 * Calculate the difference (in seconds) between local time and GMT.
590 * This enables us to convert file times to kludge-GMT.
596 struct tm gmt_tm, local_tm;
597 int days, hours, minutes, seconds;
600 gmt_tm = *(gmtime(&t));
601 local_tm = *(localtime(&t));
603 days = local_tm.tm_yday - gmt_tm.tm_yday;
604 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
605 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
606 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
610 #endif /* USE_NUMERIC_TIME_CONV */
613 #ifdef USE_NUMERIC_TIME_CONV
614 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
616 // Note that LONGLONG is a 64-bit value
619 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
620 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
621 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
624 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
629 time_t ersatz_unixTime;
632 * Must use kludge-GMT instead of real GMT.
633 * kludge-GMT is computed by adding time zone difference to localtime.
636 * ltp = gmtime(&unixTime);
638 ersatz_unixTime = unixTime - smb_NowTZ;
639 ltp = localtime(&ersatz_unixTime);
641 /* if we fail, make up something */
644 localJunk.tm_year = 89 - 20;
645 localJunk.tm_mon = 4;
646 localJunk.tm_mday = 12;
647 localJunk.tm_hour = 0;
648 localJunk.tm_min = 0;
649 localJunk.tm_sec = 0;
652 stm.wYear = ltp->tm_year + 1900;
653 stm.wMonth = ltp->tm_mon + 1;
654 stm.wDayOfWeek = ltp->tm_wday;
655 stm.wDay = ltp->tm_mday;
656 stm.wHour = ltp->tm_hour;
657 stm.wMinute = ltp->tm_min;
658 stm.wSecond = ltp->tm_sec;
659 stm.wMilliseconds = 0;
661 SystemTimeToFileTime(&stm, largeTimep);
663 #endif /* USE_NUMERIC_TIME_CONV */
665 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
667 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
668 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
669 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
671 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
673 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
674 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
676 *ft = LargeIntegerMultiplyByLong(*ft, 60);
677 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
680 ut = ConvertLongToLargeInteger(unixTime);
681 ut = LargeIntegerMultiplyByLong(ut, 10000000);
682 *ft = LargeIntegerAdd(*ft, ut);
687 #ifdef USE_NUMERIC_TIME_CONV
688 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
690 // Note that LONGLONG is a 64-bit value
693 ll = largeTimep->dwHighDateTime;
695 ll += largeTimep->dwLowDateTime;
697 ll -= 116444736000000000;
700 *unixTimep = (DWORD)ll;
702 #else /* USE_NUMERIC_TIME_CONV */
703 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
709 FileTimeToSystemTime(largeTimep, &stm);
711 lt.tm_year = stm.wYear - 1900;
712 lt.tm_mon = stm.wMonth - 1;
713 lt.tm_wday = stm.wDayOfWeek;
714 lt.tm_mday = stm.wDay;
715 lt.tm_hour = stm.wHour;
716 lt.tm_min = stm.wMinute;
717 lt.tm_sec = stm.wSecond;
720 save_timezone = _timezone;
721 _timezone += smb_NowTZ;
722 *unixTimep = mktime(<);
723 _timezone = save_timezone;
725 #endif /* USE_NUMERIC_TIME_CONV */
727 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
729 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
730 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
731 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
735 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
736 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
737 a = LargeIntegerMultiplyByLong(a, 60);
738 a = LargeIntegerMultiplyByLong(a, 10000000);
740 /* subtract it from ft */
741 a = LargeIntegerSubtract(*ft, a);
743 /* divide down to seconds */
744 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
748 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
756 ltp = localtime((time_t*) &t);
758 /* if we fail, make up something */
761 localJunk.tm_year = 89 - 20;
762 localJunk.tm_mon = 4;
763 localJunk.tm_mday = 12;
764 localJunk.tm_hour = 0;
765 localJunk.tm_min = 0;
766 localJunk.tm_sec = 0;
769 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
770 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
771 *searchTimep = (dosDate<<16) | dosTime;
774 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
776 unsigned short dosDate;
777 unsigned short dosTime;
780 dosDate = (unsigned short) (searchTime & 0xffff);
781 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
783 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
784 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
785 localTm.tm_mday = (dosDate) & 0x1f;
786 localTm.tm_hour = (dosTime>>11) & 0x1f;
787 localTm.tm_min = (dosTime >> 5) & 0x3f;
788 localTm.tm_sec = (dosTime & 0x1f) * 2;
789 localTm.tm_isdst = -1; /* compute whether DST in effect */
791 *unixTimep = mktime(&localTm);
794 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
796 time_t diff_t = unixTime - smb_localZero;
797 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
798 osi_assert(diff_t < _UI32_MAX);
800 *dosUTimep = (afs_uint32)diff_t;
803 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
806 *unixTimep = dosTime + smb_localZero;
808 /* dosTime seems to be already adjusted for GMT */
809 *unixTimep = dosTime;
813 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
817 lock_ObtainWrite(&smb_rctLock);
818 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
819 if (lsn == vcp->lsn && lana == vcp->lana) {
820 smb_HoldVCNoLock(vcp);
824 if (!vcp && (flags & SMB_FLAG_CREATE)) {
825 vcp = malloc(sizeof(*vcp));
826 memset(vcp, 0, sizeof(*vcp));
827 vcp->vcID = numVCs++;
831 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
832 vcp->nextp = smb_allVCsp;
834 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
839 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
840 /* We must obtain a challenge for extended auth
841 * in case the client negotiates smb v3
843 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
844 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
845 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
846 ULONG lsaRespSize = 0;
848 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
850 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
857 if (nts != STATUS_SUCCESS)
858 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
859 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
860 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
862 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
863 LsaFreeReturnBuffer(lsaResp);
866 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
868 if (numVCs >= CM_SESSION_RESERVED) {
870 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
873 lock_ReleaseWrite(&smb_rctLock);
877 int smb_IsStarMask(char *maskp)
882 for(i=0; i<11; i++) {
884 if (tc == '?' || tc == '*' || tc == '>') return 1;
889 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
891 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
893 osi_assert(vcp->refCount-- != 0);
899 void smb_ReleaseVC(smb_vc_t *vcp)
901 lock_ObtainWrite(&smb_rctLock);
902 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
904 osi_assert(vcp->refCount-- != 0);
908 lock_ReleaseWrite(&smb_rctLock);
911 void smb_HoldVCNoLock(smb_vc_t *vcp)
914 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
917 void smb_HoldVC(smb_vc_t *vcp)
919 lock_ObtainWrite(&smb_rctLock);
921 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
922 lock_ReleaseWrite(&smb_rctLock);
925 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
929 lock_ObtainWrite(&smb_rctLock);
930 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
931 if (tid == tidp->tid) {
936 if (!tidp && (flags & SMB_FLAG_CREATE)) {
937 tidp = malloc(sizeof(*tidp));
938 memset(tidp, 0, sizeof(*tidp));
939 tidp->nextp = vcp->tidsp;
942 smb_HoldVCNoLock(vcp);
944 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
947 lock_ReleaseWrite(&smb_rctLock);
951 void smb_ReleaseTID(smb_tid_t *tidp)
958 lock_ObtainWrite(&smb_rctLock);
959 osi_assert(tidp->refCount-- > 0);
960 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
961 ltpp = &tidp->vcp->tidsp;
962 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
966 osi_assert(tp != NULL);
968 lock_FinalizeMutex(&tidp->mx);
969 userp = tidp->userp; /* remember to drop ref later */
971 smb_ReleaseVCNoLock(tidp->vcp);
974 lock_ReleaseWrite(&smb_rctLock);
976 cm_ReleaseUser(userp);
979 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
981 smb_user_t *uidp = NULL;
983 lock_ObtainWrite(&smb_rctLock);
984 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
985 if (uid == uidp->userID) {
987 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[0x%p] found-uid[%d] name[%s]",
989 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
993 if (!uidp && (flags & SMB_FLAG_CREATE)) {
994 uidp = malloc(sizeof(*uidp));
995 memset(uidp, 0, sizeof(*uidp));
996 uidp->nextp = vcp->usersp;
999 smb_HoldVCNoLock(vcp);
1001 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1003 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[0x%p] new-uid[%d] name[%s]",vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
1005 lock_ReleaseWrite(&smb_rctLock);
1009 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1011 smb_username_t *unp= NULL;
1013 lock_ObtainWrite(&smb_rctLock);
1014 for(unp = usernamesp; unp; unp = unp->nextp) {
1015 if (stricmp(unp->name, usern) == 0 &&
1016 stricmp(unp->machine, machine) == 0) {
1021 if (!unp && (flags & SMB_FLAG_CREATE)) {
1022 unp = malloc(sizeof(*unp));
1023 memset(unp, 0, sizeof(*unp));
1025 unp->nextp = usernamesp;
1026 unp->name = strdup(usern);
1027 unp->machine = strdup(machine);
1029 lock_InitializeMutex(&unp->mx, "username_t mutex");
1031 lock_ReleaseWrite(&smb_rctLock);
1035 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1037 smb_user_t *uidp= NULL;
1039 lock_ObtainWrite(&smb_rctLock);
1040 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1043 if (stricmp(uidp->unp->name, usern) == 0) {
1045 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[0x%x] uid[%d] match-name[%s]",vcp,uidp->userID,usern);
1050 lock_ReleaseWrite(&smb_rctLock);
1053 void smb_ReleaseUID(smb_user_t *uidp)
1060 lock_ObtainWrite(&smb_rctLock);
1061 osi_assert(uidp->refCount-- > 0);
1062 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1063 lupp = &uidp->vcp->usersp;
1064 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1068 osi_assert(up != NULL);
1070 lock_FinalizeMutex(&uidp->mx);
1072 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1073 uidp->unp->userp = NULL; /* after releasing the lock */
1075 smb_ReleaseVCNoLock(uidp->vcp);
1078 lock_ReleaseWrite(&smb_rctLock);
1080 cm_ReleaseUserVCRef(userp);
1081 cm_ReleaseUser(userp);
1086 /* retrieve a held reference to a user structure corresponding to an incoming
1088 * corresponding release function is cm_ReleaseUser.
1090 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1096 smbp = (smb_t *) inp;
1097 uidp = smb_FindUID(vcp, smbp->uid, 0);
1098 if ((!uidp) || (!uidp->unp))
1101 lock_ObtainMutex(&uidp->mx);
1102 up = uidp->unp->userp;
1104 lock_ReleaseMutex(&uidp->mx);
1106 smb_ReleaseUID(uidp);
1112 * Return a pointer to a pathname extracted from a TID structure. The
1113 * TID structure is not held; assume it won't go away.
1115 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1120 tidp = smb_FindTID(vcp, tid, 0);
1124 if (tidp->flags & SMB_TIDFLAG_IPC) {
1125 code = CM_ERROR_TIDIPC;
1126 /* tidp->pathname would be NULL, but that's fine */
1128 *treepath = tidp->pathname;
1129 smb_ReleaseTID(tidp);
1134 /* check to see if we have a chained fid, that is, a fid that comes from an
1135 * OpenAndX message that ran earlier in this packet. In this case, the fid
1136 * field in a read, for example, request, isn't set, since the value is
1137 * supposed to be inherited from the openAndX call.
1139 int smb_ChainFID(int fid, smb_packet_t *inp)
1141 if (inp->fid == 0 || inp->inCount == 0)
1147 /* are we a priv'd user? What does this mean on NT? */
1148 int smb_SUser(cm_user_t *userp)
1153 /* find a file ID. If we pass in 0 we select an unused File ID.
1154 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1155 * smb_fid_t data structure if desired File ID cannot be found.
1157 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1162 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1165 lock_ObtainWrite(&smb_rctLock);
1166 /* figure out if we need to allocate a new file ID */
1169 fid = vcp->fidCounter;
1173 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1174 if (fid == fidp->fid) {
1186 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1187 char eventName[MAX_PATH];
1189 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1190 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1191 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1192 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1193 thrd_CloseHandle(event);
1200 fidp = malloc(sizeof(*fidp));
1201 memset(fidp, 0, sizeof(*fidp));
1202 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1205 smb_HoldVCNoLock(vcp);
1206 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1208 fidp->curr_chunk = fidp->prev_chunk = -2;
1209 fidp->raw_write_event = event;
1211 vcp->fidCounter = fid+1;
1212 if (vcp->fidCounter == 0)
1213 vcp->fidCounter = 1;
1217 lock_ReleaseWrite(&smb_rctLock);
1221 void smb_ReleaseFID(smb_fid_t *fidp)
1224 smb_vc_t *vcp = NULL;
1225 smb_ioctl_t *ioctlp;
1231 lock_ObtainWrite(&smb_rctLock);
1232 osi_assert(fidp->refCount-- > 0);
1233 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1236 scp = fidp->scp; /* release after lock is released */
1239 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1240 thrd_CloseHandle(fidp->raw_write_event);
1242 /* and see if there is ioctl stuff to free */
1243 ioctlp = fidp->ioctlp;
1246 cm_FreeSpace(ioctlp->prefix);
1247 if (ioctlp->inAllocp)
1248 free(ioctlp->inAllocp);
1249 if (ioctlp->outAllocp)
1250 free(ioctlp->outAllocp);
1256 smb_ReleaseVCNoLock(vcp);
1258 lock_ReleaseWrite(&smb_rctLock);
1260 /* now release the scache structure */
1262 cm_ReleaseSCache(scp);
1266 * Case-insensitive search for one string in another;
1267 * used to find variable names in submount pathnames.
1269 static char *smb_stristr(char *str1, char *str2)
1273 for (cursor = str1; *cursor; cursor++)
1274 if (stricmp(cursor, str2) == 0)
1281 * Substitute a variable value for its name in a submount pathname. Variable
1282 * name has been identified by smb_stristr() and is in substr. Variable name
1283 * length (plus one) is in substr_size. Variable value is in newstr.
1285 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1290 strcpy(temp, substr + substr_size - 1);
1291 strcpy(substr, newstr);
1295 char VNUserName[] = "%USERNAME%";
1296 char VNLCUserName[] = "%LCUSERNAME%";
1297 char VNComputerName[] = "%COMPUTERNAME%";
1298 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1301 /* List available shares */
1302 int smb_ListShares()
1306 char shareBuf[4096];
1314 /*strcpy(shareNameList[num_shares], "all");
1315 strcpy(pathNameList[num_shares++], "/afs");*/
1316 fprintf(stderr, "The following shares are available:\n");
1317 fprintf(stderr, "Share Name (AFS Path)\n");
1318 fprintf(stderr, "---------------------\n");
1319 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1322 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1323 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1325 strcpy(sbmtpath, cm_confDir);
1327 strcat(sbmtpath, "/afsdsbmt.ini");
1328 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1329 shareBuf, sizeof(shareBuf),
1335 this_share = shareBuf;
1339 /*strcpy(shareNameList[num_shares], this_share);*/
1340 len = GetPrivateProfileString("AFS Submounts", this_share,
1347 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1350 if (*p == '\\') *p = '/'; /* change to / */
1354 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1355 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1358 while (*this_share != 0) this_share++; /* find next NUL */
1359 this_share++; /* skip past the NUL */
1360 } while (*this_share != 0); /* stop at final NUL */
1366 typedef struct smb_findShare_rock {
1370 } smb_findShare_rock_t;
1372 #define SMB_FINDSHARE_EXACT_MATCH 1
1373 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1375 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1379 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1380 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1381 if(!stricmp(dep->name, vrock->shareName))
1382 matchType = SMB_FINDSHARE_EXACT_MATCH;
1384 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1385 if(vrock->match) free(vrock->match);
1386 vrock->match = strdup(dep->name);
1387 vrock->matchType = matchType;
1389 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1390 return CM_ERROR_STOPNOW;
1396 /* find a shareName in the table of submounts */
1397 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1401 char pathName[1024];
1406 char sbmtpath[MAX_PATH];
1411 DWORD allSubmount = 1;
1413 /* if allSubmounts == 0, only return the //mountRoot/all share
1414 * if in fact it has been been created in the subMounts table.
1415 * This is to allow sites that want to restrict access to the
1418 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1419 0, KEY_QUERY_VALUE, &parmKey);
1420 if (code == ERROR_SUCCESS) {
1421 len = sizeof(allSubmount);
1422 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1423 (BYTE *) &allSubmount, &len);
1424 if (code != ERROR_SUCCESS) {
1427 RegCloseKey (parmKey);
1430 if (allSubmount && _stricmp(shareName, "all") == 0) {
1435 /* In case, the all share is disabled we need to still be able
1436 * to handle ioctl requests
1438 if (_stricmp(shareName, "ioctl$") == 0) {
1439 *pathNamep = strdup("/.__ioctl__");
1443 if (_stricmp(shareName, "IPC$") == 0 ||
1444 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1445 _stricmp(shareName, "DESKTOP.INI") == 0
1452 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1453 0, KEY_QUERY_VALUE, &parmKey);
1454 if (code == ERROR_SUCCESS) {
1455 len = sizeof(pathName);
1456 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1457 (BYTE *) pathName, &len);
1458 if (code != ERROR_SUCCESS)
1460 RegCloseKey (parmKey);
1465 strcpy(sbmtpath, cm_confDir);
1466 strcat(sbmtpath, "/afsdsbmt.ini");
1467 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1468 pathName, sizeof(pathName), sbmtpath);
1470 if (len != 0 && len != sizeof(pathName) - 1) {
1471 /* We can accept either unix or PC style AFS pathnames. Convert
1472 * Unix-style to PC style here for internal use.
1475 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1476 p += strlen(cm_mountRoot); /* skip mount path */
1479 if (*q == '/') *q = '\\'; /* change to \ */
1485 if (var = smb_stristr(p, VNUserName)) {
1486 if (uidp && uidp->unp)
1487 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1489 smb_subst(p, var, sizeof(VNUserName)," ");
1491 else if (var = smb_stristr(p, VNLCUserName))
1493 if (uidp && uidp->unp)
1494 strcpy(temp, uidp->unp->name);
1498 smb_subst(p, var, sizeof(VNLCUserName), temp);
1500 else if (var = smb_stristr(p, VNComputerName))
1502 sizeTemp = sizeof(temp);
1503 GetComputerName((LPTSTR)temp, &sizeTemp);
1504 smb_subst(p, var, sizeof(VNComputerName), temp);
1506 else if (var = smb_stristr(p, VNLCComputerName))
1508 sizeTemp = sizeof(temp);
1509 GetComputerName((LPTSTR)temp, &sizeTemp);
1511 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1516 *pathNamep = strdup(p);
1521 /* First lookup shareName in root.afs */
1523 smb_findShare_rock_t vrock;
1525 char * p = shareName;
1528 /* attempt to locate a partial match in root.afs. This is because
1529 when using the ANSI RAP calls, the share name is limited to 13 chars
1530 and hence is truncated. Of course we prefer exact matches. */
1532 thyper.HighPart = 0;
1535 vrock.shareName = shareName;
1537 vrock.matchType = 0;
1539 cm_HoldSCache(cm_data.rootSCachep);
1540 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1541 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1542 cm_ReleaseSCache(cm_data.rootSCachep);
1544 if (vrock.matchType) {
1545 sprintf(pathName,"/%s/",vrock.match);
1546 *pathNamep = strdup(strlwr(pathName));
1551 /* if we get here, there was no match for the share in root.afs */
1552 /* so try to create \\<netbiosName>\<cellname> */
1557 /* Get the full name for this cell */
1558 code = cm_SearchCellFile(p, temp, 0, 0);
1559 #ifdef AFS_AFSDB_ENV
1560 if (code && cm_dnsEnabled) {
1562 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1565 /* construct the path */
1567 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1568 *pathNamep = strdup(strlwr(pathName));
1577 /* Client-side offline caching policy types */
1578 #define CSC_POLICY_MANUAL 0
1579 #define CSC_POLICY_DOCUMENTS 1
1580 #define CSC_POLICY_PROGRAMS 2
1581 #define CSC_POLICY_DISABLE 3
1583 int smb_FindShareCSCPolicy(char *shareName)
1589 int retval = CSC_POLICY_MANUAL;
1591 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1592 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1595 REG_OPTION_NON_VOLATILE,
1601 len = sizeof(policy);
1602 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1604 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1606 else if (stricmp(policy, "documents") == 0)
1608 retval = CSC_POLICY_DOCUMENTS;
1610 else if (stricmp(policy, "programs") == 0)
1612 retval = CSC_POLICY_PROGRAMS;
1614 else if (stricmp(policy, "disable") == 0)
1616 retval = CSC_POLICY_DISABLE;
1619 RegCloseKey(hkCSCPolicy);
1623 /* find a dir search structure by cookie value, and return it held.
1624 * Must be called with smb_globalLock held.
1626 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1628 smb_dirSearch_t *dsp;
1630 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1631 if (dsp->cookie == cookie) {
1632 if (dsp != smb_firstDirSearchp) {
1633 /* move to head of LRU queue, too, if we're not already there */
1634 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1635 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1636 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1637 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1638 if (!smb_lastDirSearchp)
1639 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1641 lock_ObtainMutex(&dsp->mx);
1643 lock_ReleaseMutex(&dsp->mx);
1649 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1650 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1651 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1657 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1659 lock_ObtainWrite(&smb_globalLock);
1660 lock_ObtainMutex(&dsp->mx);
1661 dsp->flags |= SMB_DIRSEARCH_DELETE;
1662 if (dsp->scp != NULL) {
1663 lock_ObtainMutex(&dsp->scp->mx);
1664 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1665 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1666 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1667 dsp->scp->bulkStatProgress = hones;
1669 lock_ReleaseMutex(&dsp->scp->mx);
1671 lock_ReleaseMutex(&dsp->mx);
1672 lock_ReleaseWrite(&smb_globalLock);
1675 /* Must be called with the smb_globalLock held */
1676 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1678 cm_scache_t *scp = NULL;
1680 lock_ObtainMutex(&dsp->mx);
1681 osi_assert(dsp->refCount-- > 0);
1682 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1683 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1684 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1685 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1686 lock_ReleaseMutex(&dsp->mx);
1687 lock_FinalizeMutex(&dsp->mx);
1691 lock_ReleaseMutex(&dsp->mx);
1693 /* do this now to avoid spurious locking hierarchy creation */
1695 cm_ReleaseSCache(scp);
1698 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1700 lock_ObtainWrite(&smb_globalLock);
1701 smb_ReleaseDirSearchNoLock(dsp);
1702 lock_ReleaseWrite(&smb_globalLock);
1705 /* find a dir search structure by cookie value, and return it held */
1706 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1708 smb_dirSearch_t *dsp;
1710 lock_ObtainWrite(&smb_globalLock);
1711 dsp = smb_FindDirSearchNoLock(cookie);
1712 lock_ReleaseWrite(&smb_globalLock);
1716 /* GC some dir search entries, in the address space expected by the specific protocol.
1717 * Must be called with smb_globalLock held; release the lock temporarily.
1719 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1720 void smb_GCDirSearches(int isV3)
1722 smb_dirSearch_t *prevp;
1723 smb_dirSearch_t *tp;
1724 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1728 victimCount = 0; /* how many have we got so far */
1729 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1730 /* we'll move tp from queue, so
1733 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1734 /* if no one is using this guy, and we're either in the new protocol,
1735 * or we're in the old one and this is a small enough ID to be useful
1736 * to the old protocol, GC this guy.
1738 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1739 /* hold and delete */
1740 tp->flags |= SMB_DIRSEARCH_DELETE;
1741 victimsp[victimCount++] = tp;
1745 /* don't do more than this */
1746 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1750 /* now release them */
1751 for (i = 0; i < victimCount; i++) {
1752 smb_ReleaseDirSearchNoLock(victimsp[i]);
1756 /* function for allocating a dir search entry. We need these to remember enough context
1757 * since we don't get passed the path from call to call during a directory search.
1759 * Returns a held dir search structure, and bumps the reference count on the vnode,
1760 * since it saves a pointer to the vnode.
1762 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1764 smb_dirSearch_t *dsp;
1770 lock_ObtainWrite(&smb_globalLock);
1773 /* what's the biggest ID allowed in this version of the protocol */
1774 maxAllowed = isV3 ? 65535 : 255;
1775 if (smb_dirSearchCounter > maxAllowed)
1776 smb_dirSearchCounter = 1;
1778 start = smb_dirSearchCounter;
1781 /* twice so we have enough tries to find guys we GC after one pass;
1782 * 10 extra is just in case I mis-counted.
1784 if (++counter > 2*maxAllowed+10)
1785 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1787 if (smb_dirSearchCounter > maxAllowed) {
1788 smb_dirSearchCounter = 1;
1790 if (smb_dirSearchCounter == start) {
1792 smb_GCDirSearches(isV3);
1795 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1797 /* don't need to watch for refcount zero and deleted, since
1798 * we haven't dropped the global lock.
1800 lock_ObtainMutex(&dsp->mx);
1802 lock_ReleaseMutex(&dsp->mx);
1803 ++smb_dirSearchCounter;
1807 dsp = malloc(sizeof(*dsp));
1808 memset(dsp, 0, sizeof(*dsp));
1809 dsp->cookie = smb_dirSearchCounter;
1810 ++smb_dirSearchCounter;
1812 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1813 dsp->lastTime = osi_Time();
1814 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1815 if (!smb_lastDirSearchp)
1816 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1819 lock_ReleaseWrite(&smb_globalLock);
1823 static smb_packet_t *GetPacket(void)
1827 unsigned int npar, seg, tb_sel;
1830 lock_ObtainWrite(&smb_globalLock);
1831 tbp = smb_packetFreeListp;
1833 smb_packetFreeListp = tbp->nextp;
1834 lock_ReleaseWrite(&smb_globalLock);
1837 tbp = calloc(65540,1);
1839 tbp = malloc(sizeof(smb_packet_t));
1841 tbp->magic = SMB_PACKETMAGIC;
1844 tbp->resumeCode = 0;
1850 tbp->ncb_length = 0;
1855 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1858 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1860 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1862 osi_panic("",__FILE__,__LINE__);
1865 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1870 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1871 tbp->dos_pkt_sel = tb_sel;
1874 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1879 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1883 memcpy(tbp, pkt, sizeof(smb_packet_t));
1884 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
1886 smb_HoldVC(tbp->vcp);
1890 static NCB *GetNCB(void)
1895 unsigned int npar, seg, tb_sel;
1898 lock_ObtainWrite(&smb_globalLock);
1899 tbp = smb_ncbFreeListp;
1901 smb_ncbFreeListp = tbp->nextp;
1902 lock_ReleaseWrite(&smb_globalLock);
1905 tbp = calloc(sizeof(*tbp),1);
1907 tbp = malloc(sizeof(*tbp));
1908 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1911 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1913 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1915 osi_panic("",__FILE__,__LINE__);
1917 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1922 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1923 tbp->dos_ncb_sel = tb_sel;
1925 tbp->magic = SMB_NCBMAGIC;
1928 osi_assert(tbp->magic == SMB_NCBMAGIC);
1930 memset(&tbp->ncb, 0, sizeof(NCB));
1933 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1938 void smb_FreePacket(smb_packet_t *tbp)
1940 smb_vc_t * vcp = NULL;
1941 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1943 lock_ObtainWrite(&smb_globalLock);
1944 tbp->nextp = smb_packetFreeListp;
1945 smb_packetFreeListp = tbp;
1946 tbp->magic = SMB_PACKETMAGIC;
1950 tbp->resumeCode = 0;
1956 tbp->ncb_length = 0;
1958 lock_ReleaseWrite(&smb_globalLock);
1964 static void FreeNCB(NCB *bufferp)
1968 tbp = (smb_ncb_t *) bufferp;
1969 osi_assert(tbp->magic == SMB_NCBMAGIC);
1971 lock_ObtainWrite(&smb_globalLock);
1972 tbp->nextp = smb_ncbFreeListp;
1973 smb_ncbFreeListp = tbp;
1974 lock_ReleaseWrite(&smb_globalLock);
1977 /* get a ptr to the data part of a packet, and its count */
1978 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1982 unsigned char *afterParmsp;
1984 parmBytes = *smbp->wctp << 1;
1985 afterParmsp = smbp->wctp + parmBytes + 1;
1987 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1988 if (nbytesp) *nbytesp = dataBytes;
1990 /* don't forget to skip the data byte count, since it follows
1991 * the parameters; that's where the "2" comes from below.
1993 return (unsigned char *) (afterParmsp + 2);
1996 /* must set all the returned parameters before playing around with the
1997 * data region, since the data region is located past the end of the
1998 * variable number of parameters.
2000 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2002 unsigned char *afterParmsp;
2004 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2006 *afterParmsp++ = dsize & 0xff;
2007 *afterParmsp = (dsize>>8) & 0xff;
2010 /* return the parm'th parameter in the smbp packet */
2011 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2014 unsigned char *parmDatap;
2016 parmCount = *smbp->wctp;
2018 if (parm >= parmCount) {
2023 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2025 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2026 parm, parmCount, smbp->ncb_length);
2029 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2030 1, smbp->ncb_length, ptbuf, smbp);
2031 DeregisterEventSource(h);
2033 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2034 parm, parmCount, smbp->ncb_length);
2035 osi_panic(s, __FILE__, __LINE__);
2037 parmDatap = smbp->wctp + (2*parm) + 1;
2039 return parmDatap[0] + (parmDatap[1] << 8);
2042 /* return the parm'th parameter in the smbp packet */
2043 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2046 unsigned char *parmDatap;
2048 parmCount = *smbp->wctp;
2050 if (parm * 2 + offset >= parmCount * 2) {
2055 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2057 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2058 parm, offset, parmCount, smbp->ncb_length);
2061 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2062 1, smbp->ncb_length, ptbuf, smbp);
2063 DeregisterEventSource(h);
2065 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2066 parm, offset, parmCount, smbp->ncb_length);
2067 osi_panic(s, __FILE__, __LINE__);
2069 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2071 return parmDatap[0] + (parmDatap[1] << 8);
2074 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2078 /* make sure we have enough slots */
2079 if (*smbp->wctp <= slot)
2080 *smbp->wctp = slot+1;
2082 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2083 *parmDatap++ = parmValue & 0xff;
2084 *parmDatap = (parmValue>>8) & 0xff;
2087 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2091 /* make sure we have enough slots */
2092 if (*smbp->wctp <= slot)
2093 *smbp->wctp = slot+2;
2095 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2096 *parmDatap++ = parmValue & 0xff;
2097 *parmDatap++ = (parmValue>>8) & 0xff;
2098 *parmDatap++ = (parmValue>>16) & 0xff;
2099 *parmDatap++ = (parmValue>>24) & 0xff;
2102 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2107 /* make sure we have enough slots */
2108 if (*smbp->wctp <= slot)
2109 *smbp->wctp = slot+4;
2111 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2113 *parmDatap++ = *parmValuep++;
2116 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2120 /* make sure we have enough slots */
2121 if (*smbp->wctp <= slot) {
2122 if (smbp->oddByte) {
2124 *smbp->wctp = slot+1;
2129 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2130 *parmDatap++ = parmValue & 0xff;
2133 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2137 lastSlashp = strrchr(inPathp, '\\');
2139 *lastComponentp = lastSlashp;
2142 if (inPathp == lastSlashp)
2144 *outPathp++ = *inPathp++;
2153 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2158 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2163 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2169 tlen = inp[0] + (inp[1]<<8);
2170 inp += 2; /* skip length field */
2173 *chainpp = inp + tlen;
2182 /* format a packet as a response */
2183 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2188 outp = (smb_t *) op;
2190 /* zero the basic structure through the smb_wct field, and zero the data
2191 * size field, assuming that wct stays zero; otherwise, you have to
2192 * explicitly set the data size field, too.
2194 inSmbp = (smb_t *) inp;
2195 memset(outp, 0, sizeof(smb_t)+2);
2201 outp->com = inSmbp->com;
2202 outp->tid = inSmbp->tid;
2203 outp->pid = inSmbp->pid;
2204 outp->uid = inSmbp->uid;
2205 outp->mid = inSmbp->mid;
2206 outp->res[0] = inSmbp->res[0];
2207 outp->res[1] = inSmbp->res[1];
2208 op->inCom = inSmbp->com;
2210 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2211 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2213 /* copy fields in generic packet area */
2214 op->wctp = &outp->wct;
2217 /* send a (probably response) packet; vcp tells us to whom to send it.
2218 * we compute the length by looking at wct and bcc fields.
2220 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2237 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2240 memset((char *)ncbp, 0, sizeof(NCB));
2242 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2243 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2244 extra += tp[0] + (tp[1]<<8);
2245 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2246 extra += 3; /* wct and length fields */
2248 ncbp->ncb_length = extra; /* bytes to send */
2249 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2250 ncbp->ncb_lana_num = vcp->lana;
2251 ncbp->ncb_command = NCBSEND; /* op means send data */
2253 ncbp->ncb_buffer = (char *) inp;/* packet */
2254 code = Netbios(ncbp);
2256 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2257 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2259 /* copy header information from virtual to DOS address space */
2260 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2261 code = Netbios(ncbp, dos_ncb);
2267 case 0x01: s = "llegal buffer length "; break;
2268 case 0x03: s = "illegal command "; break;
2269 case 0x05: s = "command timed out "; break;
2270 case 0x06: s = "message incomplete, issue another command"; break;
2271 case 0x07: s = "illegal buffer address "; break;
2272 case 0x08: s = "session number out of range "; break;
2273 case 0x09: s = "no resource available "; break;
2274 case 0x0a: s = "session closed "; break;
2275 case 0x0b: s = "command cancelled "; break;
2276 case 0x0d: s = "duplicate name "; break;
2277 case 0x0e: s = "name table full "; break;
2278 case 0x0f: s = "no deletions, name has active sessions "; break;
2279 case 0x11: s = "local session table full "; break;
2280 case 0x12: s = "remote session table full "; break;
2281 case 0x13: s = "illegal name number "; break;
2282 case 0x14: s = "no callname "; break;
2283 case 0x15: s = "cannot put * in NCB_NAME "; break;
2284 case 0x16: s = "name in use on remote adapter "; break;
2285 case 0x17: s = "name deleted "; break;
2286 case 0x18: s = "session ended abnormally "; break;
2287 case 0x19: s = "name conflict detected "; break;
2288 case 0x21: s = "interface busy, IRET before retrying "; break;
2289 case 0x22: s = "too many commands outstanding, retry later"; break;
2290 case 0x23: s = "ncb_lana_num field invalid "; break;
2291 case 0x24: s = "command completed while cancel occurring "; break;
2292 case 0x26: s = "command not valid to cancel "; break;
2293 case 0x30: s = "name defined by anther local process "; break;
2294 case 0x34: s = "environment undefined. RESET required "; break;
2295 case 0x35: s = "required OS resources exhausted "; break;
2296 case 0x36: s = "max number of applications exceeded "; break;
2297 case 0x37: s = "no saps available for netbios "; break;
2298 case 0x38: s = "requested resources are not available "; break;
2299 case 0x39: s = "invalid ncb address or length > segment "; break;
2300 case 0x3B: s = "invalid NCB DDID "; break;
2301 case 0x3C: s = "lock of user area failed "; break;
2302 case 0x3f: s = "NETBIOS not loaded "; break;
2303 case 0x40: s = "system error "; break;
2305 s = "unknown error";
2307 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2314 void smb_MapNTError(long code, unsigned long *NTStatusp)
2316 unsigned long NTStatus;
2318 /* map CM_ERROR_* errors to NT 32-bit status codes */
2319 /* NT Status codes are listed in ntstatus.h not winerror.h */
2320 if (code == CM_ERROR_NOSUCHCELL) {
2321 NTStatus = 0xC000000FL; /* No such file */
2323 else if (code == CM_ERROR_NOSUCHVOLUME) {
2324 NTStatus = 0xC000000FL; /* No such file */
2326 else if (code == CM_ERROR_TIMEDOUT) {
2328 NTStatus = 0xC00000CFL; /* Sharing Paused */
2330 NTStatus = 0x00000102L; /* Timeout */
2333 else if (code == CM_ERROR_RETRY) {
2334 NTStatus = 0xC000022DL; /* Retry */
2336 else if (code == CM_ERROR_NOACCESS) {
2337 NTStatus = 0xC0000022L; /* Access denied */
2339 else if (code == CM_ERROR_READONLY) {
2340 NTStatus = 0xC00000A2L; /* Write protected */
2342 else if (code == CM_ERROR_NOSUCHFILE) {
2343 NTStatus = 0xC000000FL; /* No such file */
2345 else if (code == CM_ERROR_NOSUCHPATH) {
2346 NTStatus = 0xC000003AL; /* Object path not found */
2348 else if (code == CM_ERROR_TOOBIG) {
2349 NTStatus = 0xC000007BL; /* Invalid image format */
2351 else if (code == CM_ERROR_INVAL) {
2352 NTStatus = 0xC000000DL; /* Invalid parameter */
2354 else if (code == CM_ERROR_BADFD) {
2355 NTStatus = 0xC0000008L; /* Invalid handle */
2357 else if (code == CM_ERROR_BADFDOP) {
2358 NTStatus = 0xC0000022L; /* Access denied */
2360 else if (code == CM_ERROR_EXISTS) {
2361 NTStatus = 0xC0000035L; /* Object name collision */
2363 else if (code == CM_ERROR_NOTEMPTY) {
2364 NTStatus = 0xC0000101L; /* Directory not empty */
2366 else if (code == CM_ERROR_CROSSDEVLINK) {
2367 NTStatus = 0xC00000D4L; /* Not same device */
2369 else if (code == CM_ERROR_NOTDIR) {
2370 NTStatus = 0xC0000103L; /* Not a directory */
2372 else if (code == CM_ERROR_ISDIR) {
2373 NTStatus = 0xC00000BAL; /* File is a directory */
2375 else if (code == CM_ERROR_BADOP) {
2377 /* I have no idea where this comes from */
2378 NTStatus = 0xC09820FFL; /* SMB no support */
2380 NTStatus = 0xC00000BBL; /* Not supported */
2381 #endif /* COMMENT */
2383 else if (code == CM_ERROR_BADSHARENAME) {
2384 NTStatus = 0xC00000CCL; /* Bad network name */
2386 else if (code == CM_ERROR_NOIPC) {
2388 NTStatus = 0xC0000022L; /* Access Denied */
2390 NTStatus = 0xC000013DL; /* Remote Resources */
2393 else if (code == CM_ERROR_CLOCKSKEW) {
2394 NTStatus = 0xC0000133L; /* Time difference at DC */
2396 else if (code == CM_ERROR_BADTID) {
2397 NTStatus = 0xC0982005L; /* SMB bad TID */
2399 else if (code == CM_ERROR_USESTD) {
2400 NTStatus = 0xC09820FBL; /* SMB use standard */
2402 else if (code == CM_ERROR_QUOTA) {
2404 NTStatus = 0xC0000044L; /* Quota exceeded */
2406 NTStatus = 0xC000007FL; /* Disk full */
2409 else if (code == CM_ERROR_SPACE) {
2410 NTStatus = 0xC000007FL; /* Disk full */
2412 else if (code == CM_ERROR_ATSYS) {
2413 NTStatus = 0xC0000033L; /* Object name invalid */
2415 else if (code == CM_ERROR_BADNTFILENAME) {
2416 NTStatus = 0xC0000033L; /* Object name invalid */
2418 else if (code == CM_ERROR_WOULDBLOCK) {
2419 NTStatus = 0xC0000055L; /* Lock not granted */
2421 else if (code == CM_ERROR_SHARING_VIOLATION) {
2422 NTStatus = 0xC0000043L; /* Sharing violation */
2424 else if (code == CM_ERROR_LOCK_CONFLICT) {
2425 NTStatus = 0xC0000054L; /* Lock conflict */
2427 else if (code == CM_ERROR_PARTIALWRITE) {
2428 NTStatus = 0xC000007FL; /* Disk full */
2430 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2431 NTStatus = 0xC0000023L; /* Buffer too small */
2433 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2434 NTStatus = 0xC0000035L; /* Object name collision */
2436 else if (code == CM_ERROR_BADPASSWORD) {
2437 NTStatus = 0xC000006DL; /* unknown username or bad password */
2439 else if (code == CM_ERROR_BADLOGONTYPE) {
2440 NTStatus = 0xC000015BL; /* logon type not granted */
2442 else if (code == CM_ERROR_GSSCONTINUE) {
2443 NTStatus = 0xC0000016L; /* more processing required */
2445 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2447 NTStatus = 0xC0000280L; /* reparse point not resolved */
2449 NTStatus = 0xC0000022L; /* Access Denied */
2452 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2453 NTStatus = 0xC0000257L; /* Path Not Covered */
2456 else if (code == CM_ERROR_ALLBUSY) {
2457 NTStatus = 0xC00000BFL; /* Network Busy */
2459 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2460 NTStatus = 0xC0000350L; /* Remote Host Down */
2463 /* we do not want to be telling the SMB/CIFS client that
2464 * the AFS Client Service is busy or down.
2466 else if (code == CM_ERROR_ALLBUSY ||
2467 code == CM_ERROR_ALLOFFLINE ||
2468 code == CM_ERROR_ALLDOWN) {
2469 NTStatus = 0xC00000BEL; /* Bad Network Path */
2472 else if (code == RXKADUNKNOWNKEY) {
2473 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2475 NTStatus = 0xC0982001L; /* SMB non-specific error */
2478 *NTStatusp = NTStatus;
2479 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2482 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2483 unsigned char *classp)
2485 unsigned char class;
2486 unsigned short error;
2488 /* map CM_ERROR_* errors to SMB errors */
2489 if (code == CM_ERROR_NOSUCHCELL) {
2491 error = 3; /* bad path */
2493 else if (code == CM_ERROR_NOSUCHVOLUME) {
2495 error = 3; /* bad path */
2497 else if (code == CM_ERROR_TIMEDOUT) {
2499 error = 81; /* server is paused */
2501 else if (code == CM_ERROR_RETRY) {
2502 class = 2; /* shouldn't happen */
2505 else if (code == CM_ERROR_NOACCESS) {
2507 error = 4; /* bad access */
2509 else if (code == CM_ERROR_READONLY) {
2511 error = 19; /* read only */
2513 else if (code == CM_ERROR_NOSUCHFILE) {
2515 error = 2; /* ENOENT! */
2517 else if (code == CM_ERROR_NOSUCHPATH) {
2519 error = 3; /* Bad path */
2521 else if (code == CM_ERROR_TOOBIG) {
2523 error = 11; /* bad format */
2525 else if (code == CM_ERROR_INVAL) {
2526 class = 2; /* server non-specific error code */
2529 else if (code == CM_ERROR_BADFD) {
2531 error = 6; /* invalid file handle */
2533 else if (code == CM_ERROR_BADFDOP) {
2534 class = 1; /* invalid op on FD */
2537 else if (code == CM_ERROR_EXISTS) {
2539 error = 80; /* file already exists */
2541 else if (code == CM_ERROR_NOTEMPTY) {
2543 error = 5; /* delete directory not empty */
2545 else if (code == CM_ERROR_CROSSDEVLINK) {
2547 error = 17; /* EXDEV */
2549 else if (code == CM_ERROR_NOTDIR) {
2550 class = 1; /* bad path */
2553 else if (code == CM_ERROR_ISDIR) {
2554 class = 1; /* access denied; DOS doesn't have a good match */
2557 else if (code == CM_ERROR_BADOP) {
2561 else if (code == CM_ERROR_BADSHARENAME) {
2565 else if (code == CM_ERROR_NOIPC) {
2567 error = 4; /* bad access */
2569 else if (code == CM_ERROR_CLOCKSKEW) {
2570 class = 1; /* invalid function */
2573 else if (code == CM_ERROR_BADTID) {
2577 else if (code == CM_ERROR_USESTD) {
2581 else if (code == CM_ERROR_REMOTECONN) {
2585 else if (code == CM_ERROR_QUOTA) {
2586 if (vcp->flags & SMB_VCFLAG_USEV3) {
2588 error = 39; /* disk full */
2592 error = 5; /* access denied */
2595 else if (code == CM_ERROR_SPACE) {
2596 if (vcp->flags & SMB_VCFLAG_USEV3) {
2598 error = 39; /* disk full */
2602 error = 5; /* access denied */
2605 else if (code == CM_ERROR_PARTIALWRITE) {
2607 error = 39; /* disk full */
2609 else if (code == CM_ERROR_ATSYS) {
2611 error = 2; /* ENOENT */
2613 else if (code == CM_ERROR_WOULDBLOCK) {
2615 error = 33; /* lock conflict */
2617 else if (code == CM_ERROR_LOCK_CONFLICT) {
2619 error = 33; /* lock conflict */
2621 else if (code == CM_ERROR_SHARING_VIOLATION) {
2623 error = 33; /* lock conflict */
2625 else if (code == CM_ERROR_NOFILES) {
2627 error = 18; /* no files in search */
2629 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2631 error = 183; /* Samba uses this */
2633 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2634 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2636 error = 2; /* bad password */
2638 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2640 error = 3; /* bad path */
2649 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2652 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2654 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2655 return CM_ERROR_BADOP;
2658 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2660 unsigned short EchoCount, i;
2661 char *data, *outdata;
2664 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2666 for (i=1; i<=EchoCount; i++) {
2667 data = smb_GetSMBData(inp, &dataSize);
2668 smb_SetSMBParm(outp, 0, i);
2669 smb_SetSMBDataLength(outp, dataSize);
2670 outdata = smb_GetSMBData(outp, NULL);
2671 memcpy(outdata, data, dataSize);
2672 smb_SendPacket(vcp, outp);
2678 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2681 long count, minCount, finalCount;
2686 cm_user_t *userp = NULL;
2690 char *rawBuf = NULL;
2692 dos_ptr rawBuf = NULL;
2699 fd = smb_GetSMBParm(inp, 0);
2700 count = smb_GetSMBParm(inp, 3);
2701 minCount = smb_GetSMBParm(inp, 4);
2702 offset.HighPart = 0; /* too bad */
2703 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2705 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2706 fd, offset.LowPart, count);
2708 fidp = smb_FindFID(vcp, fd, 0);
2712 pid = ((smb_t *) inp)->pid;
2714 LARGE_INTEGER LOffset, LLength;
2717 key = cm_GenerateKey(vcp->vcID, pid, fd);
2719 LOffset.HighPart = 0;
2720 LOffset.LowPart = offset.LowPart;
2721 LLength.HighPart = 0;
2722 LLength.LowPart = count;
2724 lock_ObtainMutex(&fidp->scp->mx);
2725 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2726 lock_ReleaseMutex(&fidp->scp->mx);
2732 lock_ObtainMutex(&smb_RawBufLock);
2734 /* Get a raw buf, from head of list */
2735 rawBuf = smb_RawBufs;
2737 smb_RawBufs = *(char **)smb_RawBufs;
2739 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2742 lock_ReleaseMutex(&smb_RawBufLock);
2746 if (fidp->flags & SMB_FID_IOCTL)
2749 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2751 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2754 /* Give back raw buffer */
2755 lock_ObtainMutex(&smb_RawBufLock);
2757 *((char **) rawBuf) = smb_RawBufs;
2759 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2762 smb_RawBufs = rawBuf;
2763 lock_ReleaseMutex(&smb_RawBufLock);
2766 smb_ReleaseFID(fidp);
2770 userp = smb_GetUser(vcp, inp);
2773 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2775 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2776 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2777 userp, &finalCount, TRUE /* rawFlag */);
2784 cm_ReleaseUser(userp);
2787 smb_ReleaseFID(fidp);
2792 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2794 memset((char *)ncbp, 0, sizeof(NCB));
2796 ncbp->ncb_length = (unsigned short) finalCount;
2797 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2798 ncbp->ncb_lana_num = vcp->lana;
2799 ncbp->ncb_command = NCBSEND;
2800 ncbp->ncb_buffer = rawBuf;
2803 code = Netbios(ncbp);
2805 code = Netbios(ncbp, dos_ncb);
2808 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2811 /* Give back raw buffer */
2812 lock_ObtainMutex(&smb_RawBufLock);
2814 *((char **) rawBuf) = smb_RawBufs;
2816 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2819 smb_RawBufs = rawBuf;
2820 lock_ReleaseMutex(&smb_RawBufLock);
2826 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2828 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2833 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2835 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2840 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2847 int protoIndex; /* index we're using */
2852 char protocol_array[10][1024]; /* protocol signature of the client */
2853 int caps; /* capabilities */
2856 TIME_ZONE_INFORMATION tzi;
2858 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2862 DWORD now = GetCurrentTime();
2863 if (now - last_msg_time >= 30000
2864 && now - last_msg_time <= 90000) {
2866 "Setting dead_vcp %x", active_vcp);
2868 smb_ReleaseVC(dead_vcp);
2870 "Previous dead_vcp %x", dead_vcp);
2872 smb_HoldVC(active_vcp);
2873 dead_vcp = active_vcp;
2874 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2879 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2881 namep = smb_GetSMBData(inp, &dbytes);
2884 coreProtoIndex = -1; /* not found */
2887 while(namex < dbytes) {
2888 osi_Log1(smb_logp, "Protocol %s",
2889 osi_LogSaveString(smb_logp, namep+1));
2890 strcpy(protocol_array[tcounter], namep+1);
2892 /* namep points at the first protocol, or really, a 0x02
2893 * byte preceding the null-terminated ASCII name.
2895 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2896 coreProtoIndex = tcounter;
2898 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2899 v3ProtoIndex = tcounter;
2901 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2902 NTProtoIndex = tcounter;
2905 /* compute size of protocol entry */
2906 entryLength = (int)strlen(namep+1);
2907 entryLength += 2; /* 0x02 bytes and null termination */
2909 /* advance over this protocol entry */
2910 namex += entryLength;
2911 namep += entryLength;
2912 tcounter++; /* which proto entry we're looking at */
2915 if (NTProtoIndex != -1) {
2916 protoIndex = NTProtoIndex;
2917 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2919 else if (v3ProtoIndex != -1) {
2920 protoIndex = v3ProtoIndex;
2921 vcp->flags |= SMB_VCFLAG_USEV3;
2923 else if (coreProtoIndex != -1) {
2924 protoIndex = coreProtoIndex;
2925 vcp->flags |= SMB_VCFLAG_USECORE;
2927 else protoIndex = -1;
2929 if (protoIndex == -1)
2930 return CM_ERROR_INVAL;
2931 else if (NTProtoIndex != -1) {
2932 smb_SetSMBParm(outp, 0, protoIndex);
2933 if (smb_authType != SMB_AUTH_NONE) {
2934 smb_SetSMBParmByte(outp, 1,
2935 NEGOTIATE_SECURITY_USER_LEVEL |
2936 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2938 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2940 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2941 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2942 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2943 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2944 /* The session key is not a well documented field however most clients
2945 * will echo back the session key to the server. Currently we are using
2946 * the same value for all sessions. We should generate a random value
2947 * and store it into the vcp
2949 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2950 smb_SetSMBParm(outp, 8, 1);
2952 * Tried changing the capabilities to support for W2K - defect 117695
2953 * Maybe something else needs to be changed here?
2957 smb_SetSMBParmLong(outp, 9, 0x43fd);
2959 smb_SetSMBParmLong(outp, 9, 0x251);
2962 * 32-bit error codes *
2967 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2969 NTNEGOTIATE_CAPABILITY_DFS |
2971 NTNEGOTIATE_CAPABILITY_NTFIND |
2972 NTNEGOTIATE_CAPABILITY_RAWMODE |
2973 NTNEGOTIATE_CAPABILITY_NTSMB;
2975 if ( smb_authType == SMB_AUTH_EXTENDED )
2976 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2978 smb_SetSMBParmLong(outp, 9, caps);
2980 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2981 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2982 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2984 GetTimeZoneInformation(&tzi);
2985 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2987 if (smb_authType == SMB_AUTH_NTLM) {
2988 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2989 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2990 /* paste in encryption key */
2991 datap = smb_GetSMBData(outp, NULL);
2992 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2993 /* and the faux domain name */
2994 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2995 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2999 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3001 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3003 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3005 datap = smb_GetSMBData(outp, NULL);
3006 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3009 datap += sizeof(smb_ServerGUID);
3010 memcpy(datap, secBlob, secBlobLength);
3014 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3015 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3018 else if (v3ProtoIndex != -1) {
3019 smb_SetSMBParm(outp, 0, protoIndex);
3021 /* NOTE: Extended authentication cannot be negotiated with v3
3022 * therefore we fail over to NTLM
3024 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3025 smb_SetSMBParm(outp, 1,
3026 NEGOTIATE_SECURITY_USER_LEVEL |
3027 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3029 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3031 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3032 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3033 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3034 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3035 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3036 smb_SetSMBParm(outp, 7, 1);
3038 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3039 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3040 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3042 GetTimeZoneInformation(&tzi);
3043 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3045 /* NOTE: Extended authentication cannot be negotiated with v3
3046 * therefore we fail over to NTLM
3048 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3049 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3050 smb_SetSMBParm(outp, 12, 0); /* resvd */
3051 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3052 datap = smb_GetSMBData(outp, NULL);
3053 /* paste in a new encryption key */
3054 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3055 /* and the faux domain name */
3056 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3058 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3059 smb_SetSMBParm(outp, 12, 0); /* resvd */
3060 smb_SetSMBDataLength(outp, 0);
3063 else if (coreProtoIndex != -1) { /* not really supported anymore */
3064 smb_SetSMBParm(outp, 0, protoIndex);
3065 smb_SetSMBDataLength(outp, 0);
3070 void smb_Daemon(void *parmp)
3072 afs_uint32 count = 0;
3074 while(smbShutdownFlag == 0) {
3078 if (smbShutdownFlag == 1)
3081 if ((count % 72) == 0) { /* every five minutes */
3083 time_t old_localZero = smb_localZero;
3085 /* Initialize smb_localZero */
3086 myTime.tm_isdst = -1; /* compute whether on DST or not */
3087 myTime.tm_year = 70;
3093 smb_localZero = mktime(&myTime);
3095 #ifndef USE_NUMERIC_TIME_CONV
3096 smb_CalculateNowTZ();
3097 #endif /* USE_NUMERIC_TIME_CONV */
3098 #ifdef AFS_FREELANCE
3099 if ( smb_localZero != old_localZero )
3100 cm_noteLocalMountPointChange();
3103 /* XXX GC dir search entries */
3107 void smb_WaitingLocksDaemon()
3109 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3110 smb_waitingLock_t *wl, *wlNext;
3113 smb_packet_t *inp, *outp;
3117 while (smbShutdownFlag == 0) {
3118 lock_ObtainWrite(&smb_globalLock);
3119 nwlRequest = smb_allWaitingLocks;
3120 if (nwlRequest == NULL) {
3121 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3131 lock_ObtainWrite(&smb_globalLock);
3133 wlRequest = nwlRequest;
3134 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3135 lock_ReleaseWrite(&smb_globalLock);
3139 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3140 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3143 /* wl->state is either _DONE or _WAITING. _ERROR
3144 would no longer be on the queue. */
3145 code = cm_RetryLock( wl->lockp,
3146 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3149 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3150 } else if (code != CM_ERROR_WOULDBLOCK) {
3151 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3156 if (code == CM_ERROR_WOULDBLOCK) {
3159 if (wlRequest->timeRemaining != 0xffffffff
3160 && (wlRequest->timeRemaining -= 1000) < 0)
3172 scp = wlRequest->scp;
3176 lock_ObtainMutex(&scp->mx);
3178 for (wl = wlRequest->locks; wl; wl = wlNext) {
3179 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3181 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3182 wl->LLength, wl->key, NULL, &req);
3184 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3189 lock_ReleaseMutex(&scp->mx);
3192 for (wl = wlRequest->locks; wl; wl = wlNext) {
3193 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3194 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3199 vcp = wlRequest->vcp;
3200 inp = wlRequest->inp;
3201 outp = wlRequest->outp;
3203 ncbp->ncb_length = inp->ncb_length;
3204 inp->spacep = cm_GetSpace();
3206 /* Remove waitingLock from list */
3207 lock_ObtainWrite(&smb_globalLock);
3208 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3210 lock_ReleaseWrite(&smb_globalLock);
3212 /* Resume packet processing */
3214 smb_SetSMBDataLength(outp, 0);
3215 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3216 outp->resumeCode = code;
3218 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3221 cm_FreeSpace(inp->spacep);
3222 smb_FreePacket(inp);
3223 smb_FreePacket(outp);
3225 cm_ReleaseSCache(wlRequest->scp);
3228 } while (nwlRequest && smbShutdownFlag == 0);
3233 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3235 osi_Log0(smb_logp, "SMB receive get disk attributes");
3237 smb_SetSMBParm(outp, 0, 32000);
3238 smb_SetSMBParm(outp, 1, 64);
3239 smb_SetSMBParm(outp, 2, 1024);
3240 smb_SetSMBParm(outp, 3, 30000);
3241 smb_SetSMBParm(outp, 4, 0);
3242 smb_SetSMBDataLength(outp, 0);
3246 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3250 unsigned short newTid;
3251 char shareName[256];
3259 osi_Log0(smb_logp, "SMB receive tree connect");
3261 /* parse input parameters */
3262 tp = smb_GetSMBData(inp, NULL);
3263 pathp = smb_ParseASCIIBlock(tp, &tp);
3264 if (smb_StoreAnsiFilenames)
3265 OemToChar(pathp,pathp);
3266 passwordp = smb_ParseASCIIBlock(tp, &tp);
3267 tp = strrchr(pathp, '\\');
3269 return CM_ERROR_BADSMB;
3270 strcpy(shareName, tp+1);
3272 userp = smb_GetUser(vcp, inp);
3274 lock_ObtainMutex(&vcp->mx);
3275 newTid = vcp->tidCounter++;
3276 lock_ReleaseMutex(&vcp->mx);
3278 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3279 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3280 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3282 smb_ReleaseUID(uidp);
3284 smb_ReleaseTID(tidp);
3285 return CM_ERROR_BADSHARENAME;
3287 lock_ObtainMutex(&tidp->mx);
3288 tidp->userp = userp;
3289 tidp->pathname = sharePath;
3290 lock_ReleaseMutex(&tidp->mx);
3291 smb_ReleaseTID(tidp);
3293 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3294 smb_SetSMBParm(rsp, 1, newTid);
3295 smb_SetSMBDataLength(rsp, 0);
3297 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3301 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3305 if (*inp++ != 0x1) return NULL;
3306 tlen = inp[0] + (inp[1]<<8);
3307 inp += 2; /* skip length field */
3310 *chainpp = inp + tlen;
3313 if (lengthp) *lengthp = tlen;
3318 /* set maskp to the mask part of the incoming path.
3319 * Mask is 11 bytes long (8.3 with the dot elided).
3320 * Returns true if succeeds with a valid name, otherwise it does
3321 * its best, but returns false.
3323 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3331 /* starts off valid */
3334 /* mask starts out all blanks */
3335 memset(maskp, ' ', 11);
3337 /* find last backslash, or use whole thing if there is none */
3338 tp = strrchr(pathp, '\\');
3339 if (!tp) tp = pathp;
3340 else tp++; /* skip slash */
3344 /* names starting with a dot are illegal */
3345 if (*tp == '.') valid8Dot3 = 0;
3349 if (tc == 0) return valid8Dot3;
3350 if (tc == '.' || tc == '"') break;
3351 if (i < 8) *up++ = tc;
3352 else valid8Dot3 = 0;
3355 /* if we get here, tp point after the dot */
3356 up = maskp+8; /* ext goes here */
3363 if (tc == '.' || tc == '"')
3366 /* copy extension if not too long */
3376 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3386 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3388 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3392 /* otherwise, we have a valid 8.3 name; see if we have a match,
3393 * treating '?' as a wildcard in maskp (but not in the file name).
3395 tp1 = umask; /* real name, in mask format */
3396 tp2 = maskp; /* mask, in mask format */
3397 for(i=0; i<11; i++) {
3398 tc1 = *tp1++; /* char from real name */
3399 tc2 = *tp2++; /* char from mask */
3400 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3401 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3404 if (tc2 == '?' && tc1 != ' ')
3411 /* we got a match */
3415 char *smb_FindMask(char *pathp)
3419 tp = strrchr(pathp, '\\'); /* find last slash */
3422 return tp+1; /* skip the slash */
3424 return pathp; /* no slash, return the entire path */
3427 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3429 unsigned char *pathp;
3431 unsigned char mask[11];
3432 unsigned char *statBlockp;
3433 unsigned char initStatBlock[21];
3436 osi_Log0(smb_logp, "SMB receive search volume");
3438 /* pull pathname and stat block out of request */
3439 tp = smb_GetSMBData(inp, NULL);
3440 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3441 osi_assert(pathp != NULL);
3442 if (smb_StoreAnsiFilenames)
3443 OemToChar(pathp,pathp);
3444 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3445 osi_assert(statBlockp != NULL);
3447 statBlockp = initStatBlock;
3451 /* for returning to caller */
3452 smb_Get8Dot3MaskFromPath(mask, pathp);
3454 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3455 tp = smb_GetSMBData(outp, NULL);
3457 *tp++ = 43; /* bytes in a dir entry */
3458 *tp++ = 0; /* high byte in counter */
3460 /* now marshall the dir entry, starting with the search status */
3461 *tp++ = statBlockp[0]; /* Reserved */
3462 memcpy(tp, mask, 11); tp += 11; /* FileName */
3464 /* now pass back server use info, with 1st byte non-zero */
3466 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3468 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3470 *tp++ = 0x8; /* attribute: volume */
3480 /* 4 byte file size */
3486 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3487 memset(tp, ' ', 13);
3490 /* set the length of the data part of the packet to 43 + 3, for the dir
3491 * entry plus the 5 and the length fields.
3493 smb_SetSMBDataLength(outp, 46);
3497 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3498 cm_user_t *userp, cm_req_t *reqp)
3506 smb_dirListPatch_t *patchp;
3507 smb_dirListPatch_t *npatchp;
3509 for (patchp = *dirPatchespp; patchp; patchp =
3510 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3512 dptr = patchp->dptr;
3514 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3516 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3517 *dptr++ = SMB_ATTR_HIDDEN;
3520 lock_ObtainMutex(&scp->mx);
3521 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3522 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3524 lock_ReleaseMutex(&scp->mx);
3525 cm_ReleaseSCache(scp);
3526 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3527 *dptr++ = SMB_ATTR_HIDDEN;
3531 attr = smb_Attributes(scp);
3532 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3533 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3534 attr |= SMB_ATTR_HIDDEN;
3538 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3541 shortTemp = (unsigned short) (dosTime & 0xffff);
3542 *((u_short *)dptr) = shortTemp;
3545 /* and copy out date */
3546 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3547 *((u_short *)dptr) = shortTemp;
3550 /* copy out file length */
3551 *((u_long *)dptr) = scp->length.LowPart;
3553 lock_ReleaseMutex(&scp->mx);
3554 cm_ReleaseSCache(scp);
3557 /* now free the patches */
3558 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3559 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3563 /* and mark the list as empty */
3564 *dirPatchespp = NULL;
3569 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3578 smb_dirListPatch_t *dirListPatchesp;
3579 smb_dirListPatch_t *curPatchp;
3583 osi_hyper_t dirLength;
3584 osi_hyper_t bufferOffset;
3585 osi_hyper_t curOffset;
3587 unsigned char *inCookiep;
3588 smb_dirSearch_t *dsp;
3592 unsigned long clientCookie;
3593 cm_pageHeader_t *pageHeaderp;
3594 cm_user_t *userp = NULL;
3601 long nextEntryCookie;
3602 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3603 char resByte; /* reserved byte from the cookie */
3604 char *op; /* output data ptr */
3605 char *origOp; /* original value of op */
3606 cm_space_t *spacep; /* for pathname buffer */
3617 maxCount = smb_GetSMBParm(inp, 0);
3619 dirListPatchesp = NULL;
3621 caseFold = CM_FLAG_CASEFOLD;
3623 tp = smb_GetSMBData(inp, NULL);
3624 pathp = smb_ParseASCIIBlock(tp, &tp);
3625 if (smb_StoreAnsiFilenames)
3626 OemToChar(pathp,pathp);
3627 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3629 /* bail out if request looks bad */
3630 if (!tp || !pathp) {
3631 return CM_ERROR_BADSMB;
3634 /* We can handle long names */
3635 if (vcp->flags & SMB_VCFLAG_USENT)
3636 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3638 /* make sure we got a whole search status */
3639 if (dataLength < 21) {
3640 nextCookie = 0; /* start at the beginning of the dir */
3643 attribute = smb_GetSMBParm(inp, 1);
3645 /* handle volume info in another function */
3646 if (attribute & 0x8)
3647 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3649 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3650 maxCount, osi_LogSaveString(smb_logp, pathp));
3652 if (*pathp == 0) { /* null pathp, treat as root dir */
3653 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3654 return CM_ERROR_NOFILES;
3658 dsp = smb_NewDirSearch(0);
3659 dsp->attribute = attribute;
3660 smb_Get8Dot3MaskFromPath(mask, pathp);
3661 memcpy(dsp->mask, mask, 11);
3663 /* track if this is likely to match a lot of entries */
3664 if (smb_IsStarMask(mask))
3669 /* pull the next cookie value out of the search status block */
3670 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3671 + (inCookiep[16]<<24);
3672 dsp = smb_FindDirSearch(inCookiep[12]);
3674 /* can't find dir search status; fatal error */
3675 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3676 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3677 return CM_ERROR_BADFD;
3679 attribute = dsp->attribute;
3680 resByte = inCookiep[0];
3682 /* copy out client cookie, in host byte order. Don't bother
3683 * interpreting it, since we're just passing it through, anyway.
3685 memcpy(&clientCookie, &inCookiep[17], 4);
3687 memcpy(mask, dsp->mask, 11);
3689 /* assume we're doing a star match if it has continued for more
3695 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3696 nextCookie, dsp->cookie, attribute);
3698 userp = smb_GetUser(vcp, inp);
3700 /* try to get the vnode for the path name next */
3701 lock_ObtainMutex(&dsp->mx);
3707 spacep = inp->spacep;
3708 smb_StripLastComponent(spacep->data, NULL, pathp);
3709 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3711 lock_ReleaseMutex(&dsp->mx);
3712 cm_ReleaseUser(userp);
3713 smb_DeleteDirSearch(dsp);
3714 smb_ReleaseDirSearch(dsp);
3715 return CM_ERROR_NOFILES;
3717 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3718 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3721 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3722 cm_ReleaseSCache(scp);
3723 lock_ReleaseMutex(&dsp->mx);
3724 cm_ReleaseUser(userp);
3725 smb_DeleteDirSearch(dsp);
3726 smb_ReleaseDirSearch(dsp);
3727 if ( WANTS_DFS_PATHNAMES(inp) )
3728 return CM_ERROR_PATH_NOT_COVERED;
3730 return CM_ERROR_BADSHARENAME;
3732 #endif /* DFS_SUPPORT */
3735 /* we need one hold for the entry we just stored into,
3736 * and one for our own processing. When we're done with this
3737 * function, we'll drop the one for our own processing.
3738 * We held it once from the namei call, and so we do another hold
3742 lock_ObtainMutex(&scp->mx);
3743 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3744 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3745 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3746 dsp->flags |= SMB_DIRSEARCH_BULKST;
3748 lock_ReleaseMutex(&scp->mx);
3751 lock_ReleaseMutex(&dsp->mx);
3753 cm_ReleaseUser(userp);
3754 smb_DeleteDirSearch(dsp);
3755 smb_ReleaseDirSearch(dsp);
3759 /* reserves space for parameter; we'll adjust it again later to the
3760 * real count of the # of entries we returned once we've actually
3761 * assembled the directory listing.
3763 smb_SetSMBParm(outp, 0, 0);
3765 /* get the directory size */
3766 lock_ObtainMutex(&scp->mx);
3767 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3768 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3770 lock_ReleaseMutex(&scp->mx);
3771 cm_ReleaseSCache(scp);
3772 cm_ReleaseUser(userp);
3773 smb_DeleteDirSearch(dsp);
3774 smb_ReleaseDirSearch(dsp);
3778 dirLength = scp->length;
3780 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3781 curOffset.HighPart = 0;
3782 curOffset.LowPart = nextCookie;
3783 origOp = op = smb_GetSMBData(outp, NULL);
3784 /* and write out the basic header */
3785 *op++ = 5; /* variable block */
3786 op += 2; /* skip vbl block length; we'll fill it in later */
3790 /* make sure that curOffset.LowPart doesn't point to the first
3791 * 32 bytes in the 2nd through last dir page, and that it doesn't
3792 * point at the first 13 32-byte chunks in the first dir page,
3793 * since those are dir and page headers, and don't contain useful
3796 temp = curOffset.LowPart & (2048-1);
3797 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3798 /* we're in the first page */
3799 if (temp < 13*32) temp = 13*32;
3802 /* we're in a later dir page */
3803 if (temp < 32) temp = 32;
3806 /* make sure the low order 5 bits are zero */
3809 /* now put temp bits back ito curOffset.LowPart */
3810 curOffset.LowPart &= ~(2048-1);
3811 curOffset.LowPart |= temp;
3813 /* check if we've returned all the names that will fit in the
3816 if (returnedNames >= maxCount) {
3817 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3818 returnedNames, maxCount);
3822 /* check if we've passed the dir's EOF */
3823 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3825 /* see if we can use the bufferp we have now; compute in which page
3826 * the current offset would be, and check whether that's the offset
3827 * of the buffer we have. If not, get the buffer.
3829 thyper.HighPart = curOffset.HighPart;
3830 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3831 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3834 buf_Release(bufferp);
3837 lock_ReleaseMutex(&scp->mx);
3838 lock_ObtainRead(&scp->bufCreateLock);
3839 code = buf_Get(scp, &thyper, &bufferp);
3840 lock_ReleaseRead(&scp->bufCreateLock);
3841 lock_ObtainMutex(&dsp->mx);
3843 /* now, if we're doing a star match, do bulk fetching of all of
3844 * the status info for files in the dir.
3847 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3848 lock_ObtainMutex(&scp->mx);
3849 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3850 LargeIntegerGreaterThanOrEqualTo(thyper,
3851 scp->bulkStatProgress)) {
3852 /* Don't bulk stat if risking timeout */
3853 int now = GetCurrentTime();
3854 if (now - req.startTime > 5000) {
3855 scp->bulkStatProgress = thyper;
3856 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3857 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3859 cm_TryBulkStat(scp, &thyper, userp, &req);
3862 lock_ObtainMutex(&scp->mx);
3864 lock_ReleaseMutex(&dsp->mx);
3866 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3870 bufferOffset = thyper;
3872 /* now get the data in the cache */
3874 code = cm_SyncOp(scp, bufferp, userp, &req,
3876 CM_SCACHESYNC_NEEDCALLBACK |
3877 CM_SCACHESYNC_READ);
3879 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3883 if (cm_HaveBuffer(scp, bufferp, 0)) {
3884 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3888 /* otherwise, load the buffer and try again */
3889 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3891 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3892 scp, bufferp, code);
3897 buf_Release(bufferp);
3901 } /* if (wrong buffer) ... */
3903 /* now we have the buffer containing the entry we're interested in; copy
3904 * it out if it represents a non-deleted entry.
3906 entryInDir = curOffset.LowPart & (2048-1);
3907 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3909 /* page header will help tell us which entries are free. Page header
3910 * can change more often than once per buffer, since AFS 3 dir page size
3911 * may be less than (but not more than a buffer package buffer.
3913 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3914 temp &= ~(2048 - 1); /* turn off intra-page bits */
3915 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3917 /* now determine which entry we're looking at in the page. If it is
3918 * free (there's a free bitmap at the start of the dir), we should
3919 * skip these 32 bytes.
3921 slotInPage = (entryInDir & 0x7e0) >> 5;
3922 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3923 /* this entry is free */
3924 numDirChunks = 1; /* only skip this guy */
3928 tp = bufferp->datap + entryInBuffer;
3929 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3931 /* while we're here, compute the next entry's location, too,
3932 * since we'll need it when writing out the cookie into the dir
3935 * XXXX Probably should do more sanity checking.
3937 numDirChunks = cm_NameEntries(dep->name, NULL);
3939 /* compute the offset of the cookie representing the next entry */
3940 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3942 /* Compute 8.3 name if necessary */
3943 actualName = dep->name;
3944 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3945 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3946 actualName = shortName;
3949 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3950 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3951 osi_LogSaveString(smb_logp, actualName));
3953 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3954 /* this is one of the entries to use: it is not deleted
3955 * and it matches the star pattern we're looking for.
3958 /* Eliminate entries that don't match requested
3961 /* no hidden files */
3962 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3963 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3967 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3969 /* We have already done the cm_TryBulkStat above */
3970 fid.cell = scp->fid.cell;
3971 fid.volume = scp->fid.volume;
3972 fid.vnode = ntohl(dep->fid.vnode);
3973 fid.unique = ntohl(dep->fid.unique);
3974 fileType = cm_FindFileType(&fid);
3975 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3976 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3978 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3979 fileType == CM_SCACHETYPE_DFSLINK ||
3980 fileType == CM_SCACHETYPE_INVALID)
3981 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3986 memcpy(op, mask, 11); op += 11;
3987 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3988 *op++ = (char)(nextEntryCookie & 0xff);
3989 *op++ = (char)((nextEntryCookie>>8) & 0xff);
3990 *op++ = (char)((nextEntryCookie>>16) & 0xff);
3991 *op++ = (char)((nextEntryCookie>>24) & 0xff);
3992 memcpy(op, &clientCookie, 4); op += 4;
3994 /* now we emit the attribute. This is sort of tricky,
3995 * since we need to really stat the file to find out
3996 * what type of entry we've got. Right now, we're
3997 * copying out data from a buffer, while holding the
3998 * scp locked, so it isn't really convenient to stat
3999 * something now. We'll put in a place holder now,
4000 * and make a second pass before returning this to get
4001 * the real attributes. So, we just skip the data for
4002 * now, and adjust it later. We allocate a patch
4003 * record to make it easy to find this point later.
4004 * The replay will happen at a time when it is safe to
4005 * unlock the directory.
4007 curPatchp = malloc(sizeof(*curPatchp));
4008 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4009 curPatchp->dptr = op;
4010 curPatchp->fid.cell = scp->fid.cell;
4011 curPatchp->fid.volume = scp->fid.volume;
4012 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4013 curPatchp->fid.unique = ntohl(dep->fid.unique);
4015 /* do hidden attribute here since name won't be around when applying
4019 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4020 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4022 curPatchp->flags = 0;
4024 op += 9; /* skip attr, time, date and size */
4026 /* zero out name area. The spec says to pad with
4027 * spaces, but Samba doesn't, and neither do we.
4031 /* finally, we get to copy out the name; we know that
4032 * it fits in 8.3 or the pattern wouldn't match, but it
4033 * never hurts to be sure.
4035 strncpy(op, actualName, 13);
4036 if (smb_StoreAnsiFilenames)
4039 /* Uppercase if requested by client */
4040 if (!KNOWS_LONG_NAMES(inp))
4045 /* now, adjust the # of entries copied */
4047 } /* if we're including this name */
4050 /* and adjust curOffset to be where the new cookie is */
4051 thyper.HighPart = 0;
4052 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4053 curOffset = LargeIntegerAdd(thyper, curOffset);
4054 } /* while copying data for dir listing */
4056 /* release the mutex */
4057 lock_ReleaseMutex(&scp->mx);
4058 if (bufferp) buf_Release(bufferp);
4060 /* apply and free last set of patches; if not doing a star match, this
4061 * will be empty, but better safe (and freeing everything) than sorry.
4063 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4065 /* special return code for unsuccessful search */
4066 if (code == 0 && dataLength < 21 && returnedNames == 0)
4067 code = CM_ERROR_NOFILES;
4069 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4070 returnedNames, code);
4073 smb_DeleteDirSearch(dsp);
4074 smb_ReleaseDirSearch(dsp);
4075 cm_ReleaseSCache(scp);
4076 cm_ReleaseUser(userp);
4080 /* finalize the output buffer */
4081 smb_SetSMBParm(outp, 0, returnedNames);
4082 temp = (long) (op - origOp);
4083 smb_SetSMBDataLength(outp, temp);
4085 /* the data area is a variable block, which has a 5 (already there)
4086 * followed by the length of the # of data bytes. We now know this to
4087 * be "temp," although that includes the 3 bytes of vbl block header.
4088 * Deduct for them and fill in the length field.
4090 temp -= 3; /* deduct vbl block info */
4091 osi_assert(temp == (43 * returnedNames));
4092 origOp[1] = (char)(temp & 0xff);
4093 origOp[2] = (char)((temp>>8) & 0xff);
4094 if (returnedNames == 0)
4095 smb_DeleteDirSearch(dsp);
4096 smb_ReleaseDirSearch(dsp);
4097 cm_ReleaseSCache(scp);
4098 cm_ReleaseUser(userp);
4102 /* verify that this is a valid path to a directory. I don't know why they
4103 * don't use the get file attributes call.
4105 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4109 cm_scache_t *rootScp;
4110 cm_scache_t *newScp;
4119 pathp = smb_GetSMBData(inp, NULL);
4120 pathp = smb_ParseASCIIBlock(pathp, NULL);
4122 return CM_ERROR_BADFD;
4123 if (smb_StoreAnsiFilenames)
4124 OemToChar(pathp,pathp);
4125 osi_Log1(smb_logp, "SMB receive check path %s",
4126 osi_LogSaveString(smb_logp, pathp));
4128 rootScp = cm_data.rootSCachep;
4130 userp = smb_GetUser(vcp, inp);
4132 caseFold = CM_FLAG_CASEFOLD;
4134 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4136 cm_ReleaseUser(userp);
4137 return CM_ERROR_NOSUCHPATH;
4139 code = cm_NameI(rootScp, pathp,
4140 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4141 userp, tidPathp, &req, &newScp);
4144 cm_ReleaseUser(userp);
4149 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4150 cm_ReleaseSCache(newScp);
4151 cm_ReleaseUser(userp);
4152 if ( WANTS_DFS_PATHNAMES(inp) )
4153 return CM_ERROR_PATH_NOT_COVERED;
4155 return CM_ERROR_BADSHARENAME;
4157 #endif /* DFS_SUPPORT */
4159 /* now lock the vnode with a callback; returns with newScp locked */
4160 lock_ObtainMutex(&newScp->mx);
4161 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4162 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4163 if (code && code != CM_ERROR_NOACCESS) {
4164 lock_ReleaseMutex(&newScp->mx);
4165 cm_ReleaseSCache(newScp);
4166 cm_ReleaseUser(userp);
4170 attrs = smb_Attributes(newScp);
4172 if (!(attrs & SMB_ATTR_DIRECTORY))
4173 code = CM_ERROR_NOTDIR;
4175 lock_ReleaseMutex(&newScp->mx);
4177 cm_ReleaseSCache(newScp);
4178 cm_ReleaseUser(userp);
4182 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4186 cm_scache_t *rootScp;
4187 unsigned short attribute;
4189 cm_scache_t *newScp;
4198 /* decode basic attributes we're passed */
4199 attribute = smb_GetSMBParm(inp, 0);
4200 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4202 pathp = smb_GetSMBData(inp, NULL);
4203 pathp = smb_ParseASCIIBlock(pathp, NULL);
4205 return CM_ERROR_BADSMB;
4206 if (smb_StoreAnsiFilenames)
4207 OemToChar(pathp,pathp);
4209 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4210 dosTime, attribute);
4212 rootScp = cm_data.rootSCachep;
4214 userp = smb_GetUser(vcp, inp);
4216 caseFold = CM_FLAG_CASEFOLD;
4218 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4220 cm_ReleaseUser(userp);
4221 return CM_ERROR_NOSUCHFILE;
4223 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4224 tidPathp, &req, &newScp);
4227 cm_ReleaseUser(userp);
4232 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4233 cm_ReleaseSCache(newScp);
4234 cm_ReleaseUser(userp);
4235 if ( WANTS_DFS_PATHNAMES(inp) )
4236 return CM_ERROR_PATH_NOT_COVERED;
4238 return CM_ERROR_BADSHARENAME;
4240 #endif /* DFS_SUPPORT */
4242 /* now lock the vnode with a callback; returns with newScp locked; we
4243 * need the current status to determine what the new status is, in some
4246 lock_ObtainMutex(&newScp->mx);
4247 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4248 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4250 lock_ReleaseMutex(&newScp->mx);
4251 cm_ReleaseSCache(newScp);
4252 cm_ReleaseUser(userp);
4256 /* Check for RO volume */
4257 if (newScp->flags & CM_SCACHEFLAG_RO) {
4258 lock_ReleaseMutex(&newScp->mx);
4259 cm_ReleaseSCache(newScp);
4260 cm_ReleaseUser(userp);
4261 return CM_ERROR_READONLY;
4264 /* prepare for setattr call */
4267 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4268 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4270 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4271 /* we're told to make a writable file read-only */
4272 attr.unixModeBits = newScp->unixModeBits & ~0222;
4273 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4275 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4276 /* we're told to make a read-only file writable */
4277 attr.unixModeBits = newScp->unixModeBits | 0222;
4278 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4280 lock_ReleaseMutex(&newScp->mx);
4282 /* now call setattr */
4284 code = cm_SetAttr(newScp, &attr, userp, &req);
4288 cm_ReleaseSCache(newScp);
4289 cm_ReleaseUser(userp);
4294 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4298 cm_scache_t *rootScp;
4299 cm_scache_t *newScp, *dscp;
4311 pathp = smb_GetSMBData(inp, NULL);
4312 pathp = smb_ParseASCIIBlock(pathp, NULL);
4314 return CM_ERROR_BADSMB;
4316 if (*pathp == 0) /* null path */
4319 if (smb_StoreAnsiFilenames)
4320 OemToChar(pathp,pathp);
4322 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4323 osi_LogSaveString(smb_logp, pathp));
4325 rootScp = cm_data.rootSCachep;
4327 userp = smb_GetUser(vcp, inp);
4329 /* we shouldn't need this for V3 requests, but we seem to */
4330 caseFold = CM_FLAG_CASEFOLD;
4332 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4334 cm_ReleaseUser(userp);
4335 return CM_ERROR_NOSUCHFILE;
4339 * XXX Strange hack XXX
4341 * As of Patch 5 (16 July 97), we are having the following problem:
4342 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4343 * requests to look up "desktop.ini" in all the subdirectories.
4344 * This can cause zillions of timeouts looking up non-existent cells
4345 * and volumes, especially in the top-level directory.
4347 * We have not found any way to avoid this or work around it except
4348 * to explicitly ignore the requests for mount points that haven't
4349 * yet been evaluated and for directories that haven't yet been
4352 * We should modify this hack to provide a fake desktop.ini file
4353 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4355 spacep = inp->spacep;
4356 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4357 #ifndef SPECIAL_FOLDERS
4358 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4359 code = cm_NameI(rootScp, spacep->data,
4360 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4361 userp, tidPathp, &req, &dscp);
4364 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4365 if ( WANTS_DFS_PATHNAMES(inp) )
4366 return CM_ERROR_PATH_NOT_COVERED;
4368 return CM_ERROR_BADSHARENAME;
4370 #endif /* DFS_SUPPORT */
4371 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4372 code = CM_ERROR_NOSUCHFILE;
4373 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4374 cm_buf_t *bp = buf_Find(dscp, &hzero);
4378 code = CM_ERROR_NOSUCHFILE;
4380 cm_ReleaseSCache(dscp);
4382 cm_ReleaseUser(userp);
4387 #endif /* SPECIAL_FOLDERS */
4389 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4390 tidPathp, &req, &newScp);
4392 cm_ReleaseUser(userp);
4397 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4398 cm_ReleaseSCache(newScp);
4399 cm_ReleaseUser(userp);
4400 if ( WANTS_DFS_PATHNAMES(inp) )
4401 return CM_ERROR_PATH_NOT_COVERED;
4403 return CM_ERROR_BADSHARENAME;
4405 #endif /* DFS_SUPPORT */
4407 /* now lock the vnode with a callback; returns with newScp locked */
4408 lock_ObtainMutex(&newScp->mx);
4409 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4410 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4412 lock_ReleaseMutex(&newScp->mx);
4413 cm_ReleaseSCache(newScp);
4414 cm_ReleaseUser(userp);
4419 /* use smb_Attributes instead. Also the fact that a file is
4420 * in a readonly volume doesn't mean it shojuld be marked as RO
4422 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4423 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4424 attrs = SMB_ATTR_DIRECTORY;
4427 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4428 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4430 attrs = smb_Attributes(newScp);
4433 smb_SetSMBParm(outp, 0, attrs);
4435 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4436 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4437 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4438 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4439 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4440 smb_SetSMBParm(outp, 5, 0);
4441 smb_SetSMBParm(outp, 6, 0);
4442 smb_SetSMBParm(outp, 7, 0);
4443 smb_SetSMBParm(outp, 8, 0);
4444 smb_SetSMBParm(outp, 9, 0);
4445 smb_SetSMBDataLength(outp, 0);
4446 lock_ReleaseMutex(&newScp->mx);
4448 cm_ReleaseSCache(newScp);
4449 cm_ReleaseUser(userp);
4454 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4458 osi_Log0(smb_logp, "SMB receive tree disconnect");
4460 /* find the tree and free it */
4461 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4463 lock_ObtainMutex(&tidp->mx);
4464 tidp->flags |= SMB_TIDFLAG_DELETE;
4465 lock_ReleaseMutex(&tidp->mx);
4466 smb_ReleaseTID(tidp);
4472 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4490 pathp = smb_GetSMBData(inp, NULL);
4491 pathp = smb_ParseASCIIBlock(pathp, NULL);
4492 if (smb_StoreAnsiFilenames)
4493 OemToChar(pathp,pathp);
4495 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4497 #ifdef DEBUG_VERBOSE
4501 hexpath = osi_HexifyString( pathp );
4502 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4507 share = smb_GetSMBParm(inp, 0);
4508 attribute = smb_GetSMBParm(inp, 1);
4510 spacep = inp->spacep;
4511 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4512 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4513 /* special case magic file name for receiving IOCTL requests
4514 * (since IOCTL calls themselves aren't getting through).
4516 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4517 smb_SetupIoctlFid(fidp, spacep);
4518 smb_SetSMBParm(outp, 0, fidp->fid);
4519 smb_SetSMBParm(outp, 1, 0); /* attrs */
4520 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4521 smb_SetSMBParm(outp, 3, 0);
4522 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4523 smb_SetSMBParm(outp, 5, 0x7fff);
4524 /* pass the open mode back */
4525 smb_SetSMBParm(outp, 6, (share & 0xf));
4526 smb_SetSMBDataLength(outp, 0);
4527 smb_ReleaseFID(fidp);
4531 userp = smb_GetUser(vcp, inp);
4533 caseFold = CM_FLAG_CASEFOLD;
4535 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4537 cm_ReleaseUser(userp);
4538 return CM_ERROR_NOSUCHPATH;
4540 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4541 tidPathp, &req, &scp);
4544 cm_ReleaseUser(userp);
4549 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4550 cm_ReleaseSCache(scp);
4551 cm_ReleaseUser(userp);
4552 if ( WANTS_DFS_PATHNAMES(inp) )
4553 return CM_ERROR_PATH_NOT_COVERED;
4555 return CM_ERROR_BADSHARENAME;
4557 #endif /* DFS_SUPPORT */
4559 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4561 cm_ReleaseSCache(scp);
4562 cm_ReleaseUser(userp);
4566 /* don't need callback to check file type, since file types never
4567 * change, and namei and cm_Lookup all stat the object at least once on
4568 * a successful return.
4570 if (scp->fileType != CM_SCACHETYPE_FILE) {
4571 cm_ReleaseSCache(scp);
4572 cm_ReleaseUser(userp);
4573 return CM_ERROR_ISDIR;
4576 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4579 /* save a pointer to the vnode */
4582 if ((share & 0xf) == 0)
4583 fidp->flags |= SMB_FID_OPENREAD;
4584 else if ((share & 0xf) == 1)
4585 fidp->flags |= SMB_FID_OPENWRITE;
4587 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4589 lock_ObtainMutex(&scp->mx);
4590 smb_SetSMBParm(outp, 0, fidp->fid);
4591 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4592 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4593 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4594 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4595 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4596 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4597 /* pass the open mode back; XXXX add access checks */
4598 smb_SetSMBParm(outp, 6, (share & 0xf));
4599 smb_SetSMBDataLength(outp, 0);
4600 lock_ReleaseMutex(&scp->mx);
4603 cm_Open(scp, 0, userp);
4605 /* send and free packet */
4606 smb_ReleaseFID(fidp);
4607 cm_ReleaseUser(userp);
4608 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4612 typedef struct smb_unlinkRock {
4617 char *maskp; /* pointer to the star pattern */
4622 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4625 smb_unlinkRock_t *rockp;
4633 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4634 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4635 caseFold |= CM_FLAG_8DOT3;
4637 matchName = dep->name;
4638 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4640 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4641 !cm_Is8Dot3(dep->name)) {
4642 cm_Gen8Dot3Name(dep, shortName, NULL);
4643 matchName = shortName;
4644 /* 8.3 matches are always case insensitive */
4645 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4648 osi_Log1(smb_logp, "Unlinking %s",
4649 osi_LogSaveString(smb_logp, matchName));
4650 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4651 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4652 smb_NotifyChange(FILE_ACTION_REMOVED,
4653 FILE_NOTIFY_CHANGE_FILE_NAME,
4654 dscp, dep->name, NULL, TRUE);
4658 /* If we made a case sensitive exact match, we might as well quit now. */
4659 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4660 code = CM_ERROR_STOPNOW;
4668 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4677 smb_unlinkRock_t rock;
4686 attribute = smb_GetSMBParm(inp, 0);
4688 tp = smb_GetSMBData(inp, NULL);
4689 pathp = smb_ParseASCIIBlock(tp, &tp);
4690 if (smb_StoreAnsiFilenames)
4691 OemToChar(pathp,pathp);
4693 osi_Log1(smb_logp, "SMB receive unlink %s",
4694 osi_LogSaveString(smb_logp, pathp));
4696 spacep = inp->spacep;
4697 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4699 userp = smb_GetUser(vcp, inp);
4701 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4703 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4705 cm_ReleaseUser(userp);
4706 return CM_ERROR_NOSUCHPATH;
4708 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4711 cm_ReleaseUser(userp);
4716 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4717 cm_ReleaseSCache(dscp);
4718 cm_ReleaseUser(userp);
4719 if ( WANTS_DFS_PATHNAMES(inp) )
4720 return CM_ERROR_PATH_NOT_COVERED;
4722 return CM_ERROR_BADSHARENAME;
4724 #endif /* DFS_SUPPORT */
4726 /* otherwise, scp points to the parent directory. */
4733 rock.maskp = smb_FindMask(pathp);
4734 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4737 thyper.HighPart = 0;
4743 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4744 * match. If that fails, we do a case insensitve match.
4746 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4747 !smb_IsStarMask(rock.maskp)) {
4748 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4751 thyper.HighPart = 0;
4752 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4757 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4759 if (code == CM_ERROR_STOPNOW)
4762 cm_ReleaseUser(userp);
4764 cm_ReleaseSCache(dscp);
4766 if (code == 0 && !rock.any)
4767 code = CM_ERROR_NOSUCHFILE;
4771 typedef struct smb_renameRock {
4772 cm_scache_t *odscp; /* old dir */
4773 cm_scache_t *ndscp; /* new dir */
4774 cm_user_t *userp; /* user */
4775 cm_req_t *reqp; /* request struct */
4776 smb_vc_t *vcp; /* virtual circuit */
4777 char *maskp; /* pointer to star pattern of old file name */
4778 int flags; /* tilde, casefold, etc */
4779 char *newNamep; /* ptr to the new file's name */
4782 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4785 smb_renameRock_t *rockp;
4790 rockp = (smb_renameRock_t *) vrockp;
4792 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4793 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4794 caseFold |= CM_FLAG_8DOT3;
4796 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4798 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4799 !cm_Is8Dot3(dep->name)) {
4800 cm_Gen8Dot3Name(dep, shortName, NULL);
4801 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4804 code = cm_Rename(rockp->odscp, dep->name,
4805 rockp->ndscp, rockp->newNamep, rockp->userp,
4807 /* if the call worked, stop doing the search now, since we
4808 * really only want to rename one file.
4811 code = CM_ERROR_STOPNOW;
4820 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4823 cm_space_t *spacep = NULL;
4824 smb_renameRock_t rock;
4825 cm_scache_t *oldDscp = NULL;
4826 cm_scache_t *newDscp = NULL;
4827 cm_scache_t *tmpscp= NULL;
4828 cm_scache_t *tmpscp2 = NULL;
4838 userp = smb_GetUser(vcp, inp);
4839 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4841 cm_ReleaseUser(userp);
4842 return CM_ERROR_NOSUCHPATH;
4846 spacep = inp->spacep;
4847 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4849 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4850 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4851 userp, tidPathp, &req, &oldDscp);
4853 cm_ReleaseUser(userp);
4858 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4859 cm_ReleaseSCache(oldDscp);
4860 cm_ReleaseUser(userp);
4861 if ( WANTS_DFS_PATHNAMES(inp) )
4862 return CM_ERROR_PATH_NOT_COVERED;
4864 return CM_ERROR_BADSHARENAME;
4866 #endif /* DFS_SUPPORT */
4868 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4869 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4870 userp, tidPathp, &req, &newDscp);
4873 cm_ReleaseSCache(oldDscp);
4874 cm_ReleaseUser(userp);
4879 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4880 cm_ReleaseSCache(oldDscp);
4881 cm_ReleaseSCache(newDscp);
4882 cm_ReleaseUser(userp);
4883 if ( WANTS_DFS_PATHNAMES(inp) )
4884 return CM_ERROR_PATH_NOT_COVERED;
4886 return CM_ERROR_BADSHARENAME;
4888 #endif /* DFS_SUPPORT */
4891 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4892 * next, get the component names, and lower case them.
4895 /* handle the old name first */
4897 oldLastNamep = oldPathp;
4901 /* and handle the new name, too */
4903 newLastNamep = newPathp;
4907 /* TODO: The old name could be a wildcard. The new name must not be */
4909 /* do the vnode call */
4910 rock.odscp = oldDscp;
4911 rock.ndscp = newDscp;
4915 rock.maskp = oldLastNamep;
4916 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4917 rock.newNamep = newLastNamep;
4919 /* Check if the file already exists; if so return error */
4920 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4921 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4922 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4923 osi_LogSaveString(afsd_logp, newLastNamep));
4925 /* Check if the old and the new names differ only in case. If so return
4926 * success, else return CM_ERROR_EXISTS
4928 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4930 /* This would be a success only if the old file is *as same as* the new file */
4931 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4933 if (tmpscp == tmpscp2)
4936 code = CM_ERROR_EXISTS;
4937 cm_ReleaseSCache(tmpscp2);
4940 code = CM_ERROR_NOSUCHFILE;
4943 /* file exist, do not rename, also fixes move */
4944 osi_Log0(smb_logp, "Can't rename. Target already exists");
4945 code = CM_ERROR_EXISTS;
4949 cm_ReleaseSCache(tmpscp);
4950 cm_ReleaseSCache(newDscp);
4951 cm_ReleaseSCache(oldDscp);
4952 cm_ReleaseUser(userp);
4956 /* Now search the directory for the pattern, and do the appropriate rename when found */
4957 thyper.LowPart = 0; /* search dir from here */
4958 thyper.HighPart = 0;
4960 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4961 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
4963 if (code == CM_ERROR_STOPNOW)
4966 code = CM_ERROR_NOSUCHFILE;
4968 /* Handle Change Notification */
4970 * Being lazy, not distinguishing between files and dirs in this
4971 * filter, since we'd have to do a lookup.
4973 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4974 if (oldDscp == newDscp) {
4975 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4976 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4977 filter, oldDscp, oldLastNamep,
4978 newLastNamep, TRUE);
4980 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4981 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4982 filter, oldDscp, oldLastNamep,
4984 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4985 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4986 filter, newDscp, newLastNamep,
4991 cm_ReleaseSCache(tmpscp);
4992 cm_ReleaseUser(userp);
4993 cm_ReleaseSCache(oldDscp);
4994 cm_ReleaseSCache(newDscp);
4999 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5002 cm_space_t *spacep = NULL;
5003 cm_scache_t *oldDscp = NULL;
5004 cm_scache_t *newDscp = NULL;
5005 cm_scache_t *tmpscp= NULL;
5006 cm_scache_t *tmpscp2 = NULL;
5007 cm_scache_t *sscp = NULL;
5016 userp = smb_GetUser(vcp, inp);
5018 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5020 cm_ReleaseUser(userp);
5021 return CM_ERROR_NOSUCHPATH;
5026 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5028 spacep = inp->spacep;
5029 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5031 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5032 userp, tidPathp, &req, &oldDscp);
5034 cm_ReleaseUser(userp);
5039 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5040 cm_ReleaseSCache(oldDscp);
5041 cm_ReleaseUser(userp);
5042 if ( WANTS_DFS_PATHNAMES(inp) )
5043 return CM_ERROR_PATH_NOT_COVERED;
5045 return CM_ERROR_BADSHARENAME;
5047 #endif /* DFS_SUPPORT */
5049 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5050 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5051 userp, tidPathp, &req, &newDscp);
5053 cm_ReleaseSCache(oldDscp);
5054 cm_ReleaseUser(userp);
5059 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5060 cm_ReleaseSCache(newDscp);
5061 cm_ReleaseSCache(oldDscp);
5062 cm_ReleaseUser(userp);
5063 if ( WANTS_DFS_PATHNAMES(inp) )
5064 return CM_ERROR_PATH_NOT_COVERED;
5066 return CM_ERROR_BADSHARENAME;
5068 #endif /* DFS_SUPPORT */
5070 /* Now, although we did two lookups for the two directories (because the same
5071 * directory can be referenced through different paths), we only allow hard links
5072 * within the same directory. */
5073 if (oldDscp != newDscp) {
5074 cm_ReleaseSCache(oldDscp);
5075 cm_ReleaseSCache(newDscp);
5076 cm_ReleaseUser(userp);
5077 return CM_ERROR_CROSSDEVLINK;
5080 /* handle the old name first */
5082 oldLastNamep = oldPathp;
5086 /* and handle the new name, too */
5088 newLastNamep = newPathp;
5092 /* now lookup the old name */
5093 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5094 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5096 cm_ReleaseSCache(oldDscp);
5097 cm_ReleaseSCache(newDscp);
5098 cm_ReleaseUser(userp);
5102 /* Check if the file already exists; if so return error */
5103 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5104 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5105 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5106 osi_LogSaveString(afsd_logp, newLastNamep));
5108 /* if the existing link is to the same file, then we return success */
5110 if(sscp == tmpscp) {
5113 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5114 code = CM_ERROR_EXISTS;
5119 cm_ReleaseSCache(tmpscp);
5120 cm_ReleaseSCache(sscp);
5121 cm_ReleaseSCache(newDscp);
5122 cm_ReleaseSCache(oldDscp);
5123 cm_ReleaseUser(userp);
5127 /* now create the hardlink */
5128 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5129 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5130 osi_Log1(smb_logp," Link returns %d", code);
5132 /* Handle Change Notification */
5134 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5135 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5136 smb_NotifyChange(FILE_ACTION_ADDED,
5137 filter, newDscp, newLastNamep,
5142 cm_ReleaseSCache(tmpscp);
5143 cm_ReleaseUser(userp);
5144 cm_ReleaseSCache(sscp);
5145 cm_ReleaseSCache(oldDscp);
5146 cm_ReleaseSCache(newDscp);
5151 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5157 tp = smb_GetSMBData(inp, NULL);
5158 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5159 if (smb_StoreAnsiFilenames)
5160 OemToChar(oldPathp,oldPathp);
5161 newPathp = smb_ParseASCIIBlock(tp, &tp);
5162 if (smb_StoreAnsiFilenames)
5163 OemToChar(newPathp,newPathp);
5165 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5166 osi_LogSaveString(smb_logp, oldPathp),
5167 osi_LogSaveString(smb_logp, newPathp));
5169 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5174 typedef struct smb_rmdirRock {
5178 char *maskp; /* pointer to the star pattern */
5183 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5186 smb_rmdirRock_t *rockp;
5191 rockp = (smb_rmdirRock_t *) vrockp;
5193 matchName = dep->name;
5194 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5195 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5197 match = (strcmp(matchName, rockp->maskp) == 0);
5199 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5200 !cm_Is8Dot3(dep->name)) {
5201 cm_Gen8Dot3Name(dep, shortName, NULL);
5202 matchName = shortName;
5203 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5206 osi_Log1(smb_logp, "Removing directory %s",
5207 osi_LogSaveString(smb_logp, matchName));
5208 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5209 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5210 smb_NotifyChange(FILE_ACTION_REMOVED,
5211 FILE_NOTIFY_CHANGE_DIR_NAME,
5212 dscp, dep->name, NULL, TRUE);
5221 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5229 smb_rmdirRock_t rock;
5238 tp = smb_GetSMBData(inp, NULL);
5239 pathp = smb_ParseASCIIBlock(tp, &tp);
5240 if (smb_StoreAnsiFilenames)
5241 OemToChar(pathp,pathp);
5243 spacep = inp->spacep;
5244 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5246 userp = smb_GetUser(vcp, inp);
5248 caseFold = CM_FLAG_CASEFOLD;
5250 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5252 cm_ReleaseUser(userp);
5253 return CM_ERROR_NOSUCHPATH;
5255 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5256 userp, tidPathp, &req, &dscp);
5259 cm_ReleaseUser(userp);
5264 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5265 cm_ReleaseSCache(dscp);
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 */
5274 /* otherwise, scp points to the parent directory. */
5281 rock.maskp = lastNamep;
5282 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5285 thyper.HighPart = 0;
5289 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5290 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5291 if (code == 0 && !rock.any) {
5293 thyper.HighPart = 0;
5294 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5295 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5298 cm_ReleaseUser(userp);
5300 cm_ReleaseSCache(dscp);
5302 if (code == 0 && !rock.any)
5303 code = CM_ERROR_NOSUCHFILE;
5307 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5317 fid = smb_GetSMBParm(inp, 0);
5319 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5321 fid = smb_ChainFID(fid, inp);
5322 fidp = smb_FindFID(vcp, fid, 0);
5323 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5325 smb_ReleaseFID(fidp);
5326 return CM_ERROR_BADFD;
5329 userp = smb_GetUser(vcp, inp);
5331 lock_ObtainMutex(&fidp->mx);
5332 if (fidp->flags & SMB_FID_OPENWRITE)
5333 code = cm_FSync(fidp->scp, userp, &req);
5336 lock_ReleaseMutex(&fidp->mx);
5338 smb_ReleaseFID(fidp);
5340 cm_ReleaseUser(userp);
5345 struct smb_FullNameRock {
5351 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5355 struct smb_FullNameRock *vrockp;
5357 vrockp = (struct smb_FullNameRock *)rockp;
5359 if (!cm_Is8Dot3(dep->name)) {
5360 cm_Gen8Dot3Name(dep, shortName, NULL);
5362 if (cm_stricmp(shortName, vrockp->name) == 0) {
5363 vrockp->fullName = strdup(dep->name);
5364 return CM_ERROR_STOPNOW;
5367 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5368 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5369 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5370 vrockp->fullName = strdup(dep->name);
5371 return CM_ERROR_STOPNOW;
5376 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5377 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5379 struct smb_FullNameRock rock;
5385 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5386 if (code == CM_ERROR_STOPNOW)
5387 *newPathp = rock.fullName;
5389 *newPathp = strdup(pathp);
5392 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5403 fid = smb_GetSMBParm(inp, 0);
5404 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5406 osi_Log1(smb_logp, "SMB close fid %d", fid);
5408 fid = smb_ChainFID(fid, inp);
5409 fidp = smb_FindFID(vcp, fid, 0);
5411 return CM_ERROR_BADFD;
5414 userp = smb_GetUser(vcp, inp);
5416 lock_ObtainMutex(&fidp->mx);
5418 /* Don't jump the gun on an async raw write */
5419 while (fidp->raw_writers) {
5420 lock_ReleaseMutex(&fidp->mx);
5421 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5422 lock_ObtainMutex(&fidp->mx);
5425 fidp->flags |= SMB_FID_DELETE;
5427 /* watch for ioctl closes, and read-only opens */
5428 if (fidp->scp != NULL &&
5429 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5430 == SMB_FID_OPENWRITE) {
5431 if (dosTime != 0 && dosTime != -1) {
5432 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5433 /* This fixes defect 10958 */
5434 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5435 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5437 code = cm_FSync(fidp->scp, userp, &req);
5442 /* unlock any pending locks */
5443 if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
5444 fidp->scp->fileType == CM_SCACHETYPE_FILE) {
5450 pid = ((smb_t *) inp)->pid;
5451 key = cm_GenerateKey(vcp->vcID, pid, fid);
5454 lock_ObtainMutex(&scp->mx);
5456 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5457 CM_SCACHESYNC_NEEDCALLBACK
5458 | CM_SCACHESYNC_GETSTATUS
5459 | CM_SCACHESYNC_LOCK);
5462 osi_Log1(smb_logp, "smb CoreClose SyncOp failure code 0x%x", tcode);
5463 goto post_syncopdone;
5466 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5468 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5472 lock_ReleaseMutex(&scp->mx);
5473 cm_ReleaseSCache(scp);
5476 if (fidp->flags & SMB_FID_DELONCLOSE) {
5477 cm_scache_t *dscp = fidp->NTopen_dscp;
5478 char *pathp = fidp->NTopen_pathp;
5481 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5482 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5483 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5484 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5485 smb_NotifyChange(FILE_ACTION_REMOVED,
5486 FILE_NOTIFY_CHANGE_DIR_NAME,
5487 dscp, fullPathp, NULL, TRUE);
5491 code = cm_Unlink(dscp, fullPathp, userp, &req);
5492 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5493 smb_NotifyChange(FILE_ACTION_REMOVED,
5494 FILE_NOTIFY_CHANGE_FILE_NAME,
5495 dscp, fullPathp, NULL, TRUE);
5499 lock_ReleaseMutex(&fidp->mx);
5501 if (fidp->flags & SMB_FID_NTOPEN) {
5502 cm_ReleaseSCache(fidp->NTopen_dscp);
5503 free(fidp->NTopen_pathp);
5505 if (fidp->NTopen_wholepathp)
5506 free(fidp->NTopen_wholepathp);
5508 smb_ReleaseFID(fidp);
5509 cm_ReleaseUser(userp);
5514 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5517 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5518 cm_user_t *userp, long *readp)
5520 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5521 cm_user_t *userp, long *readp, int dosflag)
5528 osi_hyper_t fileLength;
5530 osi_hyper_t lastByte;
5531 osi_hyper_t bufferOffset;
5532 long bufIndex, nbytes;
5542 lock_ObtainMutex(&fidp->mx);
5544 lock_ObtainMutex(&scp->mx);
5546 if (offset.HighPart == 0) {
5547 chunk = offset.LowPart >> cm_logChunkSize;
5548 if (chunk != fidp->curr_chunk) {
5549 fidp->prev_chunk = fidp->curr_chunk;
5550 fidp->curr_chunk = chunk;
5552 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5556 /* start by looking up the file's end */
5557 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5558 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5559 if (code) goto done;
5561 /* now we have the entry locked, look up the length */
5562 fileLength = scp->length;
5564 /* adjust count down so that it won't go past EOF */
5565 thyper.LowPart = count;
5566 thyper.HighPart = 0;
5567 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5569 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5570 /* we'd read past EOF, so just stop at fileLength bytes.
5571 * Start by computing how many bytes remain in the file.
5573 thyper = LargeIntegerSubtract(fileLength, offset);
5575 /* if we are past EOF, read 0 bytes */
5576 if (LargeIntegerLessThanZero(thyper))
5579 count = thyper.LowPart;
5584 /* now, copy the data one buffer at a time,
5585 * until we've filled the request packet
5588 /* if we've copied all the data requested, we're done */
5589 if (count <= 0) break;
5591 /* otherwise, load up a buffer of data */
5592 thyper.HighPart = offset.HighPart;
5593 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5594 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5597 buf_Release(bufferp);
5600 lock_ReleaseMutex(&scp->mx);
5602 lock_ObtainRead(&scp->bufCreateLock);
5603 code = buf_Get(scp, &thyper, &bufferp);
5604 lock_ReleaseRead(&scp->bufCreateLock);
5606 lock_ObtainMutex(&scp->mx);
5607 if (code) goto done;
5608 bufferOffset = thyper;
5610 /* now get the data in the cache */
5612 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5613 CM_SCACHESYNC_NEEDCALLBACK |
5614 CM_SCACHESYNC_READ);
5615 if (code) goto done;
5617 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5619 /* otherwise, load the buffer and try again */
5620 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5624 buf_Release(bufferp);
5628 } /* if (wrong buffer) ... */
5630 /* now we have the right buffer loaded. Copy out the
5631 * data from here to the user's buffer.
5633 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5635 /* and figure out how many bytes we want from this buffer */
5636 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5637 if (nbytes > count) nbytes = count; /* don't go past EOF */
5639 /* now copy the data */
5642 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5645 memcpy(op, bufferp->datap + bufIndex, nbytes);
5647 /* adjust counters, pointers, etc. */
5650 thyper.LowPart = nbytes;
5651 thyper.HighPart = 0;
5652 offset = LargeIntegerAdd(thyper, offset);
5656 lock_ReleaseMutex(&scp->mx);
5657 lock_ReleaseMutex(&fidp->mx);
5659 buf_Release(bufferp);
5661 if (code == 0 && sequential)
5662 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5668 * smb_WriteData -- common code for Write and Raw Write
5671 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5672 cm_user_t *userp, long *writtenp)
5674 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5675 cm_user_t *userp, long *writtenp, int dosflag)
5682 osi_hyper_t fileLength; /* file's length at start of write */
5683 osi_hyper_t minLength; /* don't read past this */
5684 long nbytes; /* # of bytes to transfer this iteration */
5686 osi_hyper_t thyper; /* hyper tmp variable */
5687 osi_hyper_t bufferOffset;
5688 long bufIndex; /* index in buffer where our data is */
5690 osi_hyper_t writeBackOffset;/* offset of region to write back when
5695 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5696 fidp->fid, offsetp->LowPart, count);
5706 lock_ObtainMutex(&fidp->mx);
5708 lock_ObtainMutex(&scp->mx);
5710 /* start by looking up the file's end */
5711 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5712 CM_SCACHESYNC_NEEDCALLBACK
5713 | CM_SCACHESYNC_SETSTATUS
5714 | CM_SCACHESYNC_GETSTATUS);
5718 /* make sure we have a writable FD */
5719 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5720 code = CM_ERROR_BADFDOP;
5724 /* now we have the entry locked, look up the length */
5725 fileLength = scp->length;
5726 minLength = fileLength;
5727 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5728 minLength = scp->serverLength;
5730 /* adjust file length if we extend past EOF */
5731 thyper.LowPart = count;
5732 thyper.HighPart = 0;
5733 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5734 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5735 /* we'd write past EOF, so extend the file */
5736 scp->mask |= CM_SCACHEMASK_LENGTH;
5737 scp->length = thyper;
5738 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5740 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5742 /* now, if the new position (thyper) and the old (offset) are in
5743 * different storeback windows, remember to store back the previous
5744 * storeback window when we're done with the write.
5746 if ((thyper.LowPart & (-cm_chunkSize)) !=
5747 (offset.LowPart & (-cm_chunkSize))) {
5748 /* they're different */
5750 writeBackOffset.HighPart = offset.HighPart;
5751 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5756 /* now, copy the data one buffer at a time, until we've filled the
5759 /* if we've copied all the data requested, we're done */
5763 /* handle over quota or out of space */
5764 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5765 *writtenp = written;
5766 code = CM_ERROR_QUOTA;
5770 /* otherwise, load up a buffer of data */
5771 thyper.HighPart = offset.HighPart;
5772 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5773 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5776 lock_ReleaseMutex(&bufferp->mx);
5777 buf_Release(bufferp);
5780 lock_ReleaseMutex(&scp->mx);
5782 lock_ObtainRead(&scp->bufCreateLock);
5783 code = buf_Get(scp, &thyper, &bufferp);
5784 lock_ReleaseRead(&scp->bufCreateLock);
5786 lock_ObtainMutex(&bufferp->mx);
5787 lock_ObtainMutex(&scp->mx);
5788 if (code) goto done;
5790 bufferOffset = thyper;
5792 /* now get the data in the cache */
5794 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5795 CM_SCACHESYNC_NEEDCALLBACK
5796 | CM_SCACHESYNC_WRITE
5797 | CM_SCACHESYNC_BUFLOCKED);
5801 /* If we're overwriting the entire buffer, or
5802 * if we're writing at or past EOF, mark the
5803 * buffer as current so we don't call
5804 * cm_GetBuffer. This skips the fetch from the
5805 * server in those cases where we're going to
5806 * obliterate all the data in the buffer anyway,
5807 * or in those cases where there is no useful
5808 * data at the server to start with.
5810 * Use minLength instead of scp->length, since
5811 * the latter has already been updated by this
5814 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5815 || LargeIntegerEqualTo(offset, bufferp->offset)
5816 && (count >= cm_data.buf_blockSize
5817 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5818 ConvertLongToLargeInteger(count)),
5820 if (count < cm_data.buf_blockSize
5821 && bufferp->dataVersion == -1)
5822 memset(bufferp->datap, 0,
5823 cm_data.buf_blockSize);
5824 bufferp->dataVersion = scp->dataVersion;
5827 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5829 /* otherwise, load the buffer and try again */
5830 lock_ReleaseMutex(&bufferp->mx);
5831 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5833 lock_ReleaseMutex(&scp->mx);
5834 lock_ObtainMutex(&bufferp->mx);
5835 lock_ObtainMutex(&scp->mx);
5839 lock_ReleaseMutex(&bufferp->mx);
5840 buf_Release(bufferp);
5844 } /* if (wrong buffer) ... */
5846 /* now we have the right buffer loaded. Copy out the
5847 * data from here to the user's buffer.
5849 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5851 /* and figure out how many bytes we want from this buffer */
5852 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5854 nbytes = count; /* don't go past end of request */
5856 /* now copy the data */
5859 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5862 memcpy(bufferp->datap + bufIndex, op, nbytes);
5863 buf_SetDirty(bufferp);
5865 /* and record the last writer */
5866 if (bufferp->userp != userp) {
5869 cm_ReleaseUser(bufferp->userp);
5870 bufferp->userp = userp;
5873 /* adjust counters, pointers, etc. */
5877 thyper.LowPart = nbytes;
5878 thyper.HighPart = 0;
5879 offset = LargeIntegerAdd(thyper, offset);
5883 lock_ReleaseMutex(&scp->mx);
5884 lock_ReleaseMutex(&fidp->mx);
5886 lock_ReleaseMutex(&bufferp->mx);
5887 buf_Release(bufferp);
5890 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5891 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5892 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5893 fidp->NTopen_dscp, fidp->NTopen_pathp,
5897 if (code == 0 && doWriteBack) {
5899 lock_ObtainMutex(&scp->mx);
5900 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5902 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5903 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5905 lock_ReleaseMutex(&scp->mx);
5906 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5907 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5910 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5911 fidp->fid, code, *writtenp);
5915 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5918 long count, written = 0, total_written = 0;
5924 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5926 int inDataBlockCount;
5928 fd = smb_GetSMBParm(inp, 0);
5929 count = smb_GetSMBParm(inp, 1);
5930 offset.HighPart = 0; /* too bad */
5931 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5933 op = smb_GetSMBData(inp, NULL);
5934 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5936 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5937 fd, offset.LowPart, count);
5939 fd = smb_ChainFID(fd, inp);
5940 fidp = smb_FindFID(vcp, fd, 0);
5942 return CM_ERROR_BADFD;
5945 if (fidp->flags & SMB_FID_IOCTL)
5946 return smb_IoctlWrite(fidp, vcp, inp, outp);
5948 userp = smb_GetUser(vcp, inp);
5950 /* special case: 0 bytes transferred means truncate to this position */
5956 truncAttr.mask = CM_ATTRMASK_LENGTH;
5957 truncAttr.length.LowPart = offset.LowPart;
5958 truncAttr.length.HighPart = 0;
5959 lock_ObtainMutex(&fidp->mx);
5960 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5961 lock_ReleaseMutex(&fidp->mx);
5962 smb_SetSMBParm(outp, 0, /* count */ 0);
5963 smb_SetSMBDataLength(outp, 0);
5964 fidp->flags |= SMB_FID_LENGTHSETDONE;
5970 LARGE_INTEGER LOffset;
5971 LARGE_INTEGER LLength;
5973 pid = ((smb_t *) inp)->pid;
5974 key = cm_GenerateKey(vcp->vcID, pid, fd);
5976 LOffset.HighPart = offset.HighPart;
5977 LOffset.LowPart = offset.LowPart;
5978 LLength.HighPart = 0;
5979 LLength.LowPart = count;
5981 lock_ObtainMutex(&fidp->scp->mx);
5982 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5983 lock_ReleaseMutex(&fidp->scp->mx);
5990 * Work around bug in NT client
5992 * When copying a file, the NT client should first copy the data,
5993 * then copy the last write time. But sometimes the NT client does
5994 * these in the wrong order, so the data copies would inadvertently
5995 * cause the last write time to be overwritten. We try to detect this,
5996 * and don't set client mod time if we think that would go against the
5999 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6000 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6001 fidp->scp->clientModTime = time(NULL);
6005 while ( code == 0 && count > 0 ) {
6007 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6009 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6011 if (code == 0 && written == 0)
6012 code = CM_ERROR_PARTIALWRITE;
6014 offset.LowPart += written;
6016 total_written += written;
6020 /* set the packet data length to 3 bytes for the data block header,
6021 * plus the size of the data.
6023 smb_SetSMBParm(outp, 0, total_written);
6024 smb_SetSMBDataLength(outp, 0);
6027 smb_ReleaseFID(fidp);
6028 cm_ReleaseUser(userp);
6033 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6034 NCB *ncbp, raw_write_cont_t *rwcp)
6047 fd = smb_GetSMBParm(inp, 0);
6048 fidp = smb_FindFID(vcp, fd, 0);
6050 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
6051 rwcp->offset.LowPart, rwcp->count);
6053 userp = smb_GetUser(vcp, inp);
6057 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6060 rawBuf = (dos_ptr) rwcp->buf;
6061 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6062 (unsigned char *) rawBuf, userp,
6066 if (rwcp->writeMode & 0x1) { /* synchronous */
6069 smb_FormatResponsePacket(vcp, inp, outp);
6070 op = (smb_t *) outp;
6071 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6072 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6073 smb_SetSMBDataLength(outp, 0);
6074 smb_SendPacket(vcp, outp);
6075 smb_FreePacket(outp);
6077 else { /* asynchronous */
6078 lock_ObtainMutex(&fidp->mx);
6079 fidp->raw_writers--;
6080 if (fidp->raw_writers == 0)
6081 thrd_SetEvent(fidp->raw_write_event);
6082 lock_ReleaseMutex(&fidp->mx);
6085 /* Give back raw buffer */
6086 lock_ObtainMutex(&smb_RawBufLock);
6088 *((char **)rawBuf) = smb_RawBufs;
6090 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6092 smb_RawBufs = rawBuf;
6093 lock_ReleaseMutex(&smb_RawBufLock);
6095 smb_ReleaseFID(fidp);
6096 cm_ReleaseUser(userp);
6099 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6104 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6107 long count, written = 0, total_written = 0;
6114 unsigned short writeMode;
6121 fd = smb_GetSMBParm(inp, 0);
6122 totalCount = smb_GetSMBParm(inp, 1);
6123 count = smb_GetSMBParm(inp, 10);
6124 offset.HighPart = 0; /* too bad */
6125 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6126 writeMode = smb_GetSMBParm(inp, 7);
6128 op = (char *) inp->data;
6129 op += smb_GetSMBParm(inp, 11);
6132 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
6133 fd, offset.LowPart, count, writeMode);
6135 fd = smb_ChainFID(fd, inp);
6136 fidp = smb_FindFID(vcp, fd, 0);
6138 return CM_ERROR_BADFD;
6144 LARGE_INTEGER LOffset;
6145 LARGE_INTEGER LLength;
6147 pid = ((smb_t *) inp)->pid;
6148 key = cm_GenerateKey(vcp->vcID, pid, fd);
6150 LOffset.HighPart = offset.HighPart;
6151 LOffset.LowPart = offset.LowPart;
6152 LLength.HighPart = 0;
6153 LLength.LowPart = count;
6155 lock_ObtainMutex(&fidp->scp->mx);
6156 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6157 lock_ReleaseMutex(&fidp->scp->mx);
6160 smb_ReleaseFID(fidp);
6165 userp = smb_GetUser(vcp, inp);
6168 * Work around bug in NT client
6170 * When copying a file, the NT client should first copy the data,
6171 * then copy the last write time. But sometimes the NT client does
6172 * these in the wrong order, so the data copies would inadvertently
6173 * cause the last write time to be overwritten. We try to detect this,
6174 * and don't set client mod time if we think that would go against the
6177 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6178 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6179 fidp->scp->clientModTime = time(NULL);
6183 while ( code == 0 && count > 0 ) {
6185 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6187 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6189 if (code == 0 && written == 0)
6190 code = CM_ERROR_PARTIALWRITE;
6192 offset.LowPart += written;
6194 total_written += written;
6198 /* Get a raw buffer */
6201 lock_ObtainMutex(&smb_RawBufLock);
6203 /* Get a raw buf, from head of list */
6204 rawBuf = smb_RawBufs;
6206 smb_RawBufs = *(char **)smb_RawBufs;
6208 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6212 code = CM_ERROR_USESTD;
6214 lock_ReleaseMutex(&smb_RawBufLock);
6217 /* Don't allow a premature Close */
6218 if (code == 0 && (writeMode & 1) == 0) {
6219 lock_ObtainMutex(&fidp->mx);
6220 fidp->raw_writers++;
6221 thrd_ResetEvent(fidp->raw_write_event);
6222 lock_ReleaseMutex(&fidp->mx);
6225 smb_ReleaseFID(fidp);
6226 cm_ReleaseUser(userp);
6229 smb_SetSMBParm(outp, 0, total_written);
6230 smb_SetSMBDataLength(outp, 0);
6231 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6238 rwcp->offset.HighPart = 0;
6239 rwcp->offset.LowPart = offset.LowPart + count;
6240 rwcp->count = totalCount - count;
6241 rwcp->writeMode = writeMode;
6242 rwcp->alreadyWritten = total_written;
6244 /* set the packet data length to 3 bytes for the data block header,
6245 * plus the size of the data.
6247 smb_SetSMBParm(outp, 0, 0xffff);
6248 smb_SetSMBDataLength(outp, 0);
6253 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6256 long count, finalCount;
6264 fd = smb_GetSMBParm(inp, 0);
6265 count = smb_GetSMBParm(inp, 1);
6266 offset.HighPart = 0; /* too bad */
6267 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6269 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6270 fd, offset.LowPart, count);
6272 fd = smb_ChainFID(fd, inp);
6273 fidp = smb_FindFID(vcp, fd, 0);
6275 return CM_ERROR_BADFD;
6278 if (fidp->flags & SMB_FID_IOCTL) {
6279 return smb_IoctlRead(fidp, vcp, inp, outp);
6283 LARGE_INTEGER LOffset, LLength;
6286 pid = ((smb_t *) inp)->pid;
6287 key = cm_GenerateKey(vcp->vcID, pid, fd);
6289 LOffset.HighPart = 0;
6290 LOffset.LowPart = offset.LowPart;
6291 LLength.HighPart = 0;
6292 LLength.LowPart = count;
6294 lock_ObtainMutex(&fidp->scp->mx);
6295 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6296 lock_ReleaseMutex(&fidp->scp->mx);
6299 smb_ReleaseFID(fidp);
6303 userp = smb_GetUser(vcp, inp);
6305 /* remember this for final results */
6306 smb_SetSMBParm(outp, 0, count);
6307 smb_SetSMBParm(outp, 1, 0);
6308 smb_SetSMBParm(outp, 2, 0);
6309 smb_SetSMBParm(outp, 3, 0);
6310 smb_SetSMBParm(outp, 4, 0);
6312 /* set the packet data length to 3 bytes for the data block header,
6313 * plus the size of the data.
6315 smb_SetSMBDataLength(outp, count+3);
6317 /* get op ptr after putting in the parms, since otherwise we don't
6318 * know where the data really is.
6320 op = smb_GetSMBData(outp, NULL);
6322 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6323 *op++ = 1; /* data block marker */
6324 *op++ = (unsigned char) (count & 0xff);
6325 *op++ = (unsigned char) ((count >> 8) & 0xff);
6328 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6330 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6333 /* fix some things up */
6334 smb_SetSMBParm(outp, 0, finalCount);
6335 smb_SetSMBDataLength(outp, finalCount+3);
6337 smb_ReleaseFID(fidp);
6339 cm_ReleaseUser(userp);
6343 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6350 cm_scache_t *dscp; /* dir we're dealing with */
6351 cm_scache_t *scp; /* file we're creating */
6353 int initialModeBits;
6363 /* compute initial mode bits based on read-only flag in attributes */
6364 initialModeBits = 0777;
6366 tp = smb_GetSMBData(inp, NULL);
6367 pathp = smb_ParseASCIIBlock(tp, &tp);
6368 if (smb_StoreAnsiFilenames)
6369 OemToChar(pathp,pathp);
6371 if (strcmp(pathp, "\\") == 0)
6372 return CM_ERROR_EXISTS;
6374 spacep = inp->spacep;
6375 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6377 userp = smb_GetUser(vcp, inp);
6379 caseFold = CM_FLAG_CASEFOLD;
6381 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6383 cm_ReleaseUser(userp);
6384 return CM_ERROR_NOSUCHPATH;
6387 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6388 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6389 userp, tidPathp, &req, &dscp);
6392 cm_ReleaseUser(userp);
6397 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6398 cm_ReleaseSCache(dscp);
6399 cm_ReleaseUser(userp);
6400 if ( WANTS_DFS_PATHNAMES(inp) )
6401 return CM_ERROR_PATH_NOT_COVERED;
6403 return CM_ERROR_BADSHARENAME;
6405 #endif /* DFS_SUPPORT */
6407 /* otherwise, scp points to the parent directory. Do a lookup, and
6408 * fail if we find it. Otherwise, we do the create.
6414 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6415 if (scp) cm_ReleaseSCache(scp);
6416 if (code != CM_ERROR_NOSUCHFILE) {
6417 if (code == 0) code = CM_ERROR_EXISTS;
6418 cm_ReleaseSCache(dscp);
6419 cm_ReleaseUser(userp);
6423 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6424 setAttr.clientModTime = time(NULL);
6425 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6426 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6427 smb_NotifyChange(FILE_ACTION_ADDED,
6428 FILE_NOTIFY_CHANGE_DIR_NAME,
6429 dscp, lastNamep, NULL, TRUE);
6431 /* we don't need this any longer */
6432 cm_ReleaseSCache(dscp);
6435 /* something went wrong creating or truncating the file */
6436 cm_ReleaseUser(userp);
6440 /* otherwise we succeeded */
6441 smb_SetSMBDataLength(outp, 0);
6442 cm_ReleaseUser(userp);
6447 BOOL smb_IsLegalFilename(char *filename)
6450 * Find the longest substring of filename that does not contain
6451 * any of the chars in illegalChars. If that substring is less
6452 * than the length of the whole string, then one or more of the
6453 * illegal chars is in filename.
6455 if (strcspn(filename, illegalChars) < strlen(filename))
6461 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6469 cm_scache_t *dscp; /* dir we're dealing with */
6470 cm_scache_t *scp; /* file we're creating */
6472 int initialModeBits;
6484 excl = (inp->inCom == 0x03)? 0 : 1;
6486 attributes = smb_GetSMBParm(inp, 0);
6487 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6489 /* compute initial mode bits based on read-only flag in attributes */
6490 initialModeBits = 0666;
6491 if (attributes & 1) initialModeBits &= ~0222;
6493 tp = smb_GetSMBData(inp, NULL);
6494 pathp = smb_ParseASCIIBlock(tp, &tp);
6495 if (smb_StoreAnsiFilenames)
6496 OemToChar(pathp,pathp);
6498 spacep = inp->spacep;
6499 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6501 userp = smb_GetUser(vcp, inp);
6503 caseFold = CM_FLAG_CASEFOLD;
6505 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6507 cm_ReleaseUser(userp);
6508 return CM_ERROR_NOSUCHPATH;
6510 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6511 userp, tidPathp, &req, &dscp);
6514 cm_ReleaseUser(userp);
6519 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6520 cm_ReleaseSCache(dscp);
6521 cm_ReleaseUser(userp);
6522 if ( WANTS_DFS_PATHNAMES(inp) )
6523 return CM_ERROR_PATH_NOT_COVERED;
6525 return CM_ERROR_BADSHARENAME;
6527 #endif /* DFS_SUPPORT */
6529 /* otherwise, scp points to the parent directory. Do a lookup, and
6530 * truncate the file if we find it, otherwise we create the file.
6537 if (!smb_IsLegalFilename(lastNamep))
6538 return CM_ERROR_BADNTFILENAME;
6540 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6541 #ifdef DEBUG_VERBOSE
6544 hexp = osi_HexifyString( lastNamep );
6545 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6550 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6551 if (code && code != CM_ERROR_NOSUCHFILE) {
6552 cm_ReleaseSCache(dscp);
6553 cm_ReleaseUser(userp);
6557 /* if we get here, if code is 0, the file exists and is represented by
6558 * scp. Otherwise, we have to create it.
6562 /* oops, file shouldn't be there */
6563 cm_ReleaseSCache(dscp);
6564 cm_ReleaseSCache(scp);
6565 cm_ReleaseUser(userp);
6566 return CM_ERROR_EXISTS;
6569 setAttr.mask = CM_ATTRMASK_LENGTH;
6570 setAttr.length.LowPart = 0;
6571 setAttr.length.HighPart = 0;
6572 code = cm_SetAttr(scp, &setAttr, userp, &req);
6575 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6576 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6577 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6579 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6580 smb_NotifyChange(FILE_ACTION_ADDED,
6581 FILE_NOTIFY_CHANGE_FILE_NAME,
6582 dscp, lastNamep, NULL, TRUE);
6583 if (!excl && code == CM_ERROR_EXISTS) {
6584 /* not an exclusive create, and someone else tried
6585 * creating it already, then we open it anyway. We
6586 * don't bother retrying after this, since if this next
6587 * fails, that means that the file was deleted after
6588 * we started this call.
6590 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6593 setAttr.mask = CM_ATTRMASK_LENGTH;
6594 setAttr.length.LowPart = 0;
6595 setAttr.length.HighPart = 0;
6596 code = cm_SetAttr(scp, &setAttr, userp, &req);
6601 /* we don't need this any longer */
6602 cm_ReleaseSCache(dscp);
6605 /* something went wrong creating or truncating the file */
6606 if (scp) cm_ReleaseSCache(scp);
6607 cm_ReleaseUser(userp);
6611 /* make sure we only open files */
6612 if (scp->fileType != CM_SCACHETYPE_FILE) {
6613 cm_ReleaseSCache(scp);
6614 cm_ReleaseUser(userp);
6615 return CM_ERROR_ISDIR;
6618 /* now all we have to do is open the file itself */
6619 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6622 /* save a pointer to the vnode */
6625 /* always create it open for read/write */
6626 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6628 smb_ReleaseFID(fidp);
6630 smb_SetSMBParm(outp, 0, fidp->fid);
6631 smb_SetSMBDataLength(outp, 0);
6633 cm_Open(scp, 0, userp);
6635 cm_ReleaseUser(userp);
6636 /* leave scp held since we put it in fidp->scp */
6640 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6653 fd = smb_GetSMBParm(inp, 0);
6654 whence = smb_GetSMBParm(inp, 1);
6655 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6657 /* try to find the file descriptor */
6658 fd = smb_ChainFID(fd, inp);
6659 fidp = smb_FindFID(vcp, fd, 0);
6660 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6661 return CM_ERROR_BADFD;
6664 userp = smb_GetUser(vcp, inp);
6666 lock_ObtainMutex(&fidp->mx);
6668 lock_ObtainMutex(&scp->mx);
6669 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6670 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6673 /* offset from current offset */
6674 offset += fidp->offset;
6676 else if (whence == 2) {
6677 /* offset from current EOF */
6678 offset += scp->length.LowPart;
6680 fidp->offset = offset;
6681 smb_SetSMBParm(outp, 0, offset & 0xffff);
6682 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6683 smb_SetSMBDataLength(outp, 0);
6685 lock_ReleaseMutex(&scp->mx);
6686 lock_ReleaseMutex(&fidp->mx);
6687 smb_ReleaseFID(fidp);
6688 cm_ReleaseUser(userp);
6692 /* dispatch all of the requests received in a packet. Due to chaining, this may
6693 * be more than one request.
6695 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6696 NCB *ncbp, raw_write_cont_t *rwcp)
6700 unsigned long code = 0;
6701 unsigned char *outWctp;
6702 int nparms; /* # of bytes of parameters */
6704 int nbytes; /* bytes of data, excluding count */
6707 unsigned short errCode;
6708 unsigned long NTStatus;
6710 unsigned char errClass;
6711 unsigned int oldGen;
6712 DWORD oldTime, newTime;
6714 /* get easy pointer to the data */
6715 smbp = (smb_t *) inp->data;
6717 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6718 /* setup the basic parms for the initial request in the packet */
6719 inp->inCom = smbp->com;
6720 inp->wctp = &smbp->wct;
6722 inp->ncb_length = ncbp->ncb_length;
6727 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6728 /* log it and discard it */
6733 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6734 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6736 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6737 1, ncbp->ncb_length, ptbuf, inp);
6738 DeregisterEventSource(h);
6740 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6745 /* We are an ongoing op */
6746 thrd_Increment(&ongoingOps);
6748 /* set up response packet for receiving output */
6749 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6750 smb_FormatResponsePacket(vcp, inp, outp);
6751 outWctp = outp->wctp;
6753 /* Remember session generation number and time */
6754 oldGen = sessionGen;
6755 oldTime = GetCurrentTime();
6757 while (inp->inCom != 0xff) {
6758 dp = &smb_dispatchTable[inp->inCom];
6760 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6761 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6762 code = outp->resumeCode;
6766 /* process each request in the packet; inCom, wctp and inCount
6767 * are already set up.
6769 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6772 /* now do the dispatch */
6773 /* start by formatting the response record a little, as a default */
6774 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6776 outWctp[1] = 0xff; /* no operation */
6777 outWctp[2] = 0; /* padding */
6782 /* not a chained request, this is a more reasonable default */
6783 outWctp[0] = 0; /* wct of zero */
6784 outWctp[1] = 0; /* and bcc (word) of zero */
6788 /* once set, stays set. Doesn't matter, since we never chain
6789 * "no response" calls.
6791 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6795 /* we have a recognized operation */
6797 if (inp->inCom == 0x1d)
6799 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6802 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp 0x%p lana %d lsn %d",vcp,vcp->lana,vcp->lsn);
6803 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6804 code = (*(dp->procp)) (vcp, inp, outp);
6805 osi_LogEvent("AFS Dispatch return",NULL,"Code 0x%x",code);
6806 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
6808 if ( code == CM_ERROR_BADSMB ||
6809 code == CM_ERROR_BADOP )
6811 #endif /* LOG_PACKET */
6814 if (oldGen != sessionGen) {
6819 newTime = GetCurrentTime();
6820 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6821 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6822 newTime - oldTime, ncbp->ncb_length);
6824 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6825 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6826 DeregisterEventSource(h);
6828 osi_Log1(smb_logp, "Pkt straddled session startup, "
6829 "ncb length %d", ncbp->ncb_length);
6833 /* bad opcode, fail the request, after displaying it */
6834 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6837 #endif /* LOG_PACKET */
6841 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6842 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6843 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6844 if (code == IDCANCEL)
6848 code = CM_ERROR_BADOP;
6851 /* catastrophic failure: log as much as possible */
6852 if (code == CM_ERROR_BADSMB) {
6859 "Invalid SMB, ncb_length %d",
6862 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6863 sprintf(s, "Invalid SMB message, length %d",
6866 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6867 1, ncbp->ncb_length, ptbuf, smbp);
6868 DeregisterEventSource(h);
6871 #endif /* LOG_PACKET */
6873 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6876 code = CM_ERROR_INVAL;
6879 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6880 thrd_Decrement(&ongoingOps);
6885 /* now, if we failed, turn the current response into an empty
6886 * one, and fill in the response packet's error code.
6889 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6890 smb_MapNTError(code, &NTStatus);
6891 outWctp = outp->wctp;
6892 smbp = (smb_t *) &outp->data;
6893 if (code != CM_ERROR_PARTIALWRITE
6894 && code != CM_ERROR_BUFFERTOOSMALL
6895 && code != CM_ERROR_GSSCONTINUE) {
6896 /* nuke wct and bcc. For a partial
6897 * write or an in-process authentication handshake,
6898 * assume they're OK.
6904 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6905 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6906 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6907 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6908 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6912 smb_MapCoreError(code, vcp, &errCode, &errClass);
6913 outWctp = outp->wctp;
6914 smbp = (smb_t *) &outp->data;
6915 if (code != CM_ERROR_PARTIALWRITE) {
6916 /* nuke wct and bcc. For a partial
6917 * write, assume they're OK.
6923 smbp->errLow = (unsigned char) (errCode & 0xff);
6924 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6925 smbp->rcls = errClass;
6928 } /* error occurred */
6930 /* if we're here, we've finished one request. Look to see if
6931 * this is a chained opcode. If it is, setup things to process
6932 * the chained request, and setup the output buffer to hold the
6933 * chained response. Start by finding the next input record.
6935 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6936 break; /* not a chained req */
6937 tp = inp->wctp; /* points to start of last request */
6938 /* in a chained request, the first two
6939 * parm fields are required, and are
6940 * AndXCommand/AndXReserved and
6942 if (tp[0] < 2) break;
6943 if (tp[1] == 0xff) break; /* no more chained opcodes */
6945 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6948 /* and now append the next output request to the end of this
6949 * last request. Begin by finding out where the last response
6950 * ends, since that's where we'll put our new response.
6952 outWctp = outp->wctp; /* ptr to out parameters */
6953 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6954 nparms = outWctp[0] << 1;
6955 tp = outWctp + nparms + 1; /* now points to bcc field */
6956 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6957 tp += 2 /* for the count itself */ + nbytes;
6958 /* tp now points to the new output record; go back and patch the
6959 * second parameter (off2) to point to the new record.
6961 temp = (unsigned int)(tp - outp->data);
6962 outWctp[3] = (unsigned char) (temp & 0xff);
6963 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6964 outWctp[2] = 0; /* padding */
6965 outWctp[1] = inp->inCom; /* next opcode */
6967 /* finally, setup for the next iteration */
6970 } /* while loop over all requests in the packet */
6972 /* done logging out, turn off logging-out flag */
6973 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6974 vcp->justLoggedOut = NULL;
6977 free(loggedOutName);
6978 loggedOutName = NULL;
6979 smb_ReleaseUID(loggedOutUserp);
6980 loggedOutUserp = NULL;
6984 /* now send the output packet, and return */
6986 smb_SendPacket(vcp, outp);
6987 thrd_Decrement(&ongoingOps);
6989 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6990 if (active_vcp != vcp) {
6992 smb_ReleaseVC(active_vcp);
6994 "Replacing active_vcp %x with %x", active_vcp, vcp);
6999 last_msg_time = GetCurrentTime();
7000 } else if (active_vcp == vcp) {
7001 smb_ReleaseVC(active_vcp);
7009 /* Wait for Netbios() calls to return, and make the results available to server
7010 * threads. Note that server threads can't wait on the NCBevents array
7011 * themselves, because NCB events are manual-reset, and the servers would race
7012 * each other to reset them.
7014 void smb_ClientWaiter(void *parmp)
7019 while (smbShutdownFlag == 0) {
7020 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7022 if (code == WAIT_OBJECT_0)
7025 /* error checking */
7026 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7028 int abandonIdx = code - WAIT_ABANDONED_0;
7029 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7032 if (code == WAIT_IO_COMPLETION)
7034 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7038 if (code == WAIT_TIMEOUT)
7040 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7043 if (code == WAIT_FAILED)
7045 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7048 idx = code - WAIT_OBJECT_0;
7050 /* check idx range! */
7051 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7053 /* this is fatal - log as much as possible */
7054 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7058 thrd_ResetEvent(NCBevents[idx]);
7059 thrd_SetEvent(NCBreturns[0][idx]);
7065 * Try to have one NCBRECV request waiting for every live session. Not more
7066 * than one, because if there is more than one, it's hard to handle Write Raw.
7068 void smb_ServerWaiter(void *parmp)
7071 int idx_session, idx_NCB;
7077 while (smbShutdownFlag == 0) {
7079 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7081 if (code == WAIT_OBJECT_0)
7084 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7086 int abandonIdx = code - WAIT_ABANDONED_0;
7087 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7090 if (code == WAIT_IO_COMPLETION)
7092 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7096 if (code == WAIT_TIMEOUT)
7098 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7101 if (code == WAIT_FAILED)
7103 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7106 idx_session = code - WAIT_OBJECT_0;
7108 /* check idx range! */
7109 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7111 /* this is fatal - log as much as possible */
7112 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7118 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7120 if (code == WAIT_OBJECT_0) {
7121 if (smbShutdownFlag == 1)
7127 /* error checking */
7128 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7130 int abandonIdx = code - WAIT_ABANDONED_0;
7131 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7134 if (code == WAIT_IO_COMPLETION)
7136 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7140 if (code == WAIT_TIMEOUT)
7142 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7145 if (code == WAIT_FAILED)
7147 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7150 idx_NCB = code - WAIT_OBJECT_0;
7152 /* check idx range! */
7153 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7155 /* this is fatal - log as much as possible */
7156 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7160 /* Link them together */
7161 NCBsessions[idx_NCB] = idx_session;
7164 ncbp = NCBs[idx_NCB];
7165 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7166 ncbp->ncb_command = NCBRECV | ASYNCH;
7167 ncbp->ncb_lana_num = lanas[idx_session];
7169 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7170 ncbp->ncb_event = NCBevents[idx_NCB];
7171 ncbp->ncb_length = SMB_PACKETSIZE;
7174 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7175 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7176 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7177 ncbp->ncb_length = SMB_PACKETSIZE;
7178 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7179 Netbios(ncbp, dos_ncb);
7185 * The top level loop for handling SMB request messages. Each server thread
7186 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7187 * NCB and buffer for the incoming request are loaned to us.
7189 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7190 * to immediately send a request for the rest of the data. This must come
7191 * before any other traffic for that session, so we delay setting the session
7192 * event until that data has come in.
7194 void smb_Server(VOID *parmp)
7196 INT_PTR myIdx = (INT_PTR) parmp;
7200 smb_packet_t *outbufp;
7202 int idx_NCB, idx_session;
7204 smb_vc_t *vcp = NULL;
7210 rx_StartClientThread();
7213 outbufp = GetPacket();
7214 outbufp->ncbp = outncbp;
7217 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7220 /* terminate silently if shutdown flag is set */
7221 if (code == WAIT_OBJECT_0) {
7222 if (smbShutdownFlag == 1) {
7223 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7229 /* error checking */
7230 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7232 int abandonIdx = code - WAIT_ABANDONED_0;
7233 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7236 if (code == WAIT_IO_COMPLETION)
7238 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7242 if (code == WAIT_TIMEOUT)
7244 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7247 if (code == WAIT_FAILED)
7249 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7252 idx_NCB = code - WAIT_OBJECT_0;
7254 /* check idx range! */
7255 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7257 /* this is fatal - log as much as possible */
7258 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7262 ncbp = NCBs[idx_NCB];
7264 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7266 idx_session = NCBsessions[idx_NCB];
7267 rc = ncbp->ncb_retcode;
7269 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
7272 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
7275 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
7278 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
7281 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7284 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7287 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7290 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7293 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7296 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7299 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7302 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7305 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7308 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7311 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7314 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7317 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7320 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7323 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7326 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7329 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7332 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7335 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7338 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7341 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7344 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7347 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7350 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7353 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7356 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7359 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7362 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7365 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7368 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7371 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7374 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7377 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7380 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7383 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7393 /* Can this happen? Or is it just my UNIX paranoia? */
7394 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7399 /* Client closed session */
7400 dead_sessions[idx_session] = TRUE;
7403 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7404 /* Should also release vcp. [done] 2004-05-11 jaltman
7406 * sanity check that all TID's are gone.
7408 * TODO: check if we could use LSNs[idx_session] instead,
7409 * also cleanup after dead vcp
7412 if (dead_vcp == vcp)
7413 osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7414 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7415 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7419 smb_ReleaseVC(dead_vcp);
7421 "Previous dead_vcp %x", dead_vcp);
7424 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7426 if (vcp->justLoggedOut) {
7428 loggedOutTime = vcp->logoffTime;
7429 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7430 loggedOutUserp = vcp->justLoggedOut;
7431 lock_ObtainWrite(&smb_rctLock);
7432 loggedOutUserp->refCount++;
7433 lock_ReleaseWrite(&smb_rctLock);
7439 /* Treat as transient error */
7446 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7447 sprintf(s, "SMB message incomplete, length %d",
7450 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
7452 ncbp->ncb_length, ptbuf,
7454 DeregisterEventSource(h);
7457 "dispatch smb recv failed, message incomplete, ncb_length %d",
7460 "SMB message incomplete, "
7461 "length %d", ncbp->ncb_length);
7464 * We used to discard the packet.
7465 * Instead, try handling it normally.
7473 /* A weird error code. Log it, sleep, and
7475 if (vcp && vcp->errorCount++ > 3) {
7476 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7477 dead_sessions[idx_session] = TRUE;
7481 thrd_SetEvent(SessionEvents[idx_session]);
7486 /* Success, so now dispatch on all the data in the packet */
7488 smb_concurrentCalls++;
7489 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7490 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7494 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7496 * If at this point vcp is NULL (implies that packet was invalid)
7497 * then we are in big trouble. This means either :
7498 * a) we have the wrong NCB.
7499 * b) Netbios screwed up the call.
7500 * Obviously this implies that
7501 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7502 * lanas[idx_session] != ncbp->ncb_lana_num )
7503 * Either way, we can't do anything with this packet.
7504 * Log, sleep and resume.
7513 "LSNs[idx_session]=[%d],"
7514 "lanas[idx_session]=[%d],"
7515 "ncbp->ncb_lsn=[%d],"
7516 "ncbp->ncb_lana_num=[%d]",
7520 ncbp->ncb_lana_num);
7524 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7526 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
7527 DeregisterEventSource(h);
7530 /* Also log in the trace log. */
7531 osi_Log4(smb_logp, "Server: BAD VCP!"
7532 "LSNs[idx_session]=[%d],"
7533 "lanas[idx_session]=[%d],"
7534 "ncbp->ncb_lsn=[%d],"
7535 "ncbp->ncb_lana_num=[%d]",
7539 ncbp->ncb_lana_num);
7541 /* thrd_Sleep(1000); Don't bother sleeping */
7542 thrd_SetEvent(SessionEvents[idx_session]);
7543 smb_concurrentCalls--;
7548 vcp->errorCount = 0;
7549 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7551 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7552 /* copy whole packet to virtual memory */
7553 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7555 bufp->dos_pkt / 16, bufp);*/
7557 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7559 smbp = (smb_t *)bufp->data;
7562 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7566 if (smbp->com == 0x1d) {
7567 /* Special handling for Write Raw */
7568 raw_write_cont_t rwc;
7569 EVENT_HANDLE rwevent;
7570 char eventName[MAX_PATH];
7572 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7573 if (rwc.code == 0) {
7574 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7575 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7576 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7577 ncbp->ncb_command = NCBRECV | ASYNCH;
7578 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7579 ncbp->ncb_lana_num = vcp->lana;
7580 ncbp->ncb_buffer = rwc.buf;
7581 ncbp->ncb_length = 65535;
7582 ncbp->ncb_event = rwevent;
7586 Netbios(ncbp, dos_ncb);
7588 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7589 thrd_CloseHandle(rwevent);
7591 thrd_SetEvent(SessionEvents[idx_session]);
7593 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7595 else if (smbp->com == 0xa0) {
7597 * Serialize the handling for NT Transact
7600 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7601 thrd_SetEvent(SessionEvents[idx_session]);
7603 thrd_SetEvent(SessionEvents[idx_session]);
7604 /* TODO: what else needs to be serialized? */
7605 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7607 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7609 __except( smb_ServerExceptionFilter() ) {
7613 smb_concurrentCalls--;
7616 thrd_SetEvent(NCBavails[idx_NCB]);
7623 * Exception filter for the server threads. If an exception occurs in the
7624 * dispatch routines, which is where exceptions are most common, then do a
7625 * force trace and give control to upstream exception handlers. Useful for
7628 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7629 DWORD smb_ServerExceptionFilter(void) {
7630 /* While this is not the best time to do a trace, if it succeeds, then
7631 * we have a trace (assuming tracing was enabled). Otherwise, this should
7632 * throw a second exception.
7637 ptbuf[0] = "Unhandled exception forcing trace";
7639 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7641 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7642 DeregisterEventSource(h);
7645 afsd_ForceTrace(TRUE);
7646 buf_ForceTrace(TRUE);
7647 return EXCEPTION_CONTINUE_SEARCH;
7652 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7653 * If the number of server threads is M, and the number of live sessions is
7654 * N, then the number of NCB's in use at any time either waiting for, or
7655 * holding, received messages is M + N, so that is how many NCB's get created.
7657 void InitNCBslot(int idx)
7659 struct smb_packet *bufp;
7660 EVENT_HANDLE retHandle;
7662 char eventName[MAX_PATH];
7664 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7666 NCBs[idx] = GetNCB();
7667 sprintf(eventName,"NCBavails[%d]", idx);
7668 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7669 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7670 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7672 sprintf(eventName,"NCBevents[%d]", idx);
7673 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7674 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7675 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7677 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7678 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7679 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7680 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7681 for (i=0; i<smb_NumServerThreads; i++)
7682 NCBreturns[i][idx] = retHandle;
7684 bufp->spacep = cm_GetSpace();
7688 /* listen for new connections */
7689 void smb_Listener(void *parmp)
7697 char rname[NCBNAMSZ+1];
7698 char cname[MAX_COMPUTERNAME_LENGTH+1];
7699 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7704 INT_PTR lana = (INT_PTR) parmp;
7708 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7711 /* retrieve computer name */
7712 GetComputerName(cname, &cnamelen);
7716 memset(ncbp, 0, sizeof(NCB));
7719 ncbp->ncb_command = NCBLISTEN;
7720 ncbp->ncb_rto = 0; /* No receive timeout */
7721 ncbp->ncb_sto = 0; /* No send timeout */
7723 /* pad out with spaces instead of null termination */
7724 len = (long)strlen(smb_localNamep);
7725 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7726 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7728 strcpy(ncbp->ncb_callname, "*");
7729 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7731 ncbp->ncb_lana_num = (UCHAR)lana;
7734 code = Netbios(ncbp);
7736 code = Netbios(ncbp, dos_ncb);
7745 /* terminate silently if shutdown flag is set */
7746 if (smbShutdownFlag == 1) {
7755 "NCBLISTEN lana=%d failed with code %d",
7756 ncbp->ncb_lana_num, code);
7758 "Client exiting due to network failure. Please restart client.\n");
7762 "Client exiting due to network failure. Please restart client.\n"
7763 "NCBLISTEN lana=%d failed with code %d",
7764 ncbp->ncb_lana_num, code);
7766 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7767 MB_OK|MB_SERVICE_NOTIFICATION);
7768 osi_assert(tbuffer);
7771 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7772 ncbp->ncb_lana_num, code);
7773 fprintf(stderr, "\nClient exiting due to network failure "
7774 "(possibly due to power-saving mode)\n");
7775 fprintf(stderr, "Please restart client.\n");
7776 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7780 /* check for remote conns */
7781 /* first get remote name and insert null terminator */
7782 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7783 for (i=NCBNAMSZ; i>0; i--) {
7784 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7790 /* compare with local name */
7792 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7793 flags |= SMB_VCFLAG_REMOTECONN;
7795 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7797 lock_ObtainMutex(&smb_ListenerLock);
7799 /* New generation */
7802 /* Log session startup */
7804 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7806 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7807 #endif /* NOTSERVICE */
7808 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7809 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7811 if (reportSessionStartups) {
7817 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7818 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7820 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7822 DeregisterEventSource(h);
7825 fprintf(stderr, "%s: New session %d starting from host %s\n",
7826 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7830 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7831 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7834 /* now ncbp->ncb_lsn is the connection ID */
7835 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7836 vcp->flags |= flags;
7837 strcpy(vcp->rname, rname);
7839 /* Allocate slot in session arrays */
7840 /* Re-use dead session if possible, otherwise add one more */
7841 /* But don't look at session[0], it is reserved */
7842 for (i = 1; i < numSessions; i++) {
7843 if (dead_sessions[i]) {
7844 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7845 dead_sessions[i] = FALSE;
7850 if (i >= Sessionmax - 1 || numNCBs >= NCBmax - 1) {
7851 unsigned long code = CM_ERROR_ALLBUSY;
7852 smb_packet_t * outp = GetPacket();
7853 unsigned char *outWctp;
7858 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7859 unsigned long NTStatus;
7860 smb_MapNTError(code, &NTStatus);
7861 outWctp = outp->wctp;
7862 smbp = (smb_t *) &outp->data;
7866 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7867 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7868 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7869 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7870 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7872 unsigned short errCode;
7873 unsigned char errClass;
7874 smb_MapCoreError(code, vcp, &errCode, &errClass);
7875 outWctp = outp->wctp;
7876 smbp = (smb_t *) &outp->data;
7880 smbp->errLow = (unsigned char) (errCode & 0xff);
7881 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7882 smbp->rcls = errClass;
7884 smb_SendPacket(vcp, outp);
7885 smb_FreePacket(outp);
7887 /* assert that we do not exceed the maximum number of sessions or NCBs.
7888 * we should probably want to wait for a session to be freed in case
7891 osi_assert(i < Sessionmax - 1);
7892 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7894 LSNs[i] = ncbp->ncb_lsn;
7895 lanas[i] = ncbp->ncb_lana_num;
7897 if (i == numSessions) {
7898 /* Add new NCB for new session */
7899 char eventName[MAX_PATH];
7901 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7903 InitNCBslot(numNCBs);
7905 thrd_SetEvent(NCBavails[0]);
7906 thrd_SetEvent(NCBevents[0]);
7907 for (j = 0; j < smb_NumServerThreads; j++)
7908 thrd_SetEvent(NCBreturns[j][0]);
7909 /* Also add new session event */
7910 sprintf(eventName, "SessionEvents[%d]", i);
7911 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7912 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7913 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7915 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7916 thrd_SetEvent(SessionEvents[0]);
7918 thrd_SetEvent(SessionEvents[i]);
7925 lock_ReleaseMutex(&smb_ListenerLock);
7926 } /* dispatch while loop */
7929 /* initialize Netbios */
7930 void smb_NetbiosInit()
7936 int i, lana, code, l;
7938 int delname_tried=0;
7941 OSVERSIONINFO Version;
7943 /* Get the version of Windows */
7944 memset(&Version, 0x00, sizeof(Version));
7945 Version.dwOSVersionInfoSize = sizeof(Version);
7946 GetVersionEx(&Version);
7948 /* setup the NCB system */
7951 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7955 if (smb_LANadapter == -1) {
7956 ncbp->ncb_command = NCBENUM;
7957 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7958 ncbp->ncb_length = sizeof(lana_list);
7959 code = Netbios(ncbp);
7961 afsi_log("Netbios NCBENUM error code %d", code);
7962 osi_panic(s, __FILE__, __LINE__);
7966 lana_list.length = 1;
7967 lana_list.lana[0] = smb_LANadapter;
7970 for (i = 0; i < lana_list.length; i++) {
7971 /* reset the adaptor: in Win32, this is required for every process, and
7972 * acts as an init call, not as a real hardware reset.
7974 ncbp->ncb_command = NCBRESET;
7975 ncbp->ncb_callname[0] = 100;
7976 ncbp->ncb_callname[2] = 100;
7977 ncbp->ncb_lana_num = lana_list.lana[i];
7978 code = Netbios(ncbp);
7980 code = ncbp->ncb_retcode;
7982 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7983 lana_list.lana[i] = 255; /* invalid lana */
7985 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7989 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7990 we will just fake the LANA list */
7991 if (smb_LANadapter == -1) {
7992 for (i = 0; i < 8; i++)
7993 lana_list.lana[i] = i;
7994 lana_list.length = 8;
7997 lana_list.length = 1;
7998 lana_list.lana[0] = smb_LANadapter;
8002 /* and declare our name so we can receive connections */
8003 memset(ncbp, 0, sizeof(*ncbp));
8004 len=lstrlen(smb_localNamep);
8005 memset(smb_sharename,' ',NCBNAMSZ);
8006 memcpy(smb_sharename,smb_localNamep,len);
8007 afsi_log("lana_list.length %d", lana_list.length);
8009 /* Keep the name so we can unregister it later */
8010 for (l = 0; l < lana_list.length; l++) {
8011 lana = lana_list.lana[l];
8013 ncbp->ncb_command = NCBADDNAME;
8014 ncbp->ncb_lana_num = lana;
8015 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8017 code = Netbios(ncbp);
8019 code = Netbios(ncbp, dos_ncb);
8022 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8023 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8025 char name[NCBNAMSZ+1];
8027 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8028 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8031 if (code == 0) code = ncbp->ncb_retcode;
8033 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8035 /* we only use one LANA with djgpp */
8036 lana_list.lana[0] = lana;
8037 lana_list.length = 1;
8041 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8042 if (code == NRC_BRIDGE) { /* invalid LANA num */
8043 lana_list.lana[l] = 255;
8046 else if (code == NRC_DUPNAME) {
8047 afsi_log("Name already exists; try to delete it");
8048 memset(ncbp, 0, sizeof(*ncbp));
8049 ncbp->ncb_command = NCBDELNAME;
8050 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8051 ncbp->ncb_lana_num = lana;
8053 code = Netbios(ncbp);
8055 code = Netbios(ncbp, dos_ncb);
8058 code = ncbp->ncb_retcode;
8060 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8062 if (code != 0 || delname_tried) {
8063 lana_list.lana[l] = 255;
8065 else if (code == 0) {
8066 if (!delname_tried) {
8074 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8075 lana_list.lana[l] = 255; /* invalid lana */
8076 osi_panic(s, __FILE__, __LINE__);
8080 lana_found = 1; /* at least one worked */
8087 osi_assert(lana_list.length >= 0);
8089 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8092 /* we're done with the NCB now */
8096 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8113 EVENT_HANDLE retHandle;
8114 char eventName[MAX_PATH];
8117 smb_MBfunc = aMBfunc;
8121 smb_LANadapter = LANadapt;
8123 /* Initialize smb_localZero */
8124 myTime.tm_isdst = -1; /* compute whether on DST or not */
8125 myTime.tm_year = 70;
8131 smb_localZero = mktime(&myTime);
8133 #ifndef USE_NUMERIC_TIME_CONV
8134 /* Initialize kludge-GMT */
8135 smb_CalculateNowTZ();
8136 #endif /* USE_NUMERIC_TIME_CONV */
8137 #ifdef AFS_FREELANCE_CLIENT
8138 /* Make sure the root.afs volume has the correct time */
8139 cm_noteLocalMountPointChange();
8142 /* initialize the remote debugging log */
8145 /* remember the name */
8146 len = (int)strlen(snamep);
8147 smb_localNamep = malloc(len+1);
8148 strcpy(smb_localNamep, snamep);
8149 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8151 /* and the global lock */
8152 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8153 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8155 /* Raw I/O data structures */
8156 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8158 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8160 /* 4 Raw I/O buffers */
8162 smb_RawBufs = calloc(65536,1);
8163 *((char **)smb_RawBufs) = NULL;
8164 for (i=0; i<3; i++) {
8165 char *rawBuf = calloc(65536,1);
8166 *((char **)rawBuf) = smb_RawBufs;
8167 smb_RawBufs = rawBuf;
8170 npar = 65536 >> 4; /* number of paragraphs */
8171 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8173 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8175 osi_panic("",__FILE__,__LINE__);
8178 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8181 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8183 _farpokel(_dos_ds, smb_RawBufs, NULL);
8184 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8185 npar = 65536 >> 4; /* number of paragraphs */
8186 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8188 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8190 osi_panic("",__FILE__,__LINE__);
8193 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8196 rawBuf = (seg * 16) + 0; /* DOS physical address */
8197 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8198 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8199 smb_RawBufs = rawBuf;
8203 /* global free lists */
8204 smb_ncbFreeListp = NULL;
8205 smb_packetFreeListp = NULL;
8209 /* Initialize listener and server structures */
8211 memset(dead_sessions, 0, sizeof(dead_sessions));
8212 sprintf(eventName, "SessionEvents[0]");
8213 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8214 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8215 afsi_log("Event Object Already Exists: %s", eventName);
8217 smb_NumServerThreads = nThreads;
8218 sprintf(eventName, "NCBavails[0]");
8219 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8220 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8221 afsi_log("Event Object Already Exists: %s", eventName);
8222 sprintf(eventName, "NCBevents[0]");
8223 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8224 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8225 afsi_log("Event Object Already Exists: %s", eventName);
8226 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8227 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8228 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8229 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8230 afsi_log("Event Object Already Exists: %s", eventName);
8231 for (i = 0; i < smb_NumServerThreads; i++) {
8232 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
8233 NCBreturns[i][0] = retHandle;
8236 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8237 for (i = 0; i < smb_NumServerThreads; i++) {
8238 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8239 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8240 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8241 afsi_log("Event Object Already Exists: %s", eventName);
8242 InitNCBslot((int)(i+1));
8244 numNCBs = smb_NumServerThreads + 1;
8246 /* Initialize dispatch table */
8247 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8248 /* Prepare the table for unknown operations */
8249 for(i=0; i<= SMB_NOPCODES; i++) {
8250 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8252 /* Fill in the ones we do know */
8253 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8254 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8255 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8256 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8257 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8258 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8259 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8260 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8261 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8262 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8263 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8264 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8265 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8266 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8267 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8268 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8269 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8270 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8271 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8272 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8273 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8274 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8275 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8276 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8277 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8278 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8279 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8280 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8281 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8282 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8283 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8284 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8285 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8286 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8287 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8288 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8289 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8290 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8291 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8292 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8293 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8294 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8295 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8296 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8297 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8298 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8299 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8300 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8301 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8302 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8303 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8304 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8305 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8306 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8307 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8308 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8309 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8310 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8311 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8312 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8313 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8314 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8315 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8316 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8317 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8318 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8319 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8320 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8321 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8322 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8323 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8324 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8326 /* setup tran 2 dispatch table */
8327 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8328 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8329 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8330 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8331 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8332 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8333 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8334 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8335 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8336 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8337 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8338 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8339 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8340 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8341 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8342 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8343 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8345 /* setup the rap dispatch table */
8346 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8347 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8348 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8349 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8350 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8354 /* if we are doing SMB authentication we have register outselves as a logon process */
8355 if (smb_authType != SMB_AUTH_NONE) {
8356 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8357 LSA_STRING afsProcessName;
8358 LSA_OPERATIONAL_MODE dummy; /*junk*/
8360 afsProcessName.Buffer = "OpenAFSClientDaemon";
8361 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8362 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8364 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8366 if (nts == STATUS_SUCCESS) {
8367 LSA_STRING packageName;
8368 /* we are registered. Find out the security package id */
8369 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8370 packageName.Length = (USHORT)strlen(packageName.Buffer);
8371 packageName.MaximumLength = packageName.Length + 1;
8372 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8373 if (nts == STATUS_SUCCESS) {
8375 * This code forces Windows to authenticate against the Logon Cache
8376 * first instead of attempting to authenticate against the Domain
8377 * Controller. When the Windows logon cache is enabled this improves
8378 * performance by removing the network access and works around a bug
8379 * seen at sites which are using a MIT Kerberos principal to login
8380 * to machines joined to a non-root domain in a multi-domain forest.
8382 PVOID pResponse = NULL;
8383 ULONG cbResponse = 0;
8384 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8386 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8387 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8388 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8389 OptionsRequest.DisableOptions = FALSE;
8391 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8394 sizeof(OptionsRequest),
8400 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8402 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8404 OutputDebugString(message);
8407 OutputDebugString("MsV1_0SetProcessOption success");
8408 afsi_log("MsV1_0SetProcessOption success");
8410 /* END - code from Larry */
8412 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8413 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8414 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8416 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8418 /* something went wrong. We report the error and revert back to no authentication
8419 because we can't perform any auth requests without a successful lsa handle
8420 or sec package id. */
8421 afsi_log("Reverting to NO SMB AUTH");
8422 smb_authType = SMB_AUTH_NONE;
8425 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8427 /* something went wrong. We report the error and revert back to no authentication
8428 because we can't perform any auth requests without a successful lsa handle
8429 or sec package id. */
8430 afsi_log("Reverting to NO SMB AUTH");
8431 smb_authType = SMB_AUTH_NONE;
8435 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8436 * time prevents the failure of authentication when logged into Windows with an
8437 * external Kerberos principal mapped to a local account.
8439 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8440 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8441 * then the only option is NTLMSSP anyway; so just fallback.
8446 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8447 if (secBlobLength == 0) {
8448 smb_authType = SMB_AUTH_NTLM;
8449 afsi_log("Reverting to SMB AUTH NTLM");
8458 /* Now get ourselves a domain name. */
8459 /* For now we are using the local computer name as the domain name.
8460 * It is actually the domain for local logins, and we are acting as
8461 * a local SMB server.
8463 bufsize = sizeof(smb_ServerDomainName) - 1;
8464 GetComputerName(smb_ServerDomainName, &bufsize);
8465 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8466 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8469 /* Start listeners, waiters, servers, and daemons */
8471 for (i = 0; i < lana_list.length; i++) {
8472 if (lana_list.lana[i] == 255)
8474 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8475 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8476 osi_assert(phandle != NULL);
8477 thrd_CloseHandle(phandle);
8481 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8482 NULL, 0, &lpid, "smb_ClientWaiter");
8483 osi_assert(phandle != NULL);
8484 thrd_CloseHandle(phandle);
8487 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8488 NULL, 0, &lpid, "smb_ServerWaiter");
8489 osi_assert(phandle != NULL);
8490 thrd_CloseHandle(phandle);
8492 for (i=0; i<smb_NumServerThreads; i++) {
8493 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8494 (void *) i, 0, &lpid, "smb_Server");
8495 osi_assert(phandle != NULL);
8496 thrd_CloseHandle(phandle);
8499 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8500 NULL, 0, &lpid, "smb_Daemon");
8501 osi_assert(phandle != NULL);
8502 thrd_CloseHandle(phandle);
8504 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8505 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8506 osi_assert(phandle != NULL);
8507 thrd_CloseHandle(phandle);
8516 void smb_Shutdown(void)
8526 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8528 /* setup the NCB system */
8531 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8534 /* Block new sessions by setting shutdown flag */
8535 smbShutdownFlag = 1;
8537 /* Hang up all sessions */
8538 memset((char *)ncbp, 0, sizeof(NCB));
8539 for (i = 1; i < numSessions; i++)
8541 if (dead_sessions[i])
8544 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8545 ncbp->ncb_command = NCBHANGUP;
8546 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8547 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8549 code = Netbios(ncbp);
8551 code = Netbios(ncbp, dos_ncb);
8553 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8554 if (code == 0) code = ncbp->ncb_retcode;
8556 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8557 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8561 /* Trigger the shutdown of all SMB threads */
8562 for (i = 0; i < smb_NumServerThreads; i++)
8563 thrd_SetEvent(NCBreturns[i][0]);
8565 thrd_SetEvent(NCBevents[0]);
8566 thrd_SetEvent(SessionEvents[0]);
8567 thrd_SetEvent(NCBavails[0]);
8569 for (i = 0;i < smb_NumServerThreads; i++) {
8570 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8571 if (code == WAIT_OBJECT_0) {
8574 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8575 thrd_SetEvent(NCBreturns[i--][0]);
8579 /* Delete Netbios name */
8580 memset((char *)ncbp, 0, sizeof(NCB));
8581 for (i = 0; i < lana_list.length; i++) {
8582 if (lana_list.lana[i] == 255) continue;
8583 ncbp->ncb_command = NCBDELNAME;
8584 ncbp->ncb_lana_num = lana_list.lana[i];
8585 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8587 code = Netbios(ncbp);
8589 code = Netbios(ncbp, dos_ncb);
8592 code = ncbp->ncb_retcode;
8594 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8595 ncbp->ncb_lana_num, code);
8600 /* Release the reference counts held by the VCs */
8601 lock_ObtainWrite(&smb_rctLock);
8602 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8607 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8609 if (fidp->scp != NULL) {
8612 lock_ObtainMutex(&fidp->mx);
8613 if (fidp->scp != NULL) {
8616 cm_ReleaseSCache(scp);
8618 lock_ReleaseMutex(&fidp->mx);
8622 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8624 smb_ReleaseVCNoLock(tidp->vcp);
8626 cm_user_t *userp = tidp->userp;
8628 lock_ReleaseWrite(&smb_rctLock);
8629 cm_ReleaseUser(userp);
8630 lock_ObtainWrite(&smb_rctLock);
8634 lock_ReleaseWrite(&smb_rctLock);
8637 /* Get the UNC \\<servername>\<sharename> prefix. */
8638 char *smb_GetSharename()
8642 /* Make sure we have been properly initialized. */
8643 if (smb_localNamep == NULL)
8646 /* Allocate space for \\<servername>\<sharename>, plus the
8649 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8650 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8656 void smb_LogPacket(smb_packet_t *packet)
8659 unsigned length, paramlen, datalen, i, j;
8661 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8663 if (!packet) return;
8665 osi_Log0(smb_logp, "*** SMB packet dump ***");
8667 vp = (BYTE *) packet->data;
8669 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8670 length = paramlen + 2 + datalen;
8673 for (i=0;i < length; i+=16)
8675 memset( buf, ' ', 80 );
8680 buf[strlen(buf)] = ' ';
8682 cp = (BYTE*) buf + 7;
8684 for (j=0;j < 16 && (i+j)<length; j++)
8686 *(cp++) = hex[vp[i+j] >> 4];
8687 *(cp++) = hex[vp[i+j] & 0xf];
8697 for (j=0;j < 16 && (i+j)<length;j++)
8699 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8710 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8713 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8715 #endif /* LOG_PACKET */
8718 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8726 lock_ObtainRead(&smb_rctLock);
8728 sprintf(output, "begin dumping smb_vc_t\n");
8729 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8731 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8735 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8736 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8737 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8739 sprintf(output, "begin dumping smb_fid_t\n");
8740 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8742 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8744 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",
8745 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8746 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8747 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8748 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8751 sprintf(output, "done dumping smb_fid_t\n");
8752 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8755 sprintf(output, "done dumping smb_vc_t\n");
8756 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8759 lock_ReleaseRead(&smb_rctLock);