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 void smb_CleanupDeadVC(smb_vc_t *vcp)
935 smb_user_t *userpIter;
936 smb_user_t *userpNext;
940 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
942 lock_ObtainRead(&smb_rctLock);
943 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
944 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
946 if (fidpIter->flags & SMB_FID_DELETE)
950 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
951 lock_ReleaseRead(&smb_rctLock);
953 fidp = smb_FindFID(vcp, fid, 0);
955 smb_CloseFID(vcp, fidp, NULL, 0);
956 smb_ReleaseFID(fidp);
958 lock_ObtainRead(&smb_rctLock);
961 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
962 tidpNext = tidpIter->nextp;
964 if (tidpIter->flags & SMB_TIDFLAG_DELETE)
968 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
969 lock_ReleaseRead(&smb_rctLock);
971 tidp = smb_FindTID(vcp, tid, 0);
974 lock_ObtainMutex(&tidp->mx);
975 tidp->flags |= SMB_TIDFLAG_DELETE;
976 lock_ReleaseMutex(&tidp->mx);
978 smb_ReleaseTID(tidp);
980 lock_ObtainRead(&smb_rctLock);
983 for (userpIter = vcp->usersp; userpIter; userpIter = userpNext) {
984 userpNext = userpIter->nextp;
986 if (userpIter->flags & SMB_USERFLAG_DELETE)
989 uid = userpIter->userID;
990 osi_Log2(smb_logp, " Cleanup UID %d (userp=0x%x)", uid, userpIter);
991 lock_ReleaseRead(&smb_rctLock);
993 userp = smb_FindUID(vcp, uid, 0);
996 lock_ObtainMutex(&userp->mx);
997 userp->flags |= SMB_USERFLAG_DELETE;
998 lock_ReleaseMutex(&userp->mx);
1000 smb_ReleaseUID(userp);
1002 lock_ObtainRead(&smb_rctLock);
1005 lock_ReleaseRead(&smb_rctLock);
1007 osi_Log0(smb_logp, "Done cleaning up dead vcp");
1010 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1014 lock_ObtainWrite(&smb_rctLock);
1015 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1016 if (tid == tidp->tid) {
1021 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1022 tidp = malloc(sizeof(*tidp));
1023 memset(tidp, 0, sizeof(*tidp));
1024 tidp->nextp = vcp->tidsp;
1027 smb_HoldVCNoLock(vcp);
1029 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1032 lock_ReleaseWrite(&smb_rctLock);
1036 void smb_ReleaseTID(smb_tid_t *tidp)
1043 lock_ObtainWrite(&smb_rctLock);
1044 osi_assert(tidp->refCount-- > 0);
1045 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
1046 ltpp = &tidp->vcp->tidsp;
1047 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1051 osi_assert(tp != NULL);
1053 lock_FinalizeMutex(&tidp->mx);
1054 userp = tidp->userp; /* remember to drop ref later */
1056 smb_ReleaseVCNoLock(tidp->vcp);
1059 lock_ReleaseWrite(&smb_rctLock);
1061 cm_ReleaseUser(userp);
1064 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1066 smb_user_t *uidp = NULL;
1068 lock_ObtainWrite(&smb_rctLock);
1069 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1070 if (uid == uidp->userID) {
1072 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1074 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1078 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1079 uidp = malloc(sizeof(*uidp));
1080 memset(uidp, 0, sizeof(*uidp));
1081 uidp->nextp = vcp->usersp;
1084 smb_HoldVCNoLock(vcp);
1086 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1088 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1090 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1092 lock_ReleaseWrite(&smb_rctLock);
1096 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1098 smb_username_t *unp= NULL;
1100 lock_ObtainWrite(&smb_rctLock);
1101 for(unp = usernamesp; unp; unp = unp->nextp) {
1102 if (stricmp(unp->name, usern) == 0 &&
1103 stricmp(unp->machine, machine) == 0) {
1108 if (!unp && (flags & SMB_FLAG_CREATE)) {
1109 unp = malloc(sizeof(*unp));
1110 memset(unp, 0, sizeof(*unp));
1112 unp->nextp = usernamesp;
1113 unp->name = strdup(usern);
1114 unp->machine = strdup(machine);
1116 lock_InitializeMutex(&unp->mx, "username_t mutex");
1118 lock_ReleaseWrite(&smb_rctLock);
1122 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1124 smb_user_t *uidp= NULL;
1126 lock_ObtainWrite(&smb_rctLock);
1127 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1130 if (stricmp(uidp->unp->name, usern) == 0) {
1132 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1133 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1138 lock_ReleaseWrite(&smb_rctLock);
1142 void smb_ReleaseUsername(smb_username_t *unp)
1145 smb_username_t **lupp;
1146 cm_user_t *userp = NULL;
1148 lock_ObtainWrite(&smb_rctLock);
1149 osi_assert(unp->refCount-- > 0);
1150 if (unp->refCount == 0) {
1152 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1156 osi_assert(up != NULL);
1158 lock_FinalizeMutex(&unp->mx);
1164 lock_ReleaseWrite(&smb_rctLock);
1167 cm_ReleaseUserVCRef(userp);
1168 cm_ReleaseUser(userp);
1172 void smb_ReleaseUID(smb_user_t *uidp)
1176 smb_username_t *unp = NULL;
1178 lock_ObtainWrite(&smb_rctLock);
1179 osi_assert(uidp->refCount-- > 0);
1180 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1181 lupp = &uidp->vcp->usersp;
1182 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1186 osi_assert(up != NULL);
1188 lock_FinalizeMutex(&uidp->mx);
1190 smb_ReleaseVCNoLock(uidp->vcp);
1193 lock_ReleaseWrite(&smb_rctLock);
1196 smb_ReleaseUsername(unp);
1199 /* retrieve a held reference to a user structure corresponding to an incoming
1201 * corresponding release function is cm_ReleaseUser.
1203 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1209 smbp = (smb_t *) inp;
1210 uidp = smb_FindUID(vcp, smbp->uid, 0);
1211 if ((!uidp) || (!uidp->unp))
1214 lock_ObtainMutex(&uidp->mx);
1215 up = uidp->unp->userp;
1217 lock_ReleaseMutex(&uidp->mx);
1219 smb_ReleaseUID(uidp);
1225 * Return a pointer to a pathname extracted from a TID structure. The
1226 * TID structure is not held; assume it won't go away.
1228 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1233 tidp = smb_FindTID(vcp, tid, 0);
1237 if (tidp->flags & SMB_TIDFLAG_IPC) {
1238 code = CM_ERROR_TIDIPC;
1239 /* tidp->pathname would be NULL, but that's fine */
1241 *treepath = tidp->pathname;
1242 smb_ReleaseTID(tidp);
1247 /* check to see if we have a chained fid, that is, a fid that comes from an
1248 * OpenAndX message that ran earlier in this packet. In this case, the fid
1249 * field in a read, for example, request, isn't set, since the value is
1250 * supposed to be inherited from the openAndX call.
1252 int smb_ChainFID(int fid, smb_packet_t *inp)
1254 if (inp->fid == 0 || inp->inCount == 0)
1260 /* are we a priv'd user? What does this mean on NT? */
1261 int smb_SUser(cm_user_t *userp)
1266 /* find a file ID. If we pass in 0 we select an unused File ID.
1267 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1268 * smb_fid_t data structure if desired File ID cannot be found.
1270 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1275 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1278 lock_ObtainWrite(&smb_rctLock);
1279 /* figure out if we need to allocate a new file ID */
1282 fid = vcp->fidCounter;
1286 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1287 if (fid == fidp->fid) {
1292 "New FID number wraps on vcp 0x%x", vcp);
1302 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1303 char eventName[MAX_PATH];
1305 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1306 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1307 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1308 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1309 thrd_CloseHandle(event);
1312 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1318 fidp = malloc(sizeof(*fidp));
1319 memset(fidp, 0, sizeof(*fidp));
1320 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1323 smb_HoldVCNoLock(vcp);
1324 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1326 fidp->curr_chunk = fidp->prev_chunk = -2;
1327 fidp->raw_write_event = event;
1329 vcp->fidCounter = fid+1;
1330 if (vcp->fidCounter == 0) {
1331 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1333 vcp->fidCounter = 1;
1338 lock_ReleaseWrite(&smb_rctLock);
1342 void smb_ReleaseFID(smb_fid_t *fidp)
1346 smb_vc_t *vcp = NULL;
1347 smb_ioctl_t *ioctlp;
1354 lock_ObtainWrite(&smb_rctLock);
1355 osi_assert(fidp->refCount-- > 0);
1356 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1359 scp = fidp->scp; /* release after lock is released */
1361 userp = fidp->userp;
1364 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1365 thrd_CloseHandle(fidp->raw_write_event);
1367 /* and see if there is ioctl stuff to free */
1368 ioctlp = fidp->ioctlp;
1371 cm_FreeSpace(ioctlp->prefix);
1372 if (ioctlp->inAllocp)
1373 free(ioctlp->inAllocp);
1374 if (ioctlp->outAllocp)
1375 free(ioctlp->outAllocp);
1381 smb_ReleaseVCNoLock(vcp);
1383 lock_ReleaseWrite(&smb_rctLock);
1385 /* now release the scache structure */
1387 cm_ReleaseSCache(scp);
1390 cm_ReleaseUser(userp);
1394 * Case-insensitive search for one string in another;
1395 * used to find variable names in submount pathnames.
1397 static char *smb_stristr(char *str1, char *str2)
1401 for (cursor = str1; *cursor; cursor++)
1402 if (stricmp(cursor, str2) == 0)
1409 * Substitute a variable value for its name in a submount pathname. Variable
1410 * name has been identified by smb_stristr() and is in substr. Variable name
1411 * length (plus one) is in substr_size. Variable value is in newstr.
1413 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1418 strcpy(temp, substr + substr_size - 1);
1419 strcpy(substr, newstr);
1423 char VNUserName[] = "%USERNAME%";
1424 char VNLCUserName[] = "%LCUSERNAME%";
1425 char VNComputerName[] = "%COMPUTERNAME%";
1426 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1429 /* List available shares */
1430 int smb_ListShares()
1434 char shareBuf[4096];
1442 /*strcpy(shareNameList[num_shares], "all");
1443 strcpy(pathNameList[num_shares++], "/afs");*/
1444 fprintf(stderr, "The following shares are available:\n");
1445 fprintf(stderr, "Share Name (AFS Path)\n");
1446 fprintf(stderr, "---------------------\n");
1447 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1450 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1451 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1453 strcpy(sbmtpath, cm_confDir);
1455 strcat(sbmtpath, "/afsdsbmt.ini");
1456 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1457 shareBuf, sizeof(shareBuf),
1463 this_share = shareBuf;
1467 /*strcpy(shareNameList[num_shares], this_share);*/
1468 len = GetPrivateProfileString("AFS Submounts", this_share,
1475 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1478 if (*p == '\\') *p = '/'; /* change to / */
1482 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1483 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1486 while (*this_share != 0) this_share++; /* find next NUL */
1487 this_share++; /* skip past the NUL */
1488 } while (*this_share != 0); /* stop at final NUL */
1494 typedef struct smb_findShare_rock {
1498 } smb_findShare_rock_t;
1500 #define SMB_FINDSHARE_EXACT_MATCH 1
1501 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1503 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1507 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1508 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1509 if(!stricmp(dep->name, vrock->shareName))
1510 matchType = SMB_FINDSHARE_EXACT_MATCH;
1512 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1513 if(vrock->match) free(vrock->match);
1514 vrock->match = strdup(dep->name);
1515 vrock->matchType = matchType;
1517 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1518 return CM_ERROR_STOPNOW;
1524 /* find a shareName in the table of submounts */
1525 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1529 char pathName[1024];
1534 char sbmtpath[MAX_PATH];
1539 DWORD allSubmount = 1;
1541 /* if allSubmounts == 0, only return the //mountRoot/all share
1542 * if in fact it has been been created in the subMounts table.
1543 * This is to allow sites that want to restrict access to the
1546 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1547 0, KEY_QUERY_VALUE, &parmKey);
1548 if (code == ERROR_SUCCESS) {
1549 len = sizeof(allSubmount);
1550 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1551 (BYTE *) &allSubmount, &len);
1552 if (code != ERROR_SUCCESS) {
1555 RegCloseKey (parmKey);
1558 if (allSubmount && _stricmp(shareName, "all") == 0) {
1563 /* In case, the all share is disabled we need to still be able
1564 * to handle ioctl requests
1566 if (_stricmp(shareName, "ioctl$") == 0) {
1567 *pathNamep = strdup("/.__ioctl__");
1571 if (_stricmp(shareName, "IPC$") == 0 ||
1572 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1573 _stricmp(shareName, "DESKTOP.INI") == 0
1580 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1581 0, KEY_QUERY_VALUE, &parmKey);
1582 if (code == ERROR_SUCCESS) {
1583 len = sizeof(pathName);
1584 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1585 (BYTE *) pathName, &len);
1586 if (code != ERROR_SUCCESS)
1588 RegCloseKey (parmKey);
1593 strcpy(sbmtpath, cm_confDir);
1594 strcat(sbmtpath, "/afsdsbmt.ini");
1595 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1596 pathName, sizeof(pathName), sbmtpath);
1598 if (len != 0 && len != sizeof(pathName) - 1) {
1599 /* We can accept either unix or PC style AFS pathnames. Convert
1600 * Unix-style to PC style here for internal use.
1603 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1604 p += strlen(cm_mountRoot); /* skip mount path */
1607 if (*q == '/') *q = '\\'; /* change to \ */
1613 if (var = smb_stristr(p, VNUserName)) {
1614 if (uidp && uidp->unp)
1615 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1617 smb_subst(p, var, sizeof(VNUserName)," ");
1619 else if (var = smb_stristr(p, VNLCUserName))
1621 if (uidp && uidp->unp)
1622 strcpy(temp, uidp->unp->name);
1626 smb_subst(p, var, sizeof(VNLCUserName), temp);
1628 else if (var = smb_stristr(p, VNComputerName))
1630 sizeTemp = sizeof(temp);
1631 GetComputerName((LPTSTR)temp, &sizeTemp);
1632 smb_subst(p, var, sizeof(VNComputerName), temp);
1634 else if (var = smb_stristr(p, VNLCComputerName))
1636 sizeTemp = sizeof(temp);
1637 GetComputerName((LPTSTR)temp, &sizeTemp);
1639 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1644 *pathNamep = strdup(p);
1649 /* First lookup shareName in root.afs */
1651 smb_findShare_rock_t vrock;
1653 char * p = shareName;
1656 /* attempt to locate a partial match in root.afs. This is because
1657 when using the ANSI RAP calls, the share name is limited to 13 chars
1658 and hence is truncated. Of course we prefer exact matches. */
1660 thyper.HighPart = 0;
1663 vrock.shareName = shareName;
1665 vrock.matchType = 0;
1667 cm_HoldSCache(cm_data.rootSCachep);
1668 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1669 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1670 cm_ReleaseSCache(cm_data.rootSCachep);
1672 if (vrock.matchType) {
1673 sprintf(pathName,"/%s/",vrock.match);
1674 *pathNamep = strdup(strlwr(pathName));
1679 /* if we get here, there was no match for the share in root.afs */
1680 /* so try to create \\<netbiosName>\<cellname> */
1685 /* Get the full name for this cell */
1686 code = cm_SearchCellFile(p, temp, 0, 0);
1687 #ifdef AFS_AFSDB_ENV
1688 if (code && cm_dnsEnabled) {
1690 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1693 /* construct the path */
1695 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1696 *pathNamep = strdup(strlwr(pathName));
1705 /* Client-side offline caching policy types */
1706 #define CSC_POLICY_MANUAL 0
1707 #define CSC_POLICY_DOCUMENTS 1
1708 #define CSC_POLICY_PROGRAMS 2
1709 #define CSC_POLICY_DISABLE 3
1711 int smb_FindShareCSCPolicy(char *shareName)
1717 int retval = CSC_POLICY_MANUAL;
1719 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1720 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1723 REG_OPTION_NON_VOLATILE,
1729 len = sizeof(policy);
1730 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1732 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1734 else if (stricmp(policy, "documents") == 0)
1736 retval = CSC_POLICY_DOCUMENTS;
1738 else if (stricmp(policy, "programs") == 0)
1740 retval = CSC_POLICY_PROGRAMS;
1742 else if (stricmp(policy, "disable") == 0)
1744 retval = CSC_POLICY_DISABLE;
1747 RegCloseKey(hkCSCPolicy);
1751 /* find a dir search structure by cookie value, and return it held.
1752 * Must be called with smb_globalLock held.
1754 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1756 smb_dirSearch_t *dsp;
1758 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1759 if (dsp->cookie == cookie) {
1760 if (dsp != smb_firstDirSearchp) {
1761 /* move to head of LRU queue, too, if we're not already there */
1762 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1763 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1764 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1765 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1766 if (!smb_lastDirSearchp)
1767 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1769 lock_ObtainMutex(&dsp->mx);
1771 lock_ReleaseMutex(&dsp->mx);
1777 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1778 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1779 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1785 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1787 lock_ObtainWrite(&smb_globalLock);
1788 lock_ObtainMutex(&dsp->mx);
1789 dsp->flags |= SMB_DIRSEARCH_DELETE;
1790 if (dsp->scp != NULL) {
1791 lock_ObtainMutex(&dsp->scp->mx);
1792 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1793 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1794 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1795 dsp->scp->bulkStatProgress = hones;
1797 lock_ReleaseMutex(&dsp->scp->mx);
1799 lock_ReleaseMutex(&dsp->mx);
1800 lock_ReleaseWrite(&smb_globalLock);
1803 /* Must be called with the smb_globalLock held */
1804 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1806 cm_scache_t *scp = NULL;
1808 lock_ObtainMutex(&dsp->mx);
1809 osi_assert(dsp->refCount-- > 0);
1810 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1811 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1812 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1813 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1814 lock_ReleaseMutex(&dsp->mx);
1815 lock_FinalizeMutex(&dsp->mx);
1819 lock_ReleaseMutex(&dsp->mx);
1821 /* do this now to avoid spurious locking hierarchy creation */
1823 cm_ReleaseSCache(scp);
1826 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1828 lock_ObtainWrite(&smb_globalLock);
1829 smb_ReleaseDirSearchNoLock(dsp);
1830 lock_ReleaseWrite(&smb_globalLock);
1833 /* find a dir search structure by cookie value, and return it held */
1834 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1836 smb_dirSearch_t *dsp;
1838 lock_ObtainWrite(&smb_globalLock);
1839 dsp = smb_FindDirSearchNoLock(cookie);
1840 lock_ReleaseWrite(&smb_globalLock);
1844 /* GC some dir search entries, in the address space expected by the specific protocol.
1845 * Must be called with smb_globalLock held; release the lock temporarily.
1847 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1848 void smb_GCDirSearches(int isV3)
1850 smb_dirSearch_t *prevp;
1851 smb_dirSearch_t *tp;
1852 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1856 victimCount = 0; /* how many have we got so far */
1857 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1858 /* we'll move tp from queue, so
1861 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1862 /* if no one is using this guy, and we're either in the new protocol,
1863 * or we're in the old one and this is a small enough ID to be useful
1864 * to the old protocol, GC this guy.
1866 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1867 /* hold and delete */
1868 tp->flags |= SMB_DIRSEARCH_DELETE;
1869 victimsp[victimCount++] = tp;
1873 /* don't do more than this */
1874 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1878 /* now release them */
1879 for (i = 0; i < victimCount; i++) {
1880 smb_ReleaseDirSearchNoLock(victimsp[i]);
1884 /* function for allocating a dir search entry. We need these to remember enough context
1885 * since we don't get passed the path from call to call during a directory search.
1887 * Returns a held dir search structure, and bumps the reference count on the vnode,
1888 * since it saves a pointer to the vnode.
1890 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1892 smb_dirSearch_t *dsp;
1898 lock_ObtainWrite(&smb_globalLock);
1901 /* what's the biggest ID allowed in this version of the protocol */
1902 maxAllowed = isV3 ? 65535 : 255;
1903 if (smb_dirSearchCounter > maxAllowed)
1904 smb_dirSearchCounter = 1;
1906 start = smb_dirSearchCounter;
1909 /* twice so we have enough tries to find guys we GC after one pass;
1910 * 10 extra is just in case I mis-counted.
1912 if (++counter > 2*maxAllowed+10)
1913 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1915 if (smb_dirSearchCounter > maxAllowed) {
1916 smb_dirSearchCounter = 1;
1918 if (smb_dirSearchCounter == start) {
1920 smb_GCDirSearches(isV3);
1923 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1925 /* don't need to watch for refcount zero and deleted, since
1926 * we haven't dropped the global lock.
1928 lock_ObtainMutex(&dsp->mx);
1930 lock_ReleaseMutex(&dsp->mx);
1931 ++smb_dirSearchCounter;
1935 dsp = malloc(sizeof(*dsp));
1936 memset(dsp, 0, sizeof(*dsp));
1937 dsp->cookie = smb_dirSearchCounter;
1938 ++smb_dirSearchCounter;
1940 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1941 dsp->lastTime = osi_Time();
1942 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1943 if (!smb_lastDirSearchp)
1944 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1947 lock_ReleaseWrite(&smb_globalLock);
1951 static smb_packet_t *GetPacket(void)
1955 unsigned int npar, seg, tb_sel;
1958 lock_ObtainWrite(&smb_globalLock);
1959 tbp = smb_packetFreeListp;
1961 smb_packetFreeListp = tbp->nextp;
1962 lock_ReleaseWrite(&smb_globalLock);
1965 tbp = calloc(65540,1);
1967 tbp = malloc(sizeof(smb_packet_t));
1969 tbp->magic = SMB_PACKETMAGIC;
1972 tbp->resumeCode = 0;
1978 tbp->ncb_length = 0;
1983 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1986 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1988 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1990 osi_panic("",__FILE__,__LINE__);
1993 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1998 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1999 tbp->dos_pkt_sel = tb_sel;
2002 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2007 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2011 memcpy(tbp, pkt, sizeof(smb_packet_t));
2012 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2014 smb_HoldVC(tbp->vcp);
2018 static NCB *GetNCB(void)
2023 unsigned int npar, seg, tb_sel;
2026 lock_ObtainWrite(&smb_globalLock);
2027 tbp = smb_ncbFreeListp;
2029 smb_ncbFreeListp = tbp->nextp;
2030 lock_ReleaseWrite(&smb_globalLock);
2033 tbp = calloc(sizeof(*tbp),1);
2035 tbp = malloc(sizeof(*tbp));
2036 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
2039 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2041 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2043 osi_panic("",__FILE__,__LINE__);
2045 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2050 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
2051 tbp->dos_ncb_sel = tb_sel;
2053 tbp->magic = SMB_NCBMAGIC;
2056 osi_assert(tbp->magic == SMB_NCBMAGIC);
2058 memset(&tbp->ncb, 0, sizeof(NCB));
2061 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2066 void smb_FreePacket(smb_packet_t *tbp)
2068 smb_vc_t * vcp = NULL;
2069 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2071 lock_ObtainWrite(&smb_globalLock);
2072 tbp->nextp = smb_packetFreeListp;
2073 smb_packetFreeListp = tbp;
2074 tbp->magic = SMB_PACKETMAGIC;
2078 tbp->resumeCode = 0;
2084 tbp->ncb_length = 0;
2086 lock_ReleaseWrite(&smb_globalLock);
2092 static void FreeNCB(NCB *bufferp)
2096 tbp = (smb_ncb_t *) bufferp;
2097 osi_assert(tbp->magic == SMB_NCBMAGIC);
2099 lock_ObtainWrite(&smb_globalLock);
2100 tbp->nextp = smb_ncbFreeListp;
2101 smb_ncbFreeListp = tbp;
2102 lock_ReleaseWrite(&smb_globalLock);
2105 /* get a ptr to the data part of a packet, and its count */
2106 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2110 unsigned char *afterParmsp;
2112 parmBytes = *smbp->wctp << 1;
2113 afterParmsp = smbp->wctp + parmBytes + 1;
2115 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2116 if (nbytesp) *nbytesp = dataBytes;
2118 /* don't forget to skip the data byte count, since it follows
2119 * the parameters; that's where the "2" comes from below.
2121 return (unsigned char *) (afterParmsp + 2);
2124 /* must set all the returned parameters before playing around with the
2125 * data region, since the data region is located past the end of the
2126 * variable number of parameters.
2128 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2130 unsigned char *afterParmsp;
2132 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2134 *afterParmsp++ = dsize & 0xff;
2135 *afterParmsp = (dsize>>8) & 0xff;
2138 /* return the parm'th parameter in the smbp packet */
2139 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2142 unsigned char *parmDatap;
2144 parmCount = *smbp->wctp;
2146 if (parm >= parmCount) {
2149 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2150 parm, parmCount, smbp->ncb_length);
2151 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2152 parm, parmCount, smbp->ncb_length);
2154 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2155 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2157 osi_panic(s, __FILE__, __LINE__);
2159 parmDatap = smbp->wctp + (2*parm) + 1;
2161 return parmDatap[0] + (parmDatap[1] << 8);
2164 /* return the parm'th parameter in the smbp packet */
2165 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2168 unsigned char *parmDatap;
2170 parmCount = *smbp->wctp;
2172 if (parm * 2 + offset >= parmCount * 2) {
2175 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2176 parm, offset, parmCount, smbp->ncb_length);
2178 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2179 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2181 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2182 parm, offset, parmCount, smbp->ncb_length);
2183 osi_panic(s, __FILE__, __LINE__);
2185 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2187 return parmDatap[0] + (parmDatap[1] << 8);
2190 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2194 /* make sure we have enough slots */
2195 if (*smbp->wctp <= slot)
2196 *smbp->wctp = slot+1;
2198 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2199 *parmDatap++ = parmValue & 0xff;
2200 *parmDatap = (parmValue>>8) & 0xff;
2203 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2207 /* make sure we have enough slots */
2208 if (*smbp->wctp <= slot)
2209 *smbp->wctp = slot+2;
2211 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2212 *parmDatap++ = parmValue & 0xff;
2213 *parmDatap++ = (parmValue>>8) & 0xff;
2214 *parmDatap++ = (parmValue>>16) & 0xff;
2215 *parmDatap++ = (parmValue>>24) & 0xff;
2218 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2223 /* make sure we have enough slots */
2224 if (*smbp->wctp <= slot)
2225 *smbp->wctp = slot+4;
2227 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2229 *parmDatap++ = *parmValuep++;
2232 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2236 /* make sure we have enough slots */
2237 if (*smbp->wctp <= slot) {
2238 if (smbp->oddByte) {
2240 *smbp->wctp = slot+1;
2245 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2246 *parmDatap++ = parmValue & 0xff;
2249 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2253 lastSlashp = strrchr(inPathp, '\\');
2255 *lastComponentp = lastSlashp;
2258 if (inPathp == lastSlashp)
2260 *outPathp++ = *inPathp++;
2269 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2274 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2279 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2285 tlen = inp[0] + (inp[1]<<8);
2286 inp += 2; /* skip length field */
2289 *chainpp = inp + tlen;
2298 /* format a packet as a response */
2299 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2304 outp = (smb_t *) op;
2306 /* zero the basic structure through the smb_wct field, and zero the data
2307 * size field, assuming that wct stays zero; otherwise, you have to
2308 * explicitly set the data size field, too.
2310 inSmbp = (smb_t *) inp;
2311 memset(outp, 0, sizeof(smb_t)+2);
2317 outp->com = inSmbp->com;
2318 outp->tid = inSmbp->tid;
2319 outp->pid = inSmbp->pid;
2320 outp->uid = inSmbp->uid;
2321 outp->mid = inSmbp->mid;
2322 outp->res[0] = inSmbp->res[0];
2323 outp->res[1] = inSmbp->res[1];
2324 op->inCom = inSmbp->com;
2326 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2327 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2329 /* copy fields in generic packet area */
2330 op->wctp = &outp->wct;
2333 /* send a (probably response) packet; vcp tells us to whom to send it.
2334 * we compute the length by looking at wct and bcc fields.
2336 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2353 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2356 memset((char *)ncbp, 0, sizeof(NCB));
2358 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2359 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2360 extra += tp[0] + (tp[1]<<8);
2361 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2362 extra += 3; /* wct and length fields */
2364 ncbp->ncb_length = extra; /* bytes to send */
2365 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2366 ncbp->ncb_lana_num = vcp->lana;
2367 ncbp->ncb_command = NCBSEND; /* op means send data */
2369 ncbp->ncb_buffer = (char *) inp;/* packet */
2370 code = Netbios(ncbp);
2372 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2373 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2375 /* copy header information from virtual to DOS address space */
2376 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2377 code = Netbios(ncbp, dos_ncb);
2383 case 0x01: s = "llegal buffer length "; break;
2384 case 0x03: s = "illegal command "; break;
2385 case 0x05: s = "command timed out "; break;
2386 case 0x06: s = "message incomplete, issue another command"; break;
2387 case 0x07: s = "illegal buffer address "; break;
2388 case 0x08: s = "session number out of range "; break;
2389 case 0x09: s = "no resource available "; break;
2390 case 0x0a: s = "session closed "; break;
2391 case 0x0b: s = "command cancelled "; break;
2392 case 0x0d: s = "duplicate name "; break;
2393 case 0x0e: s = "name table full "; break;
2394 case 0x0f: s = "no deletions, name has active sessions "; break;
2395 case 0x11: s = "local session table full "; break;
2396 case 0x12: s = "remote session table full "; break;
2397 case 0x13: s = "illegal name number "; break;
2398 case 0x14: s = "no callname "; break;
2399 case 0x15: s = "cannot put * in NCB_NAME "; break;
2400 case 0x16: s = "name in use on remote adapter "; break;
2401 case 0x17: s = "name deleted "; break;
2402 case 0x18: s = "session ended abnormally "; break;
2403 case 0x19: s = "name conflict detected "; break;
2404 case 0x21: s = "interface busy, IRET before retrying "; break;
2405 case 0x22: s = "too many commands outstanding, retry later"; break;
2406 case 0x23: s = "ncb_lana_num field invalid "; break;
2407 case 0x24: s = "command completed while cancel occurring "; break;
2408 case 0x26: s = "command not valid to cancel "; break;
2409 case 0x30: s = "name defined by anther local process "; break;
2410 case 0x34: s = "environment undefined. RESET required "; break;
2411 case 0x35: s = "required OS resources exhausted "; break;
2412 case 0x36: s = "max number of applications exceeded "; break;
2413 case 0x37: s = "no saps available for netbios "; break;
2414 case 0x38: s = "requested resources are not available "; break;
2415 case 0x39: s = "invalid ncb address or length > segment "; break;
2416 case 0x3B: s = "invalid NCB DDID "; break;
2417 case 0x3C: s = "lock of user area failed "; break;
2418 case 0x3f: s = "NETBIOS not loaded "; break;
2419 case 0x40: s = "system error "; break;
2421 s = "unknown error";
2423 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2430 void smb_MapNTError(long code, unsigned long *NTStatusp)
2432 unsigned long NTStatus;
2434 /* map CM_ERROR_* errors to NT 32-bit status codes */
2435 /* NT Status codes are listed in ntstatus.h not winerror.h */
2436 if (code == CM_ERROR_NOSUCHCELL) {
2437 NTStatus = 0xC000000FL; /* No such file */
2439 else if (code == CM_ERROR_NOSUCHVOLUME) {
2440 NTStatus = 0xC000000FL; /* No such file */
2442 else if (code == CM_ERROR_TIMEDOUT) {
2444 NTStatus = 0xC00000CFL; /* Sharing Paused */
2446 NTStatus = 0x00000102L; /* Timeout */
2449 else if (code == CM_ERROR_RETRY) {
2450 NTStatus = 0xC000022DL; /* Retry */
2452 else if (code == CM_ERROR_NOACCESS) {
2453 NTStatus = 0xC0000022L; /* Access denied */
2455 else if (code == CM_ERROR_READONLY) {
2456 NTStatus = 0xC00000A2L; /* Write protected */
2458 else if (code == CM_ERROR_NOSUCHFILE) {
2459 NTStatus = 0xC000000FL; /* No such file */
2461 else if (code == CM_ERROR_NOSUCHPATH) {
2462 NTStatus = 0xC000003AL; /* Object path not found */
2464 else if (code == CM_ERROR_TOOBIG) {
2465 NTStatus = 0xC000007BL; /* Invalid image format */
2467 else if (code == CM_ERROR_INVAL) {
2468 NTStatus = 0xC000000DL; /* Invalid parameter */
2470 else if (code == CM_ERROR_BADFD) {
2471 NTStatus = 0xC0000008L; /* Invalid handle */
2473 else if (code == CM_ERROR_BADFDOP) {
2474 NTStatus = 0xC0000022L; /* Access denied */
2476 else if (code == CM_ERROR_EXISTS) {
2477 NTStatus = 0xC0000035L; /* Object name collision */
2479 else if (code == CM_ERROR_NOTEMPTY) {
2480 NTStatus = 0xC0000101L; /* Directory not empty */
2482 else if (code == CM_ERROR_CROSSDEVLINK) {
2483 NTStatus = 0xC00000D4L; /* Not same device */
2485 else if (code == CM_ERROR_NOTDIR) {
2486 NTStatus = 0xC0000103L; /* Not a directory */
2488 else if (code == CM_ERROR_ISDIR) {
2489 NTStatus = 0xC00000BAL; /* File is a directory */
2491 else if (code == CM_ERROR_BADOP) {
2493 /* I have no idea where this comes from */
2494 NTStatus = 0xC09820FFL; /* SMB no support */
2496 NTStatus = 0xC00000BBL; /* Not supported */
2497 #endif /* COMMENT */
2499 else if (code == CM_ERROR_BADSHARENAME) {
2500 NTStatus = 0xC00000CCL; /* Bad network name */
2502 else if (code == CM_ERROR_NOIPC) {
2504 NTStatus = 0xC0000022L; /* Access Denied */
2506 NTStatus = 0xC000013DL; /* Remote Resources */
2509 else if (code == CM_ERROR_CLOCKSKEW) {
2510 NTStatus = 0xC0000133L; /* Time difference at DC */
2512 else if (code == CM_ERROR_BADTID) {
2513 NTStatus = 0xC0982005L; /* SMB bad TID */
2515 else if (code == CM_ERROR_USESTD) {
2516 NTStatus = 0xC09820FBL; /* SMB use standard */
2518 else if (code == CM_ERROR_QUOTA) {
2520 NTStatus = 0xC0000044L; /* Quota exceeded */
2522 NTStatus = 0xC000007FL; /* Disk full */
2525 else if (code == CM_ERROR_SPACE) {
2526 NTStatus = 0xC000007FL; /* Disk full */
2528 else if (code == CM_ERROR_ATSYS) {
2529 NTStatus = 0xC0000033L; /* Object name invalid */
2531 else if (code == CM_ERROR_BADNTFILENAME) {
2532 NTStatus = 0xC0000033L; /* Object name invalid */
2534 else if (code == CM_ERROR_WOULDBLOCK) {
2535 NTStatus = 0xC0000055L; /* Lock not granted */
2537 else if (code == CM_ERROR_SHARING_VIOLATION) {
2538 NTStatus = 0xC0000043L; /* Sharing violation */
2540 else if (code == CM_ERROR_LOCK_CONFLICT) {
2541 NTStatus = 0xC0000054L; /* Lock conflict */
2543 else if (code == CM_ERROR_PARTIALWRITE) {
2544 NTStatus = 0xC000007FL; /* Disk full */
2546 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2547 NTStatus = 0xC0000023L; /* Buffer too small */
2549 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2550 NTStatus = 0xC0000035L; /* Object name collision */
2552 else if (code == CM_ERROR_BADPASSWORD) {
2553 NTStatus = 0xC000006DL; /* unknown username or bad password */
2555 else if (code == CM_ERROR_BADLOGONTYPE) {
2556 NTStatus = 0xC000015BL; /* logon type not granted */
2558 else if (code == CM_ERROR_GSSCONTINUE) {
2559 NTStatus = 0xC0000016L; /* more processing required */
2561 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2563 NTStatus = 0xC0000280L; /* reparse point not resolved */
2565 NTStatus = 0xC0000022L; /* Access Denied */
2568 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2569 NTStatus = 0xC0000257L; /* Path Not Covered */
2572 else if (code == CM_ERROR_ALLBUSY) {
2573 NTStatus = 0xC00000BFL; /* Network Busy */
2575 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2576 NTStatus = 0xC0000350L; /* Remote Host Down */
2579 /* we do not want to be telling the SMB/CIFS client that
2580 * the AFS Client Service is busy or down.
2582 else if (code == CM_ERROR_ALLBUSY ||
2583 code == CM_ERROR_ALLOFFLINE ||
2584 code == CM_ERROR_ALLDOWN) {
2585 NTStatus = 0xC00000BEL; /* Bad Network Path */
2588 else if (code == RXKADUNKNOWNKEY) {
2589 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2591 NTStatus = 0xC0982001L; /* SMB non-specific error */
2594 *NTStatusp = NTStatus;
2595 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2598 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2599 unsigned char *classp)
2601 unsigned char class;
2602 unsigned short error;
2604 /* map CM_ERROR_* errors to SMB errors */
2605 if (code == CM_ERROR_NOSUCHCELL) {
2607 error = 3; /* bad path */
2609 else if (code == CM_ERROR_NOSUCHVOLUME) {
2611 error = 3; /* bad path */
2613 else if (code == CM_ERROR_TIMEDOUT) {
2615 error = 81; /* server is paused */
2617 else if (code == CM_ERROR_RETRY) {
2618 class = 2; /* shouldn't happen */
2621 else if (code == CM_ERROR_NOACCESS) {
2623 error = 4; /* bad access */
2625 else if (code == CM_ERROR_READONLY) {
2627 error = 19; /* read only */
2629 else if (code == CM_ERROR_NOSUCHFILE) {
2631 error = 2; /* ENOENT! */
2633 else if (code == CM_ERROR_NOSUCHPATH) {
2635 error = 3; /* Bad path */
2637 else if (code == CM_ERROR_TOOBIG) {
2639 error = 11; /* bad format */
2641 else if (code == CM_ERROR_INVAL) {
2642 class = 2; /* server non-specific error code */
2645 else if (code == CM_ERROR_BADFD) {
2647 error = 6; /* invalid file handle */
2649 else if (code == CM_ERROR_BADFDOP) {
2650 class = 1; /* invalid op on FD */
2653 else if (code == CM_ERROR_EXISTS) {
2655 error = 80; /* file already exists */
2657 else if (code == CM_ERROR_NOTEMPTY) {
2659 error = 5; /* delete directory not empty */
2661 else if (code == CM_ERROR_CROSSDEVLINK) {
2663 error = 17; /* EXDEV */
2665 else if (code == CM_ERROR_NOTDIR) {
2666 class = 1; /* bad path */
2669 else if (code == CM_ERROR_ISDIR) {
2670 class = 1; /* access denied; DOS doesn't have a good match */
2673 else if (code == CM_ERROR_BADOP) {
2677 else if (code == CM_ERROR_BADSHARENAME) {
2681 else if (code == CM_ERROR_NOIPC) {
2683 error = 4; /* bad access */
2685 else if (code == CM_ERROR_CLOCKSKEW) {
2686 class = 1; /* invalid function */
2689 else if (code == CM_ERROR_BADTID) {
2693 else if (code == CM_ERROR_USESTD) {
2697 else if (code == CM_ERROR_REMOTECONN) {
2701 else if (code == CM_ERROR_QUOTA) {
2702 if (vcp->flags & SMB_VCFLAG_USEV3) {
2704 error = 39; /* disk full */
2708 error = 5; /* access denied */
2711 else if (code == CM_ERROR_SPACE) {
2712 if (vcp->flags & SMB_VCFLAG_USEV3) {
2714 error = 39; /* disk full */
2718 error = 5; /* access denied */
2721 else if (code == CM_ERROR_PARTIALWRITE) {
2723 error = 39; /* disk full */
2725 else if (code == CM_ERROR_ATSYS) {
2727 error = 2; /* ENOENT */
2729 else if (code == CM_ERROR_WOULDBLOCK) {
2731 error = 33; /* lock conflict */
2733 else if (code == CM_ERROR_LOCK_CONFLICT) {
2735 error = 33; /* lock conflict */
2737 else if (code == CM_ERROR_SHARING_VIOLATION) {
2739 error = 33; /* lock conflict */
2741 else if (code == CM_ERROR_NOFILES) {
2743 error = 18; /* no files in search */
2745 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2747 error = 183; /* Samba uses this */
2749 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2750 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2752 error = 2; /* bad password */
2754 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2756 error = 3; /* bad path */
2765 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2768 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2770 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2771 return CM_ERROR_BADOP;
2774 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2776 unsigned short EchoCount, i;
2777 char *data, *outdata;
2780 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2782 for (i=1; i<=EchoCount; i++) {
2783 data = smb_GetSMBData(inp, &dataSize);
2784 smb_SetSMBParm(outp, 0, i);
2785 smb_SetSMBDataLength(outp, dataSize);
2786 outdata = smb_GetSMBData(outp, NULL);
2787 memcpy(outdata, data, dataSize);
2788 smb_SendPacket(vcp, outp);
2794 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2797 long count, minCount, finalCount;
2802 cm_user_t *userp = NULL;
2806 char *rawBuf = NULL;
2808 dos_ptr rawBuf = NULL;
2815 fd = smb_GetSMBParm(inp, 0);
2816 count = smb_GetSMBParm(inp, 3);
2817 minCount = smb_GetSMBParm(inp, 4);
2818 offset.HighPart = 0; /* too bad */
2819 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2821 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2822 fd, offset.LowPart, count);
2824 fidp = smb_FindFID(vcp, fd, 0);
2828 pid = ((smb_t *) inp)->pid;
2830 LARGE_INTEGER LOffset, LLength;
2833 key = cm_GenerateKey(vcp->vcID, pid, fd);
2835 LOffset.HighPart = 0;
2836 LOffset.LowPart = offset.LowPart;
2837 LLength.HighPart = 0;
2838 LLength.LowPart = count;
2840 lock_ObtainMutex(&fidp->scp->mx);
2841 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2842 lock_ReleaseMutex(&fidp->scp->mx);
2848 lock_ObtainMutex(&smb_RawBufLock);
2850 /* Get a raw buf, from head of list */
2851 rawBuf = smb_RawBufs;
2853 smb_RawBufs = *(char **)smb_RawBufs;
2855 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2858 lock_ReleaseMutex(&smb_RawBufLock);
2862 if (fidp->flags & SMB_FID_IOCTL)
2865 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2867 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2870 /* Give back raw buffer */
2871 lock_ObtainMutex(&smb_RawBufLock);
2873 *((char **) rawBuf) = smb_RawBufs;
2875 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2878 smb_RawBufs = rawBuf;
2879 lock_ReleaseMutex(&smb_RawBufLock);
2882 smb_ReleaseFID(fidp);
2886 userp = smb_GetUser(vcp, inp);
2889 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2891 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2892 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2893 userp, &finalCount, TRUE /* rawFlag */);
2900 cm_ReleaseUser(userp);
2903 smb_ReleaseFID(fidp);
2908 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2910 memset((char *)ncbp, 0, sizeof(NCB));
2912 ncbp->ncb_length = (unsigned short) finalCount;
2913 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2914 ncbp->ncb_lana_num = vcp->lana;
2915 ncbp->ncb_command = NCBSEND;
2916 ncbp->ncb_buffer = rawBuf;
2919 code = Netbios(ncbp);
2921 code = Netbios(ncbp, dos_ncb);
2924 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2927 /* Give back raw buffer */
2928 lock_ObtainMutex(&smb_RawBufLock);
2930 *((char **) rawBuf) = smb_RawBufs;
2932 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2935 smb_RawBufs = rawBuf;
2936 lock_ReleaseMutex(&smb_RawBufLock);
2942 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2944 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2949 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2951 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2956 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2963 int protoIndex; /* index we're using */
2968 char protocol_array[10][1024]; /* protocol signature of the client */
2969 int caps; /* capabilities */
2972 TIME_ZONE_INFORMATION tzi;
2974 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2978 DWORD now = GetCurrentTime();
2979 if (now - last_msg_time >= 30000
2980 && now - last_msg_time <= 90000) {
2982 "Setting dead_vcp %x", active_vcp);
2984 smb_ReleaseVC(dead_vcp);
2986 "Previous dead_vcp %x", dead_vcp);
2988 smb_HoldVC(active_vcp);
2989 dead_vcp = active_vcp;
2990 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2995 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2997 namep = smb_GetSMBData(inp, &dbytes);
3000 coreProtoIndex = -1; /* not found */
3003 while(namex < dbytes) {
3004 osi_Log1(smb_logp, "Protocol %s",
3005 osi_LogSaveString(smb_logp, namep+1));
3006 strcpy(protocol_array[tcounter], namep+1);
3008 /* namep points at the first protocol, or really, a 0x02
3009 * byte preceding the null-terminated ASCII name.
3011 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3012 coreProtoIndex = tcounter;
3014 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3015 v3ProtoIndex = tcounter;
3017 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3018 NTProtoIndex = tcounter;
3021 /* compute size of protocol entry */
3022 entryLength = (int)strlen(namep+1);
3023 entryLength += 2; /* 0x02 bytes and null termination */
3025 /* advance over this protocol entry */
3026 namex += entryLength;
3027 namep += entryLength;
3028 tcounter++; /* which proto entry we're looking at */
3031 if (NTProtoIndex != -1) {
3032 protoIndex = NTProtoIndex;
3033 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3035 else if (v3ProtoIndex != -1) {
3036 protoIndex = v3ProtoIndex;
3037 vcp->flags |= SMB_VCFLAG_USEV3;
3039 else if (coreProtoIndex != -1) {
3040 protoIndex = coreProtoIndex;
3041 vcp->flags |= SMB_VCFLAG_USECORE;
3043 else protoIndex = -1;
3045 if (protoIndex == -1)
3046 return CM_ERROR_INVAL;
3047 else if (NTProtoIndex != -1) {
3048 smb_SetSMBParm(outp, 0, protoIndex);
3049 if (smb_authType != SMB_AUTH_NONE) {
3050 smb_SetSMBParmByte(outp, 1,
3051 NEGOTIATE_SECURITY_USER_LEVEL |
3052 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3054 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3056 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3057 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3058 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3059 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3060 /* The session key is not a well documented field however most clients
3061 * will echo back the session key to the server. Currently we are using
3062 * the same value for all sessions. We should generate a random value
3063 * and store it into the vcp
3065 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3066 smb_SetSMBParm(outp, 8, 1);
3068 * Tried changing the capabilities to support for W2K - defect 117695
3069 * Maybe something else needs to be changed here?
3073 smb_SetSMBParmLong(outp, 9, 0x43fd);
3075 smb_SetSMBParmLong(outp, 9, 0x251);
3078 * 32-bit error codes *
3083 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3085 NTNEGOTIATE_CAPABILITY_DFS |
3087 NTNEGOTIATE_CAPABILITY_NTFIND |
3088 NTNEGOTIATE_CAPABILITY_RAWMODE |
3089 NTNEGOTIATE_CAPABILITY_NTSMB;
3091 if ( smb_authType == SMB_AUTH_EXTENDED )
3092 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3094 smb_SetSMBParmLong(outp, 9, caps);
3096 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3097 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3098 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3100 GetTimeZoneInformation(&tzi);
3101 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3103 if (smb_authType == SMB_AUTH_NTLM) {
3104 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3105 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3106 /* paste in encryption key */
3107 datap = smb_GetSMBData(outp, NULL);
3108 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3109 /* and the faux domain name */
3110 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3111 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3115 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3117 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3119 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3121 datap = smb_GetSMBData(outp, NULL);
3122 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3125 datap += sizeof(smb_ServerGUID);
3126 memcpy(datap, secBlob, secBlobLength);
3130 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3131 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3134 else if (v3ProtoIndex != -1) {
3135 smb_SetSMBParm(outp, 0, protoIndex);
3137 /* NOTE: Extended authentication cannot be negotiated with v3
3138 * therefore we fail over to NTLM
3140 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3141 smb_SetSMBParm(outp, 1,
3142 NEGOTIATE_SECURITY_USER_LEVEL |
3143 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3145 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3147 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3148 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3149 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3150 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3151 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3152 smb_SetSMBParm(outp, 7, 1);
3154 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3155 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3156 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3158 GetTimeZoneInformation(&tzi);
3159 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3161 /* NOTE: Extended authentication cannot be negotiated with v3
3162 * therefore we fail over to NTLM
3164 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3165 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3166 smb_SetSMBParm(outp, 12, 0); /* resvd */
3167 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3168 datap = smb_GetSMBData(outp, NULL);
3169 /* paste in a new encryption key */
3170 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3171 /* and the faux domain name */
3172 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3174 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3175 smb_SetSMBParm(outp, 12, 0); /* resvd */
3176 smb_SetSMBDataLength(outp, 0);
3179 else if (coreProtoIndex != -1) { /* not really supported anymore */
3180 smb_SetSMBParm(outp, 0, protoIndex);
3181 smb_SetSMBDataLength(outp, 0);
3186 void smb_Daemon(void *parmp)
3188 afs_uint32 count = 0;
3190 while(smbShutdownFlag == 0) {
3194 if (smbShutdownFlag == 1)
3197 if ((count % 72) == 0) { /* every five minutes */
3199 time_t old_localZero = smb_localZero;
3201 /* Initialize smb_localZero */
3202 myTime.tm_isdst = -1; /* compute whether on DST or not */
3203 myTime.tm_year = 70;
3209 smb_localZero = mktime(&myTime);
3211 #ifndef USE_NUMERIC_TIME_CONV
3212 smb_CalculateNowTZ();
3213 #endif /* USE_NUMERIC_TIME_CONV */
3214 #ifdef AFS_FREELANCE
3215 if ( smb_localZero != old_localZero )
3216 cm_noteLocalMountPointChange();
3219 /* XXX GC dir search entries */
3223 void smb_WaitingLocksDaemon()
3225 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3226 smb_waitingLock_t *wl, *wlNext;
3229 smb_packet_t *inp, *outp;
3233 while (smbShutdownFlag == 0) {
3234 lock_ObtainWrite(&smb_globalLock);
3235 nwlRequest = smb_allWaitingLocks;
3236 if (nwlRequest == NULL) {
3237 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3242 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3249 lock_ObtainWrite(&smb_globalLock);
3251 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3253 wlRequest = nwlRequest;
3254 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3255 lock_ReleaseWrite(&smb_globalLock);
3259 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3260 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3263 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3265 /* wl->state is either _DONE or _WAITING. _ERROR
3266 would no longer be on the queue. */
3267 code = cm_RetryLock( wl->lockp,
3268 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3271 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3272 } else if (code != CM_ERROR_WOULDBLOCK) {
3273 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3278 if (code == CM_ERROR_WOULDBLOCK) {
3281 if (wlRequest->timeRemaining != 0xffffffff
3282 && (wlRequest->timeRemaining -= 1000) < 0)
3294 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3297 scp = wlRequest->scp;
3301 lock_ObtainMutex(&scp->mx);
3303 for (wl = wlRequest->locks; wl; wl = wlNext) {
3304 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3306 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3307 wl->LLength, wl->key, NULL, &req);
3309 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3314 lock_ReleaseMutex(&scp->mx);
3318 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3321 for (wl = wlRequest->locks; wl; wl = wlNext) {
3322 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3323 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3328 vcp = wlRequest->vcp;
3329 inp = wlRequest->inp;
3330 outp = wlRequest->outp;
3332 ncbp->ncb_length = inp->ncb_length;
3333 inp->spacep = cm_GetSpace();
3335 /* Remove waitingLock from list */
3336 lock_ObtainWrite(&smb_globalLock);
3337 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3339 lock_ReleaseWrite(&smb_globalLock);
3341 /* Resume packet processing */
3343 smb_SetSMBDataLength(outp, 0);
3344 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3345 outp->resumeCode = code;
3347 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3350 cm_FreeSpace(inp->spacep);
3351 smb_FreePacket(inp);
3352 smb_FreePacket(outp);
3354 cm_ReleaseSCache(wlRequest->scp);
3357 } while (nwlRequest && smbShutdownFlag == 0);
3362 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3364 osi_Log0(smb_logp, "SMB receive get disk attributes");
3366 smb_SetSMBParm(outp, 0, 32000);
3367 smb_SetSMBParm(outp, 1, 64);
3368 smb_SetSMBParm(outp, 2, 1024);
3369 smb_SetSMBParm(outp, 3, 30000);
3370 smb_SetSMBParm(outp, 4, 0);
3371 smb_SetSMBDataLength(outp, 0);
3375 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3379 unsigned short newTid;
3380 char shareName[256];
3388 osi_Log0(smb_logp, "SMB receive tree connect");
3390 /* parse input parameters */
3391 tp = smb_GetSMBData(inp, NULL);
3392 pathp = smb_ParseASCIIBlock(tp, &tp);
3393 if (smb_StoreAnsiFilenames)
3394 OemToChar(pathp,pathp);
3395 passwordp = smb_ParseASCIIBlock(tp, &tp);
3396 tp = strrchr(pathp, '\\');
3398 return CM_ERROR_BADSMB;
3399 strcpy(shareName, tp+1);
3401 userp = smb_GetUser(vcp, inp);
3403 lock_ObtainMutex(&vcp->mx);
3404 newTid = vcp->tidCounter++;
3405 lock_ReleaseMutex(&vcp->mx);
3407 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3408 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3409 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3411 smb_ReleaseUID(uidp);
3413 smb_ReleaseTID(tidp);
3414 return CM_ERROR_BADSHARENAME;
3416 lock_ObtainMutex(&tidp->mx);
3417 tidp->userp = userp;
3418 tidp->pathname = sharePath;
3419 lock_ReleaseMutex(&tidp->mx);
3420 smb_ReleaseTID(tidp);
3422 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3423 smb_SetSMBParm(rsp, 1, newTid);
3424 smb_SetSMBDataLength(rsp, 0);
3426 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3430 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3434 if (*inp++ != 0x1) return NULL;
3435 tlen = inp[0] + (inp[1]<<8);
3436 inp += 2; /* skip length field */
3439 *chainpp = inp + tlen;
3442 if (lengthp) *lengthp = tlen;
3447 /* set maskp to the mask part of the incoming path.
3448 * Mask is 11 bytes long (8.3 with the dot elided).
3449 * Returns true if succeeds with a valid name, otherwise it does
3450 * its best, but returns false.
3452 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3460 /* starts off valid */
3463 /* mask starts out all blanks */
3464 memset(maskp, ' ', 11);
3466 /* find last backslash, or use whole thing if there is none */
3467 tp = strrchr(pathp, '\\');
3468 if (!tp) tp = pathp;
3469 else tp++; /* skip slash */
3473 /* names starting with a dot are illegal */
3474 if (*tp == '.') valid8Dot3 = 0;
3478 if (tc == 0) return valid8Dot3;
3479 if (tc == '.' || tc == '"') break;
3480 if (i < 8) *up++ = tc;
3481 else valid8Dot3 = 0;
3484 /* if we get here, tp point after the dot */
3485 up = maskp+8; /* ext goes here */
3492 if (tc == '.' || tc == '"')
3495 /* copy extension if not too long */
3505 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3515 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3517 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3521 /* otherwise, we have a valid 8.3 name; see if we have a match,
3522 * treating '?' as a wildcard in maskp (but not in the file name).
3524 tp1 = umask; /* real name, in mask format */
3525 tp2 = maskp; /* mask, in mask format */
3526 for(i=0; i<11; i++) {
3527 tc1 = *tp1++; /* char from real name */
3528 tc2 = *tp2++; /* char from mask */
3529 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3530 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3533 if (tc2 == '?' && tc1 != ' ')
3540 /* we got a match */
3544 char *smb_FindMask(char *pathp)
3548 tp = strrchr(pathp, '\\'); /* find last slash */
3551 return tp+1; /* skip the slash */
3553 return pathp; /* no slash, return the entire path */
3556 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3558 unsigned char *pathp;
3560 unsigned char mask[11];
3561 unsigned char *statBlockp;
3562 unsigned char initStatBlock[21];
3565 osi_Log0(smb_logp, "SMB receive search volume");
3567 /* pull pathname and stat block out of request */
3568 tp = smb_GetSMBData(inp, NULL);
3569 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3570 osi_assert(pathp != NULL);
3571 if (smb_StoreAnsiFilenames)
3572 OemToChar(pathp,pathp);
3573 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3574 osi_assert(statBlockp != NULL);
3576 statBlockp = initStatBlock;
3580 /* for returning to caller */
3581 smb_Get8Dot3MaskFromPath(mask, pathp);
3583 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3584 tp = smb_GetSMBData(outp, NULL);
3586 *tp++ = 43; /* bytes in a dir entry */
3587 *tp++ = 0; /* high byte in counter */
3589 /* now marshall the dir entry, starting with the search status */
3590 *tp++ = statBlockp[0]; /* Reserved */
3591 memcpy(tp, mask, 11); tp += 11; /* FileName */
3593 /* now pass back server use info, with 1st byte non-zero */
3595 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3597 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3599 *tp++ = 0x8; /* attribute: volume */
3609 /* 4 byte file size */
3615 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3616 memset(tp, ' ', 13);
3619 /* set the length of the data part of the packet to 43 + 3, for the dir
3620 * entry plus the 5 and the length fields.
3622 smb_SetSMBDataLength(outp, 46);
3626 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3627 cm_user_t *userp, cm_req_t *reqp)
3635 smb_dirListPatch_t *patchp;
3636 smb_dirListPatch_t *npatchp;
3638 for (patchp = *dirPatchespp; patchp; patchp =
3639 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3641 dptr = patchp->dptr;
3643 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3645 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3646 *dptr++ = SMB_ATTR_HIDDEN;
3649 lock_ObtainMutex(&scp->mx);
3650 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3651 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3653 lock_ReleaseMutex(&scp->mx);
3654 cm_ReleaseSCache(scp);
3655 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3656 *dptr++ = SMB_ATTR_HIDDEN;
3660 attr = smb_Attributes(scp);
3661 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3662 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3663 attr |= SMB_ATTR_HIDDEN;
3667 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3670 shortTemp = (unsigned short) (dosTime & 0xffff);
3671 *((u_short *)dptr) = shortTemp;
3674 /* and copy out date */
3675 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3676 *((u_short *)dptr) = shortTemp;
3679 /* copy out file length */
3680 *((u_long *)dptr) = scp->length.LowPart;
3682 lock_ReleaseMutex(&scp->mx);
3683 cm_ReleaseSCache(scp);
3686 /* now free the patches */
3687 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3688 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3692 /* and mark the list as empty */
3693 *dirPatchespp = NULL;
3698 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3707 smb_dirListPatch_t *dirListPatchesp;
3708 smb_dirListPatch_t *curPatchp;
3712 osi_hyper_t dirLength;
3713 osi_hyper_t bufferOffset;
3714 osi_hyper_t curOffset;
3716 unsigned char *inCookiep;
3717 smb_dirSearch_t *dsp;
3721 unsigned long clientCookie;
3722 cm_pageHeader_t *pageHeaderp;
3723 cm_user_t *userp = NULL;
3730 long nextEntryCookie;
3731 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3732 char resByte; /* reserved byte from the cookie */
3733 char *op; /* output data ptr */
3734 char *origOp; /* original value of op */
3735 cm_space_t *spacep; /* for pathname buffer */
3746 maxCount = smb_GetSMBParm(inp, 0);
3748 dirListPatchesp = NULL;
3750 caseFold = CM_FLAG_CASEFOLD;
3752 tp = smb_GetSMBData(inp, NULL);
3753 pathp = smb_ParseASCIIBlock(tp, &tp);
3754 if (smb_StoreAnsiFilenames)
3755 OemToChar(pathp,pathp);
3756 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3758 /* bail out if request looks bad */
3759 if (!tp || !pathp) {
3760 return CM_ERROR_BADSMB;
3763 /* We can handle long names */
3764 if (vcp->flags & SMB_VCFLAG_USENT)
3765 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3767 /* make sure we got a whole search status */
3768 if (dataLength < 21) {
3769 nextCookie = 0; /* start at the beginning of the dir */
3772 attribute = smb_GetSMBParm(inp, 1);
3774 /* handle volume info in another function */
3775 if (attribute & 0x8)
3776 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3778 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3779 maxCount, osi_LogSaveString(smb_logp, pathp));
3781 if (*pathp == 0) { /* null pathp, treat as root dir */
3782 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3783 return CM_ERROR_NOFILES;
3787 dsp = smb_NewDirSearch(0);
3788 dsp->attribute = attribute;
3789 smb_Get8Dot3MaskFromPath(mask, pathp);
3790 memcpy(dsp->mask, mask, 11);
3792 /* track if this is likely to match a lot of entries */
3793 if (smb_IsStarMask(mask))
3798 /* pull the next cookie value out of the search status block */
3799 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3800 + (inCookiep[16]<<24);
3801 dsp = smb_FindDirSearch(inCookiep[12]);
3803 /* can't find dir search status; fatal error */
3804 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3805 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3806 return CM_ERROR_BADFD;
3808 attribute = dsp->attribute;
3809 resByte = inCookiep[0];
3811 /* copy out client cookie, in host byte order. Don't bother
3812 * interpreting it, since we're just passing it through, anyway.
3814 memcpy(&clientCookie, &inCookiep[17], 4);
3816 memcpy(mask, dsp->mask, 11);
3818 /* assume we're doing a star match if it has continued for more
3824 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3825 nextCookie, dsp->cookie, attribute);
3827 userp = smb_GetUser(vcp, inp);
3829 /* try to get the vnode for the path name next */
3830 lock_ObtainMutex(&dsp->mx);
3836 spacep = inp->spacep;
3837 smb_StripLastComponent(spacep->data, NULL, pathp);
3838 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3840 lock_ReleaseMutex(&dsp->mx);
3841 cm_ReleaseUser(userp);
3842 smb_DeleteDirSearch(dsp);
3843 smb_ReleaseDirSearch(dsp);
3844 return CM_ERROR_NOFILES;
3846 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3847 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3850 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3851 cm_ReleaseSCache(scp);
3852 lock_ReleaseMutex(&dsp->mx);
3853 cm_ReleaseUser(userp);
3854 smb_DeleteDirSearch(dsp);
3855 smb_ReleaseDirSearch(dsp);
3856 if ( WANTS_DFS_PATHNAMES(inp) )
3857 return CM_ERROR_PATH_NOT_COVERED;
3859 return CM_ERROR_BADSHARENAME;
3861 #endif /* DFS_SUPPORT */
3864 /* we need one hold for the entry we just stored into,
3865 * and one for our own processing. When we're done with this
3866 * function, we'll drop the one for our own processing.
3867 * We held it once from the namei call, and so we do another hold
3871 lock_ObtainMutex(&scp->mx);
3872 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3873 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3874 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3875 dsp->flags |= SMB_DIRSEARCH_BULKST;
3877 lock_ReleaseMutex(&scp->mx);
3880 lock_ReleaseMutex(&dsp->mx);
3882 cm_ReleaseUser(userp);
3883 smb_DeleteDirSearch(dsp);
3884 smb_ReleaseDirSearch(dsp);
3888 /* reserves space for parameter; we'll adjust it again later to the
3889 * real count of the # of entries we returned once we've actually
3890 * assembled the directory listing.
3892 smb_SetSMBParm(outp, 0, 0);
3894 /* get the directory size */
3895 lock_ObtainMutex(&scp->mx);
3896 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3897 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3899 lock_ReleaseMutex(&scp->mx);
3900 cm_ReleaseSCache(scp);
3901 cm_ReleaseUser(userp);
3902 smb_DeleteDirSearch(dsp);
3903 smb_ReleaseDirSearch(dsp);
3907 dirLength = scp->length;
3909 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3910 curOffset.HighPart = 0;
3911 curOffset.LowPart = nextCookie;
3912 origOp = op = smb_GetSMBData(outp, NULL);
3913 /* and write out the basic header */
3914 *op++ = 5; /* variable block */
3915 op += 2; /* skip vbl block length; we'll fill it in later */
3919 /* make sure that curOffset.LowPart doesn't point to the first
3920 * 32 bytes in the 2nd through last dir page, and that it doesn't
3921 * point at the first 13 32-byte chunks in the first dir page,
3922 * since those are dir and page headers, and don't contain useful
3925 temp = curOffset.LowPart & (2048-1);
3926 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3927 /* we're in the first page */
3928 if (temp < 13*32) temp = 13*32;
3931 /* we're in a later dir page */
3932 if (temp < 32) temp = 32;
3935 /* make sure the low order 5 bits are zero */
3938 /* now put temp bits back ito curOffset.LowPart */
3939 curOffset.LowPart &= ~(2048-1);
3940 curOffset.LowPart |= temp;
3942 /* check if we've returned all the names that will fit in the
3945 if (returnedNames >= maxCount) {
3946 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3947 returnedNames, maxCount);
3951 /* check if we've passed the dir's EOF */
3952 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3954 /* see if we can use the bufferp we have now; compute in which page
3955 * the current offset would be, and check whether that's the offset
3956 * of the buffer we have. If not, get the buffer.
3958 thyper.HighPart = curOffset.HighPart;
3959 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3960 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3963 buf_Release(bufferp);
3966 lock_ReleaseMutex(&scp->mx);
3967 lock_ObtainRead(&scp->bufCreateLock);
3968 code = buf_Get(scp, &thyper, &bufferp);
3969 lock_ReleaseRead(&scp->bufCreateLock);
3970 lock_ObtainMutex(&dsp->mx);
3972 /* now, if we're doing a star match, do bulk fetching of all of
3973 * the status info for files in the dir.
3976 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3977 lock_ObtainMutex(&scp->mx);
3978 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3979 LargeIntegerGreaterThanOrEqualTo(thyper,
3980 scp->bulkStatProgress)) {
3981 /* Don't bulk stat if risking timeout */
3982 int now = GetCurrentTime();
3983 if (now - req.startTime > 5000) {
3984 scp->bulkStatProgress = thyper;
3985 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3986 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3988 cm_TryBulkStat(scp, &thyper, userp, &req);
3991 lock_ObtainMutex(&scp->mx);
3993 lock_ReleaseMutex(&dsp->mx);
3995 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3999 bufferOffset = thyper;
4001 /* now get the data in the cache */
4003 code = cm_SyncOp(scp, bufferp, userp, &req,
4005 CM_SCACHESYNC_NEEDCALLBACK |
4006 CM_SCACHESYNC_READ);
4008 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4012 if (cm_HaveBuffer(scp, bufferp, 0)) {
4013 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4017 /* otherwise, load the buffer and try again */
4018 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4020 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4021 scp, bufferp, code);
4026 buf_Release(bufferp);
4030 } /* if (wrong buffer) ... */
4032 /* now we have the buffer containing the entry we're interested in; copy
4033 * it out if it represents a non-deleted entry.
4035 entryInDir = curOffset.LowPart & (2048-1);
4036 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4038 /* page header will help tell us which entries are free. Page header
4039 * can change more often than once per buffer, since AFS 3 dir page size
4040 * may be less than (but not more than a buffer package buffer.
4042 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4043 temp &= ~(2048 - 1); /* turn off intra-page bits */
4044 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4046 /* now determine which entry we're looking at in the page. If it is
4047 * free (there's a free bitmap at the start of the dir), we should
4048 * skip these 32 bytes.
4050 slotInPage = (entryInDir & 0x7e0) >> 5;
4051 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4052 /* this entry is free */
4053 numDirChunks = 1; /* only skip this guy */
4057 tp = bufferp->datap + entryInBuffer;
4058 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4060 /* while we're here, compute the next entry's location, too,
4061 * since we'll need it when writing out the cookie into the dir
4064 * XXXX Probably should do more sanity checking.
4066 numDirChunks = cm_NameEntries(dep->name, NULL);
4068 /* compute the offset of the cookie representing the next entry */
4069 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4071 /* Compute 8.3 name if necessary */
4072 actualName = dep->name;
4073 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4074 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4075 actualName = shortName;
4078 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4079 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4080 osi_LogSaveString(smb_logp, actualName));
4082 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4083 /* this is one of the entries to use: it is not deleted
4084 * and it matches the star pattern we're looking for.
4087 /* Eliminate entries that don't match requested
4090 /* no hidden files */
4091 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4092 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4096 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4098 /* We have already done the cm_TryBulkStat above */
4099 fid.cell = scp->fid.cell;
4100 fid.volume = scp->fid.volume;
4101 fid.vnode = ntohl(dep->fid.vnode);
4102 fid.unique = ntohl(dep->fid.unique);
4103 fileType = cm_FindFileType(&fid);
4104 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4105 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4107 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4108 fileType == CM_SCACHETYPE_DFSLINK ||
4109 fileType == CM_SCACHETYPE_INVALID)
4110 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4115 memcpy(op, mask, 11); op += 11;
4116 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4117 *op++ = (char)(nextEntryCookie & 0xff);
4118 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4119 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4120 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4121 memcpy(op, &clientCookie, 4); op += 4;
4123 /* now we emit the attribute. This is sort of tricky,
4124 * since we need to really stat the file to find out
4125 * what type of entry we've got. Right now, we're
4126 * copying out data from a buffer, while holding the
4127 * scp locked, so it isn't really convenient to stat
4128 * something now. We'll put in a place holder now,
4129 * and make a second pass before returning this to get
4130 * the real attributes. So, we just skip the data for
4131 * now, and adjust it later. We allocate a patch
4132 * record to make it easy to find this point later.
4133 * The replay will happen at a time when it is safe to
4134 * unlock the directory.
4136 curPatchp = malloc(sizeof(*curPatchp));
4137 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4138 curPatchp->dptr = op;
4139 curPatchp->fid.cell = scp->fid.cell;
4140 curPatchp->fid.volume = scp->fid.volume;
4141 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4142 curPatchp->fid.unique = ntohl(dep->fid.unique);
4144 /* do hidden attribute here since name won't be around when applying
4148 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4149 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4151 curPatchp->flags = 0;
4153 op += 9; /* skip attr, time, date and size */
4155 /* zero out name area. The spec says to pad with
4156 * spaces, but Samba doesn't, and neither do we.
4160 /* finally, we get to copy out the name; we know that
4161 * it fits in 8.3 or the pattern wouldn't match, but it
4162 * never hurts to be sure.
4164 strncpy(op, actualName, 13);
4165 if (smb_StoreAnsiFilenames)
4168 /* Uppercase if requested by client */
4169 if (!KNOWS_LONG_NAMES(inp))
4174 /* now, adjust the # of entries copied */
4176 } /* if we're including this name */
4179 /* and adjust curOffset to be where the new cookie is */
4180 thyper.HighPart = 0;
4181 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4182 curOffset = LargeIntegerAdd(thyper, curOffset);
4183 } /* while copying data for dir listing */
4185 /* release the mutex */
4186 lock_ReleaseMutex(&scp->mx);
4187 if (bufferp) buf_Release(bufferp);
4189 /* apply and free last set of patches; if not doing a star match, this
4190 * will be empty, but better safe (and freeing everything) than sorry.
4192 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4194 /* special return code for unsuccessful search */
4195 if (code == 0 && dataLength < 21 && returnedNames == 0)
4196 code = CM_ERROR_NOFILES;
4198 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4199 returnedNames, code);
4202 smb_DeleteDirSearch(dsp);
4203 smb_ReleaseDirSearch(dsp);
4204 cm_ReleaseSCache(scp);
4205 cm_ReleaseUser(userp);
4209 /* finalize the output buffer */
4210 smb_SetSMBParm(outp, 0, returnedNames);
4211 temp = (long) (op - origOp);
4212 smb_SetSMBDataLength(outp, temp);
4214 /* the data area is a variable block, which has a 5 (already there)
4215 * followed by the length of the # of data bytes. We now know this to
4216 * be "temp," although that includes the 3 bytes of vbl block header.
4217 * Deduct for them and fill in the length field.
4219 temp -= 3; /* deduct vbl block info */
4220 osi_assert(temp == (43 * returnedNames));
4221 origOp[1] = (char)(temp & 0xff);
4222 origOp[2] = (char)((temp>>8) & 0xff);
4223 if (returnedNames == 0)
4224 smb_DeleteDirSearch(dsp);
4225 smb_ReleaseDirSearch(dsp);
4226 cm_ReleaseSCache(scp);
4227 cm_ReleaseUser(userp);
4231 /* verify that this is a valid path to a directory. I don't know why they
4232 * don't use the get file attributes call.
4234 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4238 cm_scache_t *rootScp;
4239 cm_scache_t *newScp;
4248 pathp = smb_GetSMBData(inp, NULL);
4249 pathp = smb_ParseASCIIBlock(pathp, NULL);
4251 return CM_ERROR_BADFD;
4252 if (smb_StoreAnsiFilenames)
4253 OemToChar(pathp,pathp);
4254 osi_Log1(smb_logp, "SMB receive check path %s",
4255 osi_LogSaveString(smb_logp, pathp));
4257 rootScp = cm_data.rootSCachep;
4259 userp = smb_GetUser(vcp, inp);
4261 caseFold = CM_FLAG_CASEFOLD;
4263 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4265 cm_ReleaseUser(userp);
4266 return CM_ERROR_NOSUCHPATH;
4268 code = cm_NameI(rootScp, pathp,
4269 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4270 userp, tidPathp, &req, &newScp);
4273 cm_ReleaseUser(userp);
4278 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4279 cm_ReleaseSCache(newScp);
4280 cm_ReleaseUser(userp);
4281 if ( WANTS_DFS_PATHNAMES(inp) )
4282 return CM_ERROR_PATH_NOT_COVERED;
4284 return CM_ERROR_BADSHARENAME;
4286 #endif /* DFS_SUPPORT */
4288 /* now lock the vnode with a callback; returns with newScp locked */
4289 lock_ObtainMutex(&newScp->mx);
4290 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4291 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4292 if (code && code != CM_ERROR_NOACCESS) {
4293 lock_ReleaseMutex(&newScp->mx);
4294 cm_ReleaseSCache(newScp);
4295 cm_ReleaseUser(userp);
4299 attrs = smb_Attributes(newScp);
4301 if (!(attrs & SMB_ATTR_DIRECTORY))
4302 code = CM_ERROR_NOTDIR;
4304 lock_ReleaseMutex(&newScp->mx);
4306 cm_ReleaseSCache(newScp);
4307 cm_ReleaseUser(userp);
4311 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4315 cm_scache_t *rootScp;
4316 unsigned short attribute;
4318 cm_scache_t *newScp;
4327 /* decode basic attributes we're passed */
4328 attribute = smb_GetSMBParm(inp, 0);
4329 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4331 pathp = smb_GetSMBData(inp, NULL);
4332 pathp = smb_ParseASCIIBlock(pathp, NULL);
4334 return CM_ERROR_BADSMB;
4335 if (smb_StoreAnsiFilenames)
4336 OemToChar(pathp,pathp);
4338 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4339 dosTime, attribute);
4341 rootScp = cm_data.rootSCachep;
4343 userp = smb_GetUser(vcp, inp);
4345 caseFold = CM_FLAG_CASEFOLD;
4347 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4349 cm_ReleaseUser(userp);
4350 return CM_ERROR_NOSUCHFILE;
4352 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4353 tidPathp, &req, &newScp);
4356 cm_ReleaseUser(userp);
4361 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4362 cm_ReleaseSCache(newScp);
4363 cm_ReleaseUser(userp);
4364 if ( WANTS_DFS_PATHNAMES(inp) )
4365 return CM_ERROR_PATH_NOT_COVERED;
4367 return CM_ERROR_BADSHARENAME;
4369 #endif /* DFS_SUPPORT */
4371 /* now lock the vnode with a callback; returns with newScp locked; we
4372 * need the current status to determine what the new status is, in some
4375 lock_ObtainMutex(&newScp->mx);
4376 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4377 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4379 lock_ReleaseMutex(&newScp->mx);
4380 cm_ReleaseSCache(newScp);
4381 cm_ReleaseUser(userp);
4385 /* Check for RO volume */
4386 if (newScp->flags & CM_SCACHEFLAG_RO) {
4387 lock_ReleaseMutex(&newScp->mx);
4388 cm_ReleaseSCache(newScp);
4389 cm_ReleaseUser(userp);
4390 return CM_ERROR_READONLY;
4393 /* prepare for setattr call */
4396 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4397 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4399 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4400 /* we're told to make a writable file read-only */
4401 attr.unixModeBits = newScp->unixModeBits & ~0222;
4402 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4404 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4405 /* we're told to make a read-only file writable */
4406 attr.unixModeBits = newScp->unixModeBits | 0222;
4407 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4409 lock_ReleaseMutex(&newScp->mx);
4411 /* now call setattr */
4413 code = cm_SetAttr(newScp, &attr, userp, &req);
4417 cm_ReleaseSCache(newScp);
4418 cm_ReleaseUser(userp);
4423 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4427 cm_scache_t *rootScp;
4428 cm_scache_t *newScp, *dscp;
4440 pathp = smb_GetSMBData(inp, NULL);
4441 pathp = smb_ParseASCIIBlock(pathp, NULL);
4443 return CM_ERROR_BADSMB;
4445 if (*pathp == 0) /* null path */
4448 if (smb_StoreAnsiFilenames)
4449 OemToChar(pathp,pathp);
4451 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4452 osi_LogSaveString(smb_logp, pathp));
4454 rootScp = cm_data.rootSCachep;
4456 userp = smb_GetUser(vcp, inp);
4458 /* we shouldn't need this for V3 requests, but we seem to */
4459 caseFold = CM_FLAG_CASEFOLD;
4461 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4463 cm_ReleaseUser(userp);
4464 return CM_ERROR_NOSUCHFILE;
4468 * XXX Strange hack XXX
4470 * As of Patch 5 (16 July 97), we are having the following problem:
4471 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4472 * requests to look up "desktop.ini" in all the subdirectories.
4473 * This can cause zillions of timeouts looking up non-existent cells
4474 * and volumes, especially in the top-level directory.
4476 * We have not found any way to avoid this or work around it except
4477 * to explicitly ignore the requests for mount points that haven't
4478 * yet been evaluated and for directories that haven't yet been
4481 * We should modify this hack to provide a fake desktop.ini file
4482 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4484 spacep = inp->spacep;
4485 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4486 #ifndef SPECIAL_FOLDERS
4487 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4488 code = cm_NameI(rootScp, spacep->data,
4489 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4490 userp, tidPathp, &req, &dscp);
4493 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4494 if ( WANTS_DFS_PATHNAMES(inp) )
4495 return CM_ERROR_PATH_NOT_COVERED;
4497 return CM_ERROR_BADSHARENAME;
4499 #endif /* DFS_SUPPORT */
4500 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4501 code = CM_ERROR_NOSUCHFILE;
4502 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4503 cm_buf_t *bp = buf_Find(dscp, &hzero);
4507 code = CM_ERROR_NOSUCHFILE;
4509 cm_ReleaseSCache(dscp);
4511 cm_ReleaseUser(userp);
4516 #endif /* SPECIAL_FOLDERS */
4518 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4519 tidPathp, &req, &newScp);
4521 cm_ReleaseUser(userp);
4526 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4527 cm_ReleaseSCache(newScp);
4528 cm_ReleaseUser(userp);
4529 if ( WANTS_DFS_PATHNAMES(inp) )
4530 return CM_ERROR_PATH_NOT_COVERED;
4532 return CM_ERROR_BADSHARENAME;
4534 #endif /* DFS_SUPPORT */
4536 /* now lock the vnode with a callback; returns with newScp locked */
4537 lock_ObtainMutex(&newScp->mx);
4538 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4539 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4541 lock_ReleaseMutex(&newScp->mx);
4542 cm_ReleaseSCache(newScp);
4543 cm_ReleaseUser(userp);
4548 /* use smb_Attributes instead. Also the fact that a file is
4549 * in a readonly volume doesn't mean it shojuld be marked as RO
4551 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4552 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4553 attrs = SMB_ATTR_DIRECTORY;
4556 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4557 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4559 attrs = smb_Attributes(newScp);
4562 smb_SetSMBParm(outp, 0, attrs);
4564 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4565 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4566 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4567 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4568 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4569 smb_SetSMBParm(outp, 5, 0);
4570 smb_SetSMBParm(outp, 6, 0);
4571 smb_SetSMBParm(outp, 7, 0);
4572 smb_SetSMBParm(outp, 8, 0);
4573 smb_SetSMBParm(outp, 9, 0);
4574 smb_SetSMBDataLength(outp, 0);
4575 lock_ReleaseMutex(&newScp->mx);
4577 cm_ReleaseSCache(newScp);
4578 cm_ReleaseUser(userp);
4583 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4587 osi_Log0(smb_logp, "SMB receive tree disconnect");
4589 /* find the tree and free it */
4590 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4592 lock_ObtainMutex(&tidp->mx);
4593 tidp->flags |= SMB_TIDFLAG_DELETE;
4594 lock_ReleaseMutex(&tidp->mx);
4595 smb_ReleaseTID(tidp);
4601 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4619 pathp = smb_GetSMBData(inp, NULL);
4620 pathp = smb_ParseASCIIBlock(pathp, NULL);
4621 if (smb_StoreAnsiFilenames)
4622 OemToChar(pathp,pathp);
4624 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4626 #ifdef DEBUG_VERBOSE
4630 hexpath = osi_HexifyString( pathp );
4631 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4636 share = smb_GetSMBParm(inp, 0);
4637 attribute = smb_GetSMBParm(inp, 1);
4639 spacep = inp->spacep;
4640 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4641 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4642 /* special case magic file name for receiving IOCTL requests
4643 * (since IOCTL calls themselves aren't getting through).
4645 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4646 smb_SetupIoctlFid(fidp, spacep);
4647 smb_SetSMBParm(outp, 0, fidp->fid);
4648 smb_SetSMBParm(outp, 1, 0); /* attrs */
4649 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4650 smb_SetSMBParm(outp, 3, 0);
4651 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4652 smb_SetSMBParm(outp, 5, 0x7fff);
4653 /* pass the open mode back */
4654 smb_SetSMBParm(outp, 6, (share & 0xf));
4655 smb_SetSMBDataLength(outp, 0);
4656 smb_ReleaseFID(fidp);
4660 userp = smb_GetUser(vcp, inp);
4662 caseFold = CM_FLAG_CASEFOLD;
4664 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4666 cm_ReleaseUser(userp);
4667 return CM_ERROR_NOSUCHPATH;
4669 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4670 tidPathp, &req, &scp);
4673 cm_ReleaseUser(userp);
4678 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4679 cm_ReleaseSCache(scp);
4680 cm_ReleaseUser(userp);
4681 if ( WANTS_DFS_PATHNAMES(inp) )
4682 return CM_ERROR_PATH_NOT_COVERED;
4684 return CM_ERROR_BADSHARENAME;
4686 #endif /* DFS_SUPPORT */
4688 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4690 cm_ReleaseSCache(scp);
4691 cm_ReleaseUser(userp);
4695 /* don't need callback to check file type, since file types never
4696 * change, and namei and cm_Lookup all stat the object at least once on
4697 * a successful return.
4699 if (scp->fileType != CM_SCACHETYPE_FILE) {
4700 cm_ReleaseSCache(scp);
4701 cm_ReleaseUser(userp);
4702 return CM_ERROR_ISDIR;
4705 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4708 /* save a pointer to the vnode */
4712 fidp->userp = userp;
4714 if ((share & 0xf) == 0)
4715 fidp->flags |= SMB_FID_OPENREAD;
4716 else if ((share & 0xf) == 1)
4717 fidp->flags |= SMB_FID_OPENWRITE;
4719 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4721 lock_ObtainMutex(&scp->mx);
4722 smb_SetSMBParm(outp, 0, fidp->fid);
4723 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4724 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4725 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4726 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4727 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4728 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4729 /* pass the open mode back; XXXX add access checks */
4730 smb_SetSMBParm(outp, 6, (share & 0xf));
4731 smb_SetSMBDataLength(outp, 0);
4732 lock_ReleaseMutex(&scp->mx);
4735 cm_Open(scp, 0, userp);
4737 /* send and free packet */
4738 smb_ReleaseFID(fidp);
4739 cm_ReleaseUser(userp);
4740 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4744 typedef struct smb_unlinkRock {
4749 char *maskp; /* pointer to the star pattern */
4754 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4757 smb_unlinkRock_t *rockp;
4765 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4766 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4767 caseFold |= CM_FLAG_8DOT3;
4769 matchName = dep->name;
4770 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4772 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4773 !cm_Is8Dot3(dep->name)) {
4774 cm_Gen8Dot3Name(dep, shortName, NULL);
4775 matchName = shortName;
4776 /* 8.3 matches are always case insensitive */
4777 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4780 osi_Log1(smb_logp, "Unlinking %s",
4781 osi_LogSaveString(smb_logp, matchName));
4782 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4783 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4784 smb_NotifyChange(FILE_ACTION_REMOVED,
4785 FILE_NOTIFY_CHANGE_FILE_NAME,
4786 dscp, dep->name, NULL, TRUE);
4790 /* If we made a case sensitive exact match, we might as well quit now. */
4791 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4792 code = CM_ERROR_STOPNOW;
4800 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4809 smb_unlinkRock_t rock;
4818 attribute = smb_GetSMBParm(inp, 0);
4820 tp = smb_GetSMBData(inp, NULL);
4821 pathp = smb_ParseASCIIBlock(tp, &tp);
4822 if (smb_StoreAnsiFilenames)
4823 OemToChar(pathp,pathp);
4825 osi_Log1(smb_logp, "SMB receive unlink %s",
4826 osi_LogSaveString(smb_logp, pathp));
4828 spacep = inp->spacep;
4829 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4831 userp = smb_GetUser(vcp, inp);
4833 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4835 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4837 cm_ReleaseUser(userp);
4838 return CM_ERROR_NOSUCHPATH;
4840 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4843 cm_ReleaseUser(userp);
4848 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4849 cm_ReleaseSCache(dscp);
4850 cm_ReleaseUser(userp);
4851 if ( WANTS_DFS_PATHNAMES(inp) )
4852 return CM_ERROR_PATH_NOT_COVERED;
4854 return CM_ERROR_BADSHARENAME;
4856 #endif /* DFS_SUPPORT */
4858 /* otherwise, scp points to the parent directory. */
4865 rock.maskp = smb_FindMask(pathp);
4866 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4869 thyper.HighPart = 0;
4875 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4876 * match. If that fails, we do a case insensitve match.
4878 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4879 !smb_IsStarMask(rock.maskp)) {
4880 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4883 thyper.HighPart = 0;
4884 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4889 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4891 if (code == CM_ERROR_STOPNOW)
4894 cm_ReleaseUser(userp);
4896 cm_ReleaseSCache(dscp);
4898 if (code == 0 && !rock.any)
4899 code = CM_ERROR_NOSUCHFILE;
4903 typedef struct smb_renameRock {
4904 cm_scache_t *odscp; /* old dir */
4905 cm_scache_t *ndscp; /* new dir */
4906 cm_user_t *userp; /* user */
4907 cm_req_t *reqp; /* request struct */
4908 smb_vc_t *vcp; /* virtual circuit */
4909 char *maskp; /* pointer to star pattern of old file name */
4910 int flags; /* tilde, casefold, etc */
4911 char *newNamep; /* ptr to the new file's name */
4914 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4917 smb_renameRock_t *rockp;
4922 rockp = (smb_renameRock_t *) vrockp;
4924 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4925 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4926 caseFold |= CM_FLAG_8DOT3;
4928 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4930 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4931 !cm_Is8Dot3(dep->name)) {
4932 cm_Gen8Dot3Name(dep, shortName, NULL);
4933 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4936 code = cm_Rename(rockp->odscp, dep->name,
4937 rockp->ndscp, rockp->newNamep, rockp->userp,
4939 /* if the call worked, stop doing the search now, since we
4940 * really only want to rename one file.
4943 code = CM_ERROR_STOPNOW;
4952 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4955 cm_space_t *spacep = NULL;
4956 smb_renameRock_t rock;
4957 cm_scache_t *oldDscp = NULL;
4958 cm_scache_t *newDscp = NULL;
4959 cm_scache_t *tmpscp= NULL;
4960 cm_scache_t *tmpscp2 = NULL;
4970 userp = smb_GetUser(vcp, inp);
4971 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4973 cm_ReleaseUser(userp);
4974 return CM_ERROR_NOSUCHPATH;
4978 spacep = inp->spacep;
4979 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4981 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4982 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4983 userp, tidPathp, &req, &oldDscp);
4985 cm_ReleaseUser(userp);
4990 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4991 cm_ReleaseSCache(oldDscp);
4992 cm_ReleaseUser(userp);
4993 if ( WANTS_DFS_PATHNAMES(inp) )
4994 return CM_ERROR_PATH_NOT_COVERED;
4996 return CM_ERROR_BADSHARENAME;
4998 #endif /* DFS_SUPPORT */
5000 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5001 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5002 userp, tidPathp, &req, &newDscp);
5005 cm_ReleaseSCache(oldDscp);
5006 cm_ReleaseUser(userp);
5011 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5012 cm_ReleaseSCache(oldDscp);
5013 cm_ReleaseSCache(newDscp);
5014 cm_ReleaseUser(userp);
5015 if ( WANTS_DFS_PATHNAMES(inp) )
5016 return CM_ERROR_PATH_NOT_COVERED;
5018 return CM_ERROR_BADSHARENAME;
5020 #endif /* DFS_SUPPORT */
5023 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5024 * next, get the component names, and lower case them.
5027 /* handle the old name first */
5029 oldLastNamep = oldPathp;
5033 /* and handle the new name, too */
5035 newLastNamep = newPathp;
5039 /* TODO: The old name could be a wildcard. The new name must not be */
5041 /* do the vnode call */
5042 rock.odscp = oldDscp;
5043 rock.ndscp = newDscp;
5047 rock.maskp = oldLastNamep;
5048 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5049 rock.newNamep = newLastNamep;
5051 /* Check if the file already exists; if so return error */
5052 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5053 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5054 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5055 osi_LogSaveString(afsd_logp, newLastNamep));
5057 /* Check if the old and the new names differ only in case. If so return
5058 * success, else return CM_ERROR_EXISTS
5060 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5062 /* This would be a success only if the old file is *as same as* the new file */
5063 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5065 if (tmpscp == tmpscp2)
5068 code = CM_ERROR_EXISTS;
5069 cm_ReleaseSCache(tmpscp2);
5072 code = CM_ERROR_NOSUCHFILE;
5075 /* file exist, do not rename, also fixes move */
5076 osi_Log0(smb_logp, "Can't rename. Target already exists");
5077 code = CM_ERROR_EXISTS;
5081 cm_ReleaseSCache(tmpscp);
5082 cm_ReleaseSCache(newDscp);
5083 cm_ReleaseSCache(oldDscp);
5084 cm_ReleaseUser(userp);
5088 /* Now search the directory for the pattern, and do the appropriate rename when found */
5089 thyper.LowPart = 0; /* search dir from here */
5090 thyper.HighPart = 0;
5092 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5093 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5095 if (code == CM_ERROR_STOPNOW)
5098 code = CM_ERROR_NOSUCHFILE;
5100 /* Handle Change Notification */
5102 * Being lazy, not distinguishing between files and dirs in this
5103 * filter, since we'd have to do a lookup.
5105 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5106 if (oldDscp == newDscp) {
5107 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5108 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5109 filter, oldDscp, oldLastNamep,
5110 newLastNamep, TRUE);
5112 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5113 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5114 filter, oldDscp, oldLastNamep,
5116 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5117 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5118 filter, newDscp, newLastNamep,
5123 cm_ReleaseSCache(tmpscp);
5124 cm_ReleaseUser(userp);
5125 cm_ReleaseSCache(oldDscp);
5126 cm_ReleaseSCache(newDscp);
5131 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5134 cm_space_t *spacep = NULL;
5135 cm_scache_t *oldDscp = NULL;
5136 cm_scache_t *newDscp = NULL;
5137 cm_scache_t *tmpscp= NULL;
5138 cm_scache_t *tmpscp2 = NULL;
5139 cm_scache_t *sscp = NULL;
5148 userp = smb_GetUser(vcp, inp);
5150 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5152 cm_ReleaseUser(userp);
5153 return CM_ERROR_NOSUCHPATH;
5158 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5160 spacep = inp->spacep;
5161 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5163 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5164 userp, tidPathp, &req, &oldDscp);
5166 cm_ReleaseUser(userp);
5171 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5172 cm_ReleaseSCache(oldDscp);
5173 cm_ReleaseUser(userp);
5174 if ( WANTS_DFS_PATHNAMES(inp) )
5175 return CM_ERROR_PATH_NOT_COVERED;
5177 return CM_ERROR_BADSHARENAME;
5179 #endif /* DFS_SUPPORT */
5181 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5182 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5183 userp, tidPathp, &req, &newDscp);
5185 cm_ReleaseSCache(oldDscp);
5186 cm_ReleaseUser(userp);
5191 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5192 cm_ReleaseSCache(newDscp);
5193 cm_ReleaseSCache(oldDscp);
5194 cm_ReleaseUser(userp);
5195 if ( WANTS_DFS_PATHNAMES(inp) )
5196 return CM_ERROR_PATH_NOT_COVERED;
5198 return CM_ERROR_BADSHARENAME;
5200 #endif /* DFS_SUPPORT */
5202 /* Now, although we did two lookups for the two directories (because the same
5203 * directory can be referenced through different paths), we only allow hard links
5204 * within the same directory. */
5205 if (oldDscp != newDscp) {
5206 cm_ReleaseSCache(oldDscp);
5207 cm_ReleaseSCache(newDscp);
5208 cm_ReleaseUser(userp);
5209 return CM_ERROR_CROSSDEVLINK;
5212 /* handle the old name first */
5214 oldLastNamep = oldPathp;
5218 /* and handle the new name, too */
5220 newLastNamep = newPathp;
5224 /* now lookup the old name */
5225 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5226 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5228 cm_ReleaseSCache(oldDscp);
5229 cm_ReleaseSCache(newDscp);
5230 cm_ReleaseUser(userp);
5234 /* Check if the file already exists; if so return error */
5235 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5236 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5237 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5238 osi_LogSaveString(afsd_logp, newLastNamep));
5240 /* if the existing link is to the same file, then we return success */
5242 if(sscp == tmpscp) {
5245 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5246 code = CM_ERROR_EXISTS;
5251 cm_ReleaseSCache(tmpscp);
5252 cm_ReleaseSCache(sscp);
5253 cm_ReleaseSCache(newDscp);
5254 cm_ReleaseSCache(oldDscp);
5255 cm_ReleaseUser(userp);
5259 /* now create the hardlink */
5260 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5261 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5262 osi_Log1(smb_logp," Link returns %d", code);
5264 /* Handle Change Notification */
5266 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5267 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5268 smb_NotifyChange(FILE_ACTION_ADDED,
5269 filter, newDscp, newLastNamep,
5274 cm_ReleaseSCache(tmpscp);
5275 cm_ReleaseUser(userp);
5276 cm_ReleaseSCache(sscp);
5277 cm_ReleaseSCache(oldDscp);
5278 cm_ReleaseSCache(newDscp);
5283 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5289 tp = smb_GetSMBData(inp, NULL);
5290 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5291 if (smb_StoreAnsiFilenames)
5292 OemToChar(oldPathp,oldPathp);
5293 newPathp = smb_ParseASCIIBlock(tp, &tp);
5294 if (smb_StoreAnsiFilenames)
5295 OemToChar(newPathp,newPathp);
5297 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5298 osi_LogSaveString(smb_logp, oldPathp),
5299 osi_LogSaveString(smb_logp, newPathp));
5301 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5306 typedef struct smb_rmdirRock {
5310 char *maskp; /* pointer to the star pattern */
5315 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5318 smb_rmdirRock_t *rockp;
5323 rockp = (smb_rmdirRock_t *) vrockp;
5325 matchName = dep->name;
5326 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5327 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5329 match = (strcmp(matchName, rockp->maskp) == 0);
5331 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5332 !cm_Is8Dot3(dep->name)) {
5333 cm_Gen8Dot3Name(dep, shortName, NULL);
5334 matchName = shortName;
5335 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5338 osi_Log1(smb_logp, "Removing directory %s",
5339 osi_LogSaveString(smb_logp, matchName));
5340 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5341 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5342 smb_NotifyChange(FILE_ACTION_REMOVED,
5343 FILE_NOTIFY_CHANGE_DIR_NAME,
5344 dscp, dep->name, NULL, TRUE);
5353 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5361 smb_rmdirRock_t rock;
5370 tp = smb_GetSMBData(inp, NULL);
5371 pathp = smb_ParseASCIIBlock(tp, &tp);
5372 if (smb_StoreAnsiFilenames)
5373 OemToChar(pathp,pathp);
5375 spacep = inp->spacep;
5376 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5378 userp = smb_GetUser(vcp, inp);
5380 caseFold = CM_FLAG_CASEFOLD;
5382 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5384 cm_ReleaseUser(userp);
5385 return CM_ERROR_NOSUCHPATH;
5387 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5388 userp, tidPathp, &req, &dscp);
5391 cm_ReleaseUser(userp);
5396 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5397 cm_ReleaseSCache(dscp);
5398 cm_ReleaseUser(userp);
5399 if ( WANTS_DFS_PATHNAMES(inp) )
5400 return CM_ERROR_PATH_NOT_COVERED;
5402 return CM_ERROR_BADSHARENAME;
5404 #endif /* DFS_SUPPORT */
5406 /* otherwise, scp points to the parent directory. */
5413 rock.maskp = lastNamep;
5414 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5417 thyper.HighPart = 0;
5421 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5422 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5423 if (code == 0 && !rock.any) {
5425 thyper.HighPart = 0;
5426 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5427 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5430 cm_ReleaseUser(userp);
5432 cm_ReleaseSCache(dscp);
5434 if (code == 0 && !rock.any)
5435 code = CM_ERROR_NOSUCHFILE;
5439 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5449 fid = smb_GetSMBParm(inp, 0);
5451 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5453 fid = smb_ChainFID(fid, inp);
5454 fidp = smb_FindFID(vcp, fid, 0);
5455 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5457 smb_ReleaseFID(fidp);
5458 return CM_ERROR_BADFD;
5461 userp = smb_GetUser(vcp, inp);
5463 lock_ObtainMutex(&fidp->mx);
5464 if (fidp->flags & SMB_FID_OPENWRITE)
5465 code = cm_FSync(fidp->scp, userp, &req);
5468 lock_ReleaseMutex(&fidp->mx);
5470 smb_ReleaseFID(fidp);
5472 cm_ReleaseUser(userp);
5477 struct smb_FullNameRock {
5483 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5487 struct smb_FullNameRock *vrockp;
5489 vrockp = (struct smb_FullNameRock *)rockp;
5491 if (!cm_Is8Dot3(dep->name)) {
5492 cm_Gen8Dot3Name(dep, shortName, NULL);
5494 if (cm_stricmp(shortName, vrockp->name) == 0) {
5495 vrockp->fullName = strdup(dep->name);
5496 return CM_ERROR_STOPNOW;
5499 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5500 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5501 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5502 vrockp->fullName = strdup(dep->name);
5503 return CM_ERROR_STOPNOW;
5508 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5509 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5511 struct smb_FullNameRock rock;
5517 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5518 if (code == CM_ERROR_STOPNOW)
5519 *newPathp = rock.fullName;
5521 *newPathp = strdup(pathp);
5524 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5525 afs_uint32 dosTime) {
5529 osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
5530 fidp, fidp->fid, vcp);
5534 osi_Log0(smb_logp, " No user specified. Not closing fid");
5535 return CM_ERROR_BADFD;
5538 userp = fidp->userp; /* no hold required since fidp is held
5539 throughout the function */
5544 lock_ObtainMutex(&fidp->mx);
5546 /* Don't jump the gun on an async raw write */
5547 while (fidp->raw_writers) {
5548 lock_ReleaseMutex(&fidp->mx);
5549 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5550 lock_ObtainMutex(&fidp->mx);
5553 fidp->flags |= SMB_FID_DELETE;
5555 /* watch for ioctl closes, and read-only opens */
5556 if (fidp->scp != NULL &&
5557 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5558 == SMB_FID_OPENWRITE) {
5559 if (dosTime != 0 && dosTime != -1) {
5560 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5561 /* This fixes defect 10958 */
5562 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5563 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5565 code = cm_FSync(fidp->scp, userp, &req);
5570 /* unlock any pending locks */
5571 if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
5572 fidp->scp->fileType == CM_SCACHETYPE_FILE) {
5577 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5579 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5582 lock_ObtainMutex(&scp->mx);
5584 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5585 CM_SCACHESYNC_NEEDCALLBACK
5586 | CM_SCACHESYNC_GETSTATUS
5587 | CM_SCACHESYNC_LOCK);
5591 "smb CoreClose SyncOp failure code 0x%x", tcode);
5592 goto post_syncopdone;
5595 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5597 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5601 lock_ReleaseMutex(&scp->mx);
5602 cm_ReleaseSCache(scp);
5605 if (fidp->flags & SMB_FID_DELONCLOSE) {
5606 cm_scache_t *dscp = fidp->NTopen_dscp;
5607 char *pathp = fidp->NTopen_pathp;
5610 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5611 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5612 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5613 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5614 smb_NotifyChange(FILE_ACTION_REMOVED,
5615 FILE_NOTIFY_CHANGE_DIR_NAME,
5616 dscp, fullPathp, NULL, TRUE);
5618 code = cm_Unlink(dscp, fullPathp, userp, &req);
5619 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5620 smb_NotifyChange(FILE_ACTION_REMOVED,
5621 FILE_NOTIFY_CHANGE_FILE_NAME,
5622 dscp, fullPathp, NULL, TRUE);
5626 lock_ReleaseMutex(&fidp->mx);
5628 if (fidp->flags & SMB_FID_NTOPEN) {
5629 cm_ReleaseSCache(fidp->NTopen_dscp);
5630 free(fidp->NTopen_pathp);
5631 fidp->NTopen_pathp = NULL;
5633 if (fidp->NTopen_wholepathp) {
5634 free(fidp->NTopen_wholepathp);
5635 fidp->NTopen_wholepathp = NULL;
5641 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5649 fid = smb_GetSMBParm(inp, 0);
5650 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5652 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5654 fid = smb_ChainFID(fid, inp);
5655 fidp = smb_FindFID(vcp, fid, 0);
5657 return CM_ERROR_BADFD;
5660 userp = smb_GetUser(vcp, inp);
5662 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5664 smb_ReleaseFID(fidp);
5665 cm_ReleaseUser(userp);
5670 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5673 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5674 cm_user_t *userp, long *readp)
5676 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5677 cm_user_t *userp, long *readp, int dosflag)
5684 osi_hyper_t fileLength;
5686 osi_hyper_t lastByte;
5687 osi_hyper_t bufferOffset;
5688 long bufIndex, nbytes;
5698 lock_ObtainMutex(&fidp->mx);
5700 lock_ObtainMutex(&scp->mx);
5702 if (offset.HighPart == 0) {
5703 chunk = offset.LowPart >> cm_logChunkSize;
5704 if (chunk != fidp->curr_chunk) {
5705 fidp->prev_chunk = fidp->curr_chunk;
5706 fidp->curr_chunk = chunk;
5708 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5712 /* start by looking up the file's end */
5713 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5714 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5715 if (code) goto done;
5717 /* now we have the entry locked, look up the length */
5718 fileLength = scp->length;
5720 /* adjust count down so that it won't go past EOF */
5721 thyper.LowPart = count;
5722 thyper.HighPart = 0;
5723 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5725 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5726 /* we'd read past EOF, so just stop at fileLength bytes.
5727 * Start by computing how many bytes remain in the file.
5729 thyper = LargeIntegerSubtract(fileLength, offset);
5731 /* if we are past EOF, read 0 bytes */
5732 if (LargeIntegerLessThanZero(thyper))
5735 count = thyper.LowPart;
5740 /* now, copy the data one buffer at a time,
5741 * until we've filled the request packet
5744 /* if we've copied all the data requested, we're done */
5745 if (count <= 0) break;
5747 /* otherwise, load up a buffer of data */
5748 thyper.HighPart = offset.HighPart;
5749 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5750 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5753 buf_Release(bufferp);
5756 lock_ReleaseMutex(&scp->mx);
5758 lock_ObtainRead(&scp->bufCreateLock);
5759 code = buf_Get(scp, &thyper, &bufferp);
5760 lock_ReleaseRead(&scp->bufCreateLock);
5762 lock_ObtainMutex(&scp->mx);
5763 if (code) goto done;
5764 bufferOffset = thyper;
5766 /* now get the data in the cache */
5768 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5769 CM_SCACHESYNC_NEEDCALLBACK |
5770 CM_SCACHESYNC_READ);
5771 if (code) goto done;
5773 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5775 /* otherwise, load the buffer and try again */
5776 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5780 buf_Release(bufferp);
5784 } /* if (wrong buffer) ... */
5786 /* now we have the right buffer loaded. Copy out the
5787 * data from here to the user's buffer.
5789 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5791 /* and figure out how many bytes we want from this buffer */
5792 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5793 if (nbytes > count) nbytes = count; /* don't go past EOF */
5795 /* now copy the data */
5798 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5801 memcpy(op, bufferp->datap + bufIndex, nbytes);
5803 /* adjust counters, pointers, etc. */
5806 thyper.LowPart = nbytes;
5807 thyper.HighPart = 0;
5808 offset = LargeIntegerAdd(thyper, offset);
5812 lock_ReleaseMutex(&scp->mx);
5813 lock_ReleaseMutex(&fidp->mx);
5815 buf_Release(bufferp);
5817 if (code == 0 && sequential)
5818 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5824 * smb_WriteData -- common code for Write and Raw Write
5827 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5828 cm_user_t *userp, long *writtenp)
5830 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5831 cm_user_t *userp, long *writtenp, int dosflag)
5838 osi_hyper_t fileLength; /* file's length at start of write */
5839 osi_hyper_t minLength; /* don't read past this */
5840 long nbytes; /* # of bytes to transfer this iteration */
5842 osi_hyper_t thyper; /* hyper tmp variable */
5843 osi_hyper_t bufferOffset;
5844 long bufIndex; /* index in buffer where our data is */
5846 osi_hyper_t writeBackOffset;/* offset of region to write back when
5851 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5852 fidp->fid, offsetp->LowPart, count);
5862 lock_ObtainMutex(&fidp->mx);
5864 lock_ObtainMutex(&scp->mx);
5866 /* start by looking up the file's end */
5867 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5868 CM_SCACHESYNC_NEEDCALLBACK
5869 | CM_SCACHESYNC_SETSTATUS
5870 | CM_SCACHESYNC_GETSTATUS);
5874 /* make sure we have a writable FD */
5875 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5876 code = CM_ERROR_BADFDOP;
5880 /* now we have the entry locked, look up the length */
5881 fileLength = scp->length;
5882 minLength = fileLength;
5883 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5884 minLength = scp->serverLength;
5886 /* adjust file length if we extend past EOF */
5887 thyper.LowPart = count;
5888 thyper.HighPart = 0;
5889 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5890 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5891 /* we'd write past EOF, so extend the file */
5892 scp->mask |= CM_SCACHEMASK_LENGTH;
5893 scp->length = thyper;
5894 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5896 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5898 /* now, if the new position (thyper) and the old (offset) are in
5899 * different storeback windows, remember to store back the previous
5900 * storeback window when we're done with the write.
5902 if ((thyper.LowPart & (-cm_chunkSize)) !=
5903 (offset.LowPart & (-cm_chunkSize))) {
5904 /* they're different */
5906 writeBackOffset.HighPart = offset.HighPart;
5907 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5912 /* now, copy the data one buffer at a time, until we've filled the
5915 /* if we've copied all the data requested, we're done */
5919 /* handle over quota or out of space */
5920 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5921 *writtenp = written;
5922 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
5926 /* otherwise, load up a buffer of data */
5927 thyper.HighPart = offset.HighPart;
5928 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5929 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5932 lock_ReleaseMutex(&bufferp->mx);
5933 buf_Release(bufferp);
5936 lock_ReleaseMutex(&scp->mx);
5938 lock_ObtainRead(&scp->bufCreateLock);
5939 code = buf_Get(scp, &thyper, &bufferp);
5940 lock_ReleaseRead(&scp->bufCreateLock);
5942 lock_ObtainMutex(&bufferp->mx);
5943 lock_ObtainMutex(&scp->mx);
5944 if (code) goto done;
5946 bufferOffset = thyper;
5948 /* now get the data in the cache */
5950 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5951 CM_SCACHESYNC_NEEDCALLBACK
5952 | CM_SCACHESYNC_WRITE
5953 | CM_SCACHESYNC_BUFLOCKED);
5957 /* If we're overwriting the entire buffer, or
5958 * if we're writing at or past EOF, mark the
5959 * buffer as current so we don't call
5960 * cm_GetBuffer. This skips the fetch from the
5961 * server in those cases where we're going to
5962 * obliterate all the data in the buffer anyway,
5963 * or in those cases where there is no useful
5964 * data at the server to start with.
5966 * Use minLength instead of scp->length, since
5967 * the latter has already been updated by this
5970 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5971 || LargeIntegerEqualTo(offset, bufferp->offset)
5972 && (count >= cm_data.buf_blockSize
5973 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5974 ConvertLongToLargeInteger(count)),
5976 if (count < cm_data.buf_blockSize
5977 && bufferp->dataVersion == -1)
5978 memset(bufferp->datap, 0,
5979 cm_data.buf_blockSize);
5980 bufferp->dataVersion = scp->dataVersion;
5983 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5985 /* otherwise, load the buffer and try again */
5986 lock_ReleaseMutex(&bufferp->mx);
5987 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5989 lock_ReleaseMutex(&scp->mx);
5990 lock_ObtainMutex(&bufferp->mx);
5991 lock_ObtainMutex(&scp->mx);
5995 lock_ReleaseMutex(&bufferp->mx);
5996 buf_Release(bufferp);
6000 } /* if (wrong buffer) ... */
6002 /* now we have the right buffer loaded. Copy out the
6003 * data from here to the user's buffer.
6005 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6007 /* and figure out how many bytes we want from this buffer */
6008 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6010 nbytes = count; /* don't go past end of request */
6012 /* now copy the data */
6015 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
6018 memcpy(bufferp->datap + bufIndex, op, nbytes);
6019 buf_SetDirty(bufferp);
6021 /* and record the last writer */
6022 if (bufferp->userp != userp) {
6025 cm_ReleaseUser(bufferp->userp);
6026 bufferp->userp = userp;
6029 /* adjust counters, pointers, etc. */
6033 thyper.LowPart = nbytes;
6034 thyper.HighPart = 0;
6035 offset = LargeIntegerAdd(thyper, offset);
6039 lock_ReleaseMutex(&scp->mx);
6040 lock_ReleaseMutex(&fidp->mx);
6042 lock_ReleaseMutex(&bufferp->mx);
6043 buf_Release(bufferp);
6046 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6047 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6048 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6049 fidp->NTopen_dscp, fidp->NTopen_pathp,
6053 if (code == 0 && doWriteBack) {
6055 lock_ObtainMutex(&scp->mx);
6056 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6058 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6059 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
6061 lock_ReleaseMutex(&scp->mx);
6062 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6063 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6066 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
6067 fidp->fid, code, *writtenp);
6071 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6074 long count, written = 0, total_written = 0;
6080 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6082 int inDataBlockCount;
6084 fd = smb_GetSMBParm(inp, 0);
6085 count = smb_GetSMBParm(inp, 1);
6086 offset.HighPart = 0; /* too bad */
6087 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6089 op = smb_GetSMBData(inp, NULL);
6090 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6092 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6093 fd, offset.LowPart, count);
6095 fd = smb_ChainFID(fd, inp);
6096 fidp = smb_FindFID(vcp, fd, 0);
6098 return CM_ERROR_BADFD;
6101 if (fidp->flags & SMB_FID_IOCTL)
6102 return smb_IoctlWrite(fidp, vcp, inp, outp);
6104 userp = smb_GetUser(vcp, inp);
6106 /* special case: 0 bytes transferred means truncate to this position */
6112 truncAttr.mask = CM_ATTRMASK_LENGTH;
6113 truncAttr.length.LowPart = offset.LowPart;
6114 truncAttr.length.HighPart = 0;
6115 lock_ObtainMutex(&fidp->mx);
6116 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6117 lock_ReleaseMutex(&fidp->mx);
6118 smb_SetSMBParm(outp, 0, /* count */ 0);
6119 smb_SetSMBDataLength(outp, 0);
6120 fidp->flags |= SMB_FID_LENGTHSETDONE;
6126 LARGE_INTEGER LOffset;
6127 LARGE_INTEGER LLength;
6129 pid = ((smb_t *) inp)->pid;
6130 key = cm_GenerateKey(vcp->vcID, pid, fd);
6132 LOffset.HighPart = offset.HighPart;
6133 LOffset.LowPart = offset.LowPart;
6134 LLength.HighPart = 0;
6135 LLength.LowPart = count;
6137 lock_ObtainMutex(&fidp->scp->mx);
6138 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6139 lock_ReleaseMutex(&fidp->scp->mx);
6146 * Work around bug in NT client
6148 * When copying a file, the NT client should first copy the data,
6149 * then copy the last write time. But sometimes the NT client does
6150 * these in the wrong order, so the data copies would inadvertently
6151 * cause the last write time to be overwritten. We try to detect this,
6152 * and don't set client mod time if we think that would go against the
6155 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6156 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6157 fidp->scp->clientModTime = time(NULL);
6161 while ( code == 0 && count > 0 ) {
6163 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6165 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6167 if (code == 0 && written == 0)
6168 code = CM_ERROR_PARTIALWRITE;
6170 offset.LowPart += written;
6172 total_written += written;
6176 /* set the packet data length to 3 bytes for the data block header,
6177 * plus the size of the data.
6179 smb_SetSMBParm(outp, 0, total_written);
6180 smb_SetSMBDataLength(outp, 0);
6183 smb_ReleaseFID(fidp);
6184 cm_ReleaseUser(userp);
6189 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6190 NCB *ncbp, raw_write_cont_t *rwcp)
6203 fd = smb_GetSMBParm(inp, 0);
6204 fidp = smb_FindFID(vcp, fd, 0);
6206 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
6207 rwcp->offset.LowPart, rwcp->count);
6209 userp = smb_GetUser(vcp, inp);
6213 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6216 rawBuf = (dos_ptr) rwcp->buf;
6217 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6218 (unsigned char *) rawBuf, userp,
6222 if (rwcp->writeMode & 0x1) { /* synchronous */
6225 smb_FormatResponsePacket(vcp, inp, outp);
6226 op = (smb_t *) outp;
6227 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6228 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6229 smb_SetSMBDataLength(outp, 0);
6230 smb_SendPacket(vcp, outp);
6231 smb_FreePacket(outp);
6233 else { /* asynchronous */
6234 lock_ObtainMutex(&fidp->mx);
6235 fidp->raw_writers--;
6236 if (fidp->raw_writers == 0)
6237 thrd_SetEvent(fidp->raw_write_event);
6238 lock_ReleaseMutex(&fidp->mx);
6241 /* Give back raw buffer */
6242 lock_ObtainMutex(&smb_RawBufLock);
6244 *((char **)rawBuf) = smb_RawBufs;
6246 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6248 smb_RawBufs = rawBuf;
6249 lock_ReleaseMutex(&smb_RawBufLock);
6251 smb_ReleaseFID(fidp);
6252 cm_ReleaseUser(userp);
6255 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6260 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6263 long count, written = 0, total_written = 0;
6270 unsigned short writeMode;
6277 fd = smb_GetSMBParm(inp, 0);
6278 totalCount = smb_GetSMBParm(inp, 1);
6279 count = smb_GetSMBParm(inp, 10);
6280 offset.HighPart = 0; /* too bad */
6281 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6282 writeMode = smb_GetSMBParm(inp, 7);
6284 op = (char *) inp->data;
6285 op += smb_GetSMBParm(inp, 11);
6288 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
6289 fd, offset.LowPart, count, writeMode);
6291 fd = smb_ChainFID(fd, inp);
6292 fidp = smb_FindFID(vcp, fd, 0);
6294 return CM_ERROR_BADFD;
6300 LARGE_INTEGER LOffset;
6301 LARGE_INTEGER LLength;
6303 pid = ((smb_t *) inp)->pid;
6304 key = cm_GenerateKey(vcp->vcID, pid, fd);
6306 LOffset.HighPart = offset.HighPart;
6307 LOffset.LowPart = offset.LowPart;
6308 LLength.HighPart = 0;
6309 LLength.LowPart = count;
6311 lock_ObtainMutex(&fidp->scp->mx);
6312 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6313 lock_ReleaseMutex(&fidp->scp->mx);
6316 smb_ReleaseFID(fidp);
6321 userp = smb_GetUser(vcp, inp);
6324 * Work around bug in NT client
6326 * When copying a file, the NT client should first copy the data,
6327 * then copy the last write time. But sometimes the NT client does
6328 * these in the wrong order, so the data copies would inadvertently
6329 * cause the last write time to be overwritten. We try to detect this,
6330 * and don't set client mod time if we think that would go against the
6333 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6334 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6335 fidp->scp->clientModTime = time(NULL);
6339 while ( code == 0 && count > 0 ) {
6341 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6343 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6345 if (code == 0 && written == 0)
6346 code = CM_ERROR_PARTIALWRITE;
6348 offset.LowPart += written;
6350 total_written += written;
6354 /* Get a raw buffer */
6357 lock_ObtainMutex(&smb_RawBufLock);
6359 /* Get a raw buf, from head of list */
6360 rawBuf = smb_RawBufs;
6362 smb_RawBufs = *(char **)smb_RawBufs;
6364 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
6368 code = CM_ERROR_USESTD;
6370 lock_ReleaseMutex(&smb_RawBufLock);
6373 /* Don't allow a premature Close */
6374 if (code == 0 && (writeMode & 1) == 0) {
6375 lock_ObtainMutex(&fidp->mx);
6376 fidp->raw_writers++;
6377 thrd_ResetEvent(fidp->raw_write_event);
6378 lock_ReleaseMutex(&fidp->mx);
6381 smb_ReleaseFID(fidp);
6382 cm_ReleaseUser(userp);
6385 smb_SetSMBParm(outp, 0, total_written);
6386 smb_SetSMBDataLength(outp, 0);
6387 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6394 rwcp->offset.HighPart = 0;
6395 rwcp->offset.LowPart = offset.LowPart + count;
6396 rwcp->count = totalCount - count;
6397 rwcp->writeMode = writeMode;
6398 rwcp->alreadyWritten = total_written;
6400 /* set the packet data length to 3 bytes for the data block header,
6401 * plus the size of the data.
6403 smb_SetSMBParm(outp, 0, 0xffff);
6404 smb_SetSMBDataLength(outp, 0);
6409 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6412 long count, finalCount;
6420 fd = smb_GetSMBParm(inp, 0);
6421 count = smb_GetSMBParm(inp, 1);
6422 offset.HighPart = 0; /* too bad */
6423 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6425 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6426 fd, offset.LowPart, count);
6428 fd = smb_ChainFID(fd, inp);
6429 fidp = smb_FindFID(vcp, fd, 0);
6431 return CM_ERROR_BADFD;
6434 if (fidp->flags & SMB_FID_IOCTL) {
6435 return smb_IoctlRead(fidp, vcp, inp, outp);
6439 LARGE_INTEGER LOffset, LLength;
6442 pid = ((smb_t *) inp)->pid;
6443 key = cm_GenerateKey(vcp->vcID, pid, fd);
6445 LOffset.HighPart = 0;
6446 LOffset.LowPart = offset.LowPart;
6447 LLength.HighPart = 0;
6448 LLength.LowPart = count;
6450 lock_ObtainMutex(&fidp->scp->mx);
6451 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6452 lock_ReleaseMutex(&fidp->scp->mx);
6455 smb_ReleaseFID(fidp);
6459 userp = smb_GetUser(vcp, inp);
6461 /* remember this for final results */
6462 smb_SetSMBParm(outp, 0, count);
6463 smb_SetSMBParm(outp, 1, 0);
6464 smb_SetSMBParm(outp, 2, 0);
6465 smb_SetSMBParm(outp, 3, 0);
6466 smb_SetSMBParm(outp, 4, 0);
6468 /* set the packet data length to 3 bytes for the data block header,
6469 * plus the size of the data.
6471 smb_SetSMBDataLength(outp, count+3);
6473 /* get op ptr after putting in the parms, since otherwise we don't
6474 * know where the data really is.
6476 op = smb_GetSMBData(outp, NULL);
6478 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6479 *op++ = 1; /* data block marker */
6480 *op++ = (unsigned char) (count & 0xff);
6481 *op++ = (unsigned char) ((count >> 8) & 0xff);
6484 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6486 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6489 /* fix some things up */
6490 smb_SetSMBParm(outp, 0, finalCount);
6491 smb_SetSMBDataLength(outp, finalCount+3);
6493 smb_ReleaseFID(fidp);
6495 cm_ReleaseUser(userp);
6499 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6506 cm_scache_t *dscp; /* dir we're dealing with */
6507 cm_scache_t *scp; /* file we're creating */
6509 int initialModeBits;
6519 /* compute initial mode bits based on read-only flag in attributes */
6520 initialModeBits = 0777;
6522 tp = smb_GetSMBData(inp, NULL);
6523 pathp = smb_ParseASCIIBlock(tp, &tp);
6524 if (smb_StoreAnsiFilenames)
6525 OemToChar(pathp,pathp);
6527 if (strcmp(pathp, "\\") == 0)
6528 return CM_ERROR_EXISTS;
6530 spacep = inp->spacep;
6531 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6533 userp = smb_GetUser(vcp, inp);
6535 caseFold = CM_FLAG_CASEFOLD;
6537 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6539 cm_ReleaseUser(userp);
6540 return CM_ERROR_NOSUCHPATH;
6543 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6544 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6545 userp, tidPathp, &req, &dscp);
6548 cm_ReleaseUser(userp);
6553 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6554 cm_ReleaseSCache(dscp);
6555 cm_ReleaseUser(userp);
6556 if ( WANTS_DFS_PATHNAMES(inp) )
6557 return CM_ERROR_PATH_NOT_COVERED;
6559 return CM_ERROR_BADSHARENAME;
6561 #endif /* DFS_SUPPORT */
6563 /* otherwise, scp points to the parent directory. Do a lookup, and
6564 * fail if we find it. Otherwise, we do the create.
6570 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6571 if (scp) cm_ReleaseSCache(scp);
6572 if (code != CM_ERROR_NOSUCHFILE) {
6573 if (code == 0) code = CM_ERROR_EXISTS;
6574 cm_ReleaseSCache(dscp);
6575 cm_ReleaseUser(userp);
6579 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6580 setAttr.clientModTime = time(NULL);
6581 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6582 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6583 smb_NotifyChange(FILE_ACTION_ADDED,
6584 FILE_NOTIFY_CHANGE_DIR_NAME,
6585 dscp, lastNamep, NULL, TRUE);
6587 /* we don't need this any longer */
6588 cm_ReleaseSCache(dscp);
6591 /* something went wrong creating or truncating the file */
6592 cm_ReleaseUser(userp);
6596 /* otherwise we succeeded */
6597 smb_SetSMBDataLength(outp, 0);
6598 cm_ReleaseUser(userp);
6603 BOOL smb_IsLegalFilename(char *filename)
6606 * Find the longest substring of filename that does not contain
6607 * any of the chars in illegalChars. If that substring is less
6608 * than the length of the whole string, then one or more of the
6609 * illegal chars is in filename.
6611 if (strcspn(filename, illegalChars) < strlen(filename))
6617 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6625 cm_scache_t *dscp; /* dir we're dealing with */
6626 cm_scache_t *scp; /* file we're creating */
6628 int initialModeBits;
6640 excl = (inp->inCom == 0x03)? 0 : 1;
6642 attributes = smb_GetSMBParm(inp, 0);
6643 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6645 /* compute initial mode bits based on read-only flag in attributes */
6646 initialModeBits = 0666;
6647 if (attributes & 1) initialModeBits &= ~0222;
6649 tp = smb_GetSMBData(inp, NULL);
6650 pathp = smb_ParseASCIIBlock(tp, &tp);
6651 if (smb_StoreAnsiFilenames)
6652 OemToChar(pathp,pathp);
6654 spacep = inp->spacep;
6655 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6657 userp = smb_GetUser(vcp, inp);
6659 caseFold = CM_FLAG_CASEFOLD;
6661 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6663 cm_ReleaseUser(userp);
6664 return CM_ERROR_NOSUCHPATH;
6666 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6667 userp, tidPathp, &req, &dscp);
6670 cm_ReleaseUser(userp);
6675 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6676 cm_ReleaseSCache(dscp);
6677 cm_ReleaseUser(userp);
6678 if ( WANTS_DFS_PATHNAMES(inp) )
6679 return CM_ERROR_PATH_NOT_COVERED;
6681 return CM_ERROR_BADSHARENAME;
6683 #endif /* DFS_SUPPORT */
6685 /* otherwise, scp points to the parent directory. Do a lookup, and
6686 * truncate the file if we find it, otherwise we create the file.
6693 if (!smb_IsLegalFilename(lastNamep))
6694 return CM_ERROR_BADNTFILENAME;
6696 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6697 #ifdef DEBUG_VERBOSE
6700 hexp = osi_HexifyString( lastNamep );
6701 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6706 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6707 if (code && code != CM_ERROR_NOSUCHFILE) {
6708 cm_ReleaseSCache(dscp);
6709 cm_ReleaseUser(userp);
6713 /* if we get here, if code is 0, the file exists and is represented by
6714 * scp. Otherwise, we have to create it.
6718 /* oops, file shouldn't be there */
6719 cm_ReleaseSCache(dscp);
6720 cm_ReleaseSCache(scp);
6721 cm_ReleaseUser(userp);
6722 return CM_ERROR_EXISTS;
6725 setAttr.mask = CM_ATTRMASK_LENGTH;
6726 setAttr.length.LowPart = 0;
6727 setAttr.length.HighPart = 0;
6728 code = cm_SetAttr(scp, &setAttr, userp, &req);
6731 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6732 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6733 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6735 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6736 smb_NotifyChange(FILE_ACTION_ADDED,
6737 FILE_NOTIFY_CHANGE_FILE_NAME,
6738 dscp, lastNamep, NULL, TRUE);
6739 if (!excl && code == CM_ERROR_EXISTS) {
6740 /* not an exclusive create, and someone else tried
6741 * creating it already, then we open it anyway. We
6742 * don't bother retrying after this, since if this next
6743 * fails, that means that the file was deleted after
6744 * we started this call.
6746 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6749 setAttr.mask = CM_ATTRMASK_LENGTH;
6750 setAttr.length.LowPart = 0;
6751 setAttr.length.HighPart = 0;
6752 code = cm_SetAttr(scp, &setAttr, userp, &req);
6757 /* we don't need this any longer */
6758 cm_ReleaseSCache(dscp);
6761 /* something went wrong creating or truncating the file */
6762 if (scp) cm_ReleaseSCache(scp);
6763 cm_ReleaseUser(userp);
6767 /* make sure we only open files */
6768 if (scp->fileType != CM_SCACHETYPE_FILE) {
6769 cm_ReleaseSCache(scp);
6770 cm_ReleaseUser(userp);
6771 return CM_ERROR_ISDIR;
6774 /* now all we have to do is open the file itself */
6775 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6778 /* save a pointer to the vnode */
6782 fidp->userp = userp;
6784 /* always create it open for read/write */
6785 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6787 smb_ReleaseFID(fidp);
6789 smb_SetSMBParm(outp, 0, fidp->fid);
6790 smb_SetSMBDataLength(outp, 0);
6792 cm_Open(scp, 0, userp);
6794 cm_ReleaseUser(userp);
6795 /* leave scp held since we put it in fidp->scp */
6799 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6812 fd = smb_GetSMBParm(inp, 0);
6813 whence = smb_GetSMBParm(inp, 1);
6814 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6816 /* try to find the file descriptor */
6817 fd = smb_ChainFID(fd, inp);
6818 fidp = smb_FindFID(vcp, fd, 0);
6819 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6820 return CM_ERROR_BADFD;
6823 userp = smb_GetUser(vcp, inp);
6825 lock_ObtainMutex(&fidp->mx);
6827 lock_ObtainMutex(&scp->mx);
6828 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6829 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6832 /* offset from current offset */
6833 offset += fidp->offset;
6835 else if (whence == 2) {
6836 /* offset from current EOF */
6837 offset += scp->length.LowPart;
6839 fidp->offset = offset;
6840 smb_SetSMBParm(outp, 0, offset & 0xffff);
6841 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6842 smb_SetSMBDataLength(outp, 0);
6844 lock_ReleaseMutex(&scp->mx);
6845 lock_ReleaseMutex(&fidp->mx);
6846 smb_ReleaseFID(fidp);
6847 cm_ReleaseUser(userp);
6851 /* dispatch all of the requests received in a packet. Due to chaining, this may
6852 * be more than one request.
6854 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6855 NCB *ncbp, raw_write_cont_t *rwcp)
6859 unsigned long code = 0;
6860 unsigned char *outWctp;
6861 int nparms; /* # of bytes of parameters */
6863 int nbytes; /* bytes of data, excluding count */
6866 unsigned short errCode;
6867 unsigned long NTStatus;
6869 unsigned char errClass;
6870 unsigned int oldGen;
6871 DWORD oldTime, newTime;
6873 /* get easy pointer to the data */
6874 smbp = (smb_t *) inp->data;
6876 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6877 /* setup the basic parms for the initial request in the packet */
6878 inp->inCom = smbp->com;
6879 inp->wctp = &smbp->wct;
6881 inp->ncb_length = ncbp->ncb_length;
6886 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6887 /* log it and discard it */
6889 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
6890 __FILE__, __LINE__, ncbp->ncb_length);
6892 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6896 /* We are an ongoing op */
6897 thrd_Increment(&ongoingOps);
6899 /* set up response packet for receiving output */
6900 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6901 smb_FormatResponsePacket(vcp, inp, outp);
6902 outWctp = outp->wctp;
6904 /* Remember session generation number and time */
6905 oldGen = sessionGen;
6906 oldTime = GetCurrentTime();
6908 while (inp->inCom != 0xff) {
6909 dp = &smb_dispatchTable[inp->inCom];
6911 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6912 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6913 code = outp->resumeCode;
6917 /* process each request in the packet; inCom, wctp and inCount
6918 * are already set up.
6920 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6923 /* now do the dispatch */
6924 /* start by formatting the response record a little, as a default */
6925 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6927 outWctp[1] = 0xff; /* no operation */
6928 outWctp[2] = 0; /* padding */
6933 /* not a chained request, this is a more reasonable default */
6934 outWctp[0] = 0; /* wct of zero */
6935 outWctp[1] = 0; /* and bcc (word) of zero */
6939 /* once set, stays set. Doesn't matter, since we never chain
6940 * "no response" calls.
6942 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6946 /* we have a recognized operation */
6948 if (inp->inCom == 0x1d)
6950 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6953 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6954 code = (*(dp->procp)) (vcp, inp, outp);
6955 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
6957 if ( code == CM_ERROR_BADSMB ||
6958 code == CM_ERROR_BADOP )
6960 #endif /* LOG_PACKET */
6963 if (oldGen != sessionGen) {
6964 newTime = GetCurrentTime();
6966 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
6967 newTime - oldTime, ncbp->ncb_length);
6969 osi_Log2(smb_logp, "Pkt straddled session startup, "
6970 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
6974 /* bad opcode, fail the request, after displaying it */
6975 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6978 #endif /* LOG_PACKET */
6982 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6983 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6984 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6985 if (code == IDCANCEL)
6989 code = CM_ERROR_BADOP;
6992 /* catastrophic failure: log as much as possible */
6993 if (code == CM_ERROR_BADSMB) {
6995 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7000 #endif /* LOG_PACKET */
7001 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7004 code = CM_ERROR_INVAL;
7007 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7008 thrd_Decrement(&ongoingOps);
7013 /* now, if we failed, turn the current response into an empty
7014 * one, and fill in the response packet's error code.
7017 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7018 smb_MapNTError(code, &NTStatus);
7019 outWctp = outp->wctp;
7020 smbp = (smb_t *) &outp->data;
7021 if (code != CM_ERROR_PARTIALWRITE
7022 && code != CM_ERROR_BUFFERTOOSMALL
7023 && code != CM_ERROR_GSSCONTINUE) {
7024 /* nuke wct and bcc. For a partial
7025 * write or an in-process authentication handshake,
7026 * assume they're OK.
7032 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7033 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7034 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7035 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7036 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7040 smb_MapCoreError(code, vcp, &errCode, &errClass);
7041 outWctp = outp->wctp;
7042 smbp = (smb_t *) &outp->data;
7043 if (code != CM_ERROR_PARTIALWRITE) {
7044 /* nuke wct and bcc. For a partial
7045 * write, assume they're OK.
7051 smbp->errLow = (unsigned char) (errCode & 0xff);
7052 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7053 smbp->rcls = errClass;
7056 } /* error occurred */
7058 /* if we're here, we've finished one request. Look to see if
7059 * this is a chained opcode. If it is, setup things to process
7060 * the chained request, and setup the output buffer to hold the
7061 * chained response. Start by finding the next input record.
7063 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7064 break; /* not a chained req */
7065 tp = inp->wctp; /* points to start of last request */
7066 /* in a chained request, the first two
7067 * parm fields are required, and are
7068 * AndXCommand/AndXReserved and
7070 if (tp[0] < 2) break;
7071 if (tp[1] == 0xff) break; /* no more chained opcodes */
7073 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7076 /* and now append the next output request to the end of this
7077 * last request. Begin by finding out where the last response
7078 * ends, since that's where we'll put our new response.
7080 outWctp = outp->wctp; /* ptr to out parameters */
7081 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7082 nparms = outWctp[0] << 1;
7083 tp = outWctp + nparms + 1; /* now points to bcc field */
7084 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7085 tp += 2 /* for the count itself */ + nbytes;
7086 /* tp now points to the new output record; go back and patch the
7087 * second parameter (off2) to point to the new record.
7089 temp = (unsigned int)(tp - outp->data);
7090 outWctp[3] = (unsigned char) (temp & 0xff);
7091 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7092 outWctp[2] = 0; /* padding */
7093 outWctp[1] = inp->inCom; /* next opcode */
7095 /* finally, setup for the next iteration */
7098 } /* while loop over all requests in the packet */
7100 /* done logging out, turn off logging-out flag */
7101 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
7102 vcp->justLoggedOut = NULL;
7105 free(loggedOutName);
7106 loggedOutName = NULL;
7107 smb_ReleaseUID(loggedOutUserp);
7108 loggedOutUserp = NULL;
7112 /* now send the output packet, and return */
7114 smb_SendPacket(vcp, outp);
7115 thrd_Decrement(&ongoingOps);
7117 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7118 if (active_vcp != vcp) {
7120 smb_ReleaseVC(active_vcp);
7122 "Replacing active_vcp %x with %x", active_vcp, vcp);
7127 last_msg_time = GetCurrentTime();
7128 } else if (active_vcp == vcp) {
7129 smb_ReleaseVC(active_vcp);
7137 /* Wait for Netbios() calls to return, and make the results available to server
7138 * threads. Note that server threads can't wait on the NCBevents array
7139 * themselves, because NCB events are manual-reset, and the servers would race
7140 * each other to reset them.
7142 void smb_ClientWaiter(void *parmp)
7147 while (smbShutdownFlag == 0) {
7148 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7150 if (code == WAIT_OBJECT_0)
7153 /* error checking */
7154 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7156 int abandonIdx = code - WAIT_ABANDONED_0;
7157 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7160 if (code == WAIT_IO_COMPLETION)
7162 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7166 if (code == WAIT_TIMEOUT)
7168 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7171 if (code == WAIT_FAILED)
7173 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7176 idx = code - WAIT_OBJECT_0;
7178 /* check idx range! */
7179 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7181 /* this is fatal - log as much as possible */
7182 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7186 thrd_ResetEvent(NCBevents[idx]);
7187 thrd_SetEvent(NCBreturns[0][idx]);
7193 * Try to have one NCBRECV request waiting for every live session. Not more
7194 * than one, because if there is more than one, it's hard to handle Write Raw.
7196 void smb_ServerWaiter(void *parmp)
7199 int idx_session, idx_NCB;
7205 while (smbShutdownFlag == 0) {
7207 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7209 if (code == WAIT_OBJECT_0)
7212 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7214 int abandonIdx = code - WAIT_ABANDONED_0;
7215 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7218 if (code == WAIT_IO_COMPLETION)
7220 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7224 if (code == WAIT_TIMEOUT)
7226 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7229 if (code == WAIT_FAILED)
7231 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7234 idx_session = code - WAIT_OBJECT_0;
7236 /* check idx range! */
7237 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7239 /* this is fatal - log as much as possible */
7240 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7246 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7248 if (code == WAIT_OBJECT_0) {
7249 if (smbShutdownFlag == 1)
7255 /* error checking */
7256 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7258 int abandonIdx = code - WAIT_ABANDONED_0;
7259 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7262 if (code == WAIT_IO_COMPLETION)
7264 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7268 if (code == WAIT_TIMEOUT)
7270 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7273 if (code == WAIT_FAILED)
7275 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7278 idx_NCB = code - WAIT_OBJECT_0;
7280 /* check idx range! */
7281 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7283 /* this is fatal - log as much as possible */
7284 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7288 /* Link them together */
7289 NCBsessions[idx_NCB] = idx_session;
7292 ncbp = NCBs[idx_NCB];
7293 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7294 ncbp->ncb_command = NCBRECV | ASYNCH;
7295 ncbp->ncb_lana_num = lanas[idx_session];
7297 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7298 ncbp->ncb_event = NCBevents[idx_NCB];
7299 ncbp->ncb_length = SMB_PACKETSIZE;
7302 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
7303 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
7304 ncbp->ncb_event = NCBreturns[0][idx_NCB];
7305 ncbp->ncb_length = SMB_PACKETSIZE;
7306 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7307 Netbios(ncbp, dos_ncb);
7313 * The top level loop for handling SMB request messages. Each server thread
7314 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7315 * NCB and buffer for the incoming request are loaned to us.
7317 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7318 * to immediately send a request for the rest of the data. This must come
7319 * before any other traffic for that session, so we delay setting the session
7320 * event until that data has come in.
7322 void smb_Server(VOID *parmp)
7324 INT_PTR myIdx = (INT_PTR) parmp;
7328 smb_packet_t *outbufp;
7330 int idx_NCB, idx_session;
7332 smb_vc_t *vcp = NULL;
7338 rx_StartClientThread();
7341 outbufp = GetPacket();
7342 outbufp->ncbp = outncbp;
7345 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7348 /* terminate silently if shutdown flag is set */
7349 if (code == WAIT_OBJECT_0) {
7350 if (smbShutdownFlag == 1) {
7351 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7357 /* error checking */
7358 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7360 int abandonIdx = code - WAIT_ABANDONED_0;
7361 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7364 if (code == WAIT_IO_COMPLETION)
7366 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7370 if (code == WAIT_TIMEOUT)
7372 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7375 if (code == WAIT_FAILED)
7377 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7380 idx_NCB = code - WAIT_OBJECT_0;
7382 /* check idx range! */
7383 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7385 /* this is fatal - log as much as possible */
7386 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7390 ncbp = NCBs[idx_NCB];
7392 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7394 idx_session = NCBsessions[idx_NCB];
7395 rc = ncbp->ncb_retcode;
7397 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
7400 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
7403 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
7406 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
7409 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7412 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7415 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7418 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7421 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7424 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7427 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7430 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7433 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7436 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7439 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7442 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7445 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7448 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7451 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7454 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7457 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7460 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7463 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7466 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7469 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7472 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7475 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7478 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7481 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7484 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7487 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7490 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7493 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7496 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7499 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7502 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7505 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7508 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7511 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7521 /* Can this happen? Or is it just my UNIX paranoia? */
7522 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7528 /* Client closed session */
7529 dead_sessions[idx_session] = TRUE;
7532 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7533 /* Should also release vcp. [done] 2004-05-11 jaltman
7535 * sanity check that all TID's are gone.
7537 * TODO: check if we could use LSNs[idx_session] instead,
7538 * also cleanup after dead vcp
7541 if (dead_vcp == vcp)
7542 osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7543 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7544 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7548 smb_ReleaseVC(dead_vcp);
7550 "Previous dead_vcp %x", dead_vcp);
7553 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7556 smb_CleanupDeadVC(vcp);
7558 if (vcp->justLoggedOut) {
7560 loggedOutTime = vcp->logoffTime;
7561 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7562 loggedOutUserp = vcp->justLoggedOut;
7563 lock_ObtainWrite(&smb_rctLock);
7564 loggedOutUserp->refCount++;
7565 lock_ReleaseWrite(&smb_rctLock);
7571 /* Treat as transient error */
7574 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7578 "dispatch smb recv failed, message incomplete, ncb_length %d",
7581 "SMB message incomplete, "
7582 "length %d", ncbp->ncb_length);
7585 * We used to discard the packet.
7586 * Instead, try handling it normally.
7594 /* A weird error code. Log it, sleep, and
7596 if (vcp && vcp->errorCount++ > 3) {
7597 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7598 dead_sessions[idx_session] = TRUE;
7602 thrd_SetEvent(SessionEvents[idx_session]);
7607 /* Success, so now dispatch on all the data in the packet */
7609 smb_concurrentCalls++;
7610 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7611 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7615 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7617 * If at this point vcp is NULL (implies that packet was invalid)
7618 * then we are in big trouble. This means either :
7619 * a) we have the wrong NCB.
7620 * b) Netbios screwed up the call.
7621 * Obviously this implies that
7622 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7623 * lanas[idx_session] != ncbp->ncb_lana_num )
7624 * Either way, we can't do anything with this packet.
7625 * Log, sleep and resume.
7628 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7632 ncbp->ncb_lana_num);
7634 /* Also log in the trace log. */
7635 osi_Log4(smb_logp, "Server: BAD VCP!"
7636 "LSNs[idx_session]=[%d],"
7637 "lanas[idx_session]=[%d],"
7638 "ncbp->ncb_lsn=[%d],"
7639 "ncbp->ncb_lana_num=[%d]",
7643 ncbp->ncb_lana_num);
7645 /* thrd_Sleep(1000); Don't bother sleeping */
7646 thrd_SetEvent(SessionEvents[idx_session]);
7647 smb_concurrentCalls--;
7652 vcp->errorCount = 0;
7653 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7655 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7656 /* copy whole packet to virtual memory */
7657 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7659 bufp->dos_pkt / 16, bufp);*/
7661 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7663 smbp = (smb_t *)bufp->data;
7666 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7670 if (smbp->com == 0x1d) {
7671 /* Special handling for Write Raw */
7672 raw_write_cont_t rwc;
7673 EVENT_HANDLE rwevent;
7674 char eventName[MAX_PATH];
7676 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7677 if (rwc.code == 0) {
7678 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7679 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7680 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7681 ncbp->ncb_command = NCBRECV | ASYNCH;
7682 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7683 ncbp->ncb_lana_num = vcp->lana;
7684 ncbp->ncb_buffer = rwc.buf;
7685 ncbp->ncb_length = 65535;
7686 ncbp->ncb_event = rwevent;
7690 Netbios(ncbp, dos_ncb);
7692 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7693 thrd_CloseHandle(rwevent);
7695 thrd_SetEvent(SessionEvents[idx_session]);
7697 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7699 else if (smbp->com == 0xa0) {
7701 * Serialize the handling for NT Transact
7704 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7705 thrd_SetEvent(SessionEvents[idx_session]);
7707 thrd_SetEvent(SessionEvents[idx_session]);
7708 /* TODO: what else needs to be serialized? */
7709 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7711 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7713 __except( smb_ServerExceptionFilter() ) {
7717 smb_concurrentCalls--;
7720 thrd_SetEvent(NCBavails[idx_NCB]);
7727 * Exception filter for the server threads. If an exception occurs in the
7728 * dispatch routines, which is where exceptions are most common, then do a
7729 * force trace and give control to upstream exception handlers. Useful for
7732 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7733 DWORD smb_ServerExceptionFilter(void) {
7734 /* While this is not the best time to do a trace, if it succeeds, then
7735 * we have a trace (assuming tracing was enabled). Otherwise, this should
7736 * throw a second exception.
7738 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7739 afsd_ForceTrace(TRUE);
7740 buf_ForceTrace(TRUE);
7741 return EXCEPTION_CONTINUE_SEARCH;
7746 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7747 * If the number of server threads is M, and the number of live sessions is
7748 * N, then the number of NCB's in use at any time either waiting for, or
7749 * holding, received messages is M + N, so that is how many NCB's get created.
7751 void InitNCBslot(int idx)
7753 struct smb_packet *bufp;
7754 EVENT_HANDLE retHandle;
7756 char eventName[MAX_PATH];
7758 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7760 NCBs[idx] = GetNCB();
7761 sprintf(eventName,"NCBavails[%d]", idx);
7762 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7763 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7764 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7766 sprintf(eventName,"NCBevents[%d]", idx);
7767 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7768 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7769 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7771 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7772 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7773 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7774 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7775 for (i=0; i<smb_NumServerThreads; i++)
7776 NCBreturns[i][idx] = retHandle;
7778 bufp->spacep = cm_GetSpace();
7782 /* listen for new connections */
7783 void smb_Listener(void *parmp)
7791 char rname[NCBNAMSZ+1];
7792 char cname[MAX_COMPUTERNAME_LENGTH+1];
7793 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7798 INT_PTR lana = (INT_PTR) parmp;
7802 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7805 /* retrieve computer name */
7806 GetComputerName(cname, &cnamelen);
7810 memset(ncbp, 0, sizeof(NCB));
7813 ncbp->ncb_command = NCBLISTEN;
7814 ncbp->ncb_rto = 0; /* No receive timeout */
7815 ncbp->ncb_sto = 0; /* No send timeout */
7817 /* pad out with spaces instead of null termination */
7818 len = (long)strlen(smb_localNamep);
7819 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7820 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7822 strcpy(ncbp->ncb_callname, "*");
7823 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7825 ncbp->ncb_lana_num = (UCHAR)lana;
7828 code = Netbios(ncbp);
7830 code = Netbios(ncbp, dos_ncb);
7839 /* terminate silently if shutdown flag is set */
7840 if (smbShutdownFlag == 1) {
7849 "NCBLISTEN lana=%d failed with code %d",
7850 ncbp->ncb_lana_num, code);
7852 "Client exiting due to network failure. Please restart client.\n");
7856 "Client exiting due to network failure. Please restart client.\n"
7857 "NCBLISTEN lana=%d failed with code %d",
7858 ncbp->ncb_lana_num, code);
7860 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7861 MB_OK|MB_SERVICE_NOTIFICATION);
7862 osi_assert(tbuffer);
7865 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7866 ncbp->ncb_lana_num, code);
7867 fprintf(stderr, "\nClient exiting due to network failure "
7868 "(possibly due to power-saving mode)\n");
7869 fprintf(stderr, "Please restart client.\n");
7870 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7874 /* check for remote conns */
7875 /* first get remote name and insert null terminator */
7876 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7877 for (i=NCBNAMSZ; i>0; i--) {
7878 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7884 /* compare with local name */
7886 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7887 flags |= SMB_VCFLAG_REMOTECONN;
7889 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7891 lock_ObtainMutex(&smb_ListenerLock);
7893 /* New generation */
7896 /* Log session startup */
7898 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7900 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7901 #endif /* NOTSERVICE */
7902 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7903 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7905 if (reportSessionStartups) {
7907 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
7910 fprintf(stderr, "%s: New session %d starting from host %s\n",
7911 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7915 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7916 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7919 /* now ncbp->ncb_lsn is the connection ID */
7920 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7921 vcp->flags |= flags;
7922 strcpy(vcp->rname, rname);
7924 /* Allocate slot in session arrays */
7925 /* Re-use dead session if possible, otherwise add one more */
7926 /* But don't look at session[0], it is reserved */
7927 for (i = 1; i < numSessions; i++) {
7928 if (dead_sessions[i]) {
7929 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7930 dead_sessions[i] = FALSE;
7935 if (i >= Sessionmax - 1 || numNCBs >= NCBmax - 1) {
7936 unsigned long code = CM_ERROR_ALLBUSY;
7937 smb_packet_t * outp = GetPacket();
7938 unsigned char *outWctp;
7943 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7944 unsigned long NTStatus;
7945 smb_MapNTError(code, &NTStatus);
7946 outWctp = outp->wctp;
7947 smbp = (smb_t *) &outp->data;
7951 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7952 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7953 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7954 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7955 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7957 unsigned short errCode;
7958 unsigned char errClass;
7959 smb_MapCoreError(code, vcp, &errCode, &errClass);
7960 outWctp = outp->wctp;
7961 smbp = (smb_t *) &outp->data;
7965 smbp->errLow = (unsigned char) (errCode & 0xff);
7966 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7967 smbp->rcls = errClass;
7969 smb_SendPacket(vcp, outp);
7970 smb_FreePacket(outp);
7972 /* assert that we do not exceed the maximum number of sessions or NCBs.
7973 * we should probably want to wait for a session to be freed in case
7976 osi_assert(i < Sessionmax - 1);
7977 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7979 LSNs[i] = ncbp->ncb_lsn;
7980 lanas[i] = ncbp->ncb_lana_num;
7982 if (i == numSessions) {
7983 /* Add new NCB for new session */
7984 char eventName[MAX_PATH];
7986 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7988 InitNCBslot(numNCBs);
7990 thrd_SetEvent(NCBavails[0]);
7991 thrd_SetEvent(NCBevents[0]);
7992 for (j = 0; j < smb_NumServerThreads; j++)
7993 thrd_SetEvent(NCBreturns[j][0]);
7994 /* Also add new session event */
7995 sprintf(eventName, "SessionEvents[%d]", i);
7996 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7997 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7998 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8000 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8001 thrd_SetEvent(SessionEvents[0]);
8003 thrd_SetEvent(SessionEvents[i]);
8010 lock_ReleaseMutex(&smb_ListenerLock);
8011 } /* dispatch while loop */
8014 /* initialize Netbios */
8015 void smb_NetbiosInit()
8021 int i, lana, code, l;
8023 int delname_tried=0;
8026 OSVERSIONINFO Version;
8028 /* Get the version of Windows */
8029 memset(&Version, 0x00, sizeof(Version));
8030 Version.dwOSVersionInfoSize = sizeof(Version);
8031 GetVersionEx(&Version);
8033 /* setup the NCB system */
8036 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8040 if (smb_LANadapter == -1) {
8041 ncbp->ncb_command = NCBENUM;
8042 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8043 ncbp->ncb_length = sizeof(lana_list);
8044 code = Netbios(ncbp);
8046 afsi_log("Netbios NCBENUM error code %d", code);
8047 osi_panic(s, __FILE__, __LINE__);
8051 lana_list.length = 1;
8052 lana_list.lana[0] = smb_LANadapter;
8055 for (i = 0; i < lana_list.length; i++) {
8056 /* reset the adaptor: in Win32, this is required for every process, and
8057 * acts as an init call, not as a real hardware reset.
8059 ncbp->ncb_command = NCBRESET;
8060 ncbp->ncb_callname[0] = 100;
8061 ncbp->ncb_callname[2] = 100;
8062 ncbp->ncb_lana_num = lana_list.lana[i];
8063 code = Netbios(ncbp);
8065 code = ncbp->ncb_retcode;
8067 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8068 lana_list.lana[i] = 255; /* invalid lana */
8070 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8074 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
8075 we will just fake the LANA list */
8076 if (smb_LANadapter == -1) {
8077 for (i = 0; i < 8; i++)
8078 lana_list.lana[i] = i;
8079 lana_list.length = 8;
8082 lana_list.length = 1;
8083 lana_list.lana[0] = smb_LANadapter;
8087 /* and declare our name so we can receive connections */
8088 memset(ncbp, 0, sizeof(*ncbp));
8089 len=lstrlen(smb_localNamep);
8090 memset(smb_sharename,' ',NCBNAMSZ);
8091 memcpy(smb_sharename,smb_localNamep,len);
8092 afsi_log("lana_list.length %d", lana_list.length);
8094 /* Keep the name so we can unregister it later */
8095 for (l = 0; l < lana_list.length; l++) {
8096 lana = lana_list.lana[l];
8098 ncbp->ncb_command = NCBADDNAME;
8099 ncbp->ncb_lana_num = lana;
8100 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8102 code = Netbios(ncbp);
8104 code = Netbios(ncbp, dos_ncb);
8107 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8108 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8110 char name[NCBNAMSZ+1];
8112 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8113 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8116 if (code == 0) code = ncbp->ncb_retcode;
8118 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8120 /* we only use one LANA with djgpp */
8121 lana_list.lana[0] = lana;
8122 lana_list.length = 1;
8126 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8127 if (code == NRC_BRIDGE) { /* invalid LANA num */
8128 lana_list.lana[l] = 255;
8131 else if (code == NRC_DUPNAME) {
8132 afsi_log("Name already exists; try to delete it");
8133 memset(ncbp, 0, sizeof(*ncbp));
8134 ncbp->ncb_command = NCBDELNAME;
8135 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8136 ncbp->ncb_lana_num = lana;
8138 code = Netbios(ncbp);
8140 code = Netbios(ncbp, dos_ncb);
8143 code = ncbp->ncb_retcode;
8145 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8147 if (code != 0 || delname_tried) {
8148 lana_list.lana[l] = 255;
8150 else if (code == 0) {
8151 if (!delname_tried) {
8159 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8160 lana_list.lana[l] = 255; /* invalid lana */
8161 osi_panic(s, __FILE__, __LINE__);
8165 lana_found = 1; /* at least one worked */
8172 osi_assert(lana_list.length >= 0);
8174 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
8177 /* we're done with the NCB now */
8181 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8198 EVENT_HANDLE retHandle;
8199 char eventName[MAX_PATH];
8202 smb_MBfunc = aMBfunc;
8206 smb_LANadapter = LANadapt;
8208 /* Initialize smb_localZero */
8209 myTime.tm_isdst = -1; /* compute whether on DST or not */
8210 myTime.tm_year = 70;
8216 smb_localZero = mktime(&myTime);
8218 #ifndef USE_NUMERIC_TIME_CONV
8219 /* Initialize kludge-GMT */
8220 smb_CalculateNowTZ();
8221 #endif /* USE_NUMERIC_TIME_CONV */
8222 #ifdef AFS_FREELANCE_CLIENT
8223 /* Make sure the root.afs volume has the correct time */
8224 cm_noteLocalMountPointChange();
8227 /* initialize the remote debugging log */
8230 /* remember the name */
8231 len = (int)strlen(snamep);
8232 smb_localNamep = malloc(len+1);
8233 strcpy(smb_localNamep, snamep);
8234 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8236 /* and the global lock */
8237 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8238 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8240 /* Raw I/O data structures */
8241 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8243 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8245 /* 4 Raw I/O buffers */
8247 smb_RawBufs = calloc(65536,1);
8248 *((char **)smb_RawBufs) = NULL;
8249 for (i=0; i<3; i++) {
8250 char *rawBuf = calloc(65536,1);
8251 *((char **)rawBuf) = smb_RawBufs;
8252 smb_RawBufs = rawBuf;
8255 npar = 65536 >> 4; /* number of paragraphs */
8256 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
8258 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8260 osi_panic("",__FILE__,__LINE__);
8263 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8266 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
8268 _farpokel(_dos_ds, smb_RawBufs, NULL);
8269 for (i=0; i<SMB_RAW_BUFS-1; i++) {
8270 npar = 65536 >> 4; /* number of paragraphs */
8271 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
8273 afsi_log("Cannot allocate %d paragraphs of DOS memory",
8275 osi_panic("",__FILE__,__LINE__);
8278 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
8281 rawBuf = (seg * 16) + 0; /* DOS physical address */
8282 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
8283 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
8284 smb_RawBufs = rawBuf;
8288 /* global free lists */
8289 smb_ncbFreeListp = NULL;
8290 smb_packetFreeListp = NULL;
8294 /* Initialize listener and server structures */
8296 memset(dead_sessions, 0, sizeof(dead_sessions));
8297 sprintf(eventName, "SessionEvents[0]");
8298 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8299 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8300 afsi_log("Event Object Already Exists: %s", eventName);
8302 smb_NumServerThreads = nThreads;
8303 sprintf(eventName, "NCBavails[0]");
8304 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8305 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8306 afsi_log("Event Object Already Exists: %s", eventName);
8307 sprintf(eventName, "NCBevents[0]");
8308 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8309 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8310 afsi_log("Event Object Already Exists: %s", eventName);
8311 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8312 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8313 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8314 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8315 afsi_log("Event Object Already Exists: %s", eventName);
8316 for (i = 0; i < smb_NumServerThreads; i++) {
8317 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
8318 NCBreturns[i][0] = retHandle;
8321 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8322 for (i = 0; i < smb_NumServerThreads; i++) {
8323 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8324 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8325 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8326 afsi_log("Event Object Already Exists: %s", eventName);
8327 InitNCBslot((int)(i+1));
8329 numNCBs = smb_NumServerThreads + 1;
8331 /* Initialize dispatch table */
8332 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8333 /* Prepare the table for unknown operations */
8334 for(i=0; i<= SMB_NOPCODES; i++) {
8335 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8337 /* Fill in the ones we do know */
8338 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8339 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8340 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8341 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8342 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8343 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8344 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8345 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8346 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8347 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8348 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8349 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8350 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8351 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8352 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8353 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8354 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8355 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8356 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8357 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8358 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8359 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8360 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8361 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8362 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8363 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8364 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8365 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8366 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8367 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8368 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8369 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8370 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8371 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8372 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8373 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8374 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8375 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8376 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8377 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8378 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8379 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8380 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8381 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8382 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8383 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8384 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8385 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8386 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8387 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8388 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8389 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8390 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8391 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8392 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8393 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8394 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8395 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8396 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8397 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8398 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8399 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8400 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8401 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8402 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8403 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8404 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8405 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8406 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8407 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8408 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8409 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8411 /* setup tran 2 dispatch table */
8412 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8413 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8414 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8415 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8416 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8417 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8418 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8419 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8420 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8421 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8422 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8423 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8424 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8425 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8426 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8427 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8428 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8430 /* setup the rap dispatch table */
8431 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8432 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8433 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8434 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8435 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8439 /* if we are doing SMB authentication we have register outselves as a logon process */
8440 if (smb_authType != SMB_AUTH_NONE) {
8441 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8442 LSA_STRING afsProcessName;
8443 LSA_OPERATIONAL_MODE dummy; /*junk*/
8445 afsProcessName.Buffer = "OpenAFSClientDaemon";
8446 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8447 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8449 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8451 if (nts == STATUS_SUCCESS) {
8452 LSA_STRING packageName;
8453 /* we are registered. Find out the security package id */
8454 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8455 packageName.Length = (USHORT)strlen(packageName.Buffer);
8456 packageName.MaximumLength = packageName.Length + 1;
8457 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8458 if (nts == STATUS_SUCCESS) {
8460 * This code forces Windows to authenticate against the Logon Cache
8461 * first instead of attempting to authenticate against the Domain
8462 * Controller. When the Windows logon cache is enabled this improves
8463 * performance by removing the network access and works around a bug
8464 * seen at sites which are using a MIT Kerberos principal to login
8465 * to machines joined to a non-root domain in a multi-domain forest.
8467 PVOID pResponse = NULL;
8468 ULONG cbResponse = 0;
8469 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8471 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8472 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8473 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8474 OptionsRequest.DisableOptions = FALSE;
8476 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8479 sizeof(OptionsRequest),
8485 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8487 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8489 OutputDebugString(message);
8492 OutputDebugString("MsV1_0SetProcessOption success");
8493 afsi_log("MsV1_0SetProcessOption success");
8495 /* END - code from Larry */
8497 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8498 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8499 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8501 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8503 /* something went wrong. We report the error and revert back to no authentication
8504 because we can't perform any auth requests without a successful lsa handle
8505 or sec package id. */
8506 afsi_log("Reverting to NO SMB AUTH");
8507 smb_authType = SMB_AUTH_NONE;
8510 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8512 /* something went wrong. We report the error and revert back to no authentication
8513 because we can't perform any auth requests without a successful lsa handle
8514 or sec package id. */
8515 afsi_log("Reverting to NO SMB AUTH");
8516 smb_authType = SMB_AUTH_NONE;
8520 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8521 * time prevents the failure of authentication when logged into Windows with an
8522 * external Kerberos principal mapped to a local account.
8524 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8525 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8526 * then the only option is NTLMSSP anyway; so just fallback.
8531 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8532 if (secBlobLength == 0) {
8533 smb_authType = SMB_AUTH_NTLM;
8534 afsi_log("Reverting to SMB AUTH NTLM");
8543 /* Now get ourselves a domain name. */
8544 /* For now we are using the local computer name as the domain name.
8545 * It is actually the domain for local logins, and we are acting as
8546 * a local SMB server.
8548 bufsize = sizeof(smb_ServerDomainName) - 1;
8549 GetComputerName(smb_ServerDomainName, &bufsize);
8550 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8551 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8554 /* Start listeners, waiters, servers, and daemons */
8556 for (i = 0; i < lana_list.length; i++) {
8557 if (lana_list.lana[i] == 255)
8559 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8560 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8561 osi_assert(phandle != NULL);
8562 thrd_CloseHandle(phandle);
8566 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8567 NULL, 0, &lpid, "smb_ClientWaiter");
8568 osi_assert(phandle != NULL);
8569 thrd_CloseHandle(phandle);
8572 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8573 NULL, 0, &lpid, "smb_ServerWaiter");
8574 osi_assert(phandle != NULL);
8575 thrd_CloseHandle(phandle);
8577 for (i=0; i<smb_NumServerThreads; i++) {
8578 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8579 (void *) i, 0, &lpid, "smb_Server");
8580 osi_assert(phandle != NULL);
8581 thrd_CloseHandle(phandle);
8584 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8585 NULL, 0, &lpid, "smb_Daemon");
8586 osi_assert(phandle != NULL);
8587 thrd_CloseHandle(phandle);
8589 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8590 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8591 osi_assert(phandle != NULL);
8592 thrd_CloseHandle(phandle);
8601 void smb_Shutdown(void)
8611 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8613 /* setup the NCB system */
8616 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8619 /* Block new sessions by setting shutdown flag */
8620 smbShutdownFlag = 1;
8622 /* Hang up all sessions */
8623 memset((char *)ncbp, 0, sizeof(NCB));
8624 for (i = 1; i < numSessions; i++)
8626 if (dead_sessions[i])
8629 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8630 ncbp->ncb_command = NCBHANGUP;
8631 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8632 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8634 code = Netbios(ncbp);
8636 code = Netbios(ncbp, dos_ncb);
8638 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8639 if (code == 0) code = ncbp->ncb_retcode;
8641 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8642 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8646 /* Trigger the shutdown of all SMB threads */
8647 for (i = 0; i < smb_NumServerThreads; i++)
8648 thrd_SetEvent(NCBreturns[i][0]);
8650 thrd_SetEvent(NCBevents[0]);
8651 thrd_SetEvent(SessionEvents[0]);
8652 thrd_SetEvent(NCBavails[0]);
8654 for (i = 0;i < smb_NumServerThreads; i++) {
8655 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8656 if (code == WAIT_OBJECT_0) {
8659 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8660 thrd_SetEvent(NCBreturns[i--][0]);
8664 /* Delete Netbios name */
8665 memset((char *)ncbp, 0, sizeof(NCB));
8666 for (i = 0; i < lana_list.length; i++) {
8667 if (lana_list.lana[i] == 255) continue;
8668 ncbp->ncb_command = NCBDELNAME;
8669 ncbp->ncb_lana_num = lana_list.lana[i];
8670 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8672 code = Netbios(ncbp);
8674 code = Netbios(ncbp, dos_ncb);
8677 code = ncbp->ncb_retcode;
8679 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8680 ncbp->ncb_lana_num, code);
8685 /* Release the reference counts held by the VCs */
8686 lock_ObtainWrite(&smb_rctLock);
8687 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8692 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8694 if (fidp->scp != NULL) {
8697 lock_ObtainMutex(&fidp->mx);
8698 if (fidp->scp != NULL) {
8701 cm_ReleaseSCache(scp);
8703 lock_ReleaseMutex(&fidp->mx);
8707 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8709 smb_ReleaseVCNoLock(tidp->vcp);
8711 cm_user_t *userp = tidp->userp;
8713 lock_ReleaseWrite(&smb_rctLock);
8714 cm_ReleaseUser(userp);
8715 lock_ObtainWrite(&smb_rctLock);
8719 lock_ReleaseWrite(&smb_rctLock);
8722 /* Get the UNC \\<servername>\<sharename> prefix. */
8723 char *smb_GetSharename()
8727 /* Make sure we have been properly initialized. */
8728 if (smb_localNamep == NULL)
8731 /* Allocate space for \\<servername>\<sharename>, plus the
8734 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8735 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8741 void smb_LogPacket(smb_packet_t *packet)
8744 unsigned length, paramlen, datalen, i, j;
8746 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8748 if (!packet) return;
8750 osi_Log0(smb_logp, "*** SMB packet dump ***");
8752 vp = (BYTE *) packet->data;
8754 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8755 length = paramlen + 2 + datalen;
8758 for (i=0;i < length; i+=16)
8760 memset( buf, ' ', 80 );
8765 buf[strlen(buf)] = ' ';
8767 cp = (BYTE*) buf + 7;
8769 for (j=0;j < 16 && (i+j)<length; j++)
8771 *(cp++) = hex[vp[i+j] >> 4];
8772 *(cp++) = hex[vp[i+j] & 0xf];
8782 for (j=0;j < 16 && (i+j)<length;j++)
8784 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8795 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8798 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8800 #endif /* LOG_PACKET */
8803 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8811 lock_ObtainRead(&smb_rctLock);
8813 sprintf(output, "begin dumping smb_vc_t\n");
8814 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8816 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8820 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8821 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8822 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8824 sprintf(output, "begin dumping smb_fid_t\n");
8825 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8827 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8829 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",
8830 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8831 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8832 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8833 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8836 sprintf(output, "done dumping smb_fid_t\n");
8837 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8840 sprintf(output, "done dumping smb_vc_t\n");
8841 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8844 lock_ReleaseRead(&smb_rctLock);