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
12 #include <afs/param.h>
18 #include <sys/timeb.h>
34 #include "lanahelper.h"
36 /* These characters are illegal in Windows filenames */
37 static char *illegalChars = "\\/:*?\"<>|";
38 BOOL isWindows2000 = FALSE;
40 smb_vc_t *dead_vcp = NULL;
41 smb_vc_t *active_vcp = NULL;
43 /* TODO; logout mechanism needs to be thread-safe */
44 char *loggedOutName = NULL;
45 smb_user_t *loggedOutUserp = NULL;
46 unsigned long loggedOutTime;
48 int smbShutdownFlag = 0;
50 int smb_LogoffTokenTransfer;
51 unsigned long smb_LogoffTransferTimeout;
53 DWORD last_msg_time = 0;
57 unsigned int sessionGen = 0;
59 extern void afsi_log(char *pattern, ...);
60 extern HANDLE afsi_file;
62 osi_hyper_t hzero = {0, 0};
63 osi_hyper_t hones = {0xFFFFFFFF, -1};
66 osi_rwlock_t smb_globalLock;
67 osi_rwlock_t smb_rctLock;
68 osi_mutex_t smb_ListenerLock;
71 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
74 long smb_maxObsConcurrentCalls=0;
75 long smb_concurrentCalls=0;
77 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
79 smb_packet_t *smb_packetFreeListp;
80 smb_ncb_t *smb_ncbFreeListp;
82 int smb_NumServerThreads;
84 int numNCBs, numSessions, numVCs;
86 int smb_maxVCPerServer;
87 int smb_maxMpxRequests;
89 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
91 ULONG smb_lsaSecPackage;
92 LSA_STRING smb_lsaLogonOrigin;
94 #define NCBmax MAXIMUM_WAIT_OBJECTS
95 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
96 EVENT_HANDLE **NCBreturns;
97 DWORD NCBsessions[NCBmax];
99 struct smb_packet *bufs[NCBmax];
101 #define Sessionmax MAXIMUM_WAIT_OBJECTS
102 EVENT_HANDLE SessionEvents[Sessionmax];
103 unsigned short LSNs[Sessionmax];
104 int lanas[Sessionmax];
105 BOOL dead_sessions[Sessionmax];
109 osi_mutex_t smb_RawBufLock;
111 #define SMB_RAW_BUFS 4
113 int smb_RawBufSel[SMB_RAW_BUFS];
118 #define SMB_MASKFLAG_TILDE 1
119 #define SMB_MASKFLAG_CASEFOLD 2
121 #define RAWTIMEOUT INFINITE
124 typedef struct raw_write_cont {
137 /* dir search stuff */
138 long smb_dirSearchCounter = 1;
139 smb_dirSearch_t *smb_firstDirSearchp;
140 smb_dirSearch_t *smb_lastDirSearchp;
142 /* hide dot files? */
143 int smb_hideDotFiles;
145 /* global state about V3 protocols */
146 int smb_useV3; /* try to negotiate V3 */
149 static showErrors = 1;
150 /* MessageBox or something like it */
151 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
152 extern HANDLE WaitToTerminate;
156 * Time in Unix format of midnight, 1/1/1970 local time.
157 * When added to dosUTime, gives Unix (AFS) time.
161 /* Time difference for converting to kludge-GMT */
164 char *smb_localNamep = NULL;
166 smb_vc_t *smb_allVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLock_t *smb_allWaitingLocks;
173 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
174 NCB *ncbp, raw_write_cont_t *rwcp);
175 void smb_NetbiosInit();
177 #ifndef AFS_WIN95_ENV
178 DWORD smb_ServerExceptionFilter(void);
181 extern char cm_HostName[];
182 extern char cm_confDir[];
186 #define LPTSTR char *
187 #define GetComputerName(str, sizep) \
188 strcpy((str), cm_HostName); \
189 *(sizep) = strlen(cm_HostName)
192 extern char AFSConfigKeyName[];
194 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
195 int smb_ServerDomainNameLength = 0;
196 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
197 int smb_ServerOSLength = sizeof(smb_ServerOS);
198 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
199 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
201 /* Faux server GUID. This is never checked. */
202 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
207 * To build an expiring version, comment out the definition of NOEXPIRE,
208 * and set the definition of EXPIREDATE to the desired value.
211 #define EXPIREDATE 834000000 /* Wed Jun 5 1996 */
214 char * myCrt_Dispatch(int i)
219 return "unknown SMB op";
221 return "(00)ReceiveCoreMakeDir";
223 return "(01)ReceiveCoreRemoveDir";
225 return "(02)ReceiveCoreOpen";
227 return "(03)ReceiveCoreCreate";
229 return "(04)ReceiveCoreClose";
231 return "(05)ReceiveCoreFlush";
233 return "(06)ReceiveCoreUnlink";
235 return "(07)ReceiveCoreRename";
237 return "(08)ReceiveCoreGetFileAttributes";
239 return "(09)ReceiveCoreSetFileAttributes";
241 return "(0a)ReceiveCoreRead";
243 return "(0b)ReceiveCoreWrite";
245 return "(0c)ReceiveCoreLockRecord";
247 return "(0d)ReceiveCoreUnlockRecord";
249 return "(0e)SendCoreBadOp";
251 return "(0f)ReceiveCoreCreate";
253 return "(10)ReceiveCoreCheckPath";
255 return "(11)SendCoreBadOp";
257 return "(12)ReceiveCoreSeek";
259 return "(1a)ReceiveCoreReadRaw";
261 return "(1d)ReceiveCoreWriteRawDummy";
263 return "(22)ReceiveV3SetAttributes";
265 return "(23)ReceiveV3GetAttributes";
267 return "(24)ReceiveV3LockingX";
269 return "(25)ReceiveV3Trans";
271 return "(26)ReceiveV3Trans[aux]";
273 return "(29)SendCoreBadOp";
275 return "(2b)ReceiveCoreEcho";
277 return "(2d)ReceiveV3OpenX";
279 return "(2e)ReceiveV3ReadX";
281 return "(32)ReceiveV3Tran2A";
283 return "(33)ReceiveV3Tran2A[aux]";
285 return "(34)ReceiveV3FindClose";
287 return "(35)ReceiveV3FindNotifyClose";
289 return "(70)ReceiveCoreTreeConnect";
291 return "(71)ReceiveCoreTreeDisconnect";
293 return "(72)ReceiveNegotiate";
295 return "(73)ReceiveV3SessionSetupX";
297 return "(74)ReceiveV3UserLogoffX";
299 return "(75)ReceiveV3TreeConnectX";
301 return "(80)ReceiveCoreGetDiskAttributes";
303 return "(81)ReceiveCoreSearchDir";
305 return "(A0)ReceiveNTTransact";
307 return "(A2)ReceiveNTCreateX";
309 return "(A4)ReceiveNTCancel";
311 return "(c0)SendCoreBadOp";
313 return "(c1)SendCoreBadOp";
315 return "(c2)SendCoreBadOp";
317 return "(c3)SendCoreBadOp";
321 char * myCrt_2Dispatch(int i)
326 return "unknown SMB op-2";
328 return "S(00)CreateFile";
330 return "S(01)FindFirst";
332 return "S(02)FindNext"; /* FindNext */
334 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
338 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
340 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
342 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
344 return "S(08)??_ReceiveTran2SetFileInfo";
346 return "S(09)??_ReceiveTran2FSCTL";
348 return "S(0a)_ReceiveTran2IOCTL";
350 return "S(0b)_ReceiveTran2FindNotifyFirst";
352 return "S(0c)_ReceiveTran2FindNotifyNext";
354 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
358 char * myCrt_RapDispatch(int i)
363 return "unknown RAP OP";
365 return "RAP(0)NetShareEnum";
367 return "RAP(1)NetShareGetInfo";
369 return "RAP(13)NetServerGetInfo";
371 return "RAP(63)NetWkStaGetInfo";
375 /* scache must be locked */
376 unsigned int smb_Attributes(cm_scache_t *scp)
380 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
381 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
382 attrs = SMB_ATTR_DIRECTORY;
387 * We used to mark a file RO if it was in an RO volume, but that
388 * turns out to be impolitic in NT. See defect 10007.
391 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
393 if ((scp->unixModeBits & 0222) == 0)
394 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
399 /* Check if the named file/dir is a dotfile/dotdir */
400 /* String pointed to by lastComp can have leading slashes, but otherwise should have
401 no other patch components */
402 unsigned int smb_IsDotFile(char *lastComp) {
405 /* skip over slashes */
406 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
411 /* nulls, curdir and parent dir doesn't count */
414 if(!*(s + 1)) return 0;
415 if(*(s+1) == '.' && !*(s + 2)) return 0;
421 static int ExtractBits(WORD bits, short start, short len)
428 num = bits << (16 - end);
429 num = num >> ((16 - end) + start);
435 void ShowUnixTime(char *FuncName, long unixTime)
440 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
442 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
443 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
445 int day, month, year, sec, min, hour;
448 day = ExtractBits(wDate, 0, 5);
449 month = ExtractBits(wDate, 5, 4);
450 year = ExtractBits(wDate, 9, 7) + 1980;
452 sec = ExtractBits(wTime, 0, 5);
453 min = ExtractBits(wTime, 5, 6);
454 hour = ExtractBits(wTime, 11, 5);
456 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
457 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
463 /* Determine if we are observing daylight savings time */
464 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
466 TIME_ZONE_INFORMATION timeZoneInformation;
467 SYSTEMTIME utc, local, localDST;
469 /* Get the time zone info. NT uses this to calc if we are in DST. */
470 GetTimeZoneInformation(&timeZoneInformation);
472 /* Return the daylight bias */
473 *pDstBias = timeZoneInformation.DaylightBias;
475 /* Return the bias */
476 *pBias = timeZoneInformation.Bias;
478 /* Now determine if DST is being observed */
480 /* Get the UTC (GMT) time */
483 /* Convert UTC time to local time using the time zone info. If we are
484 observing DST, the calculated local time will include this.
486 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
488 /* Set the daylight bias to 0. The daylight bias is the amount of change
489 in time that we use for daylight savings time. By setting this to 0
490 we cause there to be no change in time during daylight savings time.
492 timeZoneInformation.DaylightBias = 0;
494 /* Convert the utc time to local time again, but this time without any
495 adjustment for daylight savings time.
497 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
499 /* If the two times are different, then it means that the localDST that
500 we calculated includes the daylight bias, and therefore we are
501 observing daylight savings time.
503 *pDST = localDST.wHour != local.wHour;
506 /* Determine if we are observing daylight savings time */
507 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
513 *pDstBias = -60; /* where can this be different? */
519 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
521 BOOL dst; /* Will be TRUE if observing DST */
522 LONG dstBias; /* Offset from local time if observing DST */
523 LONG bias; /* Offset from GMT for local time */
526 * This function will adjust the last write time to compensate
527 * for two bugs in the smb client:
529 * 1) During Daylight Savings Time, the LastWriteTime is ahead
530 * in time by the DaylightBias (ignoring the sign - the
531 * DaylightBias is always stored as a negative number). If
532 * the DaylightBias is -60, then the LastWriteTime will be
533 * ahead by 60 minutes.
535 * 2) If the local time zone is a positive offset from GMT, then
536 * the LastWriteTime will be the correct local time plus the
537 * Bias (ignoring the sign - a positive offset from GMT is
538 * always stored as a negative Bias). If the Bias is -120,
539 * then the LastWriteTime will be ahead by 120 minutes.
541 * These bugs can occur at the same time.
544 GetTimeZoneInfo(&dst, &dstBias, &bias);
546 /* First adjust for DST */
548 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
550 /* Now adjust for a positive offset from GMT (a negative bias). */
552 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
556 * Calculate the difference (in seconds) between local time and GMT.
557 * This enables us to convert file times to kludge-GMT.
563 struct tm gmt_tm, local_tm;
564 int days, hours, minutes, seconds;
567 gmt_tm = *(gmtime(&t));
568 local_tm = *(localtime(&t));
570 days = local_tm.tm_yday - gmt_tm.tm_yday;
571 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
573 /* There is a problem with DST immediately after the time change
574 * which may continue to exist until the machine is rebooted
576 - (local_tm.tm_isdst ? 1 : 0)
579 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
580 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
586 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
591 long ersatz_unixTime;
594 * Must use kludge-GMT instead of real GMT.
595 * kludge-GMT is computed by adding time zone difference to localtime.
598 * ltp = gmtime(&unixTime);
600 ersatz_unixTime = unixTime - smb_NowTZ;
601 ltp = localtime(&ersatz_unixTime);
603 /* if we fail, make up something */
606 localJunk.tm_year = 89 - 20;
607 localJunk.tm_mon = 4;
608 localJunk.tm_mday = 12;
609 localJunk.tm_hour = 0;
610 localJunk.tm_min = 0;
611 localJunk.tm_sec = 0;
614 stm.wYear = ltp->tm_year + 1900;
615 stm.wMonth = ltp->tm_mon + 1;
616 stm.wDayOfWeek = ltp->tm_wday;
617 stm.wDay = ltp->tm_mday;
618 stm.wHour = ltp->tm_hour;
619 stm.wMinute = ltp->tm_min;
620 stm.wSecond = ltp->tm_sec;
621 stm.wMilliseconds = 0;
623 SystemTimeToFileTime(&stm, largeTimep);
626 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
628 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
629 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
630 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
632 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
634 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
635 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
637 *ft = LargeIntegerMultiplyByLong(*ft, 60);
638 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
641 ut = ConvertLongToLargeInteger(unixTime);
642 ut = LargeIntegerMultiplyByLong(ut, 10000000);
643 *ft = LargeIntegerAdd(*ft, ut);
648 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
654 FileTimeToSystemTime(largeTimep, &stm);
656 lt.tm_year = stm.wYear - 1900;
657 lt.tm_mon = stm.wMonth - 1;
658 lt.tm_wday = stm.wDayOfWeek;
659 lt.tm_mday = stm.wDay;
660 lt.tm_hour = stm.wHour;
661 lt.tm_min = stm.wMinute;
662 lt.tm_sec = stm.wSecond;
665 save_timezone = _timezone;
666 _timezone += smb_NowTZ;
667 *unixTimep = mktime(<);
668 _timezone = save_timezone;
671 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
673 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
674 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
675 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
679 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
680 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
681 a = LargeIntegerMultiplyByLong(a, 60);
682 a = LargeIntegerMultiplyByLong(a, 10000000);
684 /* subtract it from ft */
685 a = LargeIntegerSubtract(*ft, a);
687 /* divide down to seconds */
688 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
692 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
699 ltp = localtime((time_t*) &unixTime);
701 /* if we fail, make up something */
704 localJunk.tm_year = 89 - 20;
705 localJunk.tm_mon = 4;
706 localJunk.tm_mday = 12;
707 localJunk.tm_hour = 0;
708 localJunk.tm_min = 0;
709 localJunk.tm_sec = 0;
712 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
713 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
714 *dosTimep = (dosDate<<16) | dosTime;
717 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
719 unsigned short dosDate;
720 unsigned short dosTime;
723 dosDate = searchTime & 0xffff;
724 dosTime = (searchTime >> 16) & 0xffff;
726 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
727 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
728 localTm.tm_mday = (dosDate) & 0x1f;
729 localTm.tm_hour = (dosTime>>11) & 0x1f;
730 localTm.tm_min = (dosTime >> 5) & 0x3f;
731 localTm.tm_sec = (dosTime & 0x1f) * 2;
732 localTm.tm_isdst = -1; /* compute whether DST in effect */
734 *unixTimep = mktime(&localTm);
737 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
739 *dosUTimep = unixTime - smb_localZero;
742 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
745 *unixTimep = dosTime + smb_localZero;
747 /* dosTime seems to be already adjusted for GMT */
748 *unixTimep = dosTime;
752 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
756 lock_ObtainWrite(&smb_rctLock);
757 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
758 if (lsn == vcp->lsn && lana == vcp->lana) {
763 if (!vcp && (flags & SMB_FLAG_CREATE)) {
764 vcp = malloc(sizeof(*vcp));
765 memset(vcp, 0, sizeof(*vcp));
766 vcp->vcID = numVCs++;
770 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
771 vcp->nextp = smb_allVCsp;
773 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
778 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
779 /* We must obtain a challenge for extended auth
780 * in case the client negotiates smb v3
783 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
784 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
787 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
789 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
796 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
798 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
799 LsaFreeReturnBuffer(lsaResp);
802 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
804 lock_ReleaseWrite(&smb_rctLock);
808 int smb_IsStarMask(char *maskp)
813 for(i=0; i<11; i++) {
815 if (tc == '?' || tc == '*' || tc == '>') return 1;
820 void smb_ReleaseVC(smb_vc_t *vcp)
822 lock_ObtainWrite(&smb_rctLock);
823 osi_assert(vcp->refCount-- > 0);
824 lock_ReleaseWrite(&smb_rctLock);
827 void smb_HoldVC(smb_vc_t *vcp)
829 lock_ObtainWrite(&smb_rctLock);
831 lock_ReleaseWrite(&smb_rctLock);
834 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
838 lock_ObtainWrite(&smb_rctLock);
839 for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
840 if (tid == tidp->tid) {
845 if (!tidp && (flags & SMB_FLAG_CREATE)) {
846 tidp = malloc(sizeof(*tidp));
847 memset(tidp, 0, sizeof(*tidp));
848 tidp->nextp = vcp->tidsp;
853 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
856 lock_ReleaseWrite(&smb_rctLock);
860 void smb_ReleaseTID(smb_tid_t *tidp)
869 lock_ObtainWrite(&smb_rctLock);
870 osi_assert(tidp->refCount-- > 0);
871 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
872 ltpp = &tidp->vcp->tidsp;
873 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
874 if (tp == tidp) break;
876 osi_assert(tp != NULL);
878 lock_FinalizeMutex(&tidp->mx);
879 userp = tidp->userp; /* remember to drop ref later */
882 lock_ReleaseWrite(&smb_rctLock);
884 cm_ReleaseUser(userp);
891 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
893 smb_user_t *uidp = NULL;
895 lock_ObtainWrite(&smb_rctLock);
896 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
897 if (uid == uidp->userID) {
899 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp) ? uidp->unp->name : "");
903 if (!uidp && (flags & SMB_FLAG_CREATE)) {
904 uidp = malloc(sizeof(*uidp));
905 memset(uidp, 0, sizeof(*uidp));
906 uidp->nextp = vcp->usersp;
911 lock_InitializeMutex(&uidp->mx, "user_t mutex");
913 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[%x] new-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
915 lock_ReleaseWrite(&smb_rctLock);
919 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
921 smb_username_t *unp= NULL;
923 lock_ObtainWrite(&smb_rctLock);
924 for(unp = usernamesp; unp; unp = unp->nextp) {
925 if (stricmp(unp->name, usern) == 0 &&
926 stricmp(unp->machine, machine) == 0) {
931 if (!unp && (flags & SMB_FLAG_CREATE)) {
932 unp = malloc(sizeof(*unp));
933 memset(unp, 0, sizeof(*unp));
935 unp->nextp = usernamesp;
936 unp->name = strdup(usern);
937 unp->machine = strdup(machine);
939 lock_InitializeMutex(&unp->mx, "username_t mutex");
941 lock_ReleaseWrite(&smb_rctLock);
945 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
947 smb_user_t *uidp= NULL;
949 lock_ObtainWrite(&smb_rctLock);
950 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
953 if (stricmp(uidp->unp->name, usern) == 0) {
955 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
960 lock_ReleaseWrite(&smb_rctLock);
963 void smb_ReleaseUID(smb_user_t *uidp)
972 lock_ObtainWrite(&smb_rctLock);
973 osi_assert(uidp->refCount-- > 0);
974 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
975 lupp = &uidp->vcp->usersp;
976 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
977 if (up == uidp) break;
979 osi_assert(up != NULL);
981 lock_FinalizeMutex(&uidp->mx);
983 userp = uidp->unp->userp; /* remember to drop ref later */
984 uidp->unp->userp = NULL;
989 lock_ReleaseWrite(&smb_rctLock);
991 cm_ReleaseUserVCRef(userp);
992 cm_ReleaseUser(userp);
999 /* retrieve a held reference to a user structure corresponding to an incoming
1001 * corresponding release function is cm_ReleaseUser.
1003 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1009 smbp = (smb_t *) inp;
1010 uidp = smb_FindUID(vcp, smbp->uid, 0);
1011 if ((!uidp) || (!uidp->unp))
1014 lock_ObtainMutex(&uidp->mx);
1015 up = uidp->unp->userp;
1017 lock_ReleaseMutex(&uidp->mx);
1019 smb_ReleaseUID(uidp);
1025 * Return a pointer to a pathname extracted from a TID structure. The
1026 * TID structure is not held; assume it won't go away.
1028 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1033 tidp = smb_FindTID(vcp, tid, 0);
1037 if(tidp->flags & SMB_TIDFLAG_IPC) {
1038 code = CM_ERROR_TIDIPC;
1039 /* tidp->pathname would be NULL, but that's fine */
1041 *treepath = tidp->pathname;
1042 smb_ReleaseTID(tidp);
1047 /* check to see if we have a chained fid, that is, a fid that comes from an
1048 * OpenAndX message that ran earlier in this packet. In this case, the fid
1049 * field in a read, for example, request, isn't set, since the value is
1050 * supposed to be inherited from the openAndX call.
1052 int smb_ChainFID(int fid, smb_packet_t *inp)
1054 if (inp->fid == 0 || inp->inCount == 0)
1060 /* are we a priv'd user? What does this mean on NT? */
1061 int smb_SUser(cm_user_t *userp)
1066 /* find a file ID. If we pass in 0 we select an used File ID.
1067 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1068 * smb_fid_t data structure if desired File ID cannot be found.
1070 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1075 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1078 lock_ObtainWrite(&smb_rctLock);
1079 /* figure out if we need to allocate a new file ID */
1082 fid = vcp->fidCounter;
1086 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1087 if (fid == fidp->fid) {
1098 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1099 char eventName[MAX_PATH];
1101 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1102 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1103 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1104 afsi_log("Event Object Already Exists: %s", eventName);
1105 thrd_CloseHandle(event);
1112 fidp = malloc(sizeof(*fidp));
1113 memset(fidp, 0, sizeof(*fidp));
1114 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1118 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1120 fidp->curr_chunk = fidp->prev_chunk = -2;
1121 fidp->raw_write_event = event;
1123 vcp->fidCounter = fid+1;
1124 if (vcp->fidCounter == 0)
1125 vcp->fidCounter = 1;
1128 lock_ReleaseWrite(&smb_rctLock);
1132 void smb_ReleaseFID(smb_fid_t *fidp)
1135 smb_vc_t *vcp = NULL;
1136 smb_ioctl_t *ioctlp;
1142 lock_ObtainWrite(&smb_rctLock);
1143 osi_assert(fidp->refCount-- > 0);
1144 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1146 if (!(fidp->flags & SMB_FID_IOCTL))
1148 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1149 thrd_CloseHandle(fidp->raw_write_event);
1151 /* and see if there is ioctl stuff to free */
1152 ioctlp = fidp->ioctlp;
1154 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1155 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1156 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1162 /* do not call smb_ReleaseVC() because we already have the lock */
1165 lock_ReleaseWrite(&smb_rctLock);
1167 /* now release the scache structure */
1169 cm_ReleaseSCache(scp);
1173 * Case-insensitive search for one string in another;
1174 * used to find variable names in submount pathnames.
1176 static char *smb_stristr(char *str1, char *str2)
1180 for (cursor = str1; *cursor; cursor++)
1181 if (stricmp(cursor, str2) == 0)
1188 * Substitute a variable value for its name in a submount pathname. Variable
1189 * name has been identified by smb_stristr() and is in substr. Variable name
1190 * length (plus one) is in substr_size. Variable value is in newstr.
1192 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1197 strcpy(temp, substr + substr_size - 1);
1198 strcpy(substr, newstr);
1202 char VNUserName[] = "%USERNAME%";
1203 char VNLCUserName[] = "%LCUSERNAME%";
1204 char VNComputerName[] = "%COMPUTERNAME%";
1205 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1208 /* List available shares */
1209 int smb_ListShares()
1213 char shareBuf[4096];
1221 /*strcpy(shareNameList[num_shares], "all");
1222 strcpy(pathNameList[num_shares++], "/afs");*/
1223 fprintf(stderr, "The following shares are available:\n");
1224 fprintf(stderr, "Share Name (AFS Path)\n");
1225 fprintf(stderr, "---------------------\n");
1226 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1229 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1230 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1232 strcpy(sbmtpath, cm_confDir);
1234 strcat(sbmtpath, "/afsdsbmt.ini");
1235 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1236 shareBuf, sizeof(shareBuf),
1242 this_share = shareBuf;
1246 /*strcpy(shareNameList[num_shares], this_share);*/
1247 len = GetPrivateProfileString("AFS Submounts", this_share,
1254 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1257 if (*p == '\\') *p = '/'; /* change to / */
1261 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1262 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1265 while (*this_share != 0) this_share++; /* find next NUL */
1266 this_share++; /* skip past the NUL */
1267 } while (*this_share != 0); /* stop at final NUL */
1273 typedef struct smb_findShare_rock {
1277 } smb_findShare_rock_t;
1279 #define SMB_FINDSHARE_EXACT_MATCH 1
1280 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1282 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1286 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1287 if(!strnicmp(dep->name, vrock->shareName, 12)) {
1288 if(!stricmp(dep->name, vrock->shareName))
1289 matchType = SMB_FINDSHARE_EXACT_MATCH;
1291 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1292 if(vrock->match) free(vrock->match);
1293 vrock->match = strdup(dep->name);
1294 vrock->matchType = matchType;
1296 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1297 return CM_ERROR_STOPNOW;
1303 /* find a shareName in the table of submounts */
1304 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1308 char pathName[1024];
1313 char sbmtpath[MAX_PATH];
1318 DWORD allSubmount = 1;
1320 /* if allSubmounts == 0, only return the //mountRoot/all share
1321 * if in fact it has been been created in the subMounts table.
1322 * This is to allow sites that want to restrict access to the
1325 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1326 0, KEY_QUERY_VALUE, &parmKey);
1327 if (code == ERROR_SUCCESS) {
1328 len = sizeof(allSubmount);
1329 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1330 (BYTE *) &allSubmount, &len);
1331 if (code != ERROR_SUCCESS) {
1334 RegCloseKey (parmKey);
1337 if (allSubmount && _stricmp(shareName, "all") == 0) {
1342 /* In case, the all share is disabled we need to still be able
1343 * to handle ioctl requests
1345 if (_stricmp(shareName, "ioctl$") == 0) {
1346 *pathNamep = strdup("/.__ioctl__");
1350 if (_stricmp(shareName, "IPC$") == 0 ||
1351 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1352 _stricmp(shareName, "DESKTOP.INI") == 0
1359 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1360 0, KEY_QUERY_VALUE, &parmKey);
1361 if (code == ERROR_SUCCESS) {
1362 len = sizeof(pathName);
1363 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1364 (BYTE *) pathName, &len);
1365 if (code != ERROR_SUCCESS)
1367 RegCloseKey (parmKey);
1372 strcpy(sbmtpath, cm_confDir);
1373 strcat(sbmtpath, "/afsdsbmt.ini");
1374 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1375 pathName, sizeof(pathName), sbmtpath);
1377 if (len != 0 && len != sizeof(pathName) - 1) {
1378 /* We can accept either unix or PC style AFS pathnames. Convert
1379 * Unix-style to PC style here for internal use.
1382 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1383 p += strlen(cm_mountRoot); /* skip mount path */
1386 if (*q == '/') *q = '\\'; /* change to \ */
1392 if (var = smb_stristr(p, VNUserName)) {
1393 if (uidp && uidp->unp)
1394 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1396 smb_subst(p, var, sizeof(VNUserName)," ");
1398 else if (var = smb_stristr(p, VNLCUserName))
1400 if (uidp && uidp->unp)
1401 strcpy(temp, uidp->unp->name);
1405 smb_subst(p, var, sizeof(VNLCUserName), temp);
1407 else if (var = smb_stristr(p, VNComputerName))
1409 sizeTemp = sizeof(temp);
1410 GetComputerName((LPTSTR)temp, &sizeTemp);
1411 smb_subst(p, var, sizeof(VNComputerName), temp);
1413 else if (var = smb_stristr(p, VNLCComputerName))
1415 sizeTemp = sizeof(temp);
1416 GetComputerName((LPTSTR)temp, &sizeTemp);
1418 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1423 *pathNamep = strdup(p);
1428 /* First lookup shareName in root.afs */
1430 smb_findShare_rock_t vrock;
1432 char * p = shareName;
1435 /* attempt to locate a partial match in root.afs. This is because
1436 when using the ANSI RAP calls, the share name is limited to 13 chars
1437 and hence is truncated. Of course we prefer exact matches. */
1439 thyper.HighPart = 0;
1442 vrock.shareName = shareName;
1444 vrock.matchType = 0;
1446 cm_HoldSCache(cm_rootSCachep);
1447 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1448 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1449 cm_ReleaseSCache(cm_rootSCachep);
1451 if(vrock.matchType) {
1452 sprintf(pathName,"/%s/",vrock.match);
1453 *pathNamep = strdup(strlwr(pathName));
1458 /* if we get here, there was no match for the share in root.afs */
1459 /* so try to create \\<netbiosName>\<cellname> */
1464 /* Get the full name for this cell */
1465 code = cm_SearchCellFile(p, temp, 0, 0);
1466 #ifdef AFS_AFSDB_ENV
1467 if (code && cm_dnsEnabled) {
1469 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1472 /* construct the path */
1474 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1475 *pathNamep = strdup(strlwr(pathName));
1484 /* Client-side offline caching policy types */
1485 #define CSC_POLICY_MANUAL 0
1486 #define CSC_POLICY_DOCUMENTS 1
1487 #define CSC_POLICY_PROGRAMS 2
1488 #define CSC_POLICY_DISABLE 3
1490 int smb_FindShareCSCPolicy(char *shareName)
1496 int retval = CSC_POLICY_MANUAL;
1498 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1499 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1502 REG_OPTION_NON_VOLATILE,
1508 len = sizeof(policy);
1509 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1511 retval = CSC_POLICY_MANUAL;
1513 else if (stricmp(policy, "documents") == 0)
1515 retval = CSC_POLICY_DOCUMENTS;
1517 else if (stricmp(policy, "programs") == 0)
1519 retval = CSC_POLICY_PROGRAMS;
1521 else if (stricmp(policy, "disable") == 0)
1523 retval = CSC_POLICY_DISABLE;
1526 RegCloseKey(hkCSCPolicy);
1530 /* find a dir search structure by cookie value, and return it held.
1531 * Must be called with smb_globalLock held.
1533 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1535 smb_dirSearch_t *dsp;
1537 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1538 if (dsp->cookie == cookie) {
1539 if (dsp != smb_firstDirSearchp) {
1540 /* move to head of LRU queue, too, if we're not already there */
1541 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1542 smb_lastDirSearchp = (smb_dirSearch_t *)
1544 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1545 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1546 if (!smb_lastDirSearchp)
1547 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1556 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1558 lock_ObtainWrite(&smb_globalLock);
1559 dsp->flags |= SMB_DIRSEARCH_DELETE;
1560 lock_ReleaseWrite(&smb_globalLock);
1561 lock_ObtainMutex(&dsp->mx);
1562 if(dsp->scp != NULL) {
1563 lock_ObtainMutex(&dsp->scp->mx);
1564 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1565 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1566 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1567 dsp->scp->bulkStatProgress = hones;
1569 lock_ReleaseMutex(&dsp->scp->mx);
1571 lock_ReleaseMutex(&dsp->mx);
1574 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1580 lock_ObtainWrite(&smb_globalLock);
1581 osi_assert(dsp->refCount-- > 0);
1582 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1583 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1584 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1585 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1586 lock_FinalizeMutex(&dsp->mx);
1590 lock_ReleaseWrite(&smb_globalLock);
1592 /* do this now to avoid spurious locking hierarchy creation */
1593 if (scp) cm_ReleaseSCache(scp);
1596 /* find a dir search structure by cookie value, and return it held */
1597 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1599 smb_dirSearch_t *dsp;
1601 lock_ObtainWrite(&smb_globalLock);
1602 dsp = smb_FindDirSearchNL(cookie);
1603 lock_ReleaseWrite(&smb_globalLock);
1607 /* GC some dir search entries, in the address space expected by the specific protocol.
1608 * Must be called with smb_globalLock held; release the lock temporarily.
1610 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1611 void smb_GCDirSearches(int isV3)
1613 smb_dirSearch_t *prevp;
1614 smb_dirSearch_t *tp;
1615 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1619 victimCount = 0; /* how many have we got so far */
1620 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1621 /* we'll move tp from queue, so
1624 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1625 /* if no one is using this guy, and we're either in the new protocol,
1626 * or we're in the old one and this is a small enough ID to be useful
1627 * to the old protocol, GC this guy.
1629 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1630 /* hold and delete */
1631 tp->flags |= SMB_DIRSEARCH_DELETE;
1632 victimsp[victimCount++] = tp;
1636 /* don't do more than this */
1637 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1640 /* now release them */
1641 lock_ReleaseWrite(&smb_globalLock);
1642 for(i = 0; i < victimCount; i++) {
1643 smb_ReleaseDirSearch(victimsp[i]);
1645 lock_ObtainWrite(&smb_globalLock);
1648 /* function for allocating a dir search entry. We need these to remember enough context
1649 * since we don't get passed the path from call to call during a directory search.
1651 * Returns a held dir search structure, and bumps the reference count on the vnode,
1652 * since it saves a pointer to the vnode.
1654 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1656 smb_dirSearch_t *dsp;
1660 lock_ObtainWrite(&smb_globalLock);
1663 /* what's the biggest ID allowed in this version of the protocol */
1664 if (isV3) maxAllowed = 65535;
1665 else maxAllowed = 255;
1668 /* twice so we have enough tries to find guys we GC after one pass;
1669 * 10 extra is just in case I mis-counted.
1671 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1672 __FILE__, __LINE__);
1673 if (smb_dirSearchCounter > maxAllowed) {
1674 smb_dirSearchCounter = 1;
1675 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1677 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1679 /* don't need to watch for refcount zero and deleted, since
1680 * we haven't dropped the global lock.
1683 ++smb_dirSearchCounter;
1687 dsp = malloc(sizeof(*dsp));
1688 memset(dsp, 0, sizeof(*dsp));
1689 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1690 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1691 dsp->cookie = smb_dirSearchCounter;
1692 ++smb_dirSearchCounter;
1694 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1695 dsp->lastTime = osi_Time();
1698 lock_ReleaseWrite(&smb_globalLock);
1702 static smb_packet_t *GetPacket(void)
1706 unsigned int npar, seg, tb_sel;
1709 lock_ObtainWrite(&smb_globalLock);
1710 tbp = smb_packetFreeListp;
1712 smb_packetFreeListp = tbp->nextp;
1713 lock_ReleaseWrite(&smb_globalLock);
1716 tbp = calloc(65540,1);
1718 tbp = malloc(sizeof(smb_packet_t));
1720 tbp->magic = SMB_PACKETMAGIC;
1723 tbp->resumeCode = 0;
1729 tbp->ncb_length = 0;
1734 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1737 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1739 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1741 osi_panic("",__FILE__,__LINE__);
1744 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1749 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1750 tbp->dos_pkt_sel = tb_sel;
1753 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1758 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1762 memcpy(tbp, pkt, sizeof(smb_packet_t));
1763 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1767 static NCB *GetNCB(void)
1772 unsigned int npar, seg, tb_sel;
1775 lock_ObtainWrite(&smb_globalLock);
1776 tbp = smb_ncbFreeListp;
1778 smb_ncbFreeListp = tbp->nextp;
1779 lock_ReleaseWrite(&smb_globalLock);
1782 tbp = calloc(sizeof(*tbp),1);
1784 tbp = malloc(sizeof(*tbp));
1785 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1788 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1790 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1792 osi_panic("",__FILE__,__LINE__);
1794 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1799 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1800 tbp->dos_ncb_sel = tb_sel;
1802 tbp->magic = SMB_NCBMAGIC;
1805 osi_assert(tbp->magic == SMB_NCBMAGIC);
1807 memset(&tbp->ncb, 0, sizeof(NCB));
1810 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1815 void smb_FreePacket(smb_packet_t *tbp)
1817 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1819 lock_ObtainWrite(&smb_globalLock);
1820 tbp->nextp = smb_packetFreeListp;
1821 smb_packetFreeListp = tbp;
1822 tbp->magic = SMB_PACKETMAGIC;
1825 tbp->resumeCode = 0;
1831 tbp->ncb_length = 0;
1833 lock_ReleaseWrite(&smb_globalLock);
1836 static void FreeNCB(NCB *bufferp)
1840 tbp = (smb_ncb_t *) bufferp;
1841 osi_assert(tbp->magic == SMB_NCBMAGIC);
1843 lock_ObtainWrite(&smb_globalLock);
1844 tbp->nextp = smb_ncbFreeListp;
1845 smb_ncbFreeListp = tbp;
1846 lock_ReleaseWrite(&smb_globalLock);
1849 /* get a ptr to the data part of a packet, and its count */
1850 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1854 unsigned char *afterParmsp;
1856 parmBytes = *smbp->wctp << 1;
1857 afterParmsp = smbp->wctp + parmBytes + 1;
1859 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1860 if (nbytesp) *nbytesp = dataBytes;
1862 /* don't forget to skip the data byte count, since it follows
1863 * the parameters; that's where the "2" comes from below.
1865 return (unsigned char *) (afterParmsp + 2);
1868 /* must set all the returned parameters before playing around with the
1869 * data region, since the data region is located past the end of the
1870 * variable number of parameters.
1872 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1874 unsigned char *afterParmsp;
1876 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1878 *afterParmsp++ = dsize & 0xff;
1879 *afterParmsp = (dsize>>8) & 0xff;
1882 /* return the parm'th parameter in the smbp packet */
1883 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1886 unsigned char *parmDatap;
1888 parmCount = *smbp->wctp;
1890 if (parm >= parmCount) {
1895 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1896 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1897 parm, parmCount, smbp->ncb_length);
1899 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1900 1, smbp->ncb_length, ptbuf, smbp);
1901 DeregisterEventSource(h);
1905 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1906 parm, parmCount, smbp->ncb_length);
1907 osi_Log0(smb_logp, s);
1909 osi_panic(s, __FILE__, __LINE__);
1911 parmDatap = smbp->wctp + (2*parm) + 1;
1913 return parmDatap[0] + (parmDatap[1] << 8);
1916 /* return the parm'th parameter in the smbp packet */
1917 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1920 unsigned char *parmDatap;
1922 parmCount = *smbp->wctp;
1924 if (parm * 2 + offset >= parmCount * 2) {
1929 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1930 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1931 parm, offset, parmCount, smbp->ncb_length);
1933 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1934 1, smbp->ncb_length, ptbuf, smbp);
1935 DeregisterEventSource(h);
1939 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1941 parm, offset, parmCount, smbp->ncb_length);
1942 osi_Log0(smb_logp, s);
1945 osi_panic(s, __FILE__, __LINE__);
1947 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1949 return parmDatap[0] + (parmDatap[1] << 8);
1952 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1956 /* make sure we have enough slots */
1957 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1959 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1960 *parmDatap++ = parmValue & 0xff;
1961 *parmDatap = (parmValue>>8) & 0xff;
1964 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1968 /* make sure we have enough slots */
1969 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1971 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1972 *parmDatap++ = parmValue & 0xff;
1973 *parmDatap++ = (parmValue>>8) & 0xff;
1974 *parmDatap++ = (parmValue>>16) & 0xff;
1975 *parmDatap++ = (parmValue>>24) & 0xff;
1978 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1983 /* make sure we have enough slots */
1984 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1986 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1988 *parmDatap++ = *parmValuep++;
1991 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1995 /* make sure we have enough slots */
1996 if (*smbp->wctp <= slot) {
1997 if (smbp->oddByte) {
1999 *smbp->wctp = slot+1;
2004 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2005 *parmDatap++ = parmValue & 0xff;
2008 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2012 lastSlashp = strrchr(inPathp, '\\');
2014 *lastComponentp = lastSlashp;
2017 if (inPathp == lastSlashp)
2019 *outPathp++ = *inPathp++;
2028 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2033 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2038 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2044 tlen = inp[0] + (inp[1]<<8);
2045 inp += 2; /* skip length field */
2048 *chainpp = inp + tlen;
2057 /* format a packet as a response */
2058 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2063 outp = (smb_t *) op;
2065 /* zero the basic structure through the smb_wct field, and zero the data
2066 * size field, assuming that wct stays zero; otherwise, you have to
2067 * explicitly set the data size field, too.
2069 inSmbp = (smb_t *) inp;
2070 memset(outp, 0, sizeof(smb_t)+2);
2076 outp->com = inSmbp->com;
2077 outp->tid = inSmbp->tid;
2078 outp->pid = inSmbp->pid;
2079 outp->uid = inSmbp->uid;
2080 outp->mid = inSmbp->mid;
2081 outp->res[0] = inSmbp->res[0];
2082 outp->res[1] = inSmbp->res[1];
2083 op->inCom = inSmbp->com;
2085 outp->reb = 0x80; /* SERVER_RESP */
2086 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2088 /* copy fields in generic packet area */
2089 op->wctp = &outp->wct;
2092 /* send a (probably response) packet; vcp tells us to whom to send it.
2093 * we compute the length by looking at wct and bcc fields.
2095 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2112 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2115 memset((char *)ncbp, 0, sizeof(NCB));
2117 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2118 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2119 extra += tp[0] + (tp[1]<<8);
2120 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2121 extra += 3; /* wct and length fields */
2123 ncbp->ncb_length = extra; /* bytes to send */
2124 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2125 ncbp->ncb_lana_num = vcp->lana;
2126 ncbp->ncb_command = NCBSEND; /* op means send data */
2128 ncbp->ncb_buffer = (char *) inp;/* packet */
2129 code = Netbios(ncbp);
2131 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2132 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2134 /* copy header information from virtual to DOS address space */
2135 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2136 code = Netbios(ncbp, dos_ncb);
2140 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2146 void smb_MapNTError(long code, unsigned long *NTStatusp)
2148 unsigned long NTStatus;
2150 /* map CM_ERROR_* errors to NT 32-bit status codes */
2151 /* NT Status codes are listed in ntstatus.h not winerror.h */
2152 if (code == CM_ERROR_NOSUCHCELL) {
2153 NTStatus = 0xC000000FL; /* No such file */
2155 else if (code == CM_ERROR_NOSUCHVOLUME) {
2156 NTStatus = 0xC000000FL; /* No such file */
2158 else if (code == CM_ERROR_TIMEDOUT) {
2159 NTStatus = 0xC00000CFL; /* Sharing Paused */
2161 else if (code == CM_ERROR_RETRY) {
2162 NTStatus = 0xC000022DL; /* Retry */
2164 else if (code == CM_ERROR_NOACCESS) {
2165 NTStatus = 0xC0000022L; /* Access denied */
2167 else if (code == CM_ERROR_READONLY) {
2168 NTStatus = 0xC00000A2L; /* Write protected */
2170 else if (code == CM_ERROR_NOSUCHFILE) {
2171 NTStatus = 0xC000000FL; /* No such file */
2173 else if (code == CM_ERROR_NOSUCHPATH) {
2174 NTStatus = 0xC000003AL; /* Object path not found */
2176 else if (code == CM_ERROR_TOOBIG) {
2177 NTStatus = 0xC000007BL; /* Invalid image format */
2179 else if (code == CM_ERROR_INVAL) {
2180 NTStatus = 0xC000000DL; /* Invalid parameter */
2182 else if (code == CM_ERROR_BADFD) {
2183 NTStatus = 0xC0000008L; /* Invalid handle */
2185 else if (code == CM_ERROR_BADFDOP) {
2186 NTStatus = 0xC0000022L; /* Access denied */
2188 else if (code == CM_ERROR_EXISTS) {
2189 NTStatus = 0xC0000035L; /* Object name collision */
2191 else if (code == CM_ERROR_NOTEMPTY) {
2192 NTStatus = 0xC0000101L; /* Directory not empty */
2194 else if (code == CM_ERROR_CROSSDEVLINK) {
2195 NTStatus = 0xC00000D4L; /* Not same device */
2197 else if (code == CM_ERROR_NOTDIR) {
2198 NTStatus = 0xC0000103L; /* Not a directory */
2200 else if (code == CM_ERROR_ISDIR) {
2201 NTStatus = 0xC00000BAL; /* File is a directory */
2203 else if (code == CM_ERROR_BADOP) {
2204 NTStatus = 0xC09820FFL; /* SMB no support */
2206 else if (code == CM_ERROR_BADSHARENAME) {
2207 NTStatus = 0xC00000CCL; /* Bad network name */
2209 else if (code == CM_ERROR_NOIPC) {
2211 NTStatus = 0xC0000022L; /* Access Denied */
2213 NTStatus = 0xC000013DL; /* Remote Resources */
2216 else if (code == CM_ERROR_CLOCKSKEW) {
2217 NTStatus = 0xC0000133L; /* Time difference at DC */
2219 else if (code == CM_ERROR_BADTID) {
2220 NTStatus = 0xC0982005L; /* SMB bad TID */
2222 else if (code == CM_ERROR_USESTD) {
2223 NTStatus = 0xC09820FBL; /* SMB use standard */
2225 else if (code == CM_ERROR_QUOTA) {
2226 NTStatus = 0xC0000044L; /* Quota exceeded */
2228 else if (code == CM_ERROR_SPACE) {
2229 NTStatus = 0xC000007FL; /* Disk full */
2231 else if (code == CM_ERROR_ATSYS) {
2232 NTStatus = 0xC0000033L; /* Object name invalid */
2234 else if (code == CM_ERROR_BADNTFILENAME) {
2235 NTStatus = 0xC0000033L; /* Object name invalid */
2237 else if (code == CM_ERROR_WOULDBLOCK) {
2238 NTStatus = 0xC0000055L; /* Lock not granted */
2240 else if (code == CM_ERROR_PARTIALWRITE) {
2241 NTStatus = 0xC000007FL; /* Disk full */
2243 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2244 NTStatus = 0xC0000023L; /* Buffer too small */
2246 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2247 NTStatus = 0xC0000035L; /* Object name collision */
2249 else if (code == CM_ERROR_BADPASSWORD) {
2250 NTStatus = 0xC000006DL; /* unknown username or bad password */
2252 else if (code == CM_ERROR_BADLOGONTYPE) {
2253 NTStatus = 0xC000015BL; /* logon type not granted */
2255 else if (code == CM_ERROR_GSSCONTINUE) {
2256 NTStatus = 0xC0000016L; /* more processing required */
2259 NTStatus = 0xC0982001L; /* SMB non-specific error */
2262 *NTStatusp = NTStatus;
2263 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2266 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2267 unsigned char *classp)
2269 unsigned char class;
2270 unsigned short error;
2272 /* map CM_ERROR_* errors to SMB errors */
2273 if (code == CM_ERROR_NOSUCHCELL) {
2275 error = 3; /* bad path */
2277 else if (code == CM_ERROR_NOSUCHVOLUME) {
2279 error = 3; /* bad path */
2281 else if (code == CM_ERROR_TIMEDOUT) {
2283 error = 81; /* server is paused */
2285 else if (code == CM_ERROR_RETRY) {
2286 class = 2; /* shouldn't happen */
2289 else if (code == CM_ERROR_NOACCESS) {
2291 error = 4; /* bad access */
2293 else if (code == CM_ERROR_READONLY) {
2295 error = 19; /* read only */
2297 else if (code == CM_ERROR_NOSUCHFILE) {
2299 error = 2; /* ENOENT! */
2301 else if (code == CM_ERROR_NOSUCHPATH) {
2303 error = 3; /* Bad path */
2305 else if (code == CM_ERROR_TOOBIG) {
2307 error = 11; /* bad format */
2309 else if (code == CM_ERROR_INVAL) {
2310 class = 2; /* server non-specific error code */
2313 else if (code == CM_ERROR_BADFD) {
2315 error = 6; /* invalid file handle */
2317 else if (code == CM_ERROR_BADFDOP) {
2318 class = 1; /* invalid op on FD */
2321 else if (code == CM_ERROR_EXISTS) {
2323 error = 80; /* file already exists */
2325 else if (code == CM_ERROR_NOTEMPTY) {
2327 error = 5; /* delete directory not empty */
2329 else if (code == CM_ERROR_CROSSDEVLINK) {
2331 error = 17; /* EXDEV */
2333 else if (code == CM_ERROR_NOTDIR) {
2334 class = 1; /* bad path */
2337 else if (code == CM_ERROR_ISDIR) {
2338 class = 1; /* access denied; DOS doesn't have a good match */
2341 else if (code == CM_ERROR_BADOP) {
2345 else if (code == CM_ERROR_BADSHARENAME) {
2349 else if (code == CM_ERROR_NOIPC) {
2351 error = 4; /* bad access */
2353 else if (code == CM_ERROR_CLOCKSKEW) {
2354 class = 1; /* invalid function */
2357 else if (code == CM_ERROR_BADTID) {
2361 else if (code == CM_ERROR_USESTD) {
2365 else if (code == CM_ERROR_REMOTECONN) {
2369 else if (code == CM_ERROR_QUOTA) {
2370 if (vcp->flags & SMB_VCFLAG_USEV3) {
2372 error = 39; /* disk full */
2376 error = 5; /* access denied */
2379 else if (code == CM_ERROR_SPACE) {
2380 if (vcp->flags & SMB_VCFLAG_USEV3) {
2382 error = 39; /* disk full */
2386 error = 5; /* access denied */
2389 else if (code == CM_ERROR_PARTIALWRITE) {
2391 error = 39; /* disk full */
2393 else if (code == CM_ERROR_ATSYS) {
2395 error = 2; /* ENOENT */
2397 else if (code == CM_ERROR_WOULDBLOCK) {
2399 error = 33; /* lock conflict */
2401 else if (code == CM_ERROR_NOFILES) {
2403 error = 18; /* no files in search */
2405 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2407 error = 183; /* Samba uses this */
2409 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2410 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2412 error = 2; /* bad password */
2421 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2424 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2426 return CM_ERROR_BADOP;
2429 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2431 unsigned short EchoCount, i;
2432 char *data, *outdata;
2435 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2437 for (i=1; i<=EchoCount; i++) {
2438 data = smb_GetSMBData(inp, &dataSize);
2439 smb_SetSMBParm(outp, 0, i);
2440 smb_SetSMBDataLength(outp, dataSize);
2441 outdata = smb_GetSMBData(outp, NULL);
2442 memcpy(outdata, data, dataSize);
2443 smb_SendPacket(vcp, outp);
2449 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2452 long count, minCount, finalCount;
2456 cm_user_t *userp = NULL;
2460 char *rawBuf = NULL;
2462 dos_ptr rawBuf = NULL;
2469 fd = smb_GetSMBParm(inp, 0);
2470 count = smb_GetSMBParm(inp, 3);
2471 minCount = smb_GetSMBParm(inp, 4);
2472 offset.HighPart = 0; /* too bad */
2473 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2475 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2476 fd, offset.LowPart, count);
2478 fidp = smb_FindFID(vcp, fd, 0);
2482 lock_ObtainMutex(&smb_RawBufLock);
2484 /* Get a raw buf, from head of list */
2485 rawBuf = smb_RawBufs;
2487 smb_RawBufs = *(char **)smb_RawBufs;
2489 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2492 lock_ReleaseMutex(&smb_RawBufLock);
2496 if (fidp->flags & SMB_FID_IOCTL)
2499 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2501 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2504 /* Give back raw buffer */
2505 lock_ObtainMutex(&smb_RawBufLock);
2507 *((char **) rawBuf) = smb_RawBufs;
2509 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2512 smb_RawBufs = rawBuf;
2513 lock_ReleaseMutex(&smb_RawBufLock);
2516 smb_ReleaseFID(fidp);
2520 userp = smb_GetUser(vcp, inp);
2523 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2525 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2526 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2527 userp, &finalCount, TRUE /* rawFlag */);
2534 cm_ReleaseUser(userp);
2537 smb_ReleaseFID(fidp);
2542 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2544 memset((char *)ncbp, 0, sizeof(NCB));
2546 ncbp->ncb_length = (unsigned short) finalCount;
2547 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2548 ncbp->ncb_lana_num = vcp->lana;
2549 ncbp->ncb_command = NCBSEND;
2550 ncbp->ncb_buffer = rawBuf;
2553 code = Netbios(ncbp);
2555 code = Netbios(ncbp, dos_ncb);
2558 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2561 /* Give back raw buffer */
2562 lock_ObtainMutex(&smb_RawBufLock);
2564 *((char **) rawBuf) = smb_RawBufs;
2566 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2569 smb_RawBufs = rawBuf;
2570 lock_ReleaseMutex(&smb_RawBufLock);
2576 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2581 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2586 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2593 int protoIndex; /* index we're using */
2598 char protocol_array[10][1024]; /* protocol signature of the client */
2599 int caps; /* capabilities */
2602 TIME_ZONE_INFORMATION tzi;
2604 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2608 DWORD now = GetCurrentTime();
2609 if (now - last_msg_time >= 30000
2610 && now - last_msg_time <= 90000) {
2612 "Setting dead_vcp %x", active_vcp);
2614 smb_ReleaseVC(dead_vcp);
2616 "Previous dead_vcp %x", dead_vcp);
2618 smb_HoldVC(active_vcp);
2619 dead_vcp = active_vcp;
2620 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2625 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2627 namep = smb_GetSMBData(inp, &dbytes);
2630 coreProtoIndex = -1; /* not found */
2633 while(namex < dbytes) {
2634 osi_Log1(smb_logp, "Protocol %s",
2635 osi_LogSaveString(smb_logp, namep+1));
2636 strcpy(protocol_array[tcounter], namep+1);
2638 /* namep points at the first protocol, or really, a 0x02
2639 * byte preceding the null-terminated ASCII name.
2641 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2642 coreProtoIndex = tcounter;
2644 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2645 v3ProtoIndex = tcounter;
2647 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2648 NTProtoIndex = tcounter;
2651 /* compute size of protocol entry */
2652 entryLength = strlen(namep+1);
2653 entryLength += 2; /* 0x02 bytes and null termination */
2655 /* advance over this protocol entry */
2656 namex += entryLength;
2657 namep += entryLength;
2658 tcounter++; /* which proto entry we're looking at */
2661 if (NTProtoIndex != -1) {
2662 protoIndex = NTProtoIndex;
2663 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2665 else if (v3ProtoIndex != -1) {
2666 protoIndex = v3ProtoIndex;
2667 vcp->flags |= SMB_VCFLAG_USEV3;
2669 else if (coreProtoIndex != -1) {
2670 protoIndex = coreProtoIndex;
2671 vcp->flags |= SMB_VCFLAG_USECORE;
2673 else protoIndex = -1;
2675 if (protoIndex == -1)
2676 return CM_ERROR_INVAL;
2677 else if (NTProtoIndex != -1) {
2678 smb_SetSMBParm(outp, 0, protoIndex);
2679 if (smb_authType != SMB_AUTH_NONE) {
2680 smb_SetSMBParmByte(outp, 1,
2681 NEGOTIATE_SECURITY_USER_LEVEL |
2682 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2684 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2686 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2687 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2688 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2689 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2690 /* The session key is not a well documented field however most clients
2691 * will echo back the session key to the server. Currently we are using
2692 * the same value for all sessions. We should generate a random value
2693 * and store it into the vcp
2695 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2696 smb_SetSMBParm(outp, 8, 1);
2698 * Tried changing the capabilities to support for W2K - defect 117695
2699 * Maybe something else needs to be changed here?
2703 smb_SetSMBParmLong(outp, 9, 0x43fd);
2705 smb_SetSMBParmLong(outp, 9, 0x251);
2708 * 32-bit error codes *
2712 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2713 NTNEGOTIATE_CAPABILITY_NTFIND |
2714 NTNEGOTIATE_CAPABILITY_RAWMODE |
2715 NTNEGOTIATE_CAPABILITY_NTSMB;
2717 if ( smb_authType == SMB_AUTH_EXTENDED )
2718 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2720 smb_SetSMBParmLong(outp, 9, caps);
2722 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2723 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2724 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2726 GetTimeZoneInformation(&tzi);
2727 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2729 if (smb_authType == SMB_AUTH_NTLM) {
2730 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2731 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2732 /* paste in encryption key */
2733 datap = smb_GetSMBData(outp, NULL);
2734 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2735 /* and the faux domain name */
2736 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2737 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2741 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2743 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2745 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2747 datap = smb_GetSMBData(outp, NULL);
2748 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2751 datap += sizeof(smb_ServerGUID);
2752 memcpy(datap, secBlob, secBlobLength);
2756 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2757 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2760 else if (v3ProtoIndex != -1) {
2761 smb_SetSMBParm(outp, 0, protoIndex);
2763 /* NOTE: Extended authentication cannot be negotiated with v3
2764 * therefore we fail over to NTLM
2766 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2767 smb_SetSMBParm(outp, 1,
2768 NEGOTIATE_SECURITY_USER_LEVEL |
2769 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2771 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2773 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2774 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2775 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2776 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2777 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2778 smb_SetSMBParm(outp, 7, 1);
2780 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2781 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2782 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2784 GetTimeZoneInformation(&tzi);
2785 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2787 /* NOTE: Extended authentication cannot be negotiated with v3
2788 * therefore we fail over to NTLM
2790 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2791 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2792 smb_SetSMBParm(outp, 12, 0); /* resvd */
2793 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2794 datap = smb_GetSMBData(outp, NULL);
2795 /* paste in a new encryption key */
2796 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2797 /* and the faux domain name */
2798 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2800 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2801 smb_SetSMBParm(outp, 12, 0); /* resvd */
2802 smb_SetSMBDataLength(outp, 0);
2805 else if (coreProtoIndex != -1) { /* not really supported anymore */
2806 smb_SetSMBParm(outp, 0, protoIndex);
2807 smb_SetSMBDataLength(outp, 0);
2812 void smb_Daemon(void *parmp)
2819 if ((count % 360) == 0) { /* every hour */
2822 /* Initialize smb_localZero */
2823 myTime.tm_isdst = -1; /* compute whether on DST or not */
2824 myTime.tm_year = 70;
2830 smb_localZero = mktime(&myTime);
2832 smb_CalculateNowTZ();
2834 /* XXX GC dir search entries */
2838 void smb_WaitingLocksDaemon()
2840 smb_waitingLock_t *wL, *nwL;
2843 smb_packet_t *inp, *outp;
2848 lock_ObtainWrite(&smb_globalLock);
2849 nwL = smb_allWaitingLocks;
2851 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2860 lock_ObtainWrite(&smb_globalLock);
2862 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2863 lock_ReleaseWrite(&smb_globalLock);
2864 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2865 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2866 if (code == CM_ERROR_WOULDBLOCK) {
2868 if (wL->timeRemaining != 0xffffffff
2869 && (wL->timeRemaining -= 1000) < 0)
2878 ncbp->ncb_length = inp->ncb_length;
2879 inp->spacep = cm_GetSpace();
2881 /* Remove waitingLock from list */
2882 lock_ObtainWrite(&smb_globalLock);
2883 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2885 lock_ReleaseWrite(&smb_globalLock);
2887 /* Resume packet processing */
2889 smb_SetSMBDataLength(outp, 0);
2890 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2891 outp->resumeCode = code;
2893 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2896 cm_FreeSpace(inp->spacep);
2897 smb_FreePacket(inp);
2898 smb_FreePacket(outp);
2906 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2908 osi_Log0(smb_logp, "SMB receive get disk attributes");
2910 smb_SetSMBParm(outp, 0, 32000);
2911 smb_SetSMBParm(outp, 1, 64);
2912 smb_SetSMBParm(outp, 2, 1024);
2913 smb_SetSMBParm(outp, 3, 30000);
2914 smb_SetSMBParm(outp, 4, 0);
2915 smb_SetSMBDataLength(outp, 0);
2919 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2923 unsigned short newTid;
2924 char shareName[256];
2932 osi_Log0(smb_logp, "SMB receive tree connect");
2934 /* parse input parameters */
2935 tp = smb_GetSMBData(inp, NULL);
2936 pathp = smb_ParseASCIIBlock(tp, &tp);
2937 passwordp = smb_ParseASCIIBlock(tp, &tp);
2938 tp = strrchr(pathp, '\\');
2940 return CM_ERROR_BADSMB;
2941 strcpy(shareName, tp+1);
2943 userp = smb_GetUser(vcp, inp);
2945 lock_ObtainMutex(&vcp->mx);
2946 newTid = vcp->tidCounter++;
2947 lock_ReleaseMutex(&vcp->mx);
2949 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2950 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2951 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2953 smb_ReleaseUID(uidp);
2955 smb_ReleaseTID(tidp);
2956 return CM_ERROR_BADSHARENAME;
2958 lock_ObtainMutex(&tidp->mx);
2959 tidp->userp = userp;
2960 tidp->pathname = sharePath;
2961 lock_ReleaseMutex(&tidp->mx);
2962 smb_ReleaseTID(tidp);
2964 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2965 smb_SetSMBParm(rsp, 1, newTid);
2966 smb_SetSMBDataLength(rsp, 0);
2968 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2972 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2976 if (*inp++ != 0x1) return NULL;
2977 tlen = inp[0] + (inp[1]<<8);
2978 inp += 2; /* skip length field */
2981 *chainpp = inp + tlen;
2984 if (lengthp) *lengthp = tlen;
2989 /* set maskp to the mask part of the incoming path.
2990 * Mask is 11 bytes long (8.3 with the dot elided).
2991 * Returns true if succeeds with a valid name, otherwise it does
2992 * its best, but returns false.
2994 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3002 /* starts off valid */
3005 /* mask starts out all blanks */
3006 memset(maskp, ' ', 11);
3008 /* find last backslash, or use whole thing if there is none */
3009 tp = strrchr(pathp, '\\');
3010 if (!tp) tp = pathp;
3011 else tp++; /* skip slash */
3015 /* names starting with a dot are illegal */
3016 if (*tp == '.') valid8Dot3 = 0;
3020 if (tc == 0) return valid8Dot3;
3021 if (tc == '.' || tc == '"') break;
3022 if (i < 8) *up++ = tc;
3023 else valid8Dot3 = 0;
3026 /* if we get here, tp point after the dot */
3027 up = maskp+8; /* ext goes here */
3034 if (tc == '.' || tc == '"')
3037 /* copy extension if not too long */
3047 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3057 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3059 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3063 /* otherwise, we have a valid 8.3 name; see if we have a match,
3064 * treating '?' as a wildcard in maskp (but not in the file name).
3066 tp1 = umask; /* real name, in mask format */
3067 tp2 = maskp; /* mask, in mask format */
3068 for(i=0; i<11; i++) {
3069 tc1 = *tp1++; /* char from real name */
3070 tc2 = *tp2++; /* char from mask */
3071 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3072 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3075 if (tc2 == '?' && tc1 != ' ')
3082 /* we got a match */
3086 char *smb_FindMask(char *pathp)
3090 tp = strrchr(pathp, '\\'); /* find last slash */
3093 return tp+1; /* skip the slash */
3095 return pathp; /* no slash, return the entire path */
3098 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3100 unsigned char *pathp;
3102 unsigned char mask[11];
3103 unsigned char *statBlockp;
3104 unsigned char initStatBlock[21];
3107 osi_Log0(smb_logp, "SMB receive search volume");
3109 /* pull pathname and stat block out of request */
3110 tp = smb_GetSMBData(inp, NULL);
3111 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3112 osi_assert(pathp != NULL);
3113 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3114 osi_assert(statBlockp != NULL);
3116 statBlockp = initStatBlock;
3120 /* for returning to caller */
3121 smb_Get8Dot3MaskFromPath(mask, pathp);
3123 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3124 tp = smb_GetSMBData(outp, NULL);
3126 *tp++ = 43; /* bytes in a dir entry */
3127 *tp++ = 0; /* high byte in counter */
3129 /* now marshall the dir entry, starting with the search status */
3130 *tp++ = statBlockp[0]; /* Reserved */
3131 memcpy(tp, mask, 11); tp += 11; /* FileName */
3133 /* now pass back server use info, with 1st byte non-zero */
3135 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3137 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3139 *tp++ = 0x8; /* attribute: volume */
3149 /* 4 byte file size */
3155 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3156 memset(tp, ' ', 13);
3159 /* set the length of the data part of the packet to 43 + 3, for the dir
3160 * entry plus the 5 and the length fields.
3162 smb_SetSMBDataLength(outp, 46);
3166 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3167 cm_user_t *userp, cm_req_t *reqp)
3175 smb_dirListPatch_t *patchp;
3176 smb_dirListPatch_t *npatchp;
3178 for(patchp = *dirPatchespp; patchp; patchp =
3179 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3180 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3182 lock_ObtainMutex(&scp->mx);
3183 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3184 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3186 lock_ReleaseMutex(&scp->mx);
3187 cm_ReleaseSCache(scp);
3190 dptr = patchp->dptr;
3192 attr = smb_Attributes(scp);
3193 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3194 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3195 attr |= SMB_ATTR_HIDDEN;
3199 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3202 shortTemp = dosTime & 0xffff;
3203 *((u_short *)dptr) = shortTemp;
3206 /* and copy out date */
3207 shortTemp = (dosTime>>16) & 0xffff;
3208 *((u_short *)dptr) = shortTemp;
3211 /* copy out file length */
3212 *((u_long *)dptr) = scp->length.LowPart;
3214 lock_ReleaseMutex(&scp->mx);
3215 cm_ReleaseSCache(scp);
3218 /* now free the patches */
3219 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3220 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3224 /* and mark the list as empty */
3225 *dirPatchespp = NULL;
3230 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3239 smb_dirListPatch_t *dirListPatchesp;
3240 smb_dirListPatch_t *curPatchp;
3244 osi_hyper_t dirLength;
3245 osi_hyper_t bufferOffset;
3246 osi_hyper_t curOffset;
3248 unsigned char *inCookiep;
3249 smb_dirSearch_t *dsp;
3253 unsigned long clientCookie;
3254 cm_pageHeader_t *pageHeaderp;
3255 cm_user_t *userp = NULL;
3262 long nextEntryCookie;
3263 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3264 char resByte; /* reserved byte from the cookie */
3265 char *op; /* output data ptr */
3266 char *origOp; /* original value of op */
3267 cm_space_t *spacep; /* for pathname buffer */
3278 maxCount = smb_GetSMBParm(inp, 0);
3280 dirListPatchesp = NULL;
3282 caseFold = CM_FLAG_CASEFOLD;
3284 tp = smb_GetSMBData(inp, NULL);
3285 pathp = smb_ParseASCIIBlock(tp, &tp);
3286 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3288 /* bail out if request looks bad */
3289 if (!tp || !pathp) {
3290 return CM_ERROR_BADSMB;
3293 /* We can handle long names */
3294 if (vcp->flags & SMB_VCFLAG_USENT)
3295 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3297 /* make sure we got a whole search status */
3298 if (dataLength < 21) {
3299 nextCookie = 0; /* start at the beginning of the dir */
3302 attribute = smb_GetSMBParm(inp, 1);
3304 /* handle volume info in another function */
3305 if (attribute & 0x8)
3306 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3308 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3309 maxCount, osi_LogSaveString(smb_logp, pathp));
3311 if (*pathp == 0) { /* null pathp, treat as root dir */
3312 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3313 return CM_ERROR_NOFILES;
3317 dsp = smb_NewDirSearch(0);
3318 dsp->attribute = attribute;
3319 smb_Get8Dot3MaskFromPath(mask, pathp);
3320 memcpy(dsp->mask, mask, 11);
3322 /* track if this is likely to match a lot of entries */
3323 if (smb_IsStarMask(mask)) starPattern = 1;
3324 else starPattern = 0;
3327 /* pull the next cookie value out of the search status block */
3328 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3329 + (inCookiep[16]<<24);
3330 dsp = smb_FindDirSearch(inCookiep[12]);
3332 /* can't find dir search status; fatal error */
3333 return CM_ERROR_BADFD;
3335 attribute = dsp->attribute;
3336 resByte = inCookiep[0];
3338 /* copy out client cookie, in host byte order. Don't bother
3339 * interpreting it, since we're just passing it through, anyway.
3341 memcpy(&clientCookie, &inCookiep[17], 4);
3343 memcpy(mask, dsp->mask, 11);
3345 /* assume we're doing a star match if it has continued for more
3351 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3352 nextCookie, dsp->cookie, attribute);
3354 userp = smb_GetUser(vcp, inp);
3356 /* try to get the vnode for the path name next */
3357 lock_ObtainMutex(&dsp->mx);
3364 spacep = inp->spacep;
3365 smb_StripLastComponent(spacep->data, NULL, pathp);
3366 lock_ReleaseMutex(&dsp->mx);
3367 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3369 lock_ReleaseMutex(&dsp->mx);
3370 cm_ReleaseUser(userp);
3371 smb_DeleteDirSearch(dsp);
3372 smb_ReleaseDirSearch(dsp);
3373 return CM_ERROR_NOFILES;
3375 code = cm_NameI(cm_rootSCachep, spacep->data,
3376 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3377 lock_ObtainMutex(&dsp->mx);
3379 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3381 /* we need one hold for the entry we just stored into,
3382 * and one for our own processing. When we're done with this
3383 * function, we'll drop the one for our own processing.
3384 * We held it once from the namei call, and so we do another hold
3388 lock_ObtainMutex(&scp->mx);
3389 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3390 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3391 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3392 dsp->flags |= SMB_DIRSEARCH_BULKST;
3394 lock_ReleaseMutex(&scp->mx);
3397 lock_ReleaseMutex(&dsp->mx);
3399 cm_ReleaseUser(userp);
3400 smb_DeleteDirSearch(dsp);
3401 smb_ReleaseDirSearch(dsp);
3405 /* reserves space for parameter; we'll adjust it again later to the
3406 * real count of the # of entries we returned once we've actually
3407 * assembled the directory listing.
3409 smb_SetSMBParm(outp, 0, 0);
3411 /* get the directory size */
3412 lock_ObtainMutex(&scp->mx);
3413 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3414 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3416 lock_ReleaseMutex(&scp->mx);
3417 cm_ReleaseSCache(scp);
3418 cm_ReleaseUser(userp);
3419 smb_DeleteDirSearch(dsp);
3420 smb_ReleaseDirSearch(dsp);
3424 dirLength = scp->length;
3426 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3427 curOffset.HighPart = 0;
3428 curOffset.LowPart = nextCookie;
3429 origOp = op = smb_GetSMBData(outp, NULL);
3430 /* and write out the basic header */
3431 *op++ = 5; /* variable block */
3432 op += 2; /* skip vbl block length; we'll fill it in later */
3436 /* make sure that curOffset.LowPart doesn't point to the first
3437 * 32 bytes in the 2nd through last dir page, and that it doesn't
3438 * point at the first 13 32-byte chunks in the first dir page,
3439 * since those are dir and page headers, and don't contain useful
3442 temp = curOffset.LowPart & (2048-1);
3443 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3444 /* we're in the first page */
3445 if (temp < 13*32) temp = 13*32;
3448 /* we're in a later dir page */
3449 if (temp < 32) temp = 32;
3452 /* make sure the low order 5 bits are zero */
3455 /* now put temp bits back ito curOffset.LowPart */
3456 curOffset.LowPart &= ~(2048-1);
3457 curOffset.LowPart |= temp;
3459 /* check if we've returned all the names that will fit in the
3462 if (returnedNames >= maxCount)
3465 /* check if we've passed the dir's EOF */
3466 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3468 /* see if we can use the bufferp we have now; compute in which page
3469 * the current offset would be, and check whether that's the offset
3470 * of the buffer we have. If not, get the buffer.
3472 thyper.HighPart = curOffset.HighPart;
3473 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3474 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3477 buf_Release(bufferp);
3480 lock_ReleaseMutex(&scp->mx);
3481 lock_ObtainRead(&scp->bufCreateLock);
3482 code = buf_Get(scp, &thyper, &bufferp);
3483 lock_ReleaseRead(&scp->bufCreateLock);
3485 /* now, if we're doing a star match, do bulk fetching of all of
3486 * the status info for files in the dir.
3489 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3491 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3492 && LargeIntegerGreaterThanOrEqualTo(thyper,
3493 scp->bulkStatProgress)) {
3494 /* Don't bulk stat if risking timeout */
3495 int now = GetCurrentTime();
3496 if (now - req.startTime > 5000) {
3497 scp->bulkStatProgress = thyper;
3498 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3499 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3501 cm_TryBulkStat(scp, &thyper, userp, &req);
3505 lock_ObtainMutex(&scp->mx);
3508 bufferOffset = thyper;
3510 /* now get the data in the cache */
3512 code = cm_SyncOp(scp, bufferp, userp, &req,
3514 CM_SCACHESYNC_NEEDCALLBACK
3515 | CM_SCACHESYNC_READ);
3518 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3520 /* otherwise, load the buffer and try again */
3521 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3526 buf_Release(bufferp);
3530 } /* if (wrong buffer) ... */
3532 /* now we have the buffer containing the entry we're interested in; copy
3533 * it out if it represents a non-deleted entry.
3535 entryInDir = curOffset.LowPart & (2048-1);
3536 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3538 /* page header will help tell us which entries are free. Page header
3539 * can change more often than once per buffer, since AFS 3 dir page size
3540 * may be less than (but not more than a buffer package buffer.
3542 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3543 temp &= ~(2048 - 1); /* turn off intra-page bits */
3544 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3546 /* now determine which entry we're looking at in the page. If it is
3547 * free (there's a free bitmap at the start of the dir), we should
3548 * skip these 32 bytes.
3550 slotInPage = (entryInDir & 0x7e0) >> 5;
3551 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3552 /* this entry is free */
3553 numDirChunks = 1; /* only skip this guy */
3557 tp = bufferp->datap + entryInBuffer;
3558 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3560 /* while we're here, compute the next entry's location, too,
3561 * since we'll need it when writing out the cookie into the dir
3564 * XXXX Probably should do more sanity checking.
3566 numDirChunks = cm_NameEntries(dep->name, NULL);
3568 /* compute the offset of the cookie representing the next entry */
3569 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3571 /* Compute 8.3 name if necessary */
3572 actualName = dep->name;
3573 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3574 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3575 actualName = shortName;
3578 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3579 /* this is one of the entries to use: it is not deleted
3580 * and it matches the star pattern we're looking for.
3583 /* Eliminate entries that don't match requested
3586 /* no hidden files */
3587 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3590 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3592 /* We have already done the cm_TryBulkStat above */
3593 fid.cell = scp->fid.cell;
3594 fid.volume = scp->fid.volume;
3595 fid.vnode = ntohl(dep->fid.vnode);
3596 fid.unique = ntohl(dep->fid.unique);
3597 fileType = cm_FindFileType(&fid);
3598 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3599 "has filetype %d", dep->name,
3601 if (fileType == CM_SCACHETYPE_DIRECTORY)
3606 memcpy(op, mask, 11); op += 11;
3607 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3608 *op++ = nextEntryCookie & 0xff;
3609 *op++ = (nextEntryCookie>>8) & 0xff;
3610 *op++ = (nextEntryCookie>>16) & 0xff;
3611 *op++ = (nextEntryCookie>>24) & 0xff;
3612 memcpy(op, &clientCookie, 4); op += 4;
3614 /* now we emit the attribute. This is sort of tricky,
3615 * since we need to really stat the file to find out
3616 * what type of entry we've got. Right now, we're
3617 * copying out data from a buffer, while holding the
3618 * scp locked, so it isn't really convenient to stat
3619 * something now. We'll put in a place holder now,
3620 * and make a second pass before returning this to get
3621 * the real attributes. So, we just skip the data for
3622 * now, and adjust it later. We allocate a patch
3623 * record to make it easy to find this point later.
3624 * The replay will happen at a time when it is safe to
3625 * unlock the directory.
3627 curPatchp = malloc(sizeof(*curPatchp));
3628 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3629 curPatchp->dptr = op;
3630 curPatchp->fid.cell = scp->fid.cell;
3631 curPatchp->fid.volume = scp->fid.volume;
3632 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3633 curPatchp->fid.unique = ntohl(dep->fid.unique);
3635 /* do hidden attribute here since name won't be around when applying
3639 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3640 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3642 curPatchp->flags = 0;
3644 op += 9; /* skip attr, time, date and size */
3646 /* zero out name area. The spec says to pad with
3647 * spaces, but Samba doesn't, and neither do we.
3651 /* finally, we get to copy out the name; we know that
3652 * it fits in 8.3 or the pattern wouldn't match, but it
3653 * never hurts to be sure.
3655 strncpy(op, actualName, 13);
3657 /* Uppercase if requested by client */
3658 if ((((smb_t *)inp)->flg2 & 1) == 0)
3663 /* now, adjust the # of entries copied */
3665 } /* if we're including this name */
3668 /* and adjust curOffset to be where the new cookie is */
3669 thyper.HighPart = 0;
3670 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3671 curOffset = LargeIntegerAdd(thyper, curOffset);
3672 } /* while copying data for dir listing */
3674 /* release the mutex */
3675 lock_ReleaseMutex(&scp->mx);
3676 if (bufferp) buf_Release(bufferp);
3678 /* apply and free last set of patches; if not doing a star match, this
3679 * will be empty, but better safe (and freeing everything) than sorry.
3681 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3683 /* special return code for unsuccessful search */
3684 if (code == 0 && dataLength < 21 && returnedNames == 0)
3685 code = CM_ERROR_NOFILES;
3687 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3688 returnedNames, code);
3691 smb_DeleteDirSearch(dsp);
3692 smb_ReleaseDirSearch(dsp);
3693 cm_ReleaseSCache(scp);
3694 cm_ReleaseUser(userp);
3698 /* finalize the output buffer */
3699 smb_SetSMBParm(outp, 0, returnedNames);
3700 temp = (long) (op - origOp);
3701 smb_SetSMBDataLength(outp, temp);
3703 /* the data area is a variable block, which has a 5 (already there)
3704 * followed by the length of the # of data bytes. We now know this to
3705 * be "temp," although that includes the 3 bytes of vbl block header.
3706 * Deduct for them and fill in the length field.
3708 temp -= 3; /* deduct vbl block info */
3709 osi_assert(temp == (43 * returnedNames));
3710 origOp[1] = temp & 0xff;
3711 origOp[2] = (temp>>8) & 0xff;
3712 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3713 smb_ReleaseDirSearch(dsp);
3714 cm_ReleaseSCache(scp);
3715 cm_ReleaseUser(userp);
3719 /* verify that this is a valid path to a directory. I don't know why they
3720 * don't use the get file attributes call.
3722 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3726 cm_scache_t *rootScp;
3727 cm_scache_t *newScp;
3736 pathp = smb_GetSMBData(inp, NULL);
3737 pathp = smb_ParseASCIIBlock(pathp, NULL);
3738 osi_Log1(smb_logp, "SMB receive check path %s",
3739 osi_LogSaveString(smb_logp, pathp));
3742 return CM_ERROR_BADFD;
3745 rootScp = cm_rootSCachep;
3747 userp = smb_GetUser(vcp, inp);
3749 caseFold = CM_FLAG_CASEFOLD;
3751 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3753 cm_ReleaseUser(userp);
3754 return CM_ERROR_NOSUCHPATH;
3756 code = cm_NameI(rootScp, pathp,
3757 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3758 userp, tidPathp, &req, &newScp);
3761 cm_ReleaseUser(userp);
3765 /* now lock the vnode with a callback; returns with newScp locked */
3766 lock_ObtainMutex(&newScp->mx);
3767 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3768 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3769 if (code && code != CM_ERROR_NOACCESS) {
3770 lock_ReleaseMutex(&newScp->mx);
3771 cm_ReleaseSCache(newScp);
3772 cm_ReleaseUser(userp);
3776 attrs = smb_Attributes(newScp);
3778 if (!(attrs & 0x10))
3779 code = CM_ERROR_NOTDIR;
3781 lock_ReleaseMutex(&newScp->mx);
3783 cm_ReleaseSCache(newScp);
3784 cm_ReleaseUser(userp);
3788 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3792 cm_scache_t *rootScp;
3793 unsigned short attribute;
3795 cm_scache_t *newScp;
3804 /* decode basic attributes we're passed */
3805 attribute = smb_GetSMBParm(inp, 0);
3806 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3808 pathp = smb_GetSMBData(inp, NULL);
3809 pathp = smb_ParseASCIIBlock(pathp, NULL);
3812 return CM_ERROR_BADSMB;
3815 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3816 dosTime, attribute);
3818 rootScp = cm_rootSCachep;
3820 userp = smb_GetUser(vcp, inp);
3822 caseFold = CM_FLAG_CASEFOLD;
3824 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3826 cm_ReleaseUser(userp);
3827 return CM_ERROR_NOSUCHFILE;
3829 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3830 tidPathp, &req, &newScp);
3833 cm_ReleaseUser(userp);
3837 /* now lock the vnode with a callback; returns with newScp locked; we
3838 * need the current status to determine what the new status is, in some
3841 lock_ObtainMutex(&newScp->mx);
3842 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3843 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3845 lock_ReleaseMutex(&newScp->mx);
3846 cm_ReleaseSCache(newScp);
3847 cm_ReleaseUser(userp);
3851 /* Check for RO volume */
3852 if (newScp->flags & CM_SCACHEFLAG_RO) {
3853 lock_ReleaseMutex(&newScp->mx);
3854 cm_ReleaseSCache(newScp);
3855 cm_ReleaseUser(userp);
3856 return CM_ERROR_READONLY;
3859 /* prepare for setattr call */
3862 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3863 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3865 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3866 /* we're told to make a writable file read-only */
3867 attr.unixModeBits = newScp->unixModeBits & ~0222;
3868 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3870 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3871 /* we're told to make a read-only file writable */
3872 attr.unixModeBits = newScp->unixModeBits | 0222;
3873 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3875 lock_ReleaseMutex(&newScp->mx);
3877 /* now call setattr */
3879 code = cm_SetAttr(newScp, &attr, userp, &req);
3883 cm_ReleaseSCache(newScp);
3884 cm_ReleaseUser(userp);
3889 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3893 cm_scache_t *rootScp;
3894 cm_scache_t *newScp, *dscp;
3906 pathp = smb_GetSMBData(inp, NULL);
3907 pathp = smb_ParseASCIIBlock(pathp, NULL);
3910 return CM_ERROR_BADSMB;
3913 if (*pathp == 0) /* null path */
3916 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3917 osi_LogSaveString(smb_logp, pathp));
3919 rootScp = cm_rootSCachep;
3921 userp = smb_GetUser(vcp, inp);
3923 /* we shouldn't need this for V3 requests, but we seem to */
3924 caseFold = CM_FLAG_CASEFOLD;
3926 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3928 cm_ReleaseUser(userp);
3929 return CM_ERROR_NOSUCHFILE;
3933 * XXX Strange hack XXX
3935 * As of Patch 5 (16 July 97), we are having the following problem:
3936 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3937 * requests to look up "desktop.ini" in all the subdirectories.
3938 * This can cause zillions of timeouts looking up non-existent cells
3939 * and volumes, especially in the top-level directory.
3941 * We have not found any way to avoid this or work around it except
3942 * to explicitly ignore the requests for mount points that haven't
3943 * yet been evaluated and for directories that haven't yet been
3946 * We should modify this hack to provide a fake desktop.ini file
3947 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3949 spacep = inp->spacep;
3950 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3951 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3952 code = cm_NameI(rootScp, spacep->data,
3953 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3954 userp, tidPathp, &req, &dscp);
3956 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3957 && !dscp->mountRootFidp)
3958 code = CM_ERROR_NOSUCHFILE;
3959 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3960 cm_buf_t *bp = buf_Find(dscp, &hzero);
3964 code = CM_ERROR_NOSUCHFILE;
3966 cm_ReleaseSCache(dscp);
3968 cm_ReleaseUser(userp);
3974 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3975 tidPathp, &req, &newScp);
3978 cm_ReleaseUser(userp);
3982 /* now lock the vnode with a callback; returns with newScp locked */
3983 lock_ObtainMutex(&newScp->mx);
3984 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3985 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3987 lock_ReleaseMutex(&newScp->mx);
3988 cm_ReleaseSCache(newScp);
3989 cm_ReleaseUser(userp);
3994 /* use smb_Attributes instead. Also the fact that a file is
3995 * in a readonly volume doesn't mean it shojuld be marked as RO
3997 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
3998 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
3999 attrs = SMB_ATTR_DIRECTORY;
4002 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4003 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4005 attrs = smb_Attributes(newScp);
4008 smb_SetSMBParm(outp, 0, attrs);
4010 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4011 smb_SetSMBParm(outp, 1, dosTime & 0xffff);
4012 smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
4013 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4014 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4015 smb_SetSMBParm(outp, 5, 0);
4016 smb_SetSMBParm(outp, 6, 0);
4017 smb_SetSMBParm(outp, 7, 0);
4018 smb_SetSMBParm(outp, 8, 0);
4019 smb_SetSMBParm(outp, 9, 0);
4020 smb_SetSMBDataLength(outp, 0);
4021 lock_ReleaseMutex(&newScp->mx);
4023 cm_ReleaseSCache(newScp);
4024 cm_ReleaseUser(userp);
4029 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4033 osi_Log0(smb_logp, "SMB receive tree disconnect");
4035 /* find the tree and free it */
4036 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4038 lock_ObtainMutex(&tidp->mx);
4039 tidp->flags |= SMB_TIDFLAG_DELETE;
4040 lock_ReleaseMutex(&tidp->mx);
4041 smb_ReleaseTID(tidp);
4047 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4065 pathp = smb_GetSMBData(inp, NULL);
4066 pathp = smb_ParseASCIIBlock(pathp, NULL);
4068 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4070 #ifdef DEBUG_VERBOSE
4074 hexpath = osi_HexifyString( pathp );
4075 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4080 share = smb_GetSMBParm(inp, 0);
4081 attribute = smb_GetSMBParm(inp, 1);
4083 spacep = inp->spacep;
4084 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4085 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4086 /* special case magic file name for receiving IOCTL requests
4087 * (since IOCTL calls themselves aren't getting through).
4089 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4090 smb_SetupIoctlFid(fidp, spacep);
4091 smb_SetSMBParm(outp, 0, fidp->fid);
4092 smb_SetSMBParm(outp, 1, 0); /* attrs */
4093 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4094 smb_SetSMBParm(outp, 3, 0);
4095 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4096 smb_SetSMBParm(outp, 5, 0x7fff);
4097 /* pass the open mode back */
4098 smb_SetSMBParm(outp, 6, (share & 0xf));
4099 smb_SetSMBDataLength(outp, 0);
4100 smb_ReleaseFID(fidp);
4104 userp = smb_GetUser(vcp, inp);
4106 caseFold = CM_FLAG_CASEFOLD;
4108 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4110 cm_ReleaseUser(userp);
4111 return CM_ERROR_NOSUCHPATH;
4113 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4114 tidPathp, &req, &scp);
4117 cm_ReleaseUser(userp);
4121 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4123 cm_ReleaseSCache(scp);
4124 cm_ReleaseUser(userp);
4128 /* don't need callback to check file type, since file types never
4129 * change, and namei and cm_Lookup all stat the object at least once on
4130 * a successful return.
4132 if (scp->fileType != CM_SCACHETYPE_FILE) {
4133 cm_ReleaseSCache(scp);
4134 cm_ReleaseUser(userp);
4135 return CM_ERROR_ISDIR;
4138 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4141 /* save a pointer to the vnode */
4144 if ((share & 0xf) == 0)
4145 fidp->flags |= SMB_FID_OPENREAD;
4146 else if ((share & 0xf) == 1)
4147 fidp->flags |= SMB_FID_OPENWRITE;
4149 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4151 lock_ObtainMutex(&scp->mx);
4152 smb_SetSMBParm(outp, 0, fidp->fid);
4153 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4154 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4155 smb_SetSMBParm(outp, 2, dosTime & 0xffff);
4156 smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
4157 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4158 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4159 /* pass the open mode back; XXXX add access checks */
4160 smb_SetSMBParm(outp, 6, (share & 0xf));
4161 smb_SetSMBDataLength(outp, 0);
4162 lock_ReleaseMutex(&scp->mx);
4165 cm_Open(scp, 0, userp);
4167 /* send and free packet */
4168 smb_ReleaseFID(fidp);
4169 cm_ReleaseUser(userp);
4170 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4174 typedef struct smb_unlinkRock {
4179 char *maskp; /* pointer to the star pattern */
4184 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4187 smb_unlinkRock_t *rockp;
4195 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4196 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4197 caseFold |= CM_FLAG_8DOT3;
4199 matchName = dep->name;
4200 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4202 && (rockp->flags & SMB_MASKFLAG_TILDE)
4203 && !cm_Is8Dot3(dep->name)) {
4204 cm_Gen8Dot3Name(dep, shortName, NULL);
4205 matchName = shortName;
4206 /* 8.3 matches are always case insensitive */
4207 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4210 osi_Log1(smb_logp, "Unlinking %s",
4211 osi_LogSaveString(smb_logp, matchName));
4212 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4213 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4214 smb_NotifyChange(FILE_ACTION_REMOVED,
4215 FILE_NOTIFY_CHANGE_FILE_NAME,
4216 dscp, dep->name, NULL, TRUE);
4219 /* If we made a case sensitive exact match, we might as well quit now. */
4220 if(!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4221 code = CM_ERROR_STOPNOW;
4229 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4238 smb_unlinkRock_t rock;
4247 attribute = smb_GetSMBParm(inp, 0);
4249 tp = smb_GetSMBData(inp, NULL);
4250 pathp = smb_ParseASCIIBlock(tp, &tp);
4252 osi_Log1(smb_logp, "SMB receive unlink %s",
4253 osi_LogSaveString(smb_logp, pathp));
4255 spacep = inp->spacep;
4256 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4258 userp = smb_GetUser(vcp, inp);
4260 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4262 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4264 cm_ReleaseUser(userp);
4265 return CM_ERROR_NOSUCHPATH;
4267 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4271 cm_ReleaseUser(userp);
4275 /* otherwise, scp points to the parent directory. */
4282 rock.maskp = smb_FindMask(pathp);
4283 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4286 thyper.HighPart = 0;
4292 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4293 * match. If that fails, we do a case insensitve match.
4295 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4296 !smb_IsStarMask(rock.maskp)) {
4297 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4300 thyper.HighPart = 0;
4301 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4306 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4308 if (code == CM_ERROR_STOPNOW)
4311 cm_ReleaseUser(userp);
4313 cm_ReleaseSCache(dscp);
4315 if (code == 0 && !rock.any)
4316 code = CM_ERROR_NOSUCHFILE;
4320 typedef struct smb_renameRock {
4321 cm_scache_t *odscp; /* old dir */
4322 cm_scache_t *ndscp; /* new dir */
4323 cm_user_t *userp; /* user */
4324 cm_req_t *reqp; /* request struct */
4325 smb_vc_t *vcp; /* virtual circuit */
4326 char *maskp; /* pointer to star pattern of old file name */
4327 int flags; /* tilde, casefold, etc */
4328 char *newNamep; /* ptr to the new file's name */
4331 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4334 smb_renameRock_t *rockp;
4339 rockp = (smb_renameRock_t *) vrockp;
4341 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4342 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4343 caseFold |= CM_FLAG_8DOT3;
4345 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4347 && (rockp->flags & SMB_MASKFLAG_TILDE)
4348 && !cm_Is8Dot3(dep->name)) {
4349 cm_Gen8Dot3Name(dep, shortName, NULL);
4350 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4353 code = cm_Rename(rockp->odscp, dep->name,
4354 rockp->ndscp, rockp->newNamep, rockp->userp,
4356 /* if the call worked, stop doing the search now, since we
4357 * really only want to rename one file.
4360 code = CM_ERROR_STOPNOW;
4367 long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4373 cm_space_t *spacep = NULL;
4374 smb_renameRock_t rock;
4375 cm_scache_t *oldDscp = NULL;
4376 cm_scache_t *newDscp = NULL;
4377 cm_scache_t *tmpscp= NULL;
4378 cm_scache_t *tmpscp2 = NULL;
4390 tp = smb_GetSMBData(inp, NULL);
4391 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4392 newPathp = smb_ParseASCIIBlock(tp, &tp);
4394 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4395 osi_LogSaveString(smb_logp, oldPathp),
4396 osi_LogSaveString(smb_logp, newPathp));
4398 spacep = inp->spacep;
4399 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4401 userp = smb_GetUser(vcp, inp);
4404 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4405 * what actually exists is foo/baz. I don't know why the code used to be
4406 * the way it was. 1/29/96
4408 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4410 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4412 * caseFold = CM_FLAG_CASEFOLD;
4414 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4416 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4418 cm_ReleaseUser(userp);
4419 return CM_ERROR_NOSUCHPATH;
4421 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4422 userp, tidPathp, &req, &oldDscp);
4425 cm_ReleaseUser(userp);
4429 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4430 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4431 userp, tidPathp, &req, &newDscp);
4434 cm_ReleaseSCache(oldDscp);
4435 cm_ReleaseUser(userp);
4439 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4440 * next, get the component names, and lower case them.
4443 /* handle the old name first */
4445 oldLastNamep = oldPathp;
4449 /* and handle the new name, too */
4451 newLastNamep = newPathp;
4455 /* TODO: The old name could be a wildcard. The new name must not be */
4457 /* do the vnode call */
4458 rock.odscp = oldDscp;
4459 rock.ndscp = newDscp;
4463 rock.maskp = oldLastNamep;
4464 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4465 rock.newNamep = newLastNamep;
4467 /* Check if the file already exists; if so return error */
4468 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4469 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4470 osi_Log2(afsd_logp, " lookup returns %ld for [%s]", code,
4471 osi_LogSaveString(afsd_logp, newLastNamep));
4473 /* Check if the old and the new names differ only in case. If so return
4474 * success, else return CM_ERROR_EXISTS
4476 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4478 /* This would be a success only if the old file is *as same as* the new file */
4479 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4481 if (tmpscp == tmpscp2)
4484 code = CM_ERROR_EXISTS;
4485 cm_ReleaseSCache(tmpscp2);
4488 code = CM_ERROR_NOSUCHFILE;
4491 /* file exist, do not rename, also fixes move */
4492 osi_Log0(afsd_logp, "Can't rename. Target already exists");
4493 code = CM_ERROR_EXISTS;
4497 cm_ReleaseSCache(tmpscp);
4498 cm_ReleaseSCache(newDscp);
4499 cm_ReleaseSCache(oldDscp);
4500 cm_ReleaseUser(userp);
4504 /* Now search the directory for the pattern, and do the appropriate rename when found */
4505 thyper.LowPart = 0; /* search dir from here */
4506 thyper.HighPart = 0;
4508 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4510 if (code == CM_ERROR_STOPNOW)
4513 code = CM_ERROR_NOSUCHFILE;
4515 /* Handle Change Notification */
4517 * Being lazy, not distinguishing between files and dirs in this
4518 * filter, since we'd have to do a lookup.
4520 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4521 if (oldDscp == newDscp) {
4522 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4523 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4524 filter, oldDscp, oldLastNamep,
4525 newLastNamep, TRUE);
4527 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4528 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4529 filter, oldDscp, oldLastNamep,
4531 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4532 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4533 filter, newDscp, newLastNamep,
4538 cm_ReleaseSCache(tmpscp);
4539 cm_ReleaseUser(userp);
4540 cm_ReleaseSCache(oldDscp);
4541 cm_ReleaseSCache(newDscp);
4545 typedef struct smb_rmdirRock {
4549 char *maskp; /* pointer to the star pattern */
4554 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4557 smb_rmdirRock_t *rockp;
4562 rockp = (smb_rmdirRock_t *) vrockp;
4564 matchName = dep->name;
4565 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4566 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4568 match = (strcmp(matchName, rockp->maskp) == 0);
4570 && (rockp->flags & SMB_MASKFLAG_TILDE)
4571 && !cm_Is8Dot3(dep->name)) {
4572 cm_Gen8Dot3Name(dep, shortName, NULL);
4573 matchName = shortName;
4574 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4577 osi_Log1(smb_logp, "Removing directory %s",
4578 osi_LogSaveString(smb_logp, matchName));
4579 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4580 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4581 smb_NotifyChange(FILE_ACTION_REMOVED,
4582 FILE_NOTIFY_CHANGE_DIR_NAME,
4583 dscp, dep->name, NULL, TRUE);
4592 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4600 smb_rmdirRock_t rock;
4609 tp = smb_GetSMBData(inp, NULL);
4610 pathp = smb_ParseASCIIBlock(tp, &tp);
4612 spacep = inp->spacep;
4613 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4615 userp = smb_GetUser(vcp, inp);
4617 caseFold = CM_FLAG_CASEFOLD;
4619 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4621 cm_ReleaseUser(userp);
4622 return CM_ERROR_NOSUCHPATH;
4624 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4625 userp, tidPathp, &req, &dscp);
4628 cm_ReleaseUser(userp);
4632 /* otherwise, scp points to the parent directory. */
4639 rock.maskp = lastNamep;
4640 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4643 thyper.HighPart = 0;
4647 /* First do a case sensitive match, and if that fails, do a case insensitive match */
4648 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4649 if (code == 0 && !rock.any) {
4651 thyper.HighPart = 0;
4652 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4653 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4656 cm_ReleaseUser(userp);
4658 cm_ReleaseSCache(dscp);
4660 if (code == 0 && !rock.any)
4661 code = CM_ERROR_NOSUCHFILE;
4665 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4675 fid = smb_GetSMBParm(inp, 0);
4677 osi_Log1(smb_logp, "SMB flush fid %d", fid);
4679 fid = smb_ChainFID(fid, inp);
4680 fidp = smb_FindFID(vcp, fid, 0);
4681 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4683 smb_ReleaseFID(fidp);
4684 return CM_ERROR_BADFD;
4687 userp = smb_GetUser(vcp, inp);
4689 lock_ObtainMutex(&fidp->mx);
4690 if (fidp->flags & SMB_FID_OPENWRITE)
4691 code = cm_FSync(fidp->scp, userp, &req);
4694 lock_ReleaseMutex(&fidp->mx);
4696 smb_ReleaseFID(fidp);
4698 cm_ReleaseUser(userp);
4703 struct smb_FullNameRock {
4709 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4713 struct smb_FullNameRock *vrockp;
4715 vrockp = (struct smb_FullNameRock *)rockp;
4717 if (!cm_Is8Dot3(dep->name)) {
4718 cm_Gen8Dot3Name(dep, shortName, NULL);
4720 if (cm_stricmp(shortName, vrockp->name) == 0) {
4721 vrockp->fullName = strdup(dep->name);
4722 return CM_ERROR_STOPNOW;
4725 if (cm_stricmp(dep->name, vrockp->name) == 0
4726 && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
4727 && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4728 vrockp->fullName = strdup(dep->name);
4729 return CM_ERROR_STOPNOW;
4734 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4735 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4737 struct smb_FullNameRock rock;
4743 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL,
4745 if (code == CM_ERROR_STOPNOW)
4746 *newPathp = rock.fullName;
4748 *newPathp = strdup(pathp);
4751 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4762 fid = smb_GetSMBParm(inp, 0);
4763 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4765 osi_Log1(smb_logp, "SMB close fid %d", fid);
4767 fid = smb_ChainFID(fid, inp);
4768 fidp = smb_FindFID(vcp, fid, 0);
4770 return CM_ERROR_BADFD;
4773 userp = smb_GetUser(vcp, inp);
4775 lock_ObtainMutex(&fidp->mx);
4777 /* Don't jump the gun on an async raw write */
4778 while (fidp->raw_writers) {
4779 lock_ReleaseMutex(&fidp->mx);
4780 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4781 lock_ObtainMutex(&fidp->mx);
4784 fidp->flags |= SMB_FID_DELETE;
4786 /* watch for ioctl closes, and read-only opens */
4787 if (fidp->scp != NULL
4788 && (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4789 == SMB_FID_OPENWRITE) {
4790 if (dosTime != 0 && dosTime != -1) {
4791 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4792 /* This fixes defect 10958 */
4793 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4794 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
4796 code = cm_FSync(fidp->scp, userp, &req);
4801 if (fidp->flags & SMB_FID_DELONCLOSE) {
4802 cm_scache_t *dscp = fidp->NTopen_dscp;
4803 char *pathp = fidp->NTopen_pathp;
4806 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
4807 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
4808 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
4809 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4810 smb_NotifyChange(FILE_ACTION_REMOVED,
4811 FILE_NOTIFY_CHANGE_DIR_NAME,
4812 dscp, fullPathp, NULL, TRUE);
4816 code = cm_Unlink(dscp, fullPathp, userp, &req);
4817 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4818 smb_NotifyChange(FILE_ACTION_REMOVED,
4819 FILE_NOTIFY_CHANGE_FILE_NAME,
4820 dscp, fullPathp, NULL, TRUE);
4824 lock_ReleaseMutex(&fidp->mx);
4826 if (fidp->flags & SMB_FID_NTOPEN) {
4827 cm_ReleaseSCache(fidp->NTopen_dscp);
4828 free(fidp->NTopen_pathp);
4830 if (fidp->NTopen_wholepathp)
4831 free(fidp->NTopen_wholepathp);
4833 smb_ReleaseFID(fidp);
4834 cm_ReleaseUser(userp);
4839 * smb_ReadData -- common code for Read, Read And X, and Raw Read
4842 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4843 cm_user_t *userp, long *readp)
4845 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4846 cm_user_t *userp, long *readp, int dosflag)
4853 osi_hyper_t fileLength;
4855 osi_hyper_t lastByte;
4856 osi_hyper_t bufferOffset;
4857 long bufIndex, nbytes;
4867 lock_ObtainMutex(&fidp->mx);
4869 lock_ObtainMutex(&scp->mx);
4871 if (offset.HighPart == 0) {
4872 chunk = offset.LowPart >> cm_logChunkSize;
4873 if (chunk != fidp->curr_chunk) {
4874 fidp->prev_chunk = fidp->curr_chunk;
4875 fidp->curr_chunk = chunk;
4877 if (fidp->curr_chunk == fidp->prev_chunk + 1)
4881 /* start by looking up the file's end */
4882 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4883 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4884 if (code) goto done;
4886 /* now we have the entry locked, look up the length */
4887 fileLength = scp->length;
4889 /* adjust count down so that it won't go past EOF */
4890 thyper.LowPart = count;
4891 thyper.HighPart = 0;
4892 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
4894 if (LargeIntegerGreaterThan(thyper, fileLength)) {
4895 /* we'd read past EOF, so just stop at fileLength bytes.
4896 * Start by computing how many bytes remain in the file.
4898 thyper = LargeIntegerSubtract(fileLength, offset);
4900 /* if we are past EOF, read 0 bytes */
4901 if (LargeIntegerLessThanZero(thyper))
4904 count = thyper.LowPart;
4909 /* now, copy the data one buffer at a time,
4910 * until we've filled the request packet
4913 /* if we've copied all the data requested, we're done */
4914 if (count <= 0) break;
4916 /* otherwise, load up a buffer of data */
4917 thyper.HighPart = offset.HighPart;
4918 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4919 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4922 buf_Release(bufferp);
4925 lock_ReleaseMutex(&scp->mx);
4927 lock_ObtainRead(&scp->bufCreateLock);
4928 code = buf_Get(scp, &thyper, &bufferp);
4929 lock_ReleaseRead(&scp->bufCreateLock);
4931 lock_ObtainMutex(&scp->mx);
4932 if (code) goto done;
4933 bufferOffset = thyper;
4935 /* now get the data in the cache */
4937 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4938 CM_SCACHESYNC_NEEDCALLBACK
4939 | CM_SCACHESYNC_READ);
4940 if (code) goto done;
4942 if (cm_HaveBuffer(scp, bufferp, 0)) break;
4944 /* otherwise, load the buffer and try again */
4945 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4949 buf_Release(bufferp);
4953 } /* if (wrong buffer) ... */
4955 /* now we have the right buffer loaded. Copy out the
4956 * data from here to the user's buffer.
4958 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4960 /* and figure out how many bytes we want from this buffer */
4961 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
4962 if (nbytes > count) nbytes = count; /* don't go past EOF */
4964 /* now copy the data */
4967 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
4970 memcpy(op, bufferp->datap + bufIndex, nbytes);
4972 /* adjust counters, pointers, etc. */
4975 thyper.LowPart = nbytes;
4976 thyper.HighPart = 0;
4977 offset = LargeIntegerAdd(thyper, offset);
4981 lock_ReleaseMutex(&scp->mx);
4982 lock_ReleaseMutex(&fidp->mx);
4984 buf_Release(bufferp);
4986 if (code == 0 && sequential)
4987 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
4993 * smb_WriteData -- common code for Write and Raw Write
4996 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4997 cm_user_t *userp, long *writtenp)
4999 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5000 cm_user_t *userp, long *writtenp, int dosflag)
5007 osi_hyper_t fileLength; /* file's length at start of write */
5008 osi_hyper_t minLength; /* don't read past this */
5009 long nbytes; /* # of bytes to transfer this iteration */
5011 osi_hyper_t thyper; /* hyper tmp variable */
5012 osi_hyper_t bufferOffset;
5013 long bufIndex; /* index in buffer where our data is */
5015 osi_hyper_t writeBackOffset; /* offset of region to write back when
5020 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5021 fidp->fid, offsetp->LowPart, count);
5029 lock_ObtainMutex(&fidp->mx);
5031 lock_ObtainMutex(&scp->mx);
5033 /* start by looking up the file's end */
5034 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5036 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5037 CM_SCACHESYNC_NEEDCALLBACK
5038 | CM_SCACHESYNC_SETSTATUS
5039 | CM_SCACHESYNC_GETSTATUS);
5040 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5045 /* make sure we have a writable FD */
5046 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5047 code = CM_ERROR_BADFDOP;
5051 /* now we have the entry locked, look up the length */
5052 fileLength = scp->length;
5053 minLength = fileLength;
5054 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5055 minLength = scp->serverLength;
5057 /* adjust file length if we extend past EOF */
5058 thyper.LowPart = count;
5059 thyper.HighPart = 0;
5060 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5061 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5062 /* we'd write past EOF, so extend the file */
5063 scp->mask |= CM_SCACHEMASK_LENGTH;
5064 scp->length = thyper;
5065 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5067 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5069 /* now, if the new position (thyper) and the old (offset) are in
5070 * different storeback windows, remember to store back the previous
5071 * storeback window when we're done with the write.
5073 if ((thyper.LowPart & (-cm_chunkSize)) !=
5074 (offset.LowPart & (-cm_chunkSize))) {
5075 /* they're different */
5077 writeBackOffset.HighPart = offset.HighPart;
5078 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5083 /* now, copy the data one buffer at a time, until we've filled the
5086 /* if we've copied all the data requested, we're done */
5087 if (count <= 0) break;
5089 /* handle over quota or out of space */
5090 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5091 *writtenp = written;
5095 /* otherwise, load up a buffer of data */
5096 thyper.HighPart = offset.HighPart;
5097 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5098 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5101 lock_ReleaseMutex(&bufferp->mx);
5102 buf_Release(bufferp);
5105 lock_ReleaseMutex(&scp->mx);
5107 lock_ObtainRead(&scp->bufCreateLock);
5108 code = buf_Get(scp, &thyper, &bufferp);
5109 lock_ReleaseRead(&scp->bufCreateLock);
5111 lock_ObtainMutex(&bufferp->mx);
5112 lock_ObtainMutex(&scp->mx);
5113 if (code) goto done;
5115 bufferOffset = thyper;
5117 /* now get the data in the cache */
5119 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5121 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5122 CM_SCACHESYNC_NEEDCALLBACK
5123 | CM_SCACHESYNC_WRITE
5124 | CM_SCACHESYNC_BUFLOCKED);
5125 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5130 /* If we're overwriting the entire buffer, or
5131 * if we're writing at or past EOF, mark the
5132 * buffer as current so we don't call
5133 * cm_GetBuffer. This skips the fetch from the
5134 * server in those cases where we're going to
5135 * obliterate all the data in the buffer anyway,
5136 * or in those cases where there is no useful
5137 * data at the server to start with.
5139 * Use minLength instead of scp->length, since
5140 * the latter has already been updated by this
5143 if (LargeIntegerGreaterThanOrEqualTo(
5144 bufferp->offset, minLength)
5145 || LargeIntegerEqualTo(offset, bufferp->offset)
5146 && (count >= buf_bufferSize
5147 || LargeIntegerGreaterThanOrEqualTo(
5148 LargeIntegerAdd(offset,
5149 ConvertLongToLargeInteger(count)),
5151 if (count < buf_bufferSize
5152 && bufferp->dataVersion == -1)
5153 memset(bufferp->datap, 0,
5155 bufferp->dataVersion = scp->dataVersion;
5158 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5160 /* otherwise, load the buffer and try again */
5161 lock_ReleaseMutex(&bufferp->mx);
5162 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5164 lock_ReleaseMutex(&scp->mx);
5165 lock_ObtainMutex(&bufferp->mx);
5166 lock_ObtainMutex(&scp->mx);
5170 lock_ReleaseMutex(&bufferp->mx);
5171 buf_Release(bufferp);
5175 } /* if (wrong buffer) ... */
5177 /* now we have the right buffer loaded. Copy out the
5178 * data from here to the user's buffer.
5180 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5182 /* and figure out how many bytes we want from this buffer */
5183 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5185 nbytes = count; /* don't go past end of request */
5187 /* now copy the data */
5190 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5193 memcpy(bufferp->datap + bufIndex, op, nbytes);
5194 buf_SetDirty(bufferp);
5196 /* and record the last writer */
5197 if (bufferp->userp != userp) {
5200 cm_ReleaseUser(bufferp->userp);
5201 bufferp->userp = userp;
5204 /* adjust counters, pointers, etc. */
5208 thyper.LowPart = nbytes;
5209 thyper.HighPart = 0;
5210 offset = LargeIntegerAdd(thyper, offset);
5214 lock_ReleaseMutex(&scp->mx);
5215 lock_ReleaseMutex(&fidp->mx);
5217 lock_ReleaseMutex(&bufferp->mx);
5218 buf_Release(bufferp);
5221 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5222 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5223 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5224 fidp->NTopen_dscp, fidp->NTopen_pathp,
5228 if (code == 0 && doWriteBack) {
5230 lock_ObtainMutex(&scp->mx);
5231 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5233 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5234 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5236 lock_ReleaseMutex(&scp->mx);
5237 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5238 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5241 osi_Log2(smb_logp, "smb_WriteData fid %d returns %d",
5246 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5249 long count, written = 0;
5254 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5256 int inDataBlockCount;
5258 fd = smb_GetSMBParm(inp, 0);
5259 count = smb_GetSMBParm(inp, 1);
5260 offset.HighPart = 0; /* too bad */
5261 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5263 op = smb_GetSMBData(inp, NULL);
5264 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5266 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5267 fd, offset.LowPart, count);
5269 fd = smb_ChainFID(fd, inp);
5270 fidp = smb_FindFID(vcp, fd, 0);
5272 return CM_ERROR_BADFD;
5275 if (fidp->flags & SMB_FID_IOCTL)
5276 return smb_IoctlWrite(fidp, vcp, inp, outp);
5278 userp = smb_GetUser(vcp, inp);
5280 /* special case: 0 bytes transferred means truncate to this position */
5286 truncAttr.mask = CM_ATTRMASK_LENGTH;
5287 truncAttr.length.LowPart = offset.LowPart;
5288 truncAttr.length.HighPart = 0;
5289 lock_ObtainMutex(&fidp->mx);
5290 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5291 lock_ReleaseMutex(&fidp->mx);
5292 smb_SetSMBParm(outp, 0, /* count */ 0);
5293 smb_SetSMBDataLength(outp, 0);
5294 fidp->flags |= SMB_FID_LENGTHSETDONE;
5299 * Work around bug in NT client
5301 * When copying a file, the NT client should first copy the data,
5302 * then copy the last write time. But sometimes the NT client does
5303 * these in the wrong order, so the data copies would inadvertently
5304 * cause the last write time to be overwritten. We try to detect this,
5305 * and don't set client mod time if we think that would go against the
5308 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5309 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5310 fidp->scp->clientModTime = time(NULL);
5314 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5316 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5318 if (code == 0 && written < count)
5319 code = CM_ERROR_PARTIALWRITE;
5321 /* set the packet data length to 3 bytes for the data block header,
5322 * plus the size of the data.
5324 smb_SetSMBParm(outp, 0, written);
5325 smb_SetSMBDataLength(outp, 0);
5328 smb_ReleaseFID(fidp);
5329 cm_ReleaseUser(userp);
5334 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5335 NCB *ncbp, raw_write_cont_t *rwcp)
5348 fd = smb_GetSMBParm(inp, 0);
5349 fidp = smb_FindFID(vcp, fd, 0);
5351 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5352 rwcp->offset.LowPart, rwcp->count);
5354 userp = smb_GetUser(vcp, inp);
5358 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5361 rawBuf = (dos_ptr) rwcp->buf;
5362 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5363 (unsigned char *) rawBuf, userp,
5367 if (rwcp->writeMode & 0x1) { /* synchronous */
5370 smb_FormatResponsePacket(vcp, inp, outp);
5371 op = (smb_t *) outp;
5372 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5373 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5374 smb_SetSMBDataLength(outp, 0);
5375 smb_SendPacket(vcp, outp);
5376 smb_FreePacket(outp);
5378 else { /* asynchronous */
5379 lock_ObtainMutex(&fidp->mx);
5380 fidp->raw_writers--;
5381 if (fidp->raw_writers == 0)
5382 thrd_SetEvent(fidp->raw_write_event);
5383 lock_ReleaseMutex(&fidp->mx);
5386 /* Give back raw buffer */
5387 lock_ObtainMutex(&smb_RawBufLock);
5389 *((char **)rawBuf) = smb_RawBufs;
5391 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5393 smb_RawBufs = rawBuf;
5394 lock_ReleaseMutex(&smb_RawBufLock);
5396 smb_ReleaseFID(fidp);
5397 cm_ReleaseUser(userp);
5400 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5405 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5408 long count, written = 0;
5415 unsigned short writeMode;
5422 fd = smb_GetSMBParm(inp, 0);
5423 totalCount = smb_GetSMBParm(inp, 1);
5424 count = smb_GetSMBParm(inp, 10);
5425 offset.HighPart = 0; /* too bad */
5426 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5427 writeMode = smb_GetSMBParm(inp, 7);
5429 op = (char *) inp->data;
5430 op += smb_GetSMBParm(inp, 11);
5433 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5434 fd, offset.LowPart, count, writeMode);
5436 fd = smb_ChainFID(fd, inp);
5437 fidp = smb_FindFID(vcp, fd, 0);
5439 return CM_ERROR_BADFD;
5442 userp = smb_GetUser(vcp, inp);
5445 * Work around bug in NT client
5447 * When copying a file, the NT client should first copy the data,
5448 * then copy the last write time. But sometimes the NT client does
5449 * these in the wrong order, so the data copies would inadvertently
5450 * cause the last write time to be overwritten. We try to detect this,
5451 * and don't set client mod time if we think that would go against the
5454 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5455 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5456 fidp->scp->clientModTime = time(NULL);
5460 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5462 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5464 if (code == 0 && written < count)
5465 code = CM_ERROR_PARTIALWRITE;
5467 /* Get a raw buffer */
5470 lock_ObtainMutex(&smb_RawBufLock);
5472 /* Get a raw buf, from head of list */
5473 rawBuf = smb_RawBufs;
5475 smb_RawBufs = *(char **)smb_RawBufs;
5477 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5481 code = CM_ERROR_USESTD;
5483 lock_ReleaseMutex(&smb_RawBufLock);
5486 /* Don't allow a premature Close */
5487 if (code == 0 && (writeMode & 1) == 0) {
5488 lock_ObtainMutex(&fidp->mx);
5489 fidp->raw_writers++;
5490 thrd_ResetEvent(fidp->raw_write_event);
5491 lock_ReleaseMutex(&fidp->mx);
5494 smb_ReleaseFID(fidp);
5495 cm_ReleaseUser(userp);
5498 smb_SetSMBParm(outp, 0, written);
5499 smb_SetSMBDataLength(outp, 0);
5500 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5507 rwcp->offset.HighPart = 0;
5508 rwcp->offset.LowPart = offset.LowPart + count;
5509 rwcp->count = totalCount - count;
5510 rwcp->writeMode = writeMode;
5511 rwcp->alreadyWritten = written;
5513 /* set the packet data length to 3 bytes for the data block header,
5514 * plus the size of the data.
5516 smb_SetSMBParm(outp, 0, 0xffff);
5517 smb_SetSMBDataLength(outp, 0);
5522 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5525 long count, finalCount;
5532 fd = smb_GetSMBParm(inp, 0);
5533 count = smb_GetSMBParm(inp, 1);
5534 offset.HighPart = 0; /* too bad */
5535 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5537 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5538 fd, offset.LowPart, count);
5540 fd = smb_ChainFID(fd, inp);
5541 fidp = smb_FindFID(vcp, fd, 0);
5543 return CM_ERROR_BADFD;
5546 if (fidp->flags & SMB_FID_IOCTL) {
5547 return smb_IoctlRead(fidp, vcp, inp, outp);
5550 userp = smb_GetUser(vcp, inp);
5552 /* remember this for final results */
5553 smb_SetSMBParm(outp, 0, count);
5554 smb_SetSMBParm(outp, 1, 0);
5555 smb_SetSMBParm(outp, 2, 0);
5556 smb_SetSMBParm(outp, 3, 0);
5557 smb_SetSMBParm(outp, 4, 0);
5559 /* set the packet data length to 3 bytes for the data block header,
5560 * plus the size of the data.
5562 smb_SetSMBDataLength(outp, count+3);
5564 /* get op ptr after putting in the parms, since otherwise we don't
5565 * know where the data really is.
5567 op = smb_GetSMBData(outp, NULL);
5569 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5570 *op++ = 1; /* data block marker */
5571 *op++ = (unsigned char) (count & 0xff);
5572 *op++ = (unsigned char) ((count >> 8) & 0xff);
5575 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5577 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5580 /* fix some things up */
5581 smb_SetSMBParm(outp, 0, finalCount);
5582 smb_SetSMBDataLength(outp, finalCount+3);
5584 smb_ReleaseFID(fidp);
5586 cm_ReleaseUser(userp);
5590 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5597 cm_scache_t *dscp; /* dir we're dealing with */
5598 cm_scache_t *scp; /* file we're creating */
5600 int initialModeBits;
5610 /* compute initial mode bits based on read-only flag in attributes */
5611 initialModeBits = 0777;
5613 tp = smb_GetSMBData(inp, NULL);
5614 pathp = smb_ParseASCIIBlock(tp, &tp);
5616 if (strcmp(pathp, "\\") == 0)
5617 return CM_ERROR_EXISTS;
5619 spacep = inp->spacep;
5620 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5622 userp = smb_GetUser(vcp, inp);
5624 caseFold = CM_FLAG_CASEFOLD;
5626 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5628 cm_ReleaseUser(userp);
5629 return CM_ERROR_NOSUCHPATH;
5632 code = cm_NameI(cm_rootSCachep, spacep->data,
5633 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5634 userp, tidPathp, &req, &dscp);
5637 cm_ReleaseUser(userp);
5641 /* otherwise, scp points to the parent directory. Do a lookup, and
5642 * fail if we find it. Otherwise, we do the create.
5648 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5649 if (scp) cm_ReleaseSCache(scp);
5650 if (code != CM_ERROR_NOSUCHFILE) {
5651 if (code == 0) code = CM_ERROR_EXISTS;
5652 cm_ReleaseSCache(dscp);
5653 cm_ReleaseUser(userp);
5657 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5658 setAttr.clientModTime = time(NULL);
5659 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5660 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5661 smb_NotifyChange(FILE_ACTION_ADDED,
5662 FILE_NOTIFY_CHANGE_DIR_NAME,
5663 dscp, lastNamep, NULL, TRUE);
5665 /* we don't need this any longer */
5666 cm_ReleaseSCache(dscp);
5669 /* something went wrong creating or truncating the file */
5670 cm_ReleaseUser(userp);
5674 /* otherwise we succeeded */
5675 smb_SetSMBDataLength(outp, 0);
5676 cm_ReleaseUser(userp);
5681 BOOL smb_IsLegalFilename(char *filename)
5684 * Find the longest substring of filename that does not contain
5685 * any of the chars in illegalChars. If that substring is less
5686 * than the length of the whole string, then one or more of the
5687 * illegal chars is in filename.
5689 if (strcspn(filename, illegalChars) < strlen(filename))
5695 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5703 cm_scache_t *dscp; /* dir we're dealing with */
5704 cm_scache_t *scp; /* file we're creating */
5706 int initialModeBits;
5718 excl = (inp->inCom == 0x03)? 0 : 1;
5720 attributes = smb_GetSMBParm(inp, 0);
5721 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5723 /* compute initial mode bits based on read-only flag in attributes */
5724 initialModeBits = 0666;
5725 if (attributes & 1) initialModeBits &= ~0222;
5727 tp = smb_GetSMBData(inp, NULL);
5728 pathp = smb_ParseASCIIBlock(tp, &tp);
5730 spacep = inp->spacep;
5731 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5733 userp = smb_GetUser(vcp, inp);
5735 caseFold = CM_FLAG_CASEFOLD;
5737 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5739 cm_ReleaseUser(userp);
5740 return CM_ERROR_NOSUCHPATH;
5742 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5743 userp, tidPathp, &req, &dscp);
5746 cm_ReleaseUser(userp);
5750 /* otherwise, scp points to the parent directory. Do a lookup, and
5751 * truncate the file if we find it, otherwise we create the file.
5753 if (!lastNamep) lastNamep = pathp;
5756 if (!smb_IsLegalFilename(lastNamep))
5757 return CM_ERROR_BADNTFILENAME;
5759 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5760 #ifdef DEBUG_VERBOSE
5763 hexp = osi_HexifyString( lastNamep );
5764 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5769 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5770 if (code && code != CM_ERROR_NOSUCHFILE) {
5771 cm_ReleaseSCache(dscp);
5772 cm_ReleaseUser(userp);
5776 /* if we get here, if code is 0, the file exists and is represented by
5777 * scp. Otherwise, we have to create it.
5781 /* oops, file shouldn't be there */
5782 cm_ReleaseSCache(dscp);
5783 cm_ReleaseSCache(scp);
5784 cm_ReleaseUser(userp);
5785 return CM_ERROR_EXISTS;
5788 setAttr.mask = CM_ATTRMASK_LENGTH;
5789 setAttr.length.LowPart = 0;
5790 setAttr.length.HighPart = 0;
5791 code = cm_SetAttr(scp, &setAttr, userp, &req);
5794 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5795 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5796 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5798 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5799 smb_NotifyChange(FILE_ACTION_ADDED,
5800 FILE_NOTIFY_CHANGE_FILE_NAME,
5801 dscp, lastNamep, NULL, TRUE);
5802 if (!excl && code == CM_ERROR_EXISTS) {
5803 /* not an exclusive create, and someone else tried
5804 * creating it already, then we open it anyway. We
5805 * don't bother retrying after this, since if this next
5806 * fails, that means that the file was deleted after
5807 * we started this call.
5809 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
5812 setAttr.mask = CM_ATTRMASK_LENGTH;
5813 setAttr.length.LowPart = 0;
5814 setAttr.length.HighPart = 0;
5815 code = cm_SetAttr(scp, &setAttr, userp, &req);
5820 /* we don't need this any longer */
5821 cm_ReleaseSCache(dscp);
5824 /* something went wrong creating or truncating the file */
5825 if (scp) cm_ReleaseSCache(scp);
5826 cm_ReleaseUser(userp);
5830 /* make sure we only open files */
5831 if (scp->fileType != CM_SCACHETYPE_FILE) {
5832 cm_ReleaseSCache(scp);
5833 cm_ReleaseUser(userp);
5834 return CM_ERROR_ISDIR;
5837 /* now all we have to do is open the file itself */
5838 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5841 /* save a pointer to the vnode */
5844 /* always create it open for read/write */
5845 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
5847 smb_ReleaseFID(fidp);
5849 smb_SetSMBParm(outp, 0, fidp->fid);
5850 smb_SetSMBDataLength(outp, 0);
5852 cm_Open(scp, 0, userp);
5854 cm_ReleaseUser(userp);
5855 /* leave scp held since we put it in fidp->scp */
5859 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5872 fd = smb_GetSMBParm(inp, 0);
5873 whence = smb_GetSMBParm(inp, 1);
5874 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5876 /* try to find the file descriptor */
5877 fd = smb_ChainFID(fd, inp);
5878 fidp = smb_FindFID(vcp, fd, 0);
5879 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5880 return CM_ERROR_BADFD;
5883 userp = smb_GetUser(vcp, inp);
5885 lock_ObtainMutex(&fidp->mx);
5887 lock_ObtainMutex(&scp->mx);
5888 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5889 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5892 /* offset from current offset */
5893 offset += fidp->offset;
5895 else if (whence == 2) {
5896 /* offset from current EOF */
5897 offset += scp->length.LowPart;
5899 fidp->offset = offset;
5900 smb_SetSMBParm(outp, 0, offset & 0xffff);
5901 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
5902 smb_SetSMBDataLength(outp, 0);
5904 lock_ReleaseMutex(&scp->mx);
5905 lock_ReleaseMutex(&fidp->mx);
5906 smb_ReleaseFID(fidp);
5907 cm_ReleaseUser(userp);
5911 /* dispatch all of the requests received in a packet. Due to chaining, this may
5912 * be more than one request.
5914 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5915 NCB *ncbp, raw_write_cont_t *rwcp)
5919 unsigned long code = 0;
5920 unsigned char *outWctp;
5921 int nparms; /* # of bytes of parameters */
5923 int nbytes; /* bytes of data, excluding count */
5926 unsigned short errCode;
5927 unsigned long NTStatus;
5929 unsigned char errClass;
5930 unsigned int oldGen;
5931 DWORD oldTime, newTime;
5933 /* get easy pointer to the data */
5934 smbp = (smb_t *) inp->data;
5936 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
5937 /* setup the basic parms for the initial request in the packet */
5938 inp->inCom = smbp->com;
5939 inp->wctp = &smbp->wct;
5941 inp->ncb_length = ncbp->ncb_length;
5946 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
5947 /* log it and discard it */
5952 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5953 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
5955 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
5956 1, ncbp->ncb_length, ptbuf, inp);
5957 DeregisterEventSource(h);
5959 osi_Log1(smb_logp, "SMB message too short, len %d",
5966 /* We are an ongoing op */
5967 thrd_Increment(&ongoingOps);
5969 /* set up response packet for receiving output */
5970 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
5971 smb_FormatResponsePacket(vcp, inp, outp);
5972 outWctp = outp->wctp;
5974 /* Remember session generation number and time */
5975 oldGen = sessionGen;
5976 oldTime = GetCurrentTime();
5978 while(inp->inCom != 0xff) {
5979 dp = &smb_dispatchTable[inp->inCom];
5981 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
5982 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
5983 code = outp->resumeCode;
5987 /* process each request in the packet; inCom, wctp and inCount
5988 * are already set up.
5990 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
5993 /* now do the dispatch */
5994 /* start by formatting the response record a little, as a default */
5995 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
5997 outWctp[1] = 0xff; /* no operation */
5998 outWctp[2] = 0; /* padding */
6003 /* not a chained request, this is a more reasonable default */
6004 outWctp[0] = 0; /* wct of zero */
6005 outWctp[1] = 0; /* and bcc (word) of zero */
6009 /* once set, stays set. Doesn't matter, since we never chain
6010 * "no response" calls.
6012 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6016 /* we have a recognized operation */
6018 if (inp->inCom == 0x1d)
6020 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6023 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6024 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
6025 code = (*(dp->procp)) (vcp, inp, outp);
6026 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6027 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6030 if (oldGen != sessionGen) {
6035 newTime = GetCurrentTime();
6036 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6037 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6038 newTime - oldTime, ncbp->ncb_length);
6040 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6041 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6042 DeregisterEventSource(h);
6044 osi_Log1(smb_logp, "Pkt straddled session startup, "
6045 "ncb length %d", ncbp->ncb_length);
6050 /* bad opcode, fail the request, after displaying it */
6053 #endif /* NOTSERVICE */
6057 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6058 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6059 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6060 if (code == IDCANCEL) showErrors = 0;
6063 code = CM_ERROR_BADOP;
6066 /* catastrophic failure: log as much as possible */
6067 if (code == CM_ERROR_BADSMB) {
6074 "Invalid SMB, ncb_length %d",
6077 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6078 sprintf(s, "Invalid SMB message, length %d",
6081 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6082 1, ncbp->ncb_length, ptbuf, smbp);
6083 DeregisterEventSource(h);
6086 #endif /* NOTSERVICE */
6088 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6092 code = CM_ERROR_INVAL;
6095 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6096 thrd_Decrement(&ongoingOps);
6101 /* now, if we failed, turn the current response into an empty
6102 * one, and fill in the response packet's error code.
6105 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6106 smb_MapNTError(code, &NTStatus);
6107 outWctp = outp->wctp;
6108 smbp = (smb_t *) &outp->data;
6109 if (code != CM_ERROR_PARTIALWRITE
6110 && code != CM_ERROR_BUFFERTOOSMALL
6111 && code != CM_ERROR_GSSCONTINUE) {
6112 /* nuke wct and bcc. For a partial
6113 * write or an in-process authentication handshake,
6114 * assume they're OK.
6120 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6121 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6122 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6123 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6124 smbp->flg2 |= 0x4000;
6128 smb_MapCoreError(code, vcp, &errCode, &errClass);
6129 outWctp = outp->wctp;
6130 smbp = (smb_t *) &outp->data;
6131 if (code != CM_ERROR_PARTIALWRITE) {
6132 /* nuke wct and bcc. For a partial
6133 * write, assume they're OK.
6139 smbp->errLow = (unsigned char) (errCode & 0xff);
6140 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6141 smbp->rcls = errClass;
6144 } /* error occurred */
6146 /* if we're here, we've finished one request. Look to see if
6147 * this is a chained opcode. If it is, setup things to process
6148 * the chained request, and setup the output buffer to hold the
6149 * chained response. Start by finding the next input record.
6151 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6152 break; /* not a chained req */
6153 tp = inp->wctp; /* points to start of last request */
6154 /* in a chained request, the first two
6155 * parm fields are required, and are
6156 * AndXCommand/AndXReserved and
6158 if (tp[0] < 2) break;
6159 if (tp[1] == 0xff) break; /* no more chained opcodes */
6161 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6164 /* and now append the next output request to the end of this
6165 * last request. Begin by finding out where the last response
6166 * ends, since that's where we'll put our new response.
6168 outWctp = outp->wctp; /* ptr to out parameters */
6169 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6170 nparms = outWctp[0] << 1;
6171 tp = outWctp + nparms + 1; /* now points to bcc field */
6172 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6173 tp += 2 /* for the count itself */ + nbytes;
6174 /* tp now points to the new output record; go back and patch the
6175 * second parameter (off2) to point to the new record.
6177 temp = (unsigned int)tp - ((unsigned int) outp->data);
6178 outWctp[3] = (unsigned char) (temp & 0xff);
6179 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6180 outWctp[2] = 0; /* padding */
6181 outWctp[1] = inp->inCom; /* next opcode */
6183 /* finally, setup for the next iteration */
6186 } /* while loop over all requests in the packet */
6188 /* done logging out, turn off logging-out flag */
6189 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6190 vcp->justLoggedOut = NULL;
6193 free(loggedOutName);
6194 loggedOutName = NULL;
6195 smb_ReleaseUID(loggedOutUserp);
6196 loggedOutUserp = NULL;
6200 /* now send the output packet, and return */
6202 smb_SendPacket(vcp, outp);
6203 thrd_Decrement(&ongoingOps);
6205 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6207 smb_ReleaseVC(active_vcp);
6209 "Replacing active_vcp %x with %x", active_vcp, vcp);
6213 last_msg_time = GetCurrentTime();
6215 else if (active_vcp == vcp) {
6216 smb_ReleaseVC(active_vcp);
6224 /* Wait for Netbios() calls to return, and make the results available to server
6225 * threads. Note that server threads can't wait on the NCBevents array
6226 * themselves, because NCB events are manual-reset, and the servers would race
6227 * each other to reset them.
6229 void smb_ClientWaiter(void *parmp)
6235 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6237 if (code == WAIT_OBJECT_0)
6240 /* error checking */
6241 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6243 int abandonIdx = code - WAIT_ABANDONED_0;
6244 afsi_log("Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6247 if (code == WAIT_IO_COMPLETION)
6249 afsi_log("Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6253 if (code == WAIT_TIMEOUT)
6255 afsi_log("Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6258 if (code == WAIT_FAILED)
6260 afsi_log("Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6263 idx = code - WAIT_OBJECT_0;
6265 /* check idx range! */
6266 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6268 /* this is fatal - log as much as possible */
6269 afsi_log("Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6273 thrd_ResetEvent(NCBevents[idx]);
6274 thrd_SetEvent(NCBreturns[0][idx]);
6280 * Try to have one NCBRECV request waiting for every live session. Not more
6281 * than one, because if there is more than one, it's hard to handle Write Raw.
6283 void smb_ServerWaiter(void *parmp)
6286 int idx_session, idx_NCB;
6294 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6296 if (code == WAIT_OBJECT_0)
6299 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6301 int abandonIdx = code - WAIT_ABANDONED_0;
6302 afsi_log("Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6305 if (code == WAIT_IO_COMPLETION)
6307 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6311 if (code == WAIT_TIMEOUT)
6313 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6316 if (code == WAIT_FAILED)
6318 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6321 idx_session = code - WAIT_OBJECT_0;
6323 /* check idx range! */
6324 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6326 /* this is fatal - log as much as possible */
6327 afsi_log("Fatal: session idx [ %d ] out of range.\n", idx_session);
6333 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6335 if (code == WAIT_OBJECT_0)
6338 /* error checking */
6339 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6341 int abandonIdx = code - WAIT_ABANDONED_0;
6342 afsi_log("Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6345 if (code == WAIT_IO_COMPLETION)
6347 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6351 if (code == WAIT_TIMEOUT)
6353 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6356 if (code == WAIT_FAILED)
6358 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6361 idx_NCB = code - WAIT_OBJECT_0;
6363 /* check idx range! */
6364 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6366 /* this is fatal - log as much as possible */
6367 afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6371 /* Link them together */
6372 NCBsessions[idx_NCB] = idx_session;
6375 ncbp = NCBs[idx_NCB];
6377 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6379 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6380 ncbp->ncb_command = NCBRECV | ASYNCH;
6381 ncbp->ncb_lana_num = lanas[idx_session];
6383 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6384 ncbp->ncb_event = NCBevents[idx_NCB];
6385 ncbp->ncb_length = SMB_PACKETSIZE;
6388 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6389 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6390 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6391 ncbp->ncb_length = SMB_PACKETSIZE;
6392 Netbios(ncbp, dos_ncb);
6398 * The top level loop for handling SMB request messages. Each server thread
6399 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6400 * NCB and buffer for the incoming request are loaned to us.
6402 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6403 * to immediately send a request for the rest of the data. This must come
6404 * before any other traffic for that session, so we delay setting the session
6405 * event until that data has come in.
6407 void smb_Server(VOID *parmp)
6409 int myIdx = (int) parmp;
6413 smb_packet_t *outbufp;
6415 int idx_NCB, idx_session;
6417 smb_vc_t *vcp = NULL;
6424 outbufp = GetPacket();
6425 outbufp->ncbp = outncbp;
6429 /* check for demo expiration */
6431 unsigned long tod = time((void *) 0);
6432 if (tod > EXPIREDATE) {
6433 (*smb_MBfunc)(NULL, "AFS demo expiration",
6435 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6439 #endif /* !NOEXPIRE */
6441 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6443 if (code == WAIT_OBJECT_0) {
6447 /* error checking */
6448 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6450 int abandonIdx = code - WAIT_ABANDONED_0;
6451 afsi_log("Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6454 if (code == WAIT_IO_COMPLETION)
6456 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6460 if (code == WAIT_TIMEOUT)
6462 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6465 if (code == WAIT_FAILED)
6467 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6470 idx_NCB = code - WAIT_OBJECT_0;
6472 /* check idx range! */
6473 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6475 /* this is fatal - log as much as possible */
6476 afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6480 ncbp = NCBs[idx_NCB];
6482 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6484 idx_session = NCBsessions[idx_NCB];
6485 rc = ncbp->ncb_retcode;
6487 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6488 osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6491 case NRC_GOODRET: break;
6494 /* Can this happen? Or is it just my
6501 /* Client closed session */
6502 if (reportSessionStartups)
6504 afsi_log("session [ %d ] closed", idx_session);
6506 dead_sessions[idx_session] = TRUE;
6509 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6510 /* Should also release vcp. [done] 2004-05-11 jaltman
6512 * sanity check that all TID's are gone.
6514 * TODO: check if we could use LSNs[idx_session] instead,
6515 * also cleanup after dead vcp
6520 "dead_vcp already set, %x",
6522 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6524 "setting dead_vcp %x, user struct %x",
6528 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6530 if (vcp->justLoggedOut) {
6532 loggedOutTime = vcp->logoffTime;
6534 strdup(vcp->justLoggedOut->unp->name);
6535 loggedOutUserp = vcp->justLoggedOut;
6536 lock_ObtainWrite(&smb_rctLock);
6537 loggedOutUserp->refCount++;
6538 lock_ReleaseWrite(&smb_rctLock);
6544 /* Treat as transient error */
6551 osi_Log1(smb_logp, "dispatch smb recv failed, message incomplete, ncb_length %d",
6553 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6554 sprintf(s, "SMB message incomplete, length %d",
6557 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6559 ncbp->ncb_length, ptbuf,
6561 DeregisterEventSource(h);
6564 "dispatch smb recv failed, message incomplete, ncb_length %d",
6567 "SMB message incomplete, "
6568 "length %d", ncbp->ncb_length);
6572 * We used to discard the packet.
6573 * Instead, try handling it normally.
6581 /* A weird error code. Log it, sleep, and
6583 if (vcp && vcp->errorCount++ > 3) {
6584 afsi_log("session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6585 dead_sessions[idx_session] = TRUE;
6589 thrd_SetEvent(SessionEvents[idx_session]);
6594 /* Success, so now dispatch on all the data in the packet */
6596 smb_concurrentCalls++;
6597 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6598 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6602 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6604 * If at this point vcp is NULL (implies that packet was invalid)
6605 * then we are in big trouble. This means either :
6606 * a) we have the wrong NCB.
6607 * b) Netbios screwed up the call.
6608 * Obviously this implies that
6609 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6610 * lanas[idx_session] != ncbp->ncb_lana_num )
6611 * Either way, we can't do anything with this packet.
6612 * Log, sleep and resume.
6621 "LSNs[idx_session]=[%d],"
6622 "lanas[idx_session]=[%d],"
6623 "ncbp->ncb_lsn=[%d],"
6624 "ncbp->ncb_lana_num=[%d]",
6628 ncbp->ncb_lana_num);
6632 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6634 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6635 DeregisterEventSource(h);
6638 /* Also log in the trace log. */
6639 osi_Log4(smb_logp, "Server: BAD VCP!"
6640 "LSNs[idx_session]=[%d],"
6641 "lanas[idx_session]=[%d],"
6642 "ncbp->ncb_lsn=[%d],"
6643 "ncbp->ncb_lana_num=[%d]",
6647 ncbp->ncb_lana_num);
6649 /* thrd_Sleep(1000); Don't bother sleeping */
6650 thrd_SetEvent(SessionEvents[idx_session]);
6651 smb_concurrentCalls--;
6656 vcp->errorCount = 0;
6657 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6659 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6660 /* copy whole packet to virtual memory */
6661 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6663 bufp->dos_pkt / 16, bufp);*/
6665 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6667 smbp = (smb_t *)bufp->data;
6670 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6674 if (smbp->com == 0x1d) {
6675 /* Special handling for Write Raw */
6676 raw_write_cont_t rwc;
6677 EVENT_HANDLE rwevent;
6678 char eventName[MAX_PATH];
6680 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6681 if (rwc.code == 0) {
6682 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6683 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6684 afsi_log("Event Object Already Exists: %s", eventName);
6685 ncbp->ncb_command = NCBRECV | ASYNCH;
6686 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6687 ncbp->ncb_lana_num = vcp->lana;
6688 ncbp->ncb_buffer = rwc.buf;
6689 ncbp->ncb_length = 65535;
6690 ncbp->ncb_event = rwevent;
6694 Netbios(ncbp, dos_ncb);
6696 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6697 thrd_CloseHandle(rwevent);
6699 thrd_SetEvent(SessionEvents[idx_session]);
6701 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6702 } else if (smbp->com == 0xa0) {
6704 * Serialize the handling for NT Transact
6707 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6708 thrd_SetEvent(SessionEvents[idx_session]);
6710 thrd_SetEvent(SessionEvents[idx_session]);
6711 /* TODO: what else needs to be serialized? */
6712 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6714 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6716 __except( smb_ServerExceptionFilter() ) {
6720 smb_concurrentCalls--;
6723 thrd_SetEvent(NCBavails[idx_NCB]);
6730 * Exception filter for the server threads. If an exception occurs in the
6731 * dispatch routines, which is where exceptions are most common, then do a
6732 * force trace and give control to upstream exception handlers. Useful for
6735 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6736 DWORD smb_ServerExceptionFilter(void) {
6737 /* While this is not the best time to do a trace, if it succeeds, then
6738 * we have a trace (assuming tracing was enabled). Otherwise, this should
6739 * throw a second exception.
6744 ptbuf[0] = "Unhandled exception forcing trace";
6746 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6748 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6749 DeregisterEventSource(h);
6752 afsd_ForceTrace(TRUE);
6753 return EXCEPTION_CONTINUE_SEARCH;
6758 * Create a new NCB and associated events, packet buffer, and "space" buffer.
6759 * If the number of server threads is M, and the number of live sessions is
6760 * N, then the number of NCB's in use at any time either waiting for, or
6761 * holding, received messages is M + N, so that is how many NCB's get created.
6763 void InitNCBslot(int idx)
6765 struct smb_packet *bufp;
6766 EVENT_HANDLE retHandle;
6768 char eventName[MAX_PATH];
6770 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6772 NCBs[idx] = GetNCB();
6773 sprintf(eventName,"NCBavails[%d]", idx);
6774 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6775 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6776 afsi_log("Event Object Already Exists: %s", eventName);
6778 sprintf(eventName,"NCBevents[%d]", idx);
6779 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
6780 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6781 afsi_log("Event Object Already Exists: %s", eventName);
6783 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
6784 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6785 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6786 afsi_log("Event Object Already Exists: %s", eventName);
6787 for (i=0; i<smb_NumServerThreads; i++)
6788 NCBreturns[i][idx] = retHandle;
6790 bufp->spacep = cm_GetSpace();
6794 /* listen for new connections */
6795 void smb_Listener(void *parmp)
6803 char rname[NCBNAMSZ+1];
6804 char cname[MAX_COMPUTERNAME_LENGTH+1];
6805 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
6810 int lana = (int) parmp;
6814 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6817 /* retrieve computer name */
6818 GetComputerName(cname, &cnamelen);
6822 memset(ncbp, 0, sizeof(NCB));
6826 /* check for demo expiration */
6828 unsigned long tod = time((void *) 0);
6829 if (tod > EXPIREDATE) {
6830 (*smb_MBfunc)(NULL, "AFS demo expiration",
6832 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6840 #endif /* !NOEXPIRE */
6842 ncbp->ncb_command = NCBLISTEN;
6843 ncbp->ncb_rto = 0; /* No receive timeout */
6844 ncbp->ncb_sto = 0; /* No send timeout */
6846 /* pad out with spaces instead of null termination */
6847 len = strlen(smb_localNamep);
6848 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
6849 for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
6851 strcpy(ncbp->ncb_callname, "*");
6852 for(i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
6854 ncbp->ncb_lana_num = lana;
6857 code = Netbios(ncbp);
6859 code = Netbios(ncbp, dos_ncb);
6868 /* terminate silently if shutdown flag is set */
6869 if (smbShutdownFlag == 1) {
6878 "NCBLISTEN lana=%d failed with code %d",
6879 ncbp->ncb_lana_num, code);
6881 "Client exiting due to network failure. Please restart client.\n");
6885 "Client exiting due to network failure. Please restart client.\n"
6886 "NCBLISTEN lana=%d failed with code %d",
6887 ncbp->ncb_lana_num, code);
6889 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
6890 MB_OK|MB_SERVICE_NOTIFICATION);
6891 osi_assert(tbuffer);
6894 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
6895 ncbp->ncb_lana_num, code);
6896 fprintf(stderr, "\nClient exiting due to network failure "
6897 "(possibly due to power-saving mode)\n");
6898 fprintf(stderr, "Please restart client.\n");
6899 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
6903 /* check for remote conns */
6904 /* first get remote name and insert null terminator */
6905 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
6906 for (i=NCBNAMSZ; i>0; i--) {
6907 if (rname[i-1] != ' ' && rname[i-1] != 0) {
6913 /* compare with local name */
6915 if (strncmp(rname, cname, NCBNAMSZ) != 0)
6916 flags |= SMB_VCFLAG_REMOTECONN;
6918 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
6920 lock_ObtainMutex(&smb_ListenerLock);
6922 /* New generation */
6925 /* Log session startup */
6927 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
6929 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
6931 afsi_log("New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
6932 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname, ongoingOps);
6934 if (reportSessionStartups) {
6940 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6941 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
6943 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
6945 DeregisterEventSource(h);
6947 afsi_log("NCBLISTEN completed, call from %s",rname);
6948 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
6951 fprintf(stderr, "%s: New session %d starting from host %s\n",
6952 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
6957 /* now ncbp->ncb_lsn is the connection ID */
6958 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
6959 vcp->flags |= flags;
6960 strcpy(vcp->rname, rname);
6962 /* Allocate slot in session arrays */
6963 /* Re-use dead session if possible, otherwise add one more */
6964 /* But don't look at session[0], it is reserved */
6965 for (i = 1; i < numSessions; i++) {
6966 if (dead_sessions[i]) {
6967 afsi_log("connecting to dead session [ %d ]", i);
6968 dead_sessions[i] = FALSE;
6973 /* assert that we do not exceed the maximum number of sessions or NCBs.
6974 * we should probably want to wait for a session to be freed in case
6978 osi_assert(i < Sessionmax - 1);
6979 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
6981 LSNs[i] = ncbp->ncb_lsn;
6982 lanas[i] = ncbp->ncb_lana_num;
6984 if (i == numSessions) {
6985 /* Add new NCB for new session */
6986 char eventName[MAX_PATH];
6988 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
6990 InitNCBslot(numNCBs);
6992 thrd_SetEvent(NCBavails[0]);
6993 thrd_SetEvent(NCBevents[0]);
6994 for (j = 0; j < smb_NumServerThreads; j++)
6995 thrd_SetEvent(NCBreturns[j][0]);
6996 /* Also add new session event */
6997 sprintf(eventName, "SessionEvents[%d]", i);
6998 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6999 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7000 afsi_log("Event Object Already Exists: %s", eventName);
7002 afsi_log("increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7003 thrd_SetEvent(SessionEvents[0]);
7005 thrd_SetEvent(SessionEvents[i]);
7008 lock_ReleaseMutex(&smb_ListenerLock);
7010 } /* dispatch while loop */
7013 /* initialize Netbios */
7014 void smb_NetbiosInit()
7020 int i, lana, code, l;
7022 int delname_tried=0;
7025 OSVERSIONINFO Version;
7027 /* AFAIK, this is the default for the ms loopback adapter.*/
7028 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
7029 /*******************************************************************/
7031 /* Get the version of Windows */
7032 memset(&Version, 0x00, sizeof(Version));
7033 Version.dwOSVersionInfoSize = sizeof(Version);
7034 GetVersionEx(&Version);
7036 /* setup the NCB system */
7039 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7043 if (smb_LANadapter == -1) {
7044 ncbp->ncb_command = NCBENUM;
7045 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7046 ncbp->ncb_length = sizeof(lana_list);
7047 code = Netbios(ncbp);
7049 sprintf(s, "Netbios NCBENUM error code %d", code);
7051 osi_panic(s, __FILE__, __LINE__);
7055 lana_list.length = 1;
7056 lana_list.lana[0] = smb_LANadapter;
7059 for (i = 0; i < lana_list.length; i++) {
7060 /* reset the adaptor: in Win32, this is required for every process, and
7061 * acts as an init call, not as a real hardware reset.
7063 ncbp->ncb_command = NCBRESET;
7064 ncbp->ncb_callname[0] = 100;
7065 ncbp->ncb_callname[2] = 100;
7066 ncbp->ncb_lana_num = lana_list.lana[i];
7067 code = Netbios(ncbp);
7069 code = ncbp->ncb_retcode;
7071 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7073 lana_list.lana[i] = 255; /* invalid lana */
7075 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7080 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7081 we will just fake the LANA list */
7082 if (smb_LANadapter == -1) {
7083 for (i = 0; i < 8; i++)
7084 lana_list.lana[i] = i;
7085 lana_list.length = 8;
7088 lana_list.length = 1;
7089 lana_list.lana[0] = smb_LANadapter;
7093 /* and declare our name so we can receive connections */
7094 memset(ncbp, 0, sizeof(*ncbp));
7095 len=lstrlen(smb_localNamep);
7096 memset(smb_sharename,' ',NCBNAMSZ);
7097 memcpy(smb_sharename,smb_localNamep,len);
7098 sprintf(s, "lana_list.length %d", lana_list.length);
7101 /* Keep the name so we can unregister it later */
7102 for (l = 0; l < lana_list.length; l++) {
7103 lana = lana_list.lana[l];
7105 ncbp->ncb_command = NCBADDNAME;
7106 ncbp->ncb_lana_num = lana;
7107 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7109 code = Netbios(ncbp);
7111 code = Netbios(ncbp, dos_ncb);
7114 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7115 lana, code, ncbp->ncb_retcode,ncbp->ncb_cmd_cplt);
7117 char name[NCBNAMSZ+1];
7119 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7120 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
7123 if (code == 0) code = ncbp->ncb_retcode;
7125 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
7127 /* we only use one LANA with djgpp */
7128 lana_list.lana[0] = lana;
7129 lana_list.length = 1;
7133 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7135 if (code == NRC_BRIDGE) { /* invalid LANA num */
7136 lana_list.lana[l] = 255;
7139 else if (code == NRC_DUPNAME) {
7140 afsi_log("Name already exists; try to delete it");
7141 memset(ncbp, 0, sizeof(*ncbp));
7142 ncbp->ncb_command = NCBDELNAME;
7143 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7144 ncbp->ncb_lana_num = lana;
7146 code = Netbios(ncbp);
7148 code = Netbios(ncbp, dos_ncb);
7150 if (code == 0) code = ncbp->ncb_retcode;
7152 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7155 if (code != 0 || delname_tried) {
7156 lana_list.lana[l] = 255;
7158 else if (code == 0) {
7159 if (!delname_tried) {
7167 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7169 lana_list.lana[l] = 255; /* invalid lana */
7170 osi_panic(s, __FILE__, __LINE__);
7174 lana_found = 1; /* at least one worked */
7181 osi_assert(lana_list.length >= 0);
7183 sprintf(s, "No valid LANA numbers found!");
7184 osi_panic(s, __FILE__, __LINE__);
7187 /* we're done with the NCB now */
7191 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7208 EVENT_HANDLE retHandle;
7209 char eventName[MAX_PATH];
7212 smb_MBfunc = aMBfunc;
7216 /* check for demo expiration */
7218 unsigned long tod = time((void *) 0);
7219 if (tod > EXPIREDATE) {
7221 (*smb_MBfunc)(NULL, "AFS demo expiration", "afsd",
7222 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
7225 fprintf(stderr, "AFS demo expiration\n");
7230 #endif /* !NOEXPIRE */
7233 smb_LANadapter = LANadapt;
7235 /* Initialize smb_localZero */
7236 myTime.tm_isdst = -1; /* compute whether on DST or not */
7237 myTime.tm_year = 70;
7243 smb_localZero = mktime(&myTime);
7245 /* Initialize kludge-GMT */
7246 smb_CalculateNowTZ();
7248 /* initialize the remote debugging log */
7251 /* remember the name */
7252 len = strlen(snamep);
7253 smb_localNamep = malloc(len+1);
7254 strcpy(smb_localNamep, snamep);
7255 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7257 /* and the global lock */
7258 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7259 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7261 /* Raw I/O data structures */
7262 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7264 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7266 /* 4 Raw I/O buffers */
7268 smb_RawBufs = calloc(65536,1);
7269 *((char **)smb_RawBufs) = NULL;
7270 for (i=0; i<3; i++) {
7271 char *rawBuf = calloc(65536,1);
7272 *((char **)rawBuf) = smb_RawBufs;
7273 smb_RawBufs = rawBuf;
7276 npar = 65536 >> 4; /* number of paragraphs */
7277 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7279 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7281 osi_panic("",__FILE__,__LINE__);
7284 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7287 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7289 _farpokel(_dos_ds, smb_RawBufs, NULL);
7290 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7291 npar = 65536 >> 4; /* number of paragraphs */
7292 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7294 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7296 osi_panic("",__FILE__,__LINE__);
7299 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7302 rawBuf = (seg * 16) + 0; /* DOS physical address */
7303 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7304 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7305 smb_RawBufs = rawBuf;
7309 /* global free lists */
7310 smb_ncbFreeListp = NULL;
7311 smb_packetFreeListp = NULL;
7315 /* Initialize listener and server structures */
7317 memset(dead_sessions, 0, sizeof(dead_sessions));
7318 sprintf(eventName, "SessionEvents[0]");
7319 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7320 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7321 afsi_log("Event Object Already Exists: %s", eventName);
7323 smb_NumServerThreads = nThreads;
7324 sprintf(eventName, "NCBavails[0]");
7325 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7326 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7327 afsi_log("Event Object Already Exists: %s", eventName);
7328 sprintf(eventName, "NCBevents[0]");
7329 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7330 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7331 afsi_log("Event Object Already Exists: %s", eventName);
7332 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7333 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7334 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7335 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7336 afsi_log("Event Object Already Exists: %s", eventName);
7337 for (i = 0; i < smb_NumServerThreads; i++) {
7338 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7339 NCBreturns[i][0] = retHandle;
7341 for (i = 1; i <= nThreads; i++)
7343 numNCBs = nThreads + 1;
7345 /* Initialize dispatch table */
7346 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7347 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7348 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7349 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7350 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7351 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7352 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7353 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7354 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7355 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7356 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7357 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7358 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7359 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7360 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7361 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7362 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7363 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7364 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7365 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7366 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7367 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7368 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7369 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7370 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7371 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7372 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7373 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7374 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7375 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7376 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7377 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7378 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7379 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7380 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7381 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7382 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7383 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7384 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7385 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7386 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7387 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7388 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7389 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7390 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7391 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7392 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7393 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7394 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7395 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7396 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7397 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7398 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7399 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7400 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7401 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7402 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7403 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7404 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7405 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7406 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7407 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7408 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;
7409 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;
7410 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;
7411 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;
7412 for(i=0xd0; i<= 0xd7; i++) {
7413 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7416 /* setup tran 2 dispatch table */
7417 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7418 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7419 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7420 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7421 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7422 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7423 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7424 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7425 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7426 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7427 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7428 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7429 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7430 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2MKDir;
7432 /* setup the rap dispatch table */
7433 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
7434 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
7435 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
7436 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
7437 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
7441 /* if we are doing SMB authentication we have register outselves as a logon process */
7442 if (smb_authType != SMB_AUTH_NONE) {
7444 LSA_STRING afsProcessName;
7445 LSA_OPERATIONAL_MODE dummy; /*junk*/
7447 afsProcessName.Buffer = "OpenAFSClientDaemon";
7448 afsProcessName.Length = strlen(afsProcessName.Buffer);
7449 afsProcessName.MaximumLength = afsProcessName.Length + 1;
7451 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7453 if (nts == STATUS_SUCCESS) {
7454 LSA_STRING packageName;
7455 /* we are registered. Find out the security package id */
7456 packageName.Buffer = MSV1_0_PACKAGE_NAME;
7457 packageName.Length = strlen(packageName.Buffer);
7458 packageName.MaximumLength = packageName.Length + 1;
7459 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7460 if (nts == STATUS_SUCCESS) {
7461 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7462 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7463 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7465 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7468 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7471 if (nts != STATUS_SUCCESS) {
7472 /* something went wrong. We report the error and revert back to no authentication
7473 because we can't perform any auth requests without a successful lsa handle
7474 or sec package id. */
7475 afsi_log("Reverting to NO SMB AUTH");
7476 smb_authType = SMB_AUTH_NONE;
7479 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
7480 * time prevents the failure of authentication when logged into Windows with an
7481 * external Kerberos principal mapped to a local account.
7483 else if ( smb_authType == SMB_AUTH_EXTENDED) {
7484 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
7485 * then the only option is NTLMSSP anyway; so just fallback.
7490 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7491 if (secBlobLength == 0) {
7492 smb_authType = SMB_AUTH_NTLM;
7493 afsi_log("Reverting to SMB AUTH NTLM");
7502 /* Now get ourselves a domain name. */
7503 /* For now we are using the local computer name as the domain name.
7504 * It is actually the domain for local logins, and we are acting as
7505 * a local SMB server.
7507 bufsize = sizeof(smb_ServerDomainName) - 1;
7508 GetComputerName(smb_ServerDomainName, &bufsize);
7509 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7510 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7513 /* Start listeners, waiters, servers, and daemons */
7515 for (i = 0; i < lana_list.length; i++) {
7516 if (lana_list.lana[i] == 255) continue;
7517 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7518 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7519 osi_assert(phandle != NULL);
7520 thrd_CloseHandle(phandle);
7524 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7525 NULL, 0, &lpid, "smb_ClientWaiter");
7526 osi_assert(phandle != NULL);
7527 thrd_CloseHandle(phandle);
7530 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7531 NULL, 0, &lpid, "smb_ServerWaiter");
7532 osi_assert(phandle != NULL);
7533 thrd_CloseHandle(phandle);
7535 for (i=0; i<nThreads; i++) {
7536 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7537 (void *) i, 0, &lpid, "smb_Server");
7538 osi_assert(phandle != NULL);
7539 thrd_CloseHandle(phandle);
7542 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7543 NULL, 0, &lpid, "smb_Daemon");
7544 osi_assert(phandle != NULL);
7545 thrd_CloseHandle(phandle);
7547 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7548 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7549 osi_assert(phandle != NULL);
7550 thrd_CloseHandle(phandle);
7559 void smb_Shutdown(void)
7568 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7570 /* setup the NCB system */
7573 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7576 /* Block new sessions by setting shutdown flag */
7577 smbShutdownFlag = 1;
7579 /* Hang up all sessions */
7580 memset((char *)ncbp, 0, sizeof(NCB));
7581 for (i = 1; i < numSessions; i++)
7583 if (dead_sessions[i])
7586 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7587 ncbp->ncb_command = NCBHANGUP;
7588 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7589 ncbp->ncb_lsn = LSNs[i];
7591 code = Netbios(ncbp);
7593 code = Netbios(ncbp, dos_ncb);
7595 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7596 if (code == 0) code = ncbp->ncb_retcode;
7598 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7599 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7603 /* Delete Netbios name */
7604 memset((char *)ncbp, 0, sizeof(NCB));
7605 for (i = 0; i < lana_list.length; i++) {
7606 if (lana_list.lana[i] == 255) continue;
7607 ncbp->ncb_command = NCBDELNAME;
7608 ncbp->ncb_lana_num = lana_list.lana[i];
7609 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7611 code = Netbios(ncbp);
7613 code = Netbios(ncbp, dos_ncb);
7615 if (code == 0) code = ncbp->ncb_retcode;
7617 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7618 ncbp->ncb_lana_num, code);
7624 /* Get the UNC \\<servername>\<sharename> prefix. */
7625 char *smb_GetSharename()
7629 /* Make sure we have been properly initialized. */
7630 if (smb_localNamep == NULL)
7633 /* Allocate space for \\<servername>\<sharename>, plus the
7636 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7637 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7643 void smb_LogPacket(smb_packet_t *packet)
7646 unsigned length, paramlen, datalen, i, j;
7648 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7652 osi_Log0(smb_logp, "*** SMB packet dump ***");
7654 vp = (BYTE *) packet->data;
7656 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7657 length = paramlen + 2 + datalen;
7660 for(i=0;i < length; i+=16)
7662 memset( buf, ' ', 80 );
7667 buf[strlen(buf)] = ' ';
7669 cp = (BYTE*) buf + 7;
7671 for(j=0;j < 16 && (i+j)<length; j++)
7673 *(cp++) = hex[vp[i+j] >> 4];
7674 *(cp++) = hex[vp[i+j] & 0xf];
7684 for(j=0;j < 16 && (i+j)<length;j++)
7686 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7697 osi_Log0( smb_logp, buf );
7700 osi_Log0(smb_logp, "*** End SMB packet dump ***");
7704 #endif /* NOTSERVICE */
7706 int smb_DumpVCP(FILE *outputFile, char *cookie)
7713 lock_ObtainRead(&smb_rctLock);
7715 sprintf(output, "begin dumping vcpsp\n");
7716 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7718 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7722 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7723 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7724 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7726 sprintf(output, "begin dumping fidsp\n");
7727 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7729 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7731 sprintf(output, "%s -- fidp=0x%08X, refCount=%d, fid=%d, vcp=0x%08X, scp=0x%08X, ioctlp=0x%08X, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
7732 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
7733 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
7734 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7735 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7738 sprintf(output, "done dumping fidsp\n");
7739 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7742 sprintf(output, "done dumping vcpsp\n");
7743 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7745 lock_ReleaseRead(&smb_rctLock);