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 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
1033 tidp = smb_FindTID(vcp, tid, 0);
1036 tpath = tidp->pathname;
1037 smb_ReleaseTID(tidp);
1041 /* check to see if we have a chained fid, that is, a fid that comes from an
1042 * OpenAndX message that ran earlier in this packet. In this case, the fid
1043 * field in a read, for example, request, isn't set, since the value is
1044 * supposed to be inherited from the openAndX call.
1046 int smb_ChainFID(int fid, smb_packet_t *inp)
1048 if (inp->fid == 0 || inp->inCount == 0)
1054 /* are we a priv'd user? What does this mean on NT? */
1055 int smb_SUser(cm_user_t *userp)
1060 /* find a file ID. If we pass in 0 we select an used File ID.
1061 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1062 * smb_fid_t data structure if desired File ID cannot be found.
1064 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1069 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1072 lock_ObtainWrite(&smb_rctLock);
1073 /* figure out if we need to allocate a new file ID */
1076 fid = vcp->fidCounter;
1080 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1081 if (fid == fidp->fid) {
1092 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1093 char eventName[MAX_PATH];
1095 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1096 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1097 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1098 afsi_log("Event Object Already Exists: %s", eventName);
1099 thrd_CloseHandle(event);
1106 fidp = malloc(sizeof(*fidp));
1107 memset(fidp, 0, sizeof(*fidp));
1108 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1112 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1114 fidp->curr_chunk = fidp->prev_chunk = -2;
1115 fidp->raw_write_event = event;
1117 vcp->fidCounter = fid+1;
1118 if (vcp->fidCounter == 0)
1119 vcp->fidCounter = 1;
1122 lock_ReleaseWrite(&smb_rctLock);
1126 void smb_ReleaseFID(smb_fid_t *fidp)
1129 smb_vc_t *vcp = NULL;
1130 smb_ioctl_t *ioctlp;
1136 lock_ObtainWrite(&smb_rctLock);
1137 osi_assert(fidp->refCount-- > 0);
1138 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1140 if (!(fidp->flags & SMB_FID_IOCTL))
1142 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1143 thrd_CloseHandle(fidp->raw_write_event);
1145 /* and see if there is ioctl stuff to free */
1146 ioctlp = fidp->ioctlp;
1148 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1149 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1150 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1156 /* do not call smb_ReleaseVC() because we already have the lock */
1159 lock_ReleaseWrite(&smb_rctLock);
1161 /* now release the scache structure */
1163 cm_ReleaseSCache(scp);
1167 * Case-insensitive search for one string in another;
1168 * used to find variable names in submount pathnames.
1170 static char *smb_stristr(char *str1, char *str2)
1174 for (cursor = str1; *cursor; cursor++)
1175 if (stricmp(cursor, str2) == 0)
1182 * Substitute a variable value for its name in a submount pathname. Variable
1183 * name has been identified by smb_stristr() and is in substr. Variable name
1184 * length (plus one) is in substr_size. Variable value is in newstr.
1186 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1191 strcpy(temp, substr + substr_size - 1);
1192 strcpy(substr, newstr);
1196 char VNUserName[] = "%USERNAME%";
1197 char VNLCUserName[] = "%LCUSERNAME%";
1198 char VNComputerName[] = "%COMPUTERNAME%";
1199 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1202 /* List available shares */
1203 int smb_ListShares()
1207 char shareBuf[4096];
1215 /*strcpy(shareNameList[num_shares], "all");
1216 strcpy(pathNameList[num_shares++], "/afs");*/
1217 fprintf(stderr, "The following shares are available:\n");
1218 fprintf(stderr, "Share Name (AFS Path)\n");
1219 fprintf(stderr, "---------------------\n");
1220 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1223 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1224 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1226 strcpy(sbmtpath, cm_confDir);
1228 strcat(sbmtpath, "/afsdsbmt.ini");
1229 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1230 shareBuf, sizeof(shareBuf),
1236 this_share = shareBuf;
1240 /*strcpy(shareNameList[num_shares], this_share);*/
1241 len = GetPrivateProfileString("AFS Submounts", this_share,
1248 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1251 if (*p == '\\') *p = '/'; /* change to / */
1255 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1256 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1259 while (*this_share != 0) this_share++; /* find next NUL */
1260 this_share++; /* skip past the NUL */
1261 } while (*this_share != 0); /* stop at final NUL */
1266 /* find a shareName in the table of submounts */
1267 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1271 char pathName[1024];
1276 char sbmtpath[MAX_PATH];
1281 DWORD allSubmount = 1;
1283 /* if allSubmounts == 0, only return the //mountRoot/all share
1284 * if in fact it has been been created in the subMounts table.
1285 * This is to allow sites that want to restrict access to the
1288 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1289 0, KEY_QUERY_VALUE, &parmKey);
1290 if (code == ERROR_SUCCESS) {
1291 len = sizeof(allSubmount);
1292 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1293 (BYTE *) &allSubmount, &len);
1294 if (code != ERROR_SUCCESS) {
1297 RegCloseKey (parmKey);
1300 if (allSubmount && _stricmp(shareName, "all") == 0) {
1305 /* In case, the all share is disabled we need to still be able
1306 * to handle ioctl requests
1308 if (_stricmp(shareName, "ioctl$") == 0) {
1309 *pathNamep = strdup("/.__ioctl__");
1313 if (_stricmp(shareName, "IPC$") == 0 ||
1314 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1315 _stricmp(shareName, "DESKTOP.INI") == 0
1322 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1323 0, KEY_QUERY_VALUE, &parmKey);
1324 if (code == ERROR_SUCCESS) {
1325 len = sizeof(pathName);
1326 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1327 (BYTE *) pathName, &len);
1328 if (code != ERROR_SUCCESS)
1330 RegCloseKey (parmKey);
1335 strcpy(sbmtpath, cm_confDir);
1336 strcat(sbmtpath, "/afsdsbmt.ini");
1337 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1338 pathName, sizeof(pathName), sbmtpath);
1340 if (len != 0 && len != sizeof(pathName) - 1) {
1341 /* We can accept either unix or PC style AFS pathnames. Convert
1342 * Unix-style to PC style here for internal use.
1345 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1346 p += strlen(cm_mountRoot); /* skip mount path */
1349 if (*q == '/') *q = '\\'; /* change to \ */
1355 if (var = smb_stristr(p, VNUserName)) {
1356 if (uidp && uidp->unp)
1357 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1359 smb_subst(p, var, sizeof(VNUserName)," ");
1361 else if (var = smb_stristr(p, VNLCUserName))
1363 if (uidp && uidp->unp)
1364 strcpy(temp, uidp->unp->name);
1368 smb_subst(p, var, sizeof(VNLCUserName), temp);
1370 else if (var = smb_stristr(p, VNComputerName))
1372 sizeTemp = sizeof(temp);
1373 GetComputerName((LPTSTR)temp, &sizeTemp);
1374 smb_subst(p, var, sizeof(VNComputerName), temp);
1376 else if (var = smb_stristr(p, VNLCComputerName))
1378 sizeTemp = sizeof(temp);
1379 GetComputerName((LPTSTR)temp, &sizeTemp);
1381 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1386 *pathNamep = strdup(p);
1389 else /* create \\<netbiosName>\<cellname> */
1391 char * p = shareName;
1398 /* Get the full name for this cell */
1399 code = cm_SearchCellFile(p, temp, 0, 0);
1400 #ifdef AFS_AFSDB_ENV
1401 if (code && cm_dnsEnabled) {
1403 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1406 /* construct the path */
1408 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1409 *pathNamep = strdup(strlwr(pathName));
1418 /* Client-side offline caching policy types */
1419 #define CSC_POLICY_MANUAL 0
1420 #define CSC_POLICY_DOCUMENTS 1
1421 #define CSC_POLICY_PROGRAMS 2
1422 #define CSC_POLICY_DISABLE 3
1424 int smb_FindShareCSCPolicy(char *shareName)
1430 int retval = CSC_POLICY_MANUAL;
1432 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1433 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1436 REG_OPTION_NON_VOLATILE,
1442 len = sizeof(policy);
1443 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1445 retval = CSC_POLICY_MANUAL;
1447 else if (stricmp(policy, "documents") == 0)
1449 retval = CSC_POLICY_DOCUMENTS;
1451 else if (stricmp(policy, "programs") == 0)
1453 retval = CSC_POLICY_PROGRAMS;
1455 else if (stricmp(policy, "disable") == 0)
1457 retval = CSC_POLICY_DISABLE;
1460 RegCloseKey(hkCSCPolicy);
1464 /* find a dir search structure by cookie value, and return it held.
1465 * Must be called with smb_globalLock held.
1467 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1469 smb_dirSearch_t *dsp;
1471 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1472 if (dsp->cookie == cookie) {
1473 if (dsp != smb_firstDirSearchp) {
1474 /* move to head of LRU queue, too, if we're not already there */
1475 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1476 smb_lastDirSearchp = (smb_dirSearch_t *)
1478 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1479 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1480 if (!smb_lastDirSearchp)
1481 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1490 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1492 lock_ObtainWrite(&smb_globalLock);
1493 dsp->flags |= SMB_DIRSEARCH_DELETE;
1494 lock_ReleaseWrite(&smb_globalLock);
1495 lock_ObtainMutex(&dsp->mx);
1496 if(dsp->scp != NULL) {
1497 lock_ObtainMutex(&dsp->scp->mx);
1498 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1499 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1500 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1501 dsp->scp->bulkStatProgress = hones;
1503 lock_ReleaseMutex(&dsp->scp->mx);
1505 lock_ReleaseMutex(&dsp->mx);
1508 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1514 lock_ObtainWrite(&smb_globalLock);
1515 osi_assert(dsp->refCount-- > 0);
1516 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1517 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1518 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1519 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1520 lock_FinalizeMutex(&dsp->mx);
1524 lock_ReleaseWrite(&smb_globalLock);
1526 /* do this now to avoid spurious locking hierarchy creation */
1527 if (scp) cm_ReleaseSCache(scp);
1530 /* find a dir search structure by cookie value, and return it held */
1531 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1533 smb_dirSearch_t *dsp;
1535 lock_ObtainWrite(&smb_globalLock);
1536 dsp = smb_FindDirSearchNL(cookie);
1537 lock_ReleaseWrite(&smb_globalLock);
1541 /* GC some dir search entries, in the address space expected by the specific protocol.
1542 * Must be called with smb_globalLock held; release the lock temporarily.
1544 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1545 void smb_GCDirSearches(int isV3)
1547 smb_dirSearch_t *prevp;
1548 smb_dirSearch_t *tp;
1549 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1553 victimCount = 0; /* how many have we got so far */
1554 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1555 /* we'll move tp from queue, so
1558 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1559 /* if no one is using this guy, and we're either in the new protocol,
1560 * or we're in the old one and this is a small enough ID to be useful
1561 * to the old protocol, GC this guy.
1563 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1564 /* hold and delete */
1565 tp->flags |= SMB_DIRSEARCH_DELETE;
1566 victimsp[victimCount++] = tp;
1570 /* don't do more than this */
1571 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1574 /* now release them */
1575 lock_ReleaseWrite(&smb_globalLock);
1576 for(i = 0; i < victimCount; i++) {
1577 smb_ReleaseDirSearch(victimsp[i]);
1579 lock_ObtainWrite(&smb_globalLock);
1582 /* function for allocating a dir search entry. We need these to remember enough context
1583 * since we don't get passed the path from call to call during a directory search.
1585 * Returns a held dir search structure, and bumps the reference count on the vnode,
1586 * since it saves a pointer to the vnode.
1588 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1590 smb_dirSearch_t *dsp;
1594 lock_ObtainWrite(&smb_globalLock);
1597 /* what's the biggest ID allowed in this version of the protocol */
1598 if (isV3) maxAllowed = 65535;
1599 else maxAllowed = 255;
1602 /* twice so we have enough tries to find guys we GC after one pass;
1603 * 10 extra is just in case I mis-counted.
1605 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1606 __FILE__, __LINE__);
1607 if (smb_dirSearchCounter > maxAllowed) {
1608 smb_dirSearchCounter = 1;
1609 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1611 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1613 /* don't need to watch for refcount zero and deleted, since
1614 * we haven't dropped the global lock.
1617 ++smb_dirSearchCounter;
1621 dsp = malloc(sizeof(*dsp));
1622 memset(dsp, 0, sizeof(*dsp));
1623 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1624 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1625 dsp->cookie = smb_dirSearchCounter;
1626 ++smb_dirSearchCounter;
1628 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1629 dsp->lastTime = osi_Time();
1632 lock_ReleaseWrite(&smb_globalLock);
1636 static smb_packet_t *GetPacket(void)
1640 unsigned int npar, seg, tb_sel;
1643 lock_ObtainWrite(&smb_globalLock);
1644 tbp = smb_packetFreeListp;
1646 smb_packetFreeListp = tbp->nextp;
1647 lock_ReleaseWrite(&smb_globalLock);
1650 tbp = calloc(65540,1);
1652 tbp = malloc(sizeof(smb_packet_t));
1654 tbp->magic = SMB_PACKETMAGIC;
1657 tbp->resumeCode = 0;
1663 tbp->ncb_length = 0;
1668 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1671 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1673 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1675 osi_panic("",__FILE__,__LINE__);
1678 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1683 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1684 tbp->dos_pkt_sel = tb_sel;
1687 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1692 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1696 memcpy(tbp, pkt, sizeof(smb_packet_t));
1697 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1701 static NCB *GetNCB(void)
1706 unsigned int npar, seg, tb_sel;
1709 lock_ObtainWrite(&smb_globalLock);
1710 tbp = smb_ncbFreeListp;
1712 smb_ncbFreeListp = tbp->nextp;
1713 lock_ReleaseWrite(&smb_globalLock);
1716 tbp = calloc(sizeof(*tbp),1);
1718 tbp = malloc(sizeof(*tbp));
1719 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1722 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1724 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1726 osi_panic("",__FILE__,__LINE__);
1728 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1733 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1734 tbp->dos_ncb_sel = tb_sel;
1736 tbp->magic = SMB_NCBMAGIC;
1739 osi_assert(tbp->magic == SMB_NCBMAGIC);
1741 memset(&tbp->ncb, 0, sizeof(NCB));
1744 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1749 void smb_FreePacket(smb_packet_t *tbp)
1751 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1753 lock_ObtainWrite(&smb_globalLock);
1754 tbp->nextp = smb_packetFreeListp;
1755 smb_packetFreeListp = tbp;
1756 tbp->magic = SMB_PACKETMAGIC;
1759 tbp->resumeCode = 0;
1765 tbp->ncb_length = 0;
1767 lock_ReleaseWrite(&smb_globalLock);
1770 static void FreeNCB(NCB *bufferp)
1774 tbp = (smb_ncb_t *) bufferp;
1775 osi_assert(tbp->magic == SMB_NCBMAGIC);
1777 lock_ObtainWrite(&smb_globalLock);
1778 tbp->nextp = smb_ncbFreeListp;
1779 smb_ncbFreeListp = tbp;
1780 lock_ReleaseWrite(&smb_globalLock);
1783 /* get a ptr to the data part of a packet, and its count */
1784 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1788 unsigned char *afterParmsp;
1790 parmBytes = *smbp->wctp << 1;
1791 afterParmsp = smbp->wctp + parmBytes + 1;
1793 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1794 if (nbytesp) *nbytesp = dataBytes;
1796 /* don't forget to skip the data byte count, since it follows
1797 * the parameters; that's where the "2" comes from below.
1799 return (unsigned char *) (afterParmsp + 2);
1802 /* must set all the returned parameters before playing around with the
1803 * data region, since the data region is located past the end of the
1804 * variable number of parameters.
1806 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1808 unsigned char *afterParmsp;
1810 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1812 *afterParmsp++ = dsize & 0xff;
1813 *afterParmsp = (dsize>>8) & 0xff;
1816 /* return the parm'th parameter in the smbp packet */
1817 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1820 unsigned char *parmDatap;
1822 parmCount = *smbp->wctp;
1824 if (parm >= parmCount) {
1829 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1830 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1831 parm, parmCount, smbp->ncb_length);
1833 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1834 1, smbp->ncb_length, ptbuf, smbp);
1835 DeregisterEventSource(h);
1839 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1840 parm, parmCount, smbp->ncb_length);
1841 osi_Log0(smb_logp, s);
1843 osi_panic(s, __FILE__, __LINE__);
1845 parmDatap = smbp->wctp + (2*parm) + 1;
1847 return parmDatap[0] + (parmDatap[1] << 8);
1850 /* return the parm'th parameter in the smbp packet */
1851 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1854 unsigned char *parmDatap;
1856 parmCount = *smbp->wctp;
1858 if (parm * 2 + offset >= parmCount * 2) {
1863 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1864 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1865 parm, offset, parmCount, smbp->ncb_length);
1867 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1868 1, smbp->ncb_length, ptbuf, smbp);
1869 DeregisterEventSource(h);
1873 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1875 parm, offset, parmCount, smbp->ncb_length);
1876 osi_Log0(smb_logp, s);
1879 osi_panic(s, __FILE__, __LINE__);
1881 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1883 return parmDatap[0] + (parmDatap[1] << 8);
1886 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1890 /* make sure we have enough slots */
1891 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1893 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1894 *parmDatap++ = parmValue & 0xff;
1895 *parmDatap = (parmValue>>8) & 0xff;
1898 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1902 /* make sure we have enough slots */
1903 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1905 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1906 *parmDatap++ = parmValue & 0xff;
1907 *parmDatap++ = (parmValue>>8) & 0xff;
1908 *parmDatap++ = (parmValue>>16) & 0xff;
1909 *parmDatap++ = (parmValue>>24) & 0xff;
1912 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1917 /* make sure we have enough slots */
1918 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1920 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1922 *parmDatap++ = *parmValuep++;
1925 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1929 /* make sure we have enough slots */
1930 if (*smbp->wctp <= slot) {
1931 if (smbp->oddByte) {
1933 *smbp->wctp = slot+1;
1938 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1939 *parmDatap++ = parmValue & 0xff;
1942 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1946 lastSlashp = strrchr(inPathp, '\\');
1948 *lastComponentp = lastSlashp;
1951 if (inPathp == lastSlashp)
1953 *outPathp++ = *inPathp++;
1962 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1967 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
1972 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1978 tlen = inp[0] + (inp[1]<<8);
1979 inp += 2; /* skip length field */
1982 *chainpp = inp + tlen;
1991 /* format a packet as a response */
1992 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1997 outp = (smb_t *) op;
1999 /* zero the basic structure through the smb_wct field, and zero the data
2000 * size field, assuming that wct stays zero; otherwise, you have to
2001 * explicitly set the data size field, too.
2003 inSmbp = (smb_t *) inp;
2004 memset(outp, 0, sizeof(smb_t)+2);
2010 outp->com = inSmbp->com;
2011 outp->tid = inSmbp->tid;
2012 outp->pid = inSmbp->pid;
2013 outp->uid = inSmbp->uid;
2014 outp->mid = inSmbp->mid;
2015 outp->res[0] = inSmbp->res[0];
2016 outp->res[1] = inSmbp->res[1];
2017 op->inCom = inSmbp->com;
2019 outp->reb = 0x80; /* SERVER_RESP */
2020 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2022 /* copy fields in generic packet area */
2023 op->wctp = &outp->wct;
2026 /* send a (probably response) packet; vcp tells us to whom to send it.
2027 * we compute the length by looking at wct and bcc fields.
2029 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2046 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2049 memset((char *)ncbp, 0, sizeof(NCB));
2051 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2052 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2053 extra += tp[0] + (tp[1]<<8);
2054 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2055 extra += 3; /* wct and length fields */
2057 ncbp->ncb_length = extra; /* bytes to send */
2058 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2059 ncbp->ncb_lana_num = vcp->lana;
2060 ncbp->ncb_command = NCBSEND; /* op means send data */
2062 ncbp->ncb_buffer = (char *) inp;/* packet */
2063 code = Netbios(ncbp);
2065 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2066 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2068 /* copy header information from virtual to DOS address space */
2069 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2070 code = Netbios(ncbp, dos_ncb);
2074 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2080 void smb_MapNTError(long code, unsigned long *NTStatusp)
2082 unsigned long NTStatus;
2084 /* map CM_ERROR_* errors to NT 32-bit status codes */
2085 /* NT Status codes are listed in ntstatus.h not winerror.h */
2086 if (code == CM_ERROR_NOSUCHCELL) {
2087 NTStatus = 0xC000000FL; /* No such file */
2089 else if (code == CM_ERROR_NOSUCHVOLUME) {
2090 NTStatus = 0xC000000FL; /* No such file */
2092 else if (code == CM_ERROR_TIMEDOUT) {
2093 NTStatus = 0xC00000CFL; /* Sharing Paused */
2095 else if (code == CM_ERROR_RETRY) {
2096 NTStatus = 0xC000022DL; /* Retry */
2098 else if (code == CM_ERROR_NOACCESS) {
2099 NTStatus = 0xC0000022L; /* Access denied */
2101 else if (code == CM_ERROR_READONLY) {
2102 NTStatus = 0xC00000A2L; /* Write protected */
2104 else if (code == CM_ERROR_NOSUCHFILE) {
2105 NTStatus = 0xC000000FL; /* No such file */
2107 else if (code == CM_ERROR_NOSUCHPATH) {
2108 NTStatus = 0xC000003AL; /* Object path not found */
2110 else if (code == CM_ERROR_TOOBIG) {
2111 NTStatus = 0xC000007BL; /* Invalid image format */
2113 else if (code == CM_ERROR_INVAL) {
2114 NTStatus = 0xC000000DL; /* Invalid parameter */
2116 else if (code == CM_ERROR_BADFD) {
2117 NTStatus = 0xC0000008L; /* Invalid handle */
2119 else if (code == CM_ERROR_BADFDOP) {
2120 NTStatus = 0xC0000022L; /* Access denied */
2122 else if (code == CM_ERROR_EXISTS) {
2123 NTStatus = 0xC0000035L; /* Object name collision */
2125 else if (code == CM_ERROR_NOTEMPTY) {
2126 NTStatus = 0xC0000101L; /* Directory not empty */
2128 else if (code == CM_ERROR_CROSSDEVLINK) {
2129 NTStatus = 0xC00000D4L; /* Not same device */
2131 else if (code == CM_ERROR_NOTDIR) {
2132 NTStatus = 0xC0000103L; /* Not a directory */
2134 else if (code == CM_ERROR_ISDIR) {
2135 NTStatus = 0xC00000BAL; /* File is a directory */
2137 else if (code == CM_ERROR_BADOP) {
2138 NTStatus = 0xC09820FFL; /* SMB no support */
2140 else if (code == CM_ERROR_BADSHARENAME) {
2141 NTStatus = 0xC00000CCL; /* Bad network name */
2143 else if (code == CM_ERROR_NOIPC) {
2145 NTStatus = 0xC0000022L; /* Access Denied */
2147 NTStatus = 0xC000013DL; /* Remote Resources */
2150 else if (code == CM_ERROR_CLOCKSKEW) {
2151 NTStatus = 0xC0000133L; /* Time difference at DC */
2153 else if (code == CM_ERROR_BADTID) {
2154 NTStatus = 0xC0982005L; /* SMB bad TID */
2156 else if (code == CM_ERROR_USESTD) {
2157 NTStatus = 0xC09820FBL; /* SMB use standard */
2159 else if (code == CM_ERROR_QUOTA) {
2160 NTStatus = 0xC0000044L; /* Quota exceeded */
2162 else if (code == CM_ERROR_SPACE) {
2163 NTStatus = 0xC000007FL; /* Disk full */
2165 else if (code == CM_ERROR_ATSYS) {
2166 NTStatus = 0xC0000033L; /* Object name invalid */
2168 else if (code == CM_ERROR_BADNTFILENAME) {
2169 NTStatus = 0xC0000033L; /* Object name invalid */
2171 else if (code == CM_ERROR_WOULDBLOCK) {
2172 NTStatus = 0xC0000055L; /* Lock not granted */
2174 else if (code == CM_ERROR_PARTIALWRITE) {
2175 NTStatus = 0xC000007FL; /* Disk full */
2177 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2178 NTStatus = 0xC0000023L; /* Buffer too small */
2180 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2181 NTStatus = 0xC0000035L; /* Object name collision */
2183 else if (code == CM_ERROR_BADPASSWORD) {
2184 NTStatus = 0xC000006DL; /* unknown username or bad password */
2186 else if (code == CM_ERROR_BADLOGONTYPE) {
2187 NTStatus = 0xC000015BL; /* logon type not granted */
2189 else if (code == CM_ERROR_GSSCONTINUE) {
2190 NTStatus = 0xC0000016L; /* more processing required */
2193 NTStatus = 0xC0982001L; /* SMB non-specific error */
2196 *NTStatusp = NTStatus;
2197 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2200 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2201 unsigned char *classp)
2203 unsigned char class;
2204 unsigned short error;
2206 /* map CM_ERROR_* errors to SMB errors */
2207 if (code == CM_ERROR_NOSUCHCELL) {
2209 error = 3; /* bad path */
2211 else if (code == CM_ERROR_NOSUCHVOLUME) {
2213 error = 3; /* bad path */
2215 else if (code == CM_ERROR_TIMEDOUT) {
2217 error = 81; /* server is paused */
2219 else if (code == CM_ERROR_RETRY) {
2220 class = 2; /* shouldn't happen */
2223 else if (code == CM_ERROR_NOACCESS) {
2225 error = 4; /* bad access */
2227 else if (code == CM_ERROR_READONLY) {
2229 error = 19; /* read only */
2231 else if (code == CM_ERROR_NOSUCHFILE) {
2233 error = 2; /* ENOENT! */
2235 else if (code == CM_ERROR_NOSUCHPATH) {
2237 error = 3; /* Bad path */
2239 else if (code == CM_ERROR_TOOBIG) {
2241 error = 11; /* bad format */
2243 else if (code == CM_ERROR_INVAL) {
2244 class = 2; /* server non-specific error code */
2247 else if (code == CM_ERROR_BADFD) {
2249 error = 6; /* invalid file handle */
2251 else if (code == CM_ERROR_BADFDOP) {
2252 class = 1; /* invalid op on FD */
2255 else if (code == CM_ERROR_EXISTS) {
2257 error = 80; /* file already exists */
2259 else if (code == CM_ERROR_NOTEMPTY) {
2261 error = 5; /* delete directory not empty */
2263 else if (code == CM_ERROR_CROSSDEVLINK) {
2265 error = 17; /* EXDEV */
2267 else if (code == CM_ERROR_NOTDIR) {
2268 class = 1; /* bad path */
2271 else if (code == CM_ERROR_ISDIR) {
2272 class = 1; /* access denied; DOS doesn't have a good match */
2275 else if (code == CM_ERROR_BADOP) {
2279 else if (code == CM_ERROR_BADSHARENAME) {
2283 else if (code == CM_ERROR_NOIPC) {
2285 error = 4; /* bad access */
2287 else if (code == CM_ERROR_CLOCKSKEW) {
2288 class = 1; /* invalid function */
2291 else if (code == CM_ERROR_BADTID) {
2295 else if (code == CM_ERROR_USESTD) {
2299 else if (code == CM_ERROR_REMOTECONN) {
2303 else if (code == CM_ERROR_QUOTA) {
2304 if (vcp->flags & SMB_VCFLAG_USEV3) {
2306 error = 39; /* disk full */
2310 error = 5; /* access denied */
2313 else if (code == CM_ERROR_SPACE) {
2314 if (vcp->flags & SMB_VCFLAG_USEV3) {
2316 error = 39; /* disk full */
2320 error = 5; /* access denied */
2323 else if (code == CM_ERROR_PARTIALWRITE) {
2325 error = 39; /* disk full */
2327 else if (code == CM_ERROR_ATSYS) {
2329 error = 2; /* ENOENT */
2331 else if (code == CM_ERROR_WOULDBLOCK) {
2333 error = 33; /* lock conflict */
2335 else if (code == CM_ERROR_NOFILES) {
2337 error = 18; /* no files in search */
2339 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2341 error = 183; /* Samba uses this */
2343 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2344 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2346 error = 2; /* bad password */
2355 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2358 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2360 return CM_ERROR_BADOP;
2363 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2365 unsigned short EchoCount, i;
2366 char *data, *outdata;
2369 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2371 for (i=1; i<=EchoCount; i++) {
2372 data = smb_GetSMBData(inp, &dataSize);
2373 smb_SetSMBParm(outp, 0, i);
2374 smb_SetSMBDataLength(outp, dataSize);
2375 outdata = smb_GetSMBData(outp, NULL);
2376 memcpy(outdata, data, dataSize);
2377 smb_SendPacket(vcp, outp);
2383 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2386 long count, minCount, finalCount;
2390 cm_user_t *userp = NULL;
2394 char *rawBuf = NULL;
2396 dos_ptr rawBuf = NULL;
2403 fd = smb_GetSMBParm(inp, 0);
2404 count = smb_GetSMBParm(inp, 3);
2405 minCount = smb_GetSMBParm(inp, 4);
2406 offset.HighPart = 0; /* too bad */
2407 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2409 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2410 fd, offset.LowPart, count);
2412 fidp = smb_FindFID(vcp, fd, 0);
2416 lock_ObtainMutex(&smb_RawBufLock);
2418 /* Get a raw buf, from head of list */
2419 rawBuf = smb_RawBufs;
2421 smb_RawBufs = *(char **)smb_RawBufs;
2423 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2426 lock_ReleaseMutex(&smb_RawBufLock);
2430 if (fidp->flags & SMB_FID_IOCTL)
2433 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2435 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2438 /* Give back raw buffer */
2439 lock_ObtainMutex(&smb_RawBufLock);
2441 *((char **) rawBuf) = smb_RawBufs;
2443 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2446 smb_RawBufs = rawBuf;
2447 lock_ReleaseMutex(&smb_RawBufLock);
2450 smb_ReleaseFID(fidp);
2454 userp = smb_GetUser(vcp, inp);
2457 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2459 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2460 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2461 userp, &finalCount, TRUE /* rawFlag */);
2468 cm_ReleaseUser(userp);
2471 smb_ReleaseFID(fidp);
2476 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2478 memset((char *)ncbp, 0, sizeof(NCB));
2480 ncbp->ncb_length = (unsigned short) finalCount;
2481 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2482 ncbp->ncb_lana_num = vcp->lana;
2483 ncbp->ncb_command = NCBSEND;
2484 ncbp->ncb_buffer = rawBuf;
2487 code = Netbios(ncbp);
2489 code = Netbios(ncbp, dos_ncb);
2492 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2495 /* Give back raw buffer */
2496 lock_ObtainMutex(&smb_RawBufLock);
2498 *((char **) rawBuf) = smb_RawBufs;
2500 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2503 smb_RawBufs = rawBuf;
2504 lock_ReleaseMutex(&smb_RawBufLock);
2510 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2515 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2520 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2527 int protoIndex; /* index we're using */
2532 char protocol_array[10][1024]; /* protocol signature of the client */
2533 int caps; /* capabilities */
2536 TIME_ZONE_INFORMATION tzi;
2538 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2542 DWORD now = GetCurrentTime();
2543 if (now - last_msg_time >= 30000
2544 && now - last_msg_time <= 90000) {
2546 "Setting dead_vcp %x", active_vcp);
2548 smb_ReleaseVC(dead_vcp);
2550 "Previous dead_vcp %x", dead_vcp);
2552 smb_HoldVC(active_vcp);
2553 dead_vcp = active_vcp;
2554 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2559 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2561 namep = smb_GetSMBData(inp, &dbytes);
2564 coreProtoIndex = -1; /* not found */
2567 while(namex < dbytes) {
2568 osi_Log1(smb_logp, "Protocol %s",
2569 osi_LogSaveString(smb_logp, namep+1));
2570 strcpy(protocol_array[tcounter], namep+1);
2572 /* namep points at the first protocol, or really, a 0x02
2573 * byte preceding the null-terminated ASCII name.
2575 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2576 coreProtoIndex = tcounter;
2578 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2579 v3ProtoIndex = tcounter;
2581 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2582 NTProtoIndex = tcounter;
2585 /* compute size of protocol entry */
2586 entryLength = strlen(namep+1);
2587 entryLength += 2; /* 0x02 bytes and null termination */
2589 /* advance over this protocol entry */
2590 namex += entryLength;
2591 namep += entryLength;
2592 tcounter++; /* which proto entry we're looking at */
2595 if (NTProtoIndex != -1) {
2596 protoIndex = NTProtoIndex;
2597 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2599 else if (v3ProtoIndex != -1) {
2600 protoIndex = v3ProtoIndex;
2601 vcp->flags |= SMB_VCFLAG_USEV3;
2603 else if (coreProtoIndex != -1) {
2604 protoIndex = coreProtoIndex;
2605 vcp->flags |= SMB_VCFLAG_USECORE;
2607 else protoIndex = -1;
2609 if (protoIndex == -1)
2610 return CM_ERROR_INVAL;
2611 else if (NTProtoIndex != -1) {
2612 smb_SetSMBParm(outp, 0, protoIndex);
2613 if (smb_authType != SMB_AUTH_NONE) {
2614 smb_SetSMBParmByte(outp, 1,
2615 NEGOTIATE_SECURITY_USER_LEVEL |
2616 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2618 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2620 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2621 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2622 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2623 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2624 /* The session key is not a well documented field however most clients
2625 * will echo back the session key to the server. Currently we are using
2626 * the same value for all sessions. We should generate a random value
2627 * and store it into the vcp
2629 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2630 smb_SetSMBParm(outp, 8, 1);
2632 * Tried changing the capabilities to support for W2K - defect 117695
2633 * Maybe something else needs to be changed here?
2637 smb_SetSMBParmLong(outp, 9, 0x43fd);
2639 smb_SetSMBParmLong(outp, 9, 0x251);
2642 * 32-bit error codes *
2646 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2647 NTNEGOTIATE_CAPABILITY_NTFIND |
2648 NTNEGOTIATE_CAPABILITY_RAWMODE |
2649 NTNEGOTIATE_CAPABILITY_NTSMB;
2651 if ( smb_authType == SMB_AUTH_EXTENDED )
2652 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2654 smb_SetSMBParmLong(outp, 9, caps);
2656 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2657 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2658 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2660 GetTimeZoneInformation(&tzi);
2661 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2663 if (smb_authType == SMB_AUTH_NTLM) {
2664 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2665 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2666 /* paste in encryption key */
2667 datap = smb_GetSMBData(outp, NULL);
2668 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2669 /* and the faux domain name */
2670 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2671 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2675 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2677 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2679 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2681 datap = smb_GetSMBData(outp, NULL);
2682 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2685 datap += sizeof(smb_ServerGUID);
2686 memcpy(datap, secBlob, secBlobLength);
2690 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2691 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2694 else if (v3ProtoIndex != -1) {
2695 smb_SetSMBParm(outp, 0, protoIndex);
2697 /* NOTE: Extended authentication cannot be negotiated with v3
2698 * therefore we fail over to NTLM
2700 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2701 smb_SetSMBParm(outp, 1,
2702 NEGOTIATE_SECURITY_USER_LEVEL |
2703 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2705 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2707 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2708 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2709 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2710 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2711 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2712 smb_SetSMBParm(outp, 7, 1);
2714 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2715 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2716 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2718 GetTimeZoneInformation(&tzi);
2719 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2721 /* NOTE: Extended authentication cannot be negotiated with v3
2722 * therefore we fail over to NTLM
2724 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2725 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2726 smb_SetSMBParm(outp, 12, 0); /* resvd */
2727 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2728 datap = smb_GetSMBData(outp, NULL);
2729 /* paste in a new encryption key */
2730 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2731 /* and the faux domain name */
2732 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2734 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2735 smb_SetSMBParm(outp, 12, 0); /* resvd */
2736 smb_SetSMBDataLength(outp, 0);
2739 else if (coreProtoIndex != -1) { /* not really supported anymore */
2740 smb_SetSMBParm(outp, 0, protoIndex);
2741 smb_SetSMBDataLength(outp, 0);
2746 void smb_Daemon(void *parmp)
2753 if ((count % 360) == 0) { /* every hour */
2756 /* Initialize smb_localZero */
2757 myTime.tm_isdst = -1; /* compute whether on DST or not */
2758 myTime.tm_year = 70;
2764 smb_localZero = mktime(&myTime);
2766 smb_CalculateNowTZ();
2768 /* XXX GC dir search entries */
2772 void smb_WaitingLocksDaemon()
2774 smb_waitingLock_t *wL, *nwL;
2777 smb_packet_t *inp, *outp;
2782 lock_ObtainWrite(&smb_globalLock);
2783 nwL = smb_allWaitingLocks;
2785 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2794 lock_ObtainWrite(&smb_globalLock);
2796 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2797 lock_ReleaseWrite(&smb_globalLock);
2798 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2799 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2800 if (code == CM_ERROR_WOULDBLOCK) {
2802 if (wL->timeRemaining != 0xffffffff
2803 && (wL->timeRemaining -= 1000) < 0)
2812 ncbp->ncb_length = inp->ncb_length;
2813 inp->spacep = cm_GetSpace();
2815 /* Remove waitingLock from list */
2816 lock_ObtainWrite(&smb_globalLock);
2817 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2819 lock_ReleaseWrite(&smb_globalLock);
2821 /* Resume packet processing */
2823 smb_SetSMBDataLength(outp, 0);
2824 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2825 outp->resumeCode = code;
2827 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2830 cm_FreeSpace(inp->spacep);
2831 smb_FreePacket(inp);
2832 smb_FreePacket(outp);
2840 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2842 osi_Log0(smb_logp, "SMB receive get disk attributes");
2844 smb_SetSMBParm(outp, 0, 32000);
2845 smb_SetSMBParm(outp, 1, 64);
2846 smb_SetSMBParm(outp, 2, 1024);
2847 smb_SetSMBParm(outp, 3, 30000);
2848 smb_SetSMBParm(outp, 4, 0);
2849 smb_SetSMBDataLength(outp, 0);
2853 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2857 unsigned short newTid;
2858 char shareName[256];
2866 osi_Log0(smb_logp, "SMB receive tree connect");
2868 /* parse input parameters */
2869 tp = smb_GetSMBData(inp, NULL);
2870 pathp = smb_ParseASCIIBlock(tp, &tp);
2871 passwordp = smb_ParseASCIIBlock(tp, &tp);
2872 tp = strrchr(pathp, '\\');
2874 return CM_ERROR_BADSMB;
2875 strcpy(shareName, tp+1);
2877 userp = smb_GetUser(vcp, inp);
2879 lock_ObtainMutex(&vcp->mx);
2880 newTid = vcp->tidCounter++;
2881 lock_ReleaseMutex(&vcp->mx);
2883 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2884 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2885 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2887 smb_ReleaseUID(uidp);
2889 smb_ReleaseTID(tidp);
2890 return CM_ERROR_BADSHARENAME;
2892 lock_ObtainMutex(&tidp->mx);
2893 tidp->userp = userp;
2894 tidp->pathname = sharePath;
2895 lock_ReleaseMutex(&tidp->mx);
2896 smb_ReleaseTID(tidp);
2898 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2899 smb_SetSMBParm(rsp, 1, newTid);
2900 smb_SetSMBDataLength(rsp, 0);
2902 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2906 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2910 if (*inp++ != 0x1) return NULL;
2911 tlen = inp[0] + (inp[1]<<8);
2912 inp += 2; /* skip length field */
2915 *chainpp = inp + tlen;
2918 if (lengthp) *lengthp = tlen;
2923 /* set maskp to the mask part of the incoming path.
2924 * Mask is 11 bytes long (8.3 with the dot elided).
2925 * Returns true if succeeds with a valid name, otherwise it does
2926 * its best, but returns false.
2928 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2936 /* starts off valid */
2939 /* mask starts out all blanks */
2940 memset(maskp, ' ', 11);
2942 /* find last backslash, or use whole thing if there is none */
2943 tp = strrchr(pathp, '\\');
2944 if (!tp) tp = pathp;
2945 else tp++; /* skip slash */
2949 /* names starting with a dot are illegal */
2950 if (*tp == '.') valid8Dot3 = 0;
2954 if (tc == 0) return valid8Dot3;
2955 if (tc == '.' || tc == '"') break;
2956 if (i < 8) *up++ = tc;
2957 else valid8Dot3 = 0;
2960 /* if we get here, tp point after the dot */
2961 up = maskp+8; /* ext goes here */
2968 if (tc == '.' || tc == '"')
2971 /* copy extension if not too long */
2981 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2991 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2993 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2997 /* otherwise, we have a valid 8.3 name; see if we have a match,
2998 * treating '?' as a wildcard in maskp (but not in the file name).
3000 tp1 = umask; /* real name, in mask format */
3001 tp2 = maskp; /* mask, in mask format */
3002 for(i=0; i<11; i++) {
3003 tc1 = *tp1++; /* char from real name */
3004 tc2 = *tp2++; /* char from mask */
3005 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3006 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3009 if (tc2 == '?' && tc1 != ' ')
3016 /* we got a match */
3020 char *smb_FindMask(char *pathp)
3024 tp = strrchr(pathp, '\\'); /* find last slash */
3027 return tp+1; /* skip the slash */
3029 return pathp; /* no slash, return the entire path */
3032 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3034 unsigned char *pathp;
3036 unsigned char mask[11];
3037 unsigned char *statBlockp;
3038 unsigned char initStatBlock[21];
3041 osi_Log0(smb_logp, "SMB receive search volume");
3043 /* pull pathname and stat block out of request */
3044 tp = smb_GetSMBData(inp, NULL);
3045 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3046 osi_assert(pathp != NULL);
3047 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3048 osi_assert(statBlockp != NULL);
3050 statBlockp = initStatBlock;
3054 /* for returning to caller */
3055 smb_Get8Dot3MaskFromPath(mask, pathp);
3057 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3058 tp = smb_GetSMBData(outp, NULL);
3060 *tp++ = 43; /* bytes in a dir entry */
3061 *tp++ = 0; /* high byte in counter */
3063 /* now marshall the dir entry, starting with the search status */
3064 *tp++ = statBlockp[0]; /* Reserved */
3065 memcpy(tp, mask, 11); tp += 11; /* FileName */
3067 /* now pass back server use info, with 1st byte non-zero */
3069 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3071 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3073 *tp++ = 0x8; /* attribute: volume */
3083 /* 4 byte file size */
3089 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3090 memset(tp, ' ', 13);
3093 /* set the length of the data part of the packet to 43 + 3, for the dir
3094 * entry plus the 5 and the length fields.
3096 smb_SetSMBDataLength(outp, 46);
3100 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3101 cm_user_t *userp, cm_req_t *reqp)
3109 smb_dirListPatch_t *patchp;
3110 smb_dirListPatch_t *npatchp;
3112 for(patchp = *dirPatchespp; patchp; patchp =
3113 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3114 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3116 lock_ObtainMutex(&scp->mx);
3117 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3118 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3120 lock_ReleaseMutex(&scp->mx);
3121 cm_ReleaseSCache(scp);
3124 dptr = patchp->dptr;
3126 attr = smb_Attributes(scp);
3127 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3128 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3129 attr |= SMB_ATTR_HIDDEN;
3133 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3136 shortTemp = dosTime & 0xffff;
3137 *((u_short *)dptr) = shortTemp;
3140 /* and copy out date */
3141 shortTemp = (dosTime>>16) & 0xffff;
3142 *((u_short *)dptr) = shortTemp;
3145 /* copy out file length */
3146 *((u_long *)dptr) = scp->length.LowPart;
3148 lock_ReleaseMutex(&scp->mx);
3149 cm_ReleaseSCache(scp);
3152 /* now free the patches */
3153 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3154 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3158 /* and mark the list as empty */
3159 *dirPatchespp = NULL;
3164 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3173 smb_dirListPatch_t *dirListPatchesp;
3174 smb_dirListPatch_t *curPatchp;
3178 osi_hyper_t dirLength;
3179 osi_hyper_t bufferOffset;
3180 osi_hyper_t curOffset;
3182 unsigned char *inCookiep;
3183 smb_dirSearch_t *dsp;
3187 unsigned long clientCookie;
3188 cm_pageHeader_t *pageHeaderp;
3189 cm_user_t *userp = NULL;
3196 long nextEntryCookie;
3197 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3198 char resByte; /* reserved byte from the cookie */
3199 char *op; /* output data ptr */
3200 char *origOp; /* original value of op */
3201 cm_space_t *spacep; /* for pathname buffer */
3212 maxCount = smb_GetSMBParm(inp, 0);
3214 dirListPatchesp = NULL;
3216 caseFold = CM_FLAG_CASEFOLD;
3218 tp = smb_GetSMBData(inp, NULL);
3219 pathp = smb_ParseASCIIBlock(tp, &tp);
3220 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3222 /* bail out if request looks bad */
3223 if (!tp || !pathp) {
3224 return CM_ERROR_BADSMB;
3227 /* We can handle long names */
3228 if (vcp->flags & SMB_VCFLAG_USENT)
3229 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3231 /* make sure we got a whole search status */
3232 if (dataLength < 21) {
3233 nextCookie = 0; /* start at the beginning of the dir */
3236 attribute = smb_GetSMBParm(inp, 1);
3238 /* handle volume info in another function */
3239 if (attribute & 0x8)
3240 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3242 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3243 maxCount, osi_LogSaveString(smb_logp, pathp));
3245 if (*pathp == 0) { /* null pathp, treat as root dir */
3246 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3247 return CM_ERROR_NOFILES;
3251 dsp = smb_NewDirSearch(0);
3252 dsp->attribute = attribute;
3253 smb_Get8Dot3MaskFromPath(mask, pathp);
3254 memcpy(dsp->mask, mask, 11);
3256 /* track if this is likely to match a lot of entries */
3257 if (smb_IsStarMask(mask)) starPattern = 1;
3258 else starPattern = 0;
3261 /* pull the next cookie value out of the search status block */
3262 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3263 + (inCookiep[16]<<24);
3264 dsp = smb_FindDirSearch(inCookiep[12]);
3266 /* can't find dir search status; fatal error */
3267 return CM_ERROR_BADFD;
3269 attribute = dsp->attribute;
3270 resByte = inCookiep[0];
3272 /* copy out client cookie, in host byte order. Don't bother
3273 * interpreting it, since we're just passing it through, anyway.
3275 memcpy(&clientCookie, &inCookiep[17], 4);
3277 memcpy(mask, dsp->mask, 11);
3279 /* assume we're doing a star match if it has continued for more
3285 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3286 nextCookie, dsp->cookie, attribute);
3288 userp = smb_GetUser(vcp, inp);
3290 /* try to get the vnode for the path name next */
3291 lock_ObtainMutex(&dsp->mx);
3298 spacep = inp->spacep;
3299 smb_StripLastComponent(spacep->data, NULL, pathp);
3300 lock_ReleaseMutex(&dsp->mx);
3301 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3302 code = cm_NameI(cm_rootSCachep, spacep->data,
3303 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3304 lock_ObtainMutex(&dsp->mx);
3306 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3308 /* we need one hold for the entry we just stored into,
3309 * and one for our own processing. When we're done with this
3310 * function, we'll drop the one for our own processing.
3311 * We held it once from the namei call, and so we do another hold
3315 lock_ObtainMutex(&scp->mx);
3316 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3317 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3318 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3319 dsp->flags |= SMB_DIRSEARCH_BULKST;
3321 lock_ReleaseMutex(&scp->mx);
3324 lock_ReleaseMutex(&dsp->mx);
3326 cm_ReleaseUser(userp);
3327 smb_DeleteDirSearch(dsp);
3328 smb_ReleaseDirSearch(dsp);
3332 /* reserves space for parameter; we'll adjust it again later to the
3333 * real count of the # of entries we returned once we've actually
3334 * assembled the directory listing.
3336 smb_SetSMBParm(outp, 0, 0);
3338 /* get the directory size */
3339 lock_ObtainMutex(&scp->mx);
3340 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3341 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3343 lock_ReleaseMutex(&scp->mx);
3344 cm_ReleaseSCache(scp);
3345 cm_ReleaseUser(userp);
3346 smb_DeleteDirSearch(dsp);
3347 smb_ReleaseDirSearch(dsp);
3351 dirLength = scp->length;
3353 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3354 curOffset.HighPart = 0;
3355 curOffset.LowPart = nextCookie;
3356 origOp = op = smb_GetSMBData(outp, NULL);
3357 /* and write out the basic header */
3358 *op++ = 5; /* variable block */
3359 op += 2; /* skip vbl block length; we'll fill it in later */
3363 /* make sure that curOffset.LowPart doesn't point to the first
3364 * 32 bytes in the 2nd through last dir page, and that it doesn't
3365 * point at the first 13 32-byte chunks in the first dir page,
3366 * since those are dir and page headers, and don't contain useful
3369 temp = curOffset.LowPart & (2048-1);
3370 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3371 /* we're in the first page */
3372 if (temp < 13*32) temp = 13*32;
3375 /* we're in a later dir page */
3376 if (temp < 32) temp = 32;
3379 /* make sure the low order 5 bits are zero */
3382 /* now put temp bits back ito curOffset.LowPart */
3383 curOffset.LowPart &= ~(2048-1);
3384 curOffset.LowPart |= temp;
3386 /* check if we've returned all the names that will fit in the
3389 if (returnedNames >= maxCount)
3392 /* check if we've passed the dir's EOF */
3393 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3395 /* see if we can use the bufferp we have now; compute in which page
3396 * the current offset would be, and check whether that's the offset
3397 * of the buffer we have. If not, get the buffer.
3399 thyper.HighPart = curOffset.HighPart;
3400 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3401 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3404 buf_Release(bufferp);
3407 lock_ReleaseMutex(&scp->mx);
3408 lock_ObtainRead(&scp->bufCreateLock);
3409 code = buf_Get(scp, &thyper, &bufferp);
3410 lock_ReleaseRead(&scp->bufCreateLock);
3412 /* now, if we're doing a star match, do bulk fetching of all of
3413 * the status info for files in the dir.
3416 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3418 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3419 && LargeIntegerGreaterThanOrEqualTo(thyper,
3420 scp->bulkStatProgress)) {
3421 /* Don't bulk stat if risking timeout */
3422 int now = GetCurrentTime();
3423 if (now - req.startTime > 5000) {
3424 scp->bulkStatProgress = thyper;
3425 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3426 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3428 cm_TryBulkStat(scp, &thyper, userp, &req);
3432 lock_ObtainMutex(&scp->mx);
3435 bufferOffset = thyper;
3437 /* now get the data in the cache */
3439 code = cm_SyncOp(scp, bufferp, userp, &req,
3441 CM_SCACHESYNC_NEEDCALLBACK
3442 | CM_SCACHESYNC_READ);
3445 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3447 /* otherwise, load the buffer and try again */
3448 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3453 buf_Release(bufferp);
3457 } /* if (wrong buffer) ... */
3459 /* now we have the buffer containing the entry we're interested in; copy
3460 * it out if it represents a non-deleted entry.
3462 entryInDir = curOffset.LowPart & (2048-1);
3463 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3465 /* page header will help tell us which entries are free. Page header
3466 * can change more often than once per buffer, since AFS 3 dir page size
3467 * may be less than (but not more than a buffer package buffer.
3469 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3470 temp &= ~(2048 - 1); /* turn off intra-page bits */
3471 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3473 /* now determine which entry we're looking at in the page. If it is
3474 * free (there's a free bitmap at the start of the dir), we should
3475 * skip these 32 bytes.
3477 slotInPage = (entryInDir & 0x7e0) >> 5;
3478 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3479 /* this entry is free */
3480 numDirChunks = 1; /* only skip this guy */
3484 tp = bufferp->datap + entryInBuffer;
3485 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3487 /* while we're here, compute the next entry's location, too,
3488 * since we'll need it when writing out the cookie into the dir
3491 * XXXX Probably should do more sanity checking.
3493 numDirChunks = cm_NameEntries(dep->name, NULL);
3495 /* compute the offset of the cookie representing the next entry */
3496 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3498 /* Compute 8.3 name if necessary */
3499 actualName = dep->name;
3500 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3501 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3502 actualName = shortName;
3505 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3506 /* this is one of the entries to use: it is not deleted
3507 * and it matches the star pattern we're looking for.
3510 /* Eliminate entries that don't match requested
3513 /* no hidden files */
3514 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3517 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3519 /* We have already done the cm_TryBulkStat above */
3520 fid.cell = scp->fid.cell;
3521 fid.volume = scp->fid.volume;
3522 fid.vnode = ntohl(dep->fid.vnode);
3523 fid.unique = ntohl(dep->fid.unique);
3524 fileType = cm_FindFileType(&fid);
3525 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3526 "has filetype %d", dep->name,
3528 if (fileType == CM_SCACHETYPE_DIRECTORY)
3533 memcpy(op, mask, 11); op += 11;
3534 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3535 *op++ = nextEntryCookie & 0xff;
3536 *op++ = (nextEntryCookie>>8) & 0xff;
3537 *op++ = (nextEntryCookie>>16) & 0xff;
3538 *op++ = (nextEntryCookie>>24) & 0xff;
3539 memcpy(op, &clientCookie, 4); op += 4;
3541 /* now we emit the attribute. This is sort of tricky,
3542 * since we need to really stat the file to find out
3543 * what type of entry we've got. Right now, we're
3544 * copying out data from a buffer, while holding the
3545 * scp locked, so it isn't really convenient to stat
3546 * something now. We'll put in a place holder now,
3547 * and make a second pass before returning this to get
3548 * the real attributes. So, we just skip the data for
3549 * now, and adjust it later. We allocate a patch
3550 * record to make it easy to find this point later.
3551 * The replay will happen at a time when it is safe to
3552 * unlock the directory.
3554 curPatchp = malloc(sizeof(*curPatchp));
3555 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3556 curPatchp->dptr = op;
3557 curPatchp->fid.cell = scp->fid.cell;
3558 curPatchp->fid.volume = scp->fid.volume;
3559 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3560 curPatchp->fid.unique = ntohl(dep->fid.unique);
3562 /* do hidden attribute here since name won't be around when applying
3566 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3567 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3569 curPatchp->flags = 0;
3571 op += 9; /* skip attr, time, date and size */
3573 /* zero out name area. The spec says to pad with
3574 * spaces, but Samba doesn't, and neither do we.
3578 /* finally, we get to copy out the name; we know that
3579 * it fits in 8.3 or the pattern wouldn't match, but it
3580 * never hurts to be sure.
3582 strncpy(op, actualName, 13);
3584 /* Uppercase if requested by client */
3585 if ((((smb_t *)inp)->flg2 & 1) == 0)
3590 /* now, adjust the # of entries copied */
3592 } /* if we're including this name */
3595 /* and adjust curOffset to be where the new cookie is */
3596 thyper.HighPart = 0;
3597 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3598 curOffset = LargeIntegerAdd(thyper, curOffset);
3599 } /* while copying data for dir listing */
3601 /* release the mutex */
3602 lock_ReleaseMutex(&scp->mx);
3603 if (bufferp) buf_Release(bufferp);
3605 /* apply and free last set of patches; if not doing a star match, this
3606 * will be empty, but better safe (and freeing everything) than sorry.
3608 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3610 /* special return code for unsuccessful search */
3611 if (code == 0 && dataLength < 21 && returnedNames == 0)
3612 code = CM_ERROR_NOFILES;
3614 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3615 returnedNames, code);
3618 smb_DeleteDirSearch(dsp);
3619 smb_ReleaseDirSearch(dsp);
3620 cm_ReleaseSCache(scp);
3621 cm_ReleaseUser(userp);
3625 /* finalize the output buffer */
3626 smb_SetSMBParm(outp, 0, returnedNames);
3627 temp = (long) (op - origOp);
3628 smb_SetSMBDataLength(outp, temp);
3630 /* the data area is a variable block, which has a 5 (already there)
3631 * followed by the length of the # of data bytes. We now know this to
3632 * be "temp," although that includes the 3 bytes of vbl block header.
3633 * Deduct for them and fill in the length field.
3635 temp -= 3; /* deduct vbl block info */
3636 osi_assert(temp == (43 * returnedNames));
3637 origOp[1] = temp & 0xff;
3638 origOp[2] = (temp>>8) & 0xff;
3639 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3640 smb_ReleaseDirSearch(dsp);
3641 cm_ReleaseSCache(scp);
3642 cm_ReleaseUser(userp);
3646 /* verify that this is a valid path to a directory. I don't know why they
3647 * don't use the get file attributes call.
3649 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3653 cm_scache_t *rootScp;
3654 cm_scache_t *newScp;
3663 pathp = smb_GetSMBData(inp, NULL);
3664 pathp = smb_ParseASCIIBlock(pathp, NULL);
3665 osi_Log1(smb_logp, "SMB receive check path %s",
3666 osi_LogSaveString(smb_logp, pathp));
3669 return CM_ERROR_BADFD;
3672 rootScp = cm_rootSCachep;
3674 userp = smb_GetUser(vcp, inp);
3676 caseFold = CM_FLAG_CASEFOLD;
3678 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3679 code = cm_NameI(rootScp, pathp,
3680 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3681 userp, tidPathp, &req, &newScp);
3684 cm_ReleaseUser(userp);
3688 /* now lock the vnode with a callback; returns with newScp locked */
3689 lock_ObtainMutex(&newScp->mx);
3690 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3691 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3692 if (code && code != CM_ERROR_NOACCESS) {
3693 lock_ReleaseMutex(&newScp->mx);
3694 cm_ReleaseSCache(newScp);
3695 cm_ReleaseUser(userp);
3699 attrs = smb_Attributes(newScp);
3701 if (!(attrs & 0x10))
3702 code = CM_ERROR_NOTDIR;
3704 lock_ReleaseMutex(&newScp->mx);
3706 cm_ReleaseSCache(newScp);
3707 cm_ReleaseUser(userp);
3711 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3715 cm_scache_t *rootScp;
3716 unsigned short attribute;
3718 cm_scache_t *newScp;
3727 /* decode basic attributes we're passed */
3728 attribute = smb_GetSMBParm(inp, 0);
3729 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3731 pathp = smb_GetSMBData(inp, NULL);
3732 pathp = smb_ParseASCIIBlock(pathp, NULL);
3735 return CM_ERROR_BADSMB;
3738 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3739 dosTime, attribute);
3741 rootScp = cm_rootSCachep;
3743 userp = smb_GetUser(vcp, inp);
3745 caseFold = CM_FLAG_CASEFOLD;
3747 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3748 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3749 tidPathp, &req, &newScp);
3752 cm_ReleaseUser(userp);
3756 /* now lock the vnode with a callback; returns with newScp locked; we
3757 * need the current status to determine what the new status is, in some
3760 lock_ObtainMutex(&newScp->mx);
3761 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3762 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3764 lock_ReleaseMutex(&newScp->mx);
3765 cm_ReleaseSCache(newScp);
3766 cm_ReleaseUser(userp);
3770 /* Check for RO volume */
3771 if (newScp->flags & CM_SCACHEFLAG_RO) {
3772 lock_ReleaseMutex(&newScp->mx);
3773 cm_ReleaseSCache(newScp);
3774 cm_ReleaseUser(userp);
3775 return CM_ERROR_READONLY;
3778 /* prepare for setattr call */
3781 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3782 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3784 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3785 /* we're told to make a writable file read-only */
3786 attr.unixModeBits = newScp->unixModeBits & ~0222;
3787 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3789 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3790 /* we're told to make a read-only file writable */
3791 attr.unixModeBits = newScp->unixModeBits | 0222;
3792 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3794 lock_ReleaseMutex(&newScp->mx);
3796 /* now call setattr */
3798 code = cm_SetAttr(newScp, &attr, userp, &req);
3802 cm_ReleaseSCache(newScp);
3803 cm_ReleaseUser(userp);
3808 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3812 cm_scache_t *rootScp;
3813 cm_scache_t *newScp, *dscp;
3825 pathp = smb_GetSMBData(inp, NULL);
3826 pathp = smb_ParseASCIIBlock(pathp, NULL);
3829 return CM_ERROR_BADSMB;
3832 if (*pathp == 0) /* null path */
3835 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3836 osi_LogSaveString(smb_logp, pathp));
3838 rootScp = cm_rootSCachep;
3840 userp = smb_GetUser(vcp, inp);
3842 /* we shouldn't need this for V3 requests, but we seem to */
3843 caseFold = CM_FLAG_CASEFOLD;
3845 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3848 * XXX Strange hack XXX
3850 * As of Patch 5 (16 July 97), we are having the following problem:
3851 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3852 * requests to look up "desktop.ini" in all the subdirectories.
3853 * This can cause zillions of timeouts looking up non-existent cells
3854 * and volumes, especially in the top-level directory.
3856 * We have not found any way to avoid this or work around it except
3857 * to explicitly ignore the requests for mount points that haven't
3858 * yet been evaluated and for directories that haven't yet been
3861 * We should modify this hack to provide a fake desktop.ini file
3862 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3864 spacep = inp->spacep;
3865 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3866 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3867 code = cm_NameI(rootScp, spacep->data,
3868 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3869 userp, tidPathp, &req, &dscp);
3871 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3872 && !dscp->mountRootFidp)
3873 code = CM_ERROR_NOSUCHFILE;
3874 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3875 cm_buf_t *bp = buf_Find(dscp, &hzero);
3879 code = CM_ERROR_NOSUCHFILE;
3881 cm_ReleaseSCache(dscp);
3883 cm_ReleaseUser(userp);
3889 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3890 tidPathp, &req, &newScp);
3893 cm_ReleaseUser(userp);
3897 /* now lock the vnode with a callback; returns with newScp locked */
3898 lock_ObtainMutex(&newScp->mx);
3899 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3900 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3902 lock_ReleaseMutex(&newScp->mx);
3903 cm_ReleaseSCache(newScp);
3904 cm_ReleaseUser(userp);
3909 /* use smb_Attributes instead. Also the fact that a file is
3910 * in a readonly volume doesn't mean it shojuld be marked as RO
3912 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
3913 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
3914 attrs = SMB_ATTR_DIRECTORY;
3917 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
3918 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
3920 attrs = smb_Attributes(newScp);
3923 smb_SetSMBParm(outp, 0, attrs);
3925 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
3926 smb_SetSMBParm(outp, 1, dosTime & 0xffff);
3927 smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
3928 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
3929 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
3930 smb_SetSMBParm(outp, 5, 0);
3931 smb_SetSMBParm(outp, 6, 0);
3932 smb_SetSMBParm(outp, 7, 0);
3933 smb_SetSMBParm(outp, 8, 0);
3934 smb_SetSMBParm(outp, 9, 0);
3935 smb_SetSMBDataLength(outp, 0);
3936 lock_ReleaseMutex(&newScp->mx);
3938 cm_ReleaseSCache(newScp);
3939 cm_ReleaseUser(userp);
3944 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3948 osi_Log0(smb_logp, "SMB receive tree disconnect");
3950 /* find the tree and free it */
3951 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
3953 lock_ObtainMutex(&tidp->mx);
3954 tidp->flags |= SMB_TIDFLAG_DELETE;
3955 lock_ReleaseMutex(&tidp->mx);
3956 smb_ReleaseTID(tidp);
3962 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3980 pathp = smb_GetSMBData(inp, NULL);
3981 pathp = smb_ParseASCIIBlock(pathp, NULL);
3983 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
3985 #ifdef DEBUG_VERBOSE
3989 hexpath = osi_HexifyString( pathp );
3990 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
3995 share = smb_GetSMBParm(inp, 0);
3996 attribute = smb_GetSMBParm(inp, 1);
3998 spacep = inp->spacep;
3999 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4000 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4001 /* special case magic file name for receiving IOCTL requests
4002 * (since IOCTL calls themselves aren't getting through).
4004 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4005 smb_SetupIoctlFid(fidp, spacep);
4006 smb_SetSMBParm(outp, 0, fidp->fid);
4007 smb_SetSMBParm(outp, 1, 0); /* attrs */
4008 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4009 smb_SetSMBParm(outp, 3, 0);
4010 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4011 smb_SetSMBParm(outp, 5, 0x7fff);
4012 /* pass the open mode back */
4013 smb_SetSMBParm(outp, 6, (share & 0xf));
4014 smb_SetSMBDataLength(outp, 0);
4015 smb_ReleaseFID(fidp);
4019 userp = smb_GetUser(vcp, inp);
4021 caseFold = CM_FLAG_CASEFOLD;
4023 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4024 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4025 tidPathp, &req, &scp);
4028 cm_ReleaseUser(userp);
4032 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4034 cm_ReleaseSCache(scp);
4035 cm_ReleaseUser(userp);
4039 /* don't need callback to check file type, since file types never
4040 * change, and namei and cm_Lookup all stat the object at least once on
4041 * a successful return.
4043 if (scp->fileType != CM_SCACHETYPE_FILE) {
4044 cm_ReleaseSCache(scp);
4045 cm_ReleaseUser(userp);
4046 return CM_ERROR_ISDIR;
4049 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4052 /* save a pointer to the vnode */
4055 if ((share & 0xf) == 0)
4056 fidp->flags |= SMB_FID_OPENREAD;
4057 else if ((share & 0xf) == 1)
4058 fidp->flags |= SMB_FID_OPENWRITE;
4060 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4062 lock_ObtainMutex(&scp->mx);
4063 smb_SetSMBParm(outp, 0, fidp->fid);
4064 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4065 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4066 smb_SetSMBParm(outp, 2, dosTime & 0xffff);
4067 smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
4068 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4069 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4070 /* pass the open mode back; XXXX add access checks */
4071 smb_SetSMBParm(outp, 6, (share & 0xf));
4072 smb_SetSMBDataLength(outp, 0);
4073 lock_ReleaseMutex(&scp->mx);
4076 cm_Open(scp, 0, userp);
4078 /* send and free packet */
4079 smb_ReleaseFID(fidp);
4080 cm_ReleaseUser(userp);
4081 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4085 typedef struct smb_unlinkRock {
4090 char *maskp; /* pointer to the star pattern */
4095 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4098 smb_unlinkRock_t *rockp;
4106 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4107 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4108 caseFold |= CM_FLAG_8DOT3;
4110 matchName = dep->name;
4111 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4113 && (rockp->flags & SMB_MASKFLAG_TILDE)
4114 && !cm_Is8Dot3(dep->name)) {
4115 cm_Gen8Dot3Name(dep, shortName, NULL);
4116 matchName = shortName;
4117 /* 8.3 matches are always case insensitive */
4118 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4121 osi_Log1(smb_logp, "Unlinking %s",
4122 osi_LogSaveString(smb_logp, matchName));
4123 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4124 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4125 smb_NotifyChange(FILE_ACTION_REMOVED,
4126 FILE_NOTIFY_CHANGE_FILE_NAME,
4127 dscp, dep->name, NULL, TRUE);
4130 /* If we made a case sensitive exact match, we might as well quit now. */
4131 if(!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4132 code = CM_ERROR_STOPNOW;
4140 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4149 smb_unlinkRock_t rock;
4158 attribute = smb_GetSMBParm(inp, 0);
4160 tp = smb_GetSMBData(inp, NULL);
4161 pathp = smb_ParseASCIIBlock(tp, &tp);
4163 osi_Log1(smb_logp, "SMB receive unlink %s",
4164 osi_LogSaveString(smb_logp, pathp));
4166 spacep = inp->spacep;
4167 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4169 userp = smb_GetUser(vcp, inp);
4171 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4173 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4174 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4178 cm_ReleaseUser(userp);
4182 /* otherwise, scp points to the parent directory. */
4189 rock.maskp = smb_FindMask(pathp);
4190 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4193 thyper.HighPart = 0;
4199 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4200 * match. If that fails, we do a case insensitve match.
4202 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4203 !smb_IsStarMask(rock.maskp)) {
4204 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4207 thyper.HighPart = 0;
4208 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4213 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4215 if (code == CM_ERROR_STOPNOW)
4218 cm_ReleaseUser(userp);
4220 cm_ReleaseSCache(dscp);
4222 if (code == 0 && !rock.any)
4223 code = CM_ERROR_NOSUCHFILE;
4227 typedef struct smb_renameRock {
4228 cm_scache_t *odscp; /* old dir */
4229 cm_scache_t *ndscp; /* new dir */
4230 cm_user_t *userp; /* user */
4231 cm_req_t *reqp; /* request struct */
4232 smb_vc_t *vcp; /* virtual circuit */
4233 char *maskp; /* pointer to star pattern of old file name */
4234 int flags; /* tilde, casefold, etc */
4235 char *newNamep; /* ptr to the new file's name */
4238 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4241 smb_renameRock_t *rockp;
4246 rockp = (smb_renameRock_t *) vrockp;
4248 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4249 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4250 caseFold |= CM_FLAG_8DOT3;
4252 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4254 && (rockp->flags & SMB_MASKFLAG_TILDE)
4255 && !cm_Is8Dot3(dep->name)) {
4256 cm_Gen8Dot3Name(dep, shortName, NULL);
4257 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4260 code = cm_Rename(rockp->odscp, dep->name,
4261 rockp->ndscp, rockp->newNamep, rockp->userp,
4263 /* if the call worked, stop doing the search now, since we
4264 * really only want to rename one file.
4267 code = CM_ERROR_STOPNOW;
4274 long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4280 cm_space_t *spacep = NULL;
4281 smb_renameRock_t rock;
4282 cm_scache_t *oldDscp = NULL;
4283 cm_scache_t *newDscp = NULL;
4284 cm_scache_t *tmpscp= NULL;
4285 cm_scache_t *tmpscp2 = NULL;
4297 tp = smb_GetSMBData(inp, NULL);
4298 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4299 newPathp = smb_ParseASCIIBlock(tp, &tp);
4301 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4302 osi_LogSaveString(smb_logp, oldPathp),
4303 osi_LogSaveString(smb_logp, newPathp));
4305 spacep = inp->spacep;
4306 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4308 userp = smb_GetUser(vcp, inp);
4311 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4312 * what actually exists is foo/baz. I don't know why the code used to be
4313 * the way it was. 1/29/96
4315 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4317 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4319 * caseFold = CM_FLAG_CASEFOLD;
4321 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4323 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4324 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4325 userp, tidPathp, &req, &oldDscp);
4328 cm_ReleaseUser(userp);
4332 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4333 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4334 userp, tidPathp, &req, &newDscp);
4337 cm_ReleaseSCache(oldDscp);
4338 cm_ReleaseUser(userp);
4342 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4343 * next, get the component names, and lower case them.
4346 /* handle the old name first */
4348 oldLastNamep = oldPathp;
4352 /* and handle the new name, too */
4354 newLastNamep = newPathp;
4358 /* TODO: The old name could be a wildcard. The new name must not be */
4360 /* do the vnode call */
4361 rock.odscp = oldDscp;
4362 rock.ndscp = newDscp;
4366 rock.maskp = oldLastNamep;
4367 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4368 rock.newNamep = newLastNamep;
4370 /* Check if the file already exists; if so return error */
4371 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4372 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4373 osi_Log2(afsd_logp, " lookup returns %ld for [%s]", code,
4374 osi_LogSaveString(afsd_logp, newLastNamep));
4376 /* Check if the old and the new names differ only in case. If so return
4377 * success, else return CM_ERROR_EXISTS
4379 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4381 /* This would be a success only if the old file is *as same as* the new file */
4382 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4384 if (tmpscp == tmpscp2)
4387 code = CM_ERROR_EXISTS;
4388 cm_ReleaseSCache(tmpscp2);
4391 code = CM_ERROR_NOSUCHFILE;
4394 /* file exist, do not rename, also fixes move */
4395 osi_Log0(afsd_logp, "Can't rename. Target already exists");
4396 code = CM_ERROR_EXISTS;
4400 cm_ReleaseSCache(tmpscp);
4401 cm_ReleaseSCache(newDscp);
4402 cm_ReleaseSCache(oldDscp);
4403 cm_ReleaseUser(userp);
4407 /* Now search the directory for the pattern, and do the appropriate rename when found */
4408 thyper.LowPart = 0; /* search dir from here */
4409 thyper.HighPart = 0;
4411 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4413 if (code == CM_ERROR_STOPNOW)
4416 code = CM_ERROR_NOSUCHFILE;
4418 /* Handle Change Notification */
4420 * Being lazy, not distinguishing between files and dirs in this
4421 * filter, since we'd have to do a lookup.
4423 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4424 if (oldDscp == newDscp) {
4425 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4426 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4427 filter, oldDscp, oldLastNamep,
4428 newLastNamep, TRUE);
4430 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4431 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4432 filter, oldDscp, oldLastNamep,
4434 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4435 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4436 filter, newDscp, newLastNamep,
4441 cm_ReleaseSCache(tmpscp);
4442 cm_ReleaseUser(userp);
4443 cm_ReleaseSCache(oldDscp);
4444 cm_ReleaseSCache(newDscp);
4448 typedef struct smb_rmdirRock {
4452 char *maskp; /* pointer to the star pattern */
4457 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4460 smb_rmdirRock_t *rockp;
4465 rockp = (smb_rmdirRock_t *) vrockp;
4467 matchName = dep->name;
4468 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4469 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4471 match = (strcmp(matchName, rockp->maskp) == 0);
4473 && (rockp->flags & SMB_MASKFLAG_TILDE)
4474 && !cm_Is8Dot3(dep->name)) {
4475 cm_Gen8Dot3Name(dep, shortName, NULL);
4476 matchName = shortName;
4477 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4480 osi_Log1(smb_logp, "Removing directory %s",
4481 osi_LogSaveString(smb_logp, matchName));
4482 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4483 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4484 smb_NotifyChange(FILE_ACTION_REMOVED,
4485 FILE_NOTIFY_CHANGE_DIR_NAME,
4486 dscp, dep->name, NULL, TRUE);
4495 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4503 smb_rmdirRock_t rock;
4512 tp = smb_GetSMBData(inp, NULL);
4513 pathp = smb_ParseASCIIBlock(tp, &tp);
4515 spacep = inp->spacep;
4516 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4518 userp = smb_GetUser(vcp, inp);
4520 caseFold = CM_FLAG_CASEFOLD;
4522 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4523 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4524 userp, tidPathp, &req, &dscp);
4527 cm_ReleaseUser(userp);
4531 /* otherwise, scp points to the parent directory. */
4538 rock.maskp = lastNamep;
4539 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4542 thyper.HighPart = 0;
4546 /* First do a case sensitive match, and if that fails, do a case insensitive match */
4547 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4548 if (code == 0 && !rock.any) {
4550 thyper.HighPart = 0;
4551 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4552 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4555 cm_ReleaseUser(userp);
4557 cm_ReleaseSCache(dscp);
4559 if (code == 0 && !rock.any)
4560 code = CM_ERROR_NOSUCHFILE;
4564 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4574 fid = smb_GetSMBParm(inp, 0);
4576 osi_Log1(smb_logp, "SMB flush fid %d", fid);
4578 fid = smb_ChainFID(fid, inp);
4579 fidp = smb_FindFID(vcp, fid, 0);
4580 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4582 smb_ReleaseFID(fidp);
4583 return CM_ERROR_BADFD;
4586 userp = smb_GetUser(vcp, inp);
4588 lock_ObtainMutex(&fidp->mx);
4589 if (fidp->flags & SMB_FID_OPENWRITE)
4590 code = cm_FSync(fidp->scp, userp, &req);
4593 lock_ReleaseMutex(&fidp->mx);
4595 smb_ReleaseFID(fidp);
4597 cm_ReleaseUser(userp);
4602 struct smb_FullNameRock {
4608 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4612 struct smb_FullNameRock *vrockp;
4614 vrockp = (struct smb_FullNameRock *)rockp;
4616 if (!cm_Is8Dot3(dep->name)) {
4617 cm_Gen8Dot3Name(dep, shortName, NULL);
4619 if (cm_stricmp(shortName, vrockp->name) == 0) {
4620 vrockp->fullName = strdup(dep->name);
4621 return CM_ERROR_STOPNOW;
4624 if (cm_stricmp(dep->name, vrockp->name) == 0
4625 && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
4626 && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4627 vrockp->fullName = strdup(dep->name);
4628 return CM_ERROR_STOPNOW;
4633 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4634 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4636 struct smb_FullNameRock rock;
4642 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL,
4644 if (code == CM_ERROR_STOPNOW)
4645 *newPathp = rock.fullName;
4647 *newPathp = strdup(pathp);
4650 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4661 fid = smb_GetSMBParm(inp, 0);
4662 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4664 osi_Log1(smb_logp, "SMB close fid %d", fid);
4666 fid = smb_ChainFID(fid, inp);
4667 fidp = smb_FindFID(vcp, fid, 0);
4669 return CM_ERROR_BADFD;
4672 userp = smb_GetUser(vcp, inp);
4674 lock_ObtainMutex(&fidp->mx);
4676 /* Don't jump the gun on an async raw write */
4677 while (fidp->raw_writers) {
4678 lock_ReleaseMutex(&fidp->mx);
4679 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4680 lock_ObtainMutex(&fidp->mx);
4683 fidp->flags |= SMB_FID_DELETE;
4685 /* watch for ioctl closes, and read-only opens */
4686 if (fidp->scp != NULL
4687 && (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4688 == SMB_FID_OPENWRITE) {
4689 if (dosTime != 0 && dosTime != -1) {
4690 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4691 /* This fixes defect 10958 */
4692 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4693 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
4695 code = cm_FSync(fidp->scp, userp, &req);
4700 if (fidp->flags & SMB_FID_DELONCLOSE) {
4701 cm_scache_t *dscp = fidp->NTopen_dscp;
4702 char *pathp = fidp->NTopen_pathp;
4705 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
4706 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
4707 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
4708 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4709 smb_NotifyChange(FILE_ACTION_REMOVED,
4710 FILE_NOTIFY_CHANGE_DIR_NAME,
4711 dscp, fullPathp, NULL, TRUE);
4715 code = cm_Unlink(dscp, fullPathp, userp, &req);
4716 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4717 smb_NotifyChange(FILE_ACTION_REMOVED,
4718 FILE_NOTIFY_CHANGE_FILE_NAME,
4719 dscp, fullPathp, NULL, TRUE);
4723 lock_ReleaseMutex(&fidp->mx);
4725 if (fidp->flags & SMB_FID_NTOPEN) {
4726 cm_ReleaseSCache(fidp->NTopen_dscp);
4727 free(fidp->NTopen_pathp);
4729 if (fidp->NTopen_wholepathp)
4730 free(fidp->NTopen_wholepathp);
4732 smb_ReleaseFID(fidp);
4733 cm_ReleaseUser(userp);
4738 * smb_ReadData -- common code for Read, Read And X, and Raw Read
4741 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4742 cm_user_t *userp, long *readp)
4744 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4745 cm_user_t *userp, long *readp, int dosflag)
4752 osi_hyper_t fileLength;
4754 osi_hyper_t lastByte;
4755 osi_hyper_t bufferOffset;
4756 long bufIndex, nbytes;
4766 lock_ObtainMutex(&fidp->mx);
4768 lock_ObtainMutex(&scp->mx);
4770 if (offset.HighPart == 0) {
4771 chunk = offset.LowPart >> cm_logChunkSize;
4772 if (chunk != fidp->curr_chunk) {
4773 fidp->prev_chunk = fidp->curr_chunk;
4774 fidp->curr_chunk = chunk;
4776 if (fidp->curr_chunk == fidp->prev_chunk + 1)
4780 /* start by looking up the file's end */
4781 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4782 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4783 if (code) goto done;
4785 /* now we have the entry locked, look up the length */
4786 fileLength = scp->length;
4788 /* adjust count down so that it won't go past EOF */
4789 thyper.LowPart = count;
4790 thyper.HighPart = 0;
4791 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
4793 if (LargeIntegerGreaterThan(thyper, fileLength)) {
4794 /* we'd read past EOF, so just stop at fileLength bytes.
4795 * Start by computing how many bytes remain in the file.
4797 thyper = LargeIntegerSubtract(fileLength, offset);
4799 /* if we are past EOF, read 0 bytes */
4800 if (LargeIntegerLessThanZero(thyper))
4803 count = thyper.LowPart;
4808 /* now, copy the data one buffer at a time,
4809 * until we've filled the request packet
4812 /* if we've copied all the data requested, we're done */
4813 if (count <= 0) break;
4815 /* otherwise, load up a buffer of data */
4816 thyper.HighPart = offset.HighPart;
4817 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4818 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4821 buf_Release(bufferp);
4824 lock_ReleaseMutex(&scp->mx);
4826 lock_ObtainRead(&scp->bufCreateLock);
4827 code = buf_Get(scp, &thyper, &bufferp);
4828 lock_ReleaseRead(&scp->bufCreateLock);
4830 lock_ObtainMutex(&scp->mx);
4831 if (code) goto done;
4832 bufferOffset = thyper;
4834 /* now get the data in the cache */
4836 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4837 CM_SCACHESYNC_NEEDCALLBACK
4838 | CM_SCACHESYNC_READ);
4839 if (code) goto done;
4841 if (cm_HaveBuffer(scp, bufferp, 0)) break;
4843 /* otherwise, load the buffer and try again */
4844 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4848 buf_Release(bufferp);
4852 } /* if (wrong buffer) ... */
4854 /* now we have the right buffer loaded. Copy out the
4855 * data from here to the user's buffer.
4857 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4859 /* and figure out how many bytes we want from this buffer */
4860 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
4861 if (nbytes > count) nbytes = count; /* don't go past EOF */
4863 /* now copy the data */
4866 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
4869 memcpy(op, bufferp->datap + bufIndex, nbytes);
4871 /* adjust counters, pointers, etc. */
4874 thyper.LowPart = nbytes;
4875 thyper.HighPart = 0;
4876 offset = LargeIntegerAdd(thyper, offset);
4880 lock_ReleaseMutex(&scp->mx);
4881 lock_ReleaseMutex(&fidp->mx);
4883 buf_Release(bufferp);
4885 if (code == 0 && sequential)
4886 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
4892 * smb_WriteData -- common code for Write and Raw Write
4895 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4896 cm_user_t *userp, long *writtenp)
4898 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4899 cm_user_t *userp, long *writtenp, int dosflag)
4906 osi_hyper_t fileLength; /* file's length at start of write */
4907 osi_hyper_t minLength; /* don't read past this */
4908 long nbytes; /* # of bytes to transfer this iteration */
4910 osi_hyper_t thyper; /* hyper tmp variable */
4911 osi_hyper_t bufferOffset;
4912 long bufIndex; /* index in buffer where our data is */
4914 osi_hyper_t writeBackOffset; /* offset of region to write back when
4919 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
4920 fidp->fid, offsetp->LowPart, count);
4928 lock_ObtainMutex(&fidp->mx);
4930 lock_ObtainMutex(&scp->mx);
4932 /* start by looking up the file's end */
4933 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
4935 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4936 CM_SCACHESYNC_NEEDCALLBACK
4937 | CM_SCACHESYNC_SETSTATUS
4938 | CM_SCACHESYNC_GETSTATUS);
4939 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
4944 /* make sure we have a writable FD */
4945 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
4946 code = CM_ERROR_BADFDOP;
4950 /* now we have the entry locked, look up the length */
4951 fileLength = scp->length;
4952 minLength = fileLength;
4953 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
4954 minLength = scp->serverLength;
4956 /* adjust file length if we extend past EOF */
4957 thyper.LowPart = count;
4958 thyper.HighPart = 0;
4959 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
4960 if (LargeIntegerGreaterThan(thyper, fileLength)) {
4961 /* we'd write past EOF, so extend the file */
4962 scp->mask |= CM_SCACHEMASK_LENGTH;
4963 scp->length = thyper;
4964 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
4966 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
4968 /* now, if the new position (thyper) and the old (offset) are in
4969 * different storeback windows, remember to store back the previous
4970 * storeback window when we're done with the write.
4972 if ((thyper.LowPart & (-cm_chunkSize)) !=
4973 (offset.LowPart & (-cm_chunkSize))) {
4974 /* they're different */
4976 writeBackOffset.HighPart = offset.HighPart;
4977 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
4982 /* now, copy the data one buffer at a time, until we've filled the
4985 /* if we've copied all the data requested, we're done */
4986 if (count <= 0) break;
4988 /* handle over quota or out of space */
4989 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
4990 *writtenp = written;
4994 /* otherwise, load up a buffer of data */
4995 thyper.HighPart = offset.HighPart;
4996 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4997 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5000 lock_ReleaseMutex(&bufferp->mx);
5001 buf_Release(bufferp);
5004 lock_ReleaseMutex(&scp->mx);
5006 lock_ObtainRead(&scp->bufCreateLock);
5007 code = buf_Get(scp, &thyper, &bufferp);
5008 lock_ReleaseRead(&scp->bufCreateLock);
5010 lock_ObtainMutex(&bufferp->mx);
5011 lock_ObtainMutex(&scp->mx);
5012 if (code) goto done;
5014 bufferOffset = thyper;
5016 /* now get the data in the cache */
5018 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5020 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5021 CM_SCACHESYNC_NEEDCALLBACK
5022 | CM_SCACHESYNC_WRITE
5023 | CM_SCACHESYNC_BUFLOCKED);
5024 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5029 /* If we're overwriting the entire buffer, or
5030 * if we're writing at or past EOF, mark the
5031 * buffer as current so we don't call
5032 * cm_GetBuffer. This skips the fetch from the
5033 * server in those cases where we're going to
5034 * obliterate all the data in the buffer anyway,
5035 * or in those cases where there is no useful
5036 * data at the server to start with.
5038 * Use minLength instead of scp->length, since
5039 * the latter has already been updated by this
5042 if (LargeIntegerGreaterThanOrEqualTo(
5043 bufferp->offset, minLength)
5044 || LargeIntegerEqualTo(offset, bufferp->offset)
5045 && (count >= buf_bufferSize
5046 || LargeIntegerGreaterThanOrEqualTo(
5047 LargeIntegerAdd(offset,
5048 ConvertLongToLargeInteger(count)),
5050 if (count < buf_bufferSize
5051 && bufferp->dataVersion == -1)
5052 memset(bufferp->datap, 0,
5054 bufferp->dataVersion = scp->dataVersion;
5057 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5059 /* otherwise, load the buffer and try again */
5060 lock_ReleaseMutex(&bufferp->mx);
5061 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5063 lock_ReleaseMutex(&scp->mx);
5064 lock_ObtainMutex(&bufferp->mx);
5065 lock_ObtainMutex(&scp->mx);
5069 lock_ReleaseMutex(&bufferp->mx);
5070 buf_Release(bufferp);
5074 } /* if (wrong buffer) ... */
5076 /* now we have the right buffer loaded. Copy out the
5077 * data from here to the user's buffer.
5079 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5081 /* and figure out how many bytes we want from this buffer */
5082 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5084 nbytes = count; /* don't go past end of request */
5086 /* now copy the data */
5089 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5092 memcpy(bufferp->datap + bufIndex, op, nbytes);
5093 buf_SetDirty(bufferp);
5095 /* and record the last writer */
5096 if (bufferp->userp != userp) {
5099 cm_ReleaseUser(bufferp->userp);
5100 bufferp->userp = userp;
5103 /* adjust counters, pointers, etc. */
5107 thyper.LowPart = nbytes;
5108 thyper.HighPart = 0;
5109 offset = LargeIntegerAdd(thyper, offset);
5113 lock_ReleaseMutex(&scp->mx);
5114 lock_ReleaseMutex(&fidp->mx);
5116 lock_ReleaseMutex(&bufferp->mx);
5117 buf_Release(bufferp);
5120 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5121 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5122 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5123 fidp->NTopen_dscp, fidp->NTopen_pathp,
5127 if (code == 0 && doWriteBack) {
5129 lock_ObtainMutex(&scp->mx);
5130 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5132 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5133 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5135 lock_ReleaseMutex(&scp->mx);
5136 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5137 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5140 osi_Log2(smb_logp, "smb_WriteData fid %d returns %d",
5145 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5148 long count, written = 0;
5153 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5155 int inDataBlockCount;
5157 fd = smb_GetSMBParm(inp, 0);
5158 count = smb_GetSMBParm(inp, 1);
5159 offset.HighPart = 0; /* too bad */
5160 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5162 op = smb_GetSMBData(inp, NULL);
5163 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5165 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5166 fd, offset.LowPart, count);
5168 fd = smb_ChainFID(fd, inp);
5169 fidp = smb_FindFID(vcp, fd, 0);
5171 return CM_ERROR_BADFD;
5174 if (fidp->flags & SMB_FID_IOCTL)
5175 return smb_IoctlWrite(fidp, vcp, inp, outp);
5177 userp = smb_GetUser(vcp, inp);
5179 /* special case: 0 bytes transferred means truncate to this position */
5185 truncAttr.mask = CM_ATTRMASK_LENGTH;
5186 truncAttr.length.LowPart = offset.LowPart;
5187 truncAttr.length.HighPart = 0;
5188 lock_ObtainMutex(&fidp->mx);
5189 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5190 lock_ReleaseMutex(&fidp->mx);
5191 smb_SetSMBParm(outp, 0, /* count */ 0);
5192 smb_SetSMBDataLength(outp, 0);
5193 fidp->flags |= SMB_FID_LENGTHSETDONE;
5198 * Work around bug in NT client
5200 * When copying a file, the NT client should first copy the data,
5201 * then copy the last write time. But sometimes the NT client does
5202 * these in the wrong order, so the data copies would inadvertently
5203 * cause the last write time to be overwritten. We try to detect this,
5204 * and don't set client mod time if we think that would go against the
5207 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5208 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5209 fidp->scp->clientModTime = time(NULL);
5213 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5215 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5217 if (code == 0 && written < count)
5218 code = CM_ERROR_PARTIALWRITE;
5220 /* set the packet data length to 3 bytes for the data block header,
5221 * plus the size of the data.
5223 smb_SetSMBParm(outp, 0, written);
5224 smb_SetSMBDataLength(outp, 0);
5227 smb_ReleaseFID(fidp);
5228 cm_ReleaseUser(userp);
5233 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5234 NCB *ncbp, raw_write_cont_t *rwcp)
5247 fd = smb_GetSMBParm(inp, 0);
5248 fidp = smb_FindFID(vcp, fd, 0);
5250 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5251 rwcp->offset.LowPart, rwcp->count);
5253 userp = smb_GetUser(vcp, inp);
5257 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5260 rawBuf = (dos_ptr) rwcp->buf;
5261 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5262 (unsigned char *) rawBuf, userp,
5266 if (rwcp->writeMode & 0x1) { /* synchronous */
5269 smb_FormatResponsePacket(vcp, inp, outp);
5270 op = (smb_t *) outp;
5271 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5272 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5273 smb_SetSMBDataLength(outp, 0);
5274 smb_SendPacket(vcp, outp);
5275 smb_FreePacket(outp);
5277 else { /* asynchronous */
5278 lock_ObtainMutex(&fidp->mx);
5279 fidp->raw_writers--;
5280 if (fidp->raw_writers == 0)
5281 thrd_SetEvent(fidp->raw_write_event);
5282 lock_ReleaseMutex(&fidp->mx);
5285 /* Give back raw buffer */
5286 lock_ObtainMutex(&smb_RawBufLock);
5288 *((char **)rawBuf) = smb_RawBufs;
5290 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5292 smb_RawBufs = rawBuf;
5293 lock_ReleaseMutex(&smb_RawBufLock);
5295 smb_ReleaseFID(fidp);
5296 cm_ReleaseUser(userp);
5299 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5304 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5307 long count, written = 0;
5314 unsigned short writeMode;
5321 fd = smb_GetSMBParm(inp, 0);
5322 totalCount = smb_GetSMBParm(inp, 1);
5323 count = smb_GetSMBParm(inp, 10);
5324 offset.HighPart = 0; /* too bad */
5325 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5326 writeMode = smb_GetSMBParm(inp, 7);
5328 op = (char *) inp->data;
5329 op += smb_GetSMBParm(inp, 11);
5332 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5333 fd, offset.LowPart, count, writeMode);
5335 fd = smb_ChainFID(fd, inp);
5336 fidp = smb_FindFID(vcp, fd, 0);
5338 return CM_ERROR_BADFD;
5341 userp = smb_GetUser(vcp, inp);
5344 * Work around bug in NT client
5346 * When copying a file, the NT client should first copy the data,
5347 * then copy the last write time. But sometimes the NT client does
5348 * these in the wrong order, so the data copies would inadvertently
5349 * cause the last write time to be overwritten. We try to detect this,
5350 * and don't set client mod time if we think that would go against the
5353 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5354 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5355 fidp->scp->clientModTime = time(NULL);
5359 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5361 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5363 if (code == 0 && written < count)
5364 code = CM_ERROR_PARTIALWRITE;
5366 /* Get a raw buffer */
5369 lock_ObtainMutex(&smb_RawBufLock);
5371 /* Get a raw buf, from head of list */
5372 rawBuf = smb_RawBufs;
5374 smb_RawBufs = *(char **)smb_RawBufs;
5376 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5380 code = CM_ERROR_USESTD;
5382 lock_ReleaseMutex(&smb_RawBufLock);
5385 /* Don't allow a premature Close */
5386 if (code == 0 && (writeMode & 1) == 0) {
5387 lock_ObtainMutex(&fidp->mx);
5388 fidp->raw_writers++;
5389 thrd_ResetEvent(fidp->raw_write_event);
5390 lock_ReleaseMutex(&fidp->mx);
5393 smb_ReleaseFID(fidp);
5394 cm_ReleaseUser(userp);
5397 smb_SetSMBParm(outp, 0, written);
5398 smb_SetSMBDataLength(outp, 0);
5399 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5406 rwcp->offset.HighPart = 0;
5407 rwcp->offset.LowPart = offset.LowPart + count;
5408 rwcp->count = totalCount - count;
5409 rwcp->writeMode = writeMode;
5410 rwcp->alreadyWritten = written;
5412 /* set the packet data length to 3 bytes for the data block header,
5413 * plus the size of the data.
5415 smb_SetSMBParm(outp, 0, 0xffff);
5416 smb_SetSMBDataLength(outp, 0);
5421 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5424 long count, finalCount;
5431 fd = smb_GetSMBParm(inp, 0);
5432 count = smb_GetSMBParm(inp, 1);
5433 offset.HighPart = 0; /* too bad */
5434 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5436 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5437 fd, offset.LowPart, count);
5439 fd = smb_ChainFID(fd, inp);
5440 fidp = smb_FindFID(vcp, fd, 0);
5442 return CM_ERROR_BADFD;
5445 if (fidp->flags & SMB_FID_IOCTL) {
5446 return smb_IoctlRead(fidp, vcp, inp, outp);
5449 userp = smb_GetUser(vcp, inp);
5451 /* remember this for final results */
5452 smb_SetSMBParm(outp, 0, count);
5453 smb_SetSMBParm(outp, 1, 0);
5454 smb_SetSMBParm(outp, 2, 0);
5455 smb_SetSMBParm(outp, 3, 0);
5456 smb_SetSMBParm(outp, 4, 0);
5458 /* set the packet data length to 3 bytes for the data block header,
5459 * plus the size of the data.
5461 smb_SetSMBDataLength(outp, count+3);
5463 /* get op ptr after putting in the parms, since otherwise we don't
5464 * know where the data really is.
5466 op = smb_GetSMBData(outp, NULL);
5468 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5469 *op++ = 1; /* data block marker */
5470 *op++ = (unsigned char) (count & 0xff);
5471 *op++ = (unsigned char) ((count >> 8) & 0xff);
5474 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5476 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5479 /* fix some things up */
5480 smb_SetSMBParm(outp, 0, finalCount);
5481 smb_SetSMBDataLength(outp, finalCount+3);
5483 smb_ReleaseFID(fidp);
5485 cm_ReleaseUser(userp);
5489 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5496 cm_scache_t *dscp; /* dir we're dealing with */
5497 cm_scache_t *scp; /* file we're creating */
5499 int initialModeBits;
5509 /* compute initial mode bits based on read-only flag in attributes */
5510 initialModeBits = 0777;
5512 tp = smb_GetSMBData(inp, NULL);
5513 pathp = smb_ParseASCIIBlock(tp, &tp);
5515 if (strcmp(pathp, "\\") == 0)
5516 return CM_ERROR_EXISTS;
5518 spacep = inp->spacep;
5519 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5521 userp = smb_GetUser(vcp, inp);
5523 caseFold = CM_FLAG_CASEFOLD;
5525 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5527 code = cm_NameI(cm_rootSCachep, spacep->data,
5528 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5529 userp, tidPathp, &req, &dscp);
5532 cm_ReleaseUser(userp);
5536 /* otherwise, scp points to the parent directory. Do a lookup, and
5537 * fail if we find it. Otherwise, we do the create.
5543 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5544 if (scp) cm_ReleaseSCache(scp);
5545 if (code != CM_ERROR_NOSUCHFILE) {
5546 if (code == 0) code = CM_ERROR_EXISTS;
5547 cm_ReleaseSCache(dscp);
5548 cm_ReleaseUser(userp);
5552 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5553 setAttr.clientModTime = time(NULL);
5554 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5555 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5556 smb_NotifyChange(FILE_ACTION_ADDED,
5557 FILE_NOTIFY_CHANGE_DIR_NAME,
5558 dscp, lastNamep, NULL, TRUE);
5560 /* we don't need this any longer */
5561 cm_ReleaseSCache(dscp);
5564 /* something went wrong creating or truncating the file */
5565 cm_ReleaseUser(userp);
5569 /* otherwise we succeeded */
5570 smb_SetSMBDataLength(outp, 0);
5571 cm_ReleaseUser(userp);
5576 BOOL smb_IsLegalFilename(char *filename)
5579 * Find the longest substring of filename that does not contain
5580 * any of the chars in illegalChars. If that substring is less
5581 * than the length of the whole string, then one or more of the
5582 * illegal chars is in filename.
5584 if (strcspn(filename, illegalChars) < strlen(filename))
5590 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5598 cm_scache_t *dscp; /* dir we're dealing with */
5599 cm_scache_t *scp; /* file we're creating */
5601 int initialModeBits;
5613 excl = (inp->inCom == 0x03)? 0 : 1;
5615 attributes = smb_GetSMBParm(inp, 0);
5616 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5618 /* compute initial mode bits based on read-only flag in attributes */
5619 initialModeBits = 0666;
5620 if (attributes & 1) initialModeBits &= ~0222;
5622 tp = smb_GetSMBData(inp, NULL);
5623 pathp = smb_ParseASCIIBlock(tp, &tp);
5625 spacep = inp->spacep;
5626 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5628 userp = smb_GetUser(vcp, inp);
5630 caseFold = CM_FLAG_CASEFOLD;
5632 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5633 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5634 userp, tidPathp, &req, &dscp);
5637 cm_ReleaseUser(userp);
5641 /* otherwise, scp points to the parent directory. Do a lookup, and
5642 * truncate the file if we find it, otherwise we create the file.
5644 if (!lastNamep) lastNamep = pathp;
5647 if (!smb_IsLegalFilename(lastNamep))
5648 return CM_ERROR_BADNTFILENAME;
5650 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5651 #ifdef DEBUG_VERBOSE
5654 hexp = osi_HexifyString( lastNamep );
5655 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5660 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5661 if (code && code != CM_ERROR_NOSUCHFILE) {
5662 cm_ReleaseSCache(dscp);
5663 cm_ReleaseUser(userp);
5667 /* if we get here, if code is 0, the file exists and is represented by
5668 * scp. Otherwise, we have to create it.
5672 /* oops, file shouldn't be there */
5673 cm_ReleaseSCache(dscp);
5674 cm_ReleaseSCache(scp);
5675 cm_ReleaseUser(userp);
5676 return CM_ERROR_EXISTS;
5679 setAttr.mask = CM_ATTRMASK_LENGTH;
5680 setAttr.length.LowPart = 0;
5681 setAttr.length.HighPart = 0;
5682 code = cm_SetAttr(scp, &setAttr, userp, &req);
5685 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5686 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5687 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5689 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5690 smb_NotifyChange(FILE_ACTION_ADDED,
5691 FILE_NOTIFY_CHANGE_FILE_NAME,
5692 dscp, lastNamep, NULL, TRUE);
5693 if (!excl && code == CM_ERROR_EXISTS) {
5694 /* not an exclusive create, and someone else tried
5695 * creating it already, then we open it anyway. We
5696 * don't bother retrying after this, since if this next
5697 * fails, that means that the file was deleted after
5698 * we started this call.
5700 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
5703 setAttr.mask = CM_ATTRMASK_LENGTH;
5704 setAttr.length.LowPart = 0;
5705 setAttr.length.HighPart = 0;
5706 code = cm_SetAttr(scp, &setAttr, userp, &req);
5711 /* we don't need this any longer */
5712 cm_ReleaseSCache(dscp);
5715 /* something went wrong creating or truncating the file */
5716 if (scp) cm_ReleaseSCache(scp);
5717 cm_ReleaseUser(userp);
5721 /* make sure we only open files */
5722 if (scp->fileType != CM_SCACHETYPE_FILE) {
5723 cm_ReleaseSCache(scp);
5724 cm_ReleaseUser(userp);
5725 return CM_ERROR_ISDIR;
5728 /* now all we have to do is open the file itself */
5729 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5732 /* save a pointer to the vnode */
5735 /* always create it open for read/write */
5736 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
5738 smb_ReleaseFID(fidp);
5740 smb_SetSMBParm(outp, 0, fidp->fid);
5741 smb_SetSMBDataLength(outp, 0);
5743 cm_Open(scp, 0, userp);
5745 cm_ReleaseUser(userp);
5746 /* leave scp held since we put it in fidp->scp */
5750 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5763 fd = smb_GetSMBParm(inp, 0);
5764 whence = smb_GetSMBParm(inp, 1);
5765 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5767 /* try to find the file descriptor */
5768 fd = smb_ChainFID(fd, inp);
5769 fidp = smb_FindFID(vcp, fd, 0);
5770 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5771 return CM_ERROR_BADFD;
5774 userp = smb_GetUser(vcp, inp);
5776 lock_ObtainMutex(&fidp->mx);
5778 lock_ObtainMutex(&scp->mx);
5779 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5780 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5783 /* offset from current offset */
5784 offset += fidp->offset;
5786 else if (whence == 2) {
5787 /* offset from current EOF */
5788 offset += scp->length.LowPart;
5790 fidp->offset = offset;
5791 smb_SetSMBParm(outp, 0, offset & 0xffff);
5792 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
5793 smb_SetSMBDataLength(outp, 0);
5795 lock_ReleaseMutex(&scp->mx);
5796 lock_ReleaseMutex(&fidp->mx);
5797 smb_ReleaseFID(fidp);
5798 cm_ReleaseUser(userp);
5802 /* dispatch all of the requests received in a packet. Due to chaining, this may
5803 * be more than one request.
5805 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5806 NCB *ncbp, raw_write_cont_t *rwcp)
5810 unsigned long code = 0;
5811 unsigned char *outWctp;
5812 int nparms; /* # of bytes of parameters */
5814 int nbytes; /* bytes of data, excluding count */
5817 unsigned short errCode;
5818 unsigned long NTStatus;
5820 unsigned char errClass;
5821 unsigned int oldGen;
5822 DWORD oldTime, newTime;
5824 /* get easy pointer to the data */
5825 smbp = (smb_t *) inp->data;
5827 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
5828 /* setup the basic parms for the initial request in the packet */
5829 inp->inCom = smbp->com;
5830 inp->wctp = &smbp->wct;
5832 inp->ncb_length = ncbp->ncb_length;
5837 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
5838 /* log it and discard it */
5843 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5844 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
5846 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
5847 1, ncbp->ncb_length, ptbuf, inp);
5848 DeregisterEventSource(h);
5850 osi_Log1(smb_logp, "SMB message too short, len %d",
5857 /* We are an ongoing op */
5858 thrd_Increment(&ongoingOps);
5860 /* set up response packet for receiving output */
5861 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
5862 smb_FormatResponsePacket(vcp, inp, outp);
5863 outWctp = outp->wctp;
5865 /* Remember session generation number and time */
5866 oldGen = sessionGen;
5867 oldTime = GetCurrentTime();
5869 while(inp->inCom != 0xff) {
5870 dp = &smb_dispatchTable[inp->inCom];
5872 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
5873 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
5874 code = outp->resumeCode;
5878 /* process each request in the packet; inCom, wctp and inCount
5879 * are already set up.
5881 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
5884 /* now do the dispatch */
5885 /* start by formatting the response record a little, as a default */
5886 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
5888 outWctp[1] = 0xff; /* no operation */
5889 outWctp[2] = 0; /* padding */
5894 /* not a chained request, this is a more reasonable default */
5895 outWctp[0] = 0; /* wct of zero */
5896 outWctp[1] = 0; /* and bcc (word) of zero */
5900 /* once set, stays set. Doesn't matter, since we never chain
5901 * "no response" calls.
5903 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
5907 /* we have a recognized operation */
5909 if (inp->inCom == 0x1d)
5911 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
5914 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
5915 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
5916 code = (*(dp->procp)) (vcp, inp, outp);
5917 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5918 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5921 if (oldGen != sessionGen) {
5926 newTime = GetCurrentTime();
5927 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5928 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
5929 newTime - oldTime, ncbp->ncb_length);
5931 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
5932 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
5933 DeregisterEventSource(h);
5935 osi_Log1(smb_logp, "Pkt straddled session startup, "
5936 "ncb length %d", ncbp->ncb_length);
5941 /* bad opcode, fail the request, after displaying it */
5944 #endif /* NOTSERVICE */
5948 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
5949 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
5950 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
5951 if (code == IDCANCEL) showErrors = 0;
5954 code = CM_ERROR_BADOP;
5957 /* catastrophic failure: log as much as possible */
5958 if (code == CM_ERROR_BADSMB) {
5965 "Invalid SMB, ncb_length %d",
5968 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5969 sprintf(s, "Invalid SMB message, length %d",
5972 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
5973 1, ncbp->ncb_length, ptbuf, smbp);
5974 DeregisterEventSource(h);
5977 #endif /* NOTSERVICE */
5979 osi_Log1(smb_logp, "Invalid SMB message, length %d",
5983 code = CM_ERROR_INVAL;
5986 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
5987 thrd_Decrement(&ongoingOps);
5992 /* now, if we failed, turn the current response into an empty
5993 * one, and fill in the response packet's error code.
5996 if (vcp->flags & SMB_VCFLAG_STATUS32) {
5997 smb_MapNTError(code, &NTStatus);
5998 outWctp = outp->wctp;
5999 smbp = (smb_t *) &outp->data;
6000 if (code != CM_ERROR_PARTIALWRITE
6001 && code != CM_ERROR_BUFFERTOOSMALL
6002 && code != CM_ERROR_GSSCONTINUE) {
6003 /* nuke wct and bcc. For a partial
6004 * write or an in-process authentication handshake,
6005 * assume they're OK.
6011 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6012 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6013 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6014 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6015 smbp->flg2 |= 0x4000;
6019 smb_MapCoreError(code, vcp, &errCode, &errClass);
6020 outWctp = outp->wctp;
6021 smbp = (smb_t *) &outp->data;
6022 if (code != CM_ERROR_PARTIALWRITE) {
6023 /* nuke wct and bcc. For a partial
6024 * write, assume they're OK.
6030 smbp->errLow = (unsigned char) (errCode & 0xff);
6031 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6032 smbp->rcls = errClass;
6035 } /* error occurred */
6037 /* if we're here, we've finished one request. Look to see if
6038 * this is a chained opcode. If it is, setup things to process
6039 * the chained request, and setup the output buffer to hold the
6040 * chained response. Start by finding the next input record.
6042 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6043 break; /* not a chained req */
6044 tp = inp->wctp; /* points to start of last request */
6045 /* in a chained request, the first two
6046 * parm fields are required, and are
6047 * AndXCommand/AndXReserved and
6049 if (tp[0] < 2) break;
6050 if (tp[1] == 0xff) break; /* no more chained opcodes */
6052 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6055 /* and now append the next output request to the end of this
6056 * last request. Begin by finding out where the last response
6057 * ends, since that's where we'll put our new response.
6059 outWctp = outp->wctp; /* ptr to out parameters */
6060 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6061 nparms = outWctp[0] << 1;
6062 tp = outWctp + nparms + 1; /* now points to bcc field */
6063 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6064 tp += 2 /* for the count itself */ + nbytes;
6065 /* tp now points to the new output record; go back and patch the
6066 * second parameter (off2) to point to the new record.
6068 temp = (unsigned int)tp - ((unsigned int) outp->data);
6069 outWctp[3] = (unsigned char) (temp & 0xff);
6070 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6071 outWctp[2] = 0; /* padding */
6072 outWctp[1] = inp->inCom; /* next opcode */
6074 /* finally, setup for the next iteration */
6077 } /* while loop over all requests in the packet */
6079 /* done logging out, turn off logging-out flag */
6080 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6081 vcp->justLoggedOut = NULL;
6084 free(loggedOutName);
6085 loggedOutName = NULL;
6086 smb_ReleaseUID(loggedOutUserp);
6087 loggedOutUserp = NULL;
6091 /* now send the output packet, and return */
6093 smb_SendPacket(vcp, outp);
6094 thrd_Decrement(&ongoingOps);
6096 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6098 smb_ReleaseVC(active_vcp);
6100 "Replacing active_vcp %x with %x", active_vcp, vcp);
6104 last_msg_time = GetCurrentTime();
6106 else if (active_vcp == vcp) {
6107 smb_ReleaseVC(active_vcp);
6115 /* Wait for Netbios() calls to return, and make the results available to server
6116 * threads. Note that server threads can't wait on the NCBevents array
6117 * themselves, because NCB events are manual-reset, and the servers would race
6118 * each other to reset them.
6120 void smb_ClientWaiter(void *parmp)
6126 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6128 if (code == WAIT_OBJECT_0)
6131 /* error checking */
6132 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6134 int abandonIdx = code - WAIT_ABANDONED_0;
6135 afsi_log("Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6138 if (code == WAIT_IO_COMPLETION)
6140 afsi_log("Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6144 if (code == WAIT_TIMEOUT)
6146 afsi_log("Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6149 if (code == WAIT_FAILED)
6151 afsi_log("Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6154 idx = code - WAIT_OBJECT_0;
6156 /* check idx range! */
6157 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6159 /* this is fatal - log as much as possible */
6160 afsi_log("Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6164 thrd_ResetEvent(NCBevents[idx]);
6165 thrd_SetEvent(NCBreturns[0][idx]);
6171 * Try to have one NCBRECV request waiting for every live session. Not more
6172 * than one, because if there is more than one, it's hard to handle Write Raw.
6174 void smb_ServerWaiter(void *parmp)
6177 int idx_session, idx_NCB;
6185 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6187 if (code == WAIT_OBJECT_0)
6190 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6192 int abandonIdx = code - WAIT_ABANDONED_0;
6193 afsi_log("Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6196 if (code == WAIT_IO_COMPLETION)
6198 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6202 if (code == WAIT_TIMEOUT)
6204 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6207 if (code == WAIT_FAILED)
6209 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6212 idx_session = code - WAIT_OBJECT_0;
6214 /* check idx range! */
6215 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6217 /* this is fatal - log as much as possible */
6218 afsi_log("Fatal: session idx [ %d ] out of range.\n", idx_session);
6224 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6226 if (code == WAIT_OBJECT_0)
6229 /* error checking */
6230 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6232 int abandonIdx = code - WAIT_ABANDONED_0;
6233 afsi_log("Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6236 if (code == WAIT_IO_COMPLETION)
6238 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6242 if (code == WAIT_TIMEOUT)
6244 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6247 if (code == WAIT_FAILED)
6249 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6252 idx_NCB = code - WAIT_OBJECT_0;
6254 /* check idx range! */
6255 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6257 /* this is fatal - log as much as possible */
6258 afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6262 /* Link them together */
6263 NCBsessions[idx_NCB] = idx_session;
6266 ncbp = NCBs[idx_NCB];
6268 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6270 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6271 ncbp->ncb_command = NCBRECV | ASYNCH;
6272 ncbp->ncb_lana_num = lanas[idx_session];
6274 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6275 ncbp->ncb_event = NCBevents[idx_NCB];
6276 ncbp->ncb_length = SMB_PACKETSIZE;
6279 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6280 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6281 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6282 ncbp->ncb_length = SMB_PACKETSIZE;
6283 Netbios(ncbp, dos_ncb);
6289 * The top level loop for handling SMB request messages. Each server thread
6290 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6291 * NCB and buffer for the incoming request are loaned to us.
6293 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6294 * to immediately send a request for the rest of the data. This must come
6295 * before any other traffic for that session, so we delay setting the session
6296 * event until that data has come in.
6298 void smb_Server(VOID *parmp)
6300 int myIdx = (int) parmp;
6304 smb_packet_t *outbufp;
6306 int idx_NCB, idx_session;
6308 smb_vc_t *vcp = NULL;
6315 outbufp = GetPacket();
6316 outbufp->ncbp = outncbp;
6320 /* check for demo expiration */
6322 unsigned long tod = time((void *) 0);
6323 if (tod > EXPIREDATE) {
6324 (*smb_MBfunc)(NULL, "AFS demo expiration",
6326 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6330 #endif /* !NOEXPIRE */
6332 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6334 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_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6345 if (code == WAIT_IO_COMPLETION)
6347 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6351 if (code == WAIT_TIMEOUT)
6353 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6356 if (code == WAIT_FAILED)
6358 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6361 idx_NCB = code - WAIT_OBJECT_0;
6363 /* check idx range! */
6364 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6366 /* this is fatal - log as much as possible */
6367 afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6371 ncbp = NCBs[idx_NCB];
6373 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6375 idx_session = NCBsessions[idx_NCB];
6376 rc = ncbp->ncb_retcode;
6378 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6379 osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6382 case NRC_GOODRET: break;
6385 /* Can this happen? Or is it just my
6392 /* Client closed session */
6393 if (reportSessionStartups)
6395 afsi_log("session [ %d ] closed", idx_session);
6397 dead_sessions[idx_session] = TRUE;
6400 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6401 /* Should also release vcp. [done] 2004-05-11 jaltman
6403 * sanity check that all TID's are gone.
6405 * TODO: check if we could use LSNs[idx_session] instead,
6406 * also cleanup after dead vcp
6411 "dead_vcp already set, %x",
6413 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6415 "setting dead_vcp %x, user struct %x",
6419 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6421 if (vcp->justLoggedOut) {
6423 loggedOutTime = vcp->logoffTime;
6425 strdup(vcp->justLoggedOut->unp->name);
6426 loggedOutUserp = vcp->justLoggedOut;
6427 lock_ObtainWrite(&smb_rctLock);
6428 loggedOutUserp->refCount++;
6429 lock_ReleaseWrite(&smb_rctLock);
6435 /* Treat as transient error */
6442 osi_Log1(smb_logp, "dispatch smb recv failed, message incomplete, ncb_length %d",
6444 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6445 sprintf(s, "SMB message incomplete, length %d",
6448 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6450 ncbp->ncb_length, ptbuf,
6452 DeregisterEventSource(h);
6455 "dispatch smb recv failed, message incomplete, ncb_length %d",
6458 "SMB message incomplete, "
6459 "length %d", ncbp->ncb_length);
6463 * We used to discard the packet.
6464 * Instead, try handling it normally.
6472 /* A weird error code. Log it, sleep, and
6474 if (vcp && vcp->errorCount++ > 3) {
6475 afsi_log("session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6476 dead_sessions[idx_session] = TRUE;
6480 thrd_SetEvent(SessionEvents[idx_session]);
6485 /* Success, so now dispatch on all the data in the packet */
6487 smb_concurrentCalls++;
6488 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6489 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6493 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6495 * If at this point vcp is NULL (implies that packet was invalid)
6496 * then we are in big trouble. This means either :
6497 * a) we have the wrong NCB.
6498 * b) Netbios screwed up the call.
6499 * Obviously this implies that
6500 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6501 * lanas[idx_session] != ncbp->ncb_lana_num )
6502 * Either way, we can't do anything with this packet.
6503 * Log, sleep and resume.
6512 "LSNs[idx_session]=[%d],"
6513 "lanas[idx_session]=[%d],"
6514 "ncbp->ncb_lsn=[%d],"
6515 "ncbp->ncb_lana_num=[%d]",
6519 ncbp->ncb_lana_num);
6523 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6525 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6526 DeregisterEventSource(h);
6529 /* Also log in the trace log. */
6530 osi_Log4(smb_logp, "Server: BAD VCP!"
6531 "LSNs[idx_session]=[%d],"
6532 "lanas[idx_session]=[%d],"
6533 "ncbp->ncb_lsn=[%d],"
6534 "ncbp->ncb_lana_num=[%d]",
6538 ncbp->ncb_lana_num);
6540 /* thrd_Sleep(1000); Don't bother sleeping */
6541 thrd_SetEvent(SessionEvents[idx_session]);
6542 smb_concurrentCalls--;
6547 vcp->errorCount = 0;
6548 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6550 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6551 /* copy whole packet to virtual memory */
6552 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6554 bufp->dos_pkt / 16, bufp);*/
6556 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6558 smbp = (smb_t *)bufp->data;
6561 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6565 if (smbp->com == 0x1d) {
6566 /* Special handling for Write Raw */
6567 raw_write_cont_t rwc;
6568 EVENT_HANDLE rwevent;
6569 char eventName[MAX_PATH];
6571 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6572 if (rwc.code == 0) {
6573 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6574 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6575 afsi_log("Event Object Already Exists: %s", eventName);
6576 ncbp->ncb_command = NCBRECV | ASYNCH;
6577 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6578 ncbp->ncb_lana_num = vcp->lana;
6579 ncbp->ncb_buffer = rwc.buf;
6580 ncbp->ncb_length = 65535;
6581 ncbp->ncb_event = rwevent;
6585 Netbios(ncbp, dos_ncb);
6587 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6588 thrd_CloseHandle(rwevent);
6590 thrd_SetEvent(SessionEvents[idx_session]);
6592 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6593 } else if (smbp->com == 0xa0) {
6595 * Serialize the handling for NT Transact
6598 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6599 thrd_SetEvent(SessionEvents[idx_session]);
6601 thrd_SetEvent(SessionEvents[idx_session]);
6602 /* TODO: what else needs to be serialized? */
6603 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6605 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6607 __except( smb_ServerExceptionFilter() ) {
6611 smb_concurrentCalls--;
6614 thrd_SetEvent(NCBavails[idx_NCB]);
6621 * Exception filter for the server threads. If an exception occurs in the
6622 * dispatch routines, which is where exceptions are most common, then do a
6623 * force trace and give control to upstream exception handlers. Useful for
6626 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6627 DWORD smb_ServerExceptionFilter(void) {
6628 /* While this is not the best time to do a trace, if it succeeds, then
6629 * we have a trace (assuming tracing was enabled). Otherwise, this should
6630 * throw a second exception.
6635 ptbuf[0] = "Unhandled exception forcing trace";
6637 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6639 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6640 DeregisterEventSource(h);
6643 afsd_ForceTrace(TRUE);
6644 return EXCEPTION_CONTINUE_SEARCH;
6649 * Create a new NCB and associated events, packet buffer, and "space" buffer.
6650 * If the number of server threads is M, and the number of live sessions is
6651 * N, then the number of NCB's in use at any time either waiting for, or
6652 * holding, received messages is M + N, so that is how many NCB's get created.
6654 void InitNCBslot(int idx)
6656 struct smb_packet *bufp;
6657 EVENT_HANDLE retHandle;
6659 char eventName[MAX_PATH];
6661 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6663 NCBs[idx] = GetNCB();
6664 sprintf(eventName,"NCBavails[%d]", idx);
6665 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6666 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6667 afsi_log("Event Object Already Exists: %s", eventName);
6669 sprintf(eventName,"NCBevents[%d]", idx);
6670 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
6671 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6672 afsi_log("Event Object Already Exists: %s", eventName);
6674 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
6675 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6676 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6677 afsi_log("Event Object Already Exists: %s", eventName);
6678 for (i=0; i<smb_NumServerThreads; i++)
6679 NCBreturns[i][idx] = retHandle;
6681 bufp->spacep = cm_GetSpace();
6685 /* listen for new connections */
6686 void smb_Listener(void *parmp)
6694 char rname[NCBNAMSZ+1];
6695 char cname[MAX_COMPUTERNAME_LENGTH+1];
6696 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
6701 int lana = (int) parmp;
6705 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6708 /* retrieve computer name */
6709 GetComputerName(cname, &cnamelen);
6713 memset(ncbp, 0, sizeof(NCB));
6717 /* check for demo expiration */
6719 unsigned long tod = time((void *) 0);
6720 if (tod > EXPIREDATE) {
6721 (*smb_MBfunc)(NULL, "AFS demo expiration",
6723 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6731 #endif /* !NOEXPIRE */
6733 ncbp->ncb_command = NCBLISTEN;
6734 ncbp->ncb_rto = 0; /* No receive timeout */
6735 ncbp->ncb_sto = 0; /* No send timeout */
6737 /* pad out with spaces instead of null termination */
6738 len = strlen(smb_localNamep);
6739 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
6740 for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
6742 strcpy(ncbp->ncb_callname, "*");
6743 for(i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
6745 ncbp->ncb_lana_num = lana;
6748 code = Netbios(ncbp);
6750 code = Netbios(ncbp, dos_ncb);
6759 /* terminate silently if shutdown flag is set */
6760 if (smbShutdownFlag == 1) {
6769 "NCBLISTEN lana=%d failed with code %d",
6770 ncbp->ncb_lana_num, code);
6772 "Client exiting due to network failure. Please restart client.\n");
6776 "Client exiting due to network failure. Please restart client.\n"
6777 "NCBLISTEN lana=%d failed with code %d",
6778 ncbp->ncb_lana_num, code);
6780 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
6781 MB_OK|MB_SERVICE_NOTIFICATION);
6782 osi_assert(tbuffer);
6785 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
6786 ncbp->ncb_lana_num, code);
6787 fprintf(stderr, "\nClient exiting due to network failure "
6788 "(possibly due to power-saving mode)\n");
6789 fprintf(stderr, "Please restart client.\n");
6790 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
6794 /* check for remote conns */
6795 /* first get remote name and insert null terminator */
6796 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
6797 for (i=NCBNAMSZ; i>0; i--) {
6798 if (rname[i-1] != ' ' && rname[i-1] != 0) {
6804 /* compare with local name */
6806 if (strncmp(rname, cname, NCBNAMSZ) != 0)
6807 flags |= SMB_VCFLAG_REMOTECONN;
6809 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
6811 lock_ObtainMutex(&smb_ListenerLock);
6813 /* New generation */
6816 /* Log session startup */
6818 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
6820 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
6822 afsi_log("New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
6823 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname, ongoingOps);
6825 if (reportSessionStartups) {
6831 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6832 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
6834 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
6836 DeregisterEventSource(h);
6838 afsi_log("NCBLISTEN completed, call from %s",rname);
6839 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
6842 fprintf(stderr, "%s: New session %d starting from host %s\n",
6843 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
6848 /* now ncbp->ncb_lsn is the connection ID */
6849 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
6850 vcp->flags |= flags;
6851 strcpy(vcp->rname, rname);
6853 /* Allocate slot in session arrays */
6854 /* Re-use dead session if possible, otherwise add one more */
6855 /* But don't look at session[0], it is reserved */
6856 for (i = 1; i < numSessions; i++) {
6857 if (dead_sessions[i]) {
6858 afsi_log("connecting to dead session [ %d ]", i);
6859 dead_sessions[i] = FALSE;
6864 /* assert that we do not exceed the maximum number of sessions or NCBs.
6865 * we should probably want to wait for a session to be freed in case
6869 osi_assert(i < Sessionmax - 1);
6870 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
6872 LSNs[i] = ncbp->ncb_lsn;
6873 lanas[i] = ncbp->ncb_lana_num;
6875 if (i == numSessions) {
6876 /* Add new NCB for new session */
6877 char eventName[MAX_PATH];
6879 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
6881 InitNCBslot(numNCBs);
6883 thrd_SetEvent(NCBavails[0]);
6884 thrd_SetEvent(NCBevents[0]);
6885 for (j = 0; j < smb_NumServerThreads; j++)
6886 thrd_SetEvent(NCBreturns[j][0]);
6887 /* Also add new session event */
6888 sprintf(eventName, "SessionEvents[%d]", i);
6889 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6890 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6891 afsi_log("Event Object Already Exists: %s", eventName);
6893 afsi_log("increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
6894 thrd_SetEvent(SessionEvents[0]);
6896 thrd_SetEvent(SessionEvents[i]);
6899 lock_ReleaseMutex(&smb_ListenerLock);
6901 } /* dispatch while loop */
6904 /* initialize Netbios */
6905 void smb_NetbiosInit()
6911 int i, lana, code, l;
6913 int delname_tried=0;
6916 OSVERSIONINFO Version;
6918 /* AFAIK, this is the default for the ms loopback adapter.*/
6919 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
6920 /*******************************************************************/
6922 /* Get the version of Windows */
6923 memset(&Version, 0x00, sizeof(Version));
6924 Version.dwOSVersionInfoSize = sizeof(Version);
6925 GetVersionEx(&Version);
6927 /* setup the NCB system */
6930 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6934 if (smb_LANadapter == -1) {
6935 ncbp->ncb_command = NCBENUM;
6936 ncbp->ncb_buffer = (PUCHAR)&lana_list;
6937 ncbp->ncb_length = sizeof(lana_list);
6938 code = Netbios(ncbp);
6940 sprintf(s, "Netbios NCBENUM error code %d", code);
6942 osi_panic(s, __FILE__, __LINE__);
6946 lana_list.length = 1;
6947 lana_list.lana[0] = smb_LANadapter;
6950 for (i = 0; i < lana_list.length; i++) {
6951 /* reset the adaptor: in Win32, this is required for every process, and
6952 * acts as an init call, not as a real hardware reset.
6954 ncbp->ncb_command = NCBRESET;
6955 ncbp->ncb_callname[0] = 100;
6956 ncbp->ncb_callname[2] = 100;
6957 ncbp->ncb_lana_num = lana_list.lana[i];
6958 code = Netbios(ncbp);
6960 code = ncbp->ncb_retcode;
6962 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
6964 lana_list.lana[i] = 255; /* invalid lana */
6966 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
6971 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
6972 we will just fake the LANA list */
6973 if (smb_LANadapter == -1) {
6974 for (i = 0; i < 8; i++)
6975 lana_list.lana[i] = i;
6976 lana_list.length = 8;
6979 lana_list.length = 1;
6980 lana_list.lana[0] = smb_LANadapter;
6984 /* and declare our name so we can receive connections */
6985 memset(ncbp, 0, sizeof(*ncbp));
6986 len=lstrlen(smb_localNamep);
6987 memset(smb_sharename,' ',NCBNAMSZ);
6988 memcpy(smb_sharename,smb_localNamep,len);
6989 sprintf(s, "lana_list.length %d", lana_list.length);
6992 /* Keep the name so we can unregister it later */
6993 for (l = 0; l < lana_list.length; l++) {
6994 lana = lana_list.lana[l];
6996 ncbp->ncb_command = NCBADDNAME;
6997 ncbp->ncb_lana_num = lana;
6998 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7000 code = Netbios(ncbp);
7002 code = Netbios(ncbp, dos_ncb);
7005 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7006 lana, code, ncbp->ncb_retcode,ncbp->ncb_cmd_cplt);
7008 char name[NCBNAMSZ+1];
7010 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7011 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
7014 if (code == 0) code = ncbp->ncb_retcode;
7016 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
7018 /* we only use one LANA with djgpp */
7019 lana_list.lana[0] = lana;
7020 lana_list.length = 1;
7024 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7026 if (code == NRC_BRIDGE) { /* invalid LANA num */
7027 lana_list.lana[l] = 255;
7030 else if (code == NRC_DUPNAME) {
7031 afsi_log("Name already exists; try to delete it");
7032 memset(ncbp, 0, sizeof(*ncbp));
7033 ncbp->ncb_command = NCBDELNAME;
7034 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7035 ncbp->ncb_lana_num = lana;
7037 code = Netbios(ncbp);
7039 code = Netbios(ncbp, dos_ncb);
7041 if (code == 0) code = ncbp->ncb_retcode;
7043 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7046 if (code != 0 || delname_tried) {
7047 lana_list.lana[l] = 255;
7049 else if (code == 0) {
7050 if (!delname_tried) {
7058 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7060 lana_list.lana[l] = 255; /* invalid lana */
7061 osi_panic(s, __FILE__, __LINE__);
7065 lana_found = 1; /* at least one worked */
7072 osi_assert(lana_list.length >= 0);
7074 sprintf(s, "No valid LANA numbers found!");
7075 osi_panic(s, __FILE__, __LINE__);
7078 /* we're done with the NCB now */
7082 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7099 EVENT_HANDLE retHandle;
7100 char eventName[MAX_PATH];
7103 smb_MBfunc = aMBfunc;
7107 /* check for demo expiration */
7109 unsigned long tod = time((void *) 0);
7110 if (tod > EXPIREDATE) {
7112 (*smb_MBfunc)(NULL, "AFS demo expiration", "afsd",
7113 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
7116 fprintf(stderr, "AFS demo expiration\n");
7121 #endif /* !NOEXPIRE */
7124 smb_LANadapter = LANadapt;
7126 /* Initialize smb_localZero */
7127 myTime.tm_isdst = -1; /* compute whether on DST or not */
7128 myTime.tm_year = 70;
7134 smb_localZero = mktime(&myTime);
7136 /* Initialize kludge-GMT */
7137 smb_CalculateNowTZ();
7139 /* initialize the remote debugging log */
7142 /* remember the name */
7143 len = strlen(snamep);
7144 smb_localNamep = malloc(len+1);
7145 strcpy(smb_localNamep, snamep);
7146 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7148 /* and the global lock */
7149 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7150 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7152 /* Raw I/O data structures */
7153 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7155 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7157 /* 4 Raw I/O buffers */
7159 smb_RawBufs = calloc(65536,1);
7160 *((char **)smb_RawBufs) = NULL;
7161 for (i=0; i<3; i++) {
7162 char *rawBuf = calloc(65536,1);
7163 *((char **)rawBuf) = smb_RawBufs;
7164 smb_RawBufs = rawBuf;
7167 npar = 65536 >> 4; /* number of paragraphs */
7168 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7170 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7172 osi_panic("",__FILE__,__LINE__);
7175 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7178 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7180 _farpokel(_dos_ds, smb_RawBufs, NULL);
7181 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7182 npar = 65536 >> 4; /* number of paragraphs */
7183 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7185 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7187 osi_panic("",__FILE__,__LINE__);
7190 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7193 rawBuf = (seg * 16) + 0; /* DOS physical address */
7194 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7195 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7196 smb_RawBufs = rawBuf;
7200 /* global free lists */
7201 smb_ncbFreeListp = NULL;
7202 smb_packetFreeListp = NULL;
7206 /* Initialize listener and server structures */
7208 memset(dead_sessions, 0, sizeof(dead_sessions));
7209 sprintf(eventName, "SessionEvents[0]");
7210 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7211 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7212 afsi_log("Event Object Already Exists: %s", eventName);
7214 smb_NumServerThreads = nThreads;
7215 sprintf(eventName, "NCBavails[0]");
7216 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7217 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7218 afsi_log("Event Object Already Exists: %s", eventName);
7219 sprintf(eventName, "NCBevents[0]");
7220 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7221 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7222 afsi_log("Event Object Already Exists: %s", eventName);
7223 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7224 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7225 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7226 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7227 afsi_log("Event Object Already Exists: %s", eventName);
7228 for (i = 0; i < smb_NumServerThreads; i++) {
7229 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7230 NCBreturns[i][0] = retHandle;
7232 for (i = 1; i <= nThreads; i++)
7234 numNCBs = nThreads + 1;
7236 /* Initialize dispatch table */
7237 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7238 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7239 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7240 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7241 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7242 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7243 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7244 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7245 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7246 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7247 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7248 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7249 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7250 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7251 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7252 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7253 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7254 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7255 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7256 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7257 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7258 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7259 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7260 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7261 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7262 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7263 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7264 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7265 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7266 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7267 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7268 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7269 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7270 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7271 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7272 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7273 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7274 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7275 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7276 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7277 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7278 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7279 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7280 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7281 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7282 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7283 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7284 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7285 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7286 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7287 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7288 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7289 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7290 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7291 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7292 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7293 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7294 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7295 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7296 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7297 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7298 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7299 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;
7300 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;
7301 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;
7302 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;
7303 for(i=0xd0; i<= 0xd7; i++) {
7304 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7307 /* setup tran 2 dispatch table */
7308 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7309 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7310 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7311 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7312 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7313 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7314 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7315 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7316 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7317 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7318 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7319 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7320 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7321 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2MKDir;
7323 /* setup the rap dispatch table */
7324 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
7325 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
7326 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
7327 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
7328 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
7332 /* if we are doing SMB authentication we have register outselves as a logon process */
7333 if (smb_authType != SMB_AUTH_NONE) {
7335 LSA_STRING afsProcessName;
7336 LSA_OPERATIONAL_MODE dummy; /*junk*/
7338 afsProcessName.Buffer = "OpenAFSClientDaemon";
7339 afsProcessName.Length = strlen(afsProcessName.Buffer);
7340 afsProcessName.MaximumLength = afsProcessName.Length + 1;
7342 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7344 if (nts == STATUS_SUCCESS) {
7345 LSA_STRING packageName;
7346 /* we are registered. Find out the security package id */
7347 packageName.Buffer = MSV1_0_PACKAGE_NAME;
7348 packageName.Length = strlen(packageName.Buffer);
7349 packageName.MaximumLength = packageName.Length + 1;
7350 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7351 if (nts == STATUS_SUCCESS) {
7352 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7353 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7354 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7356 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7359 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7362 if (nts != STATUS_SUCCESS) {
7363 /* something went wrong. We report the error and revert back to no authentication
7364 because we can't perform any auth requests without a successful lsa handle
7365 or sec package id. */
7366 afsi_log("Reverting to NO SMB AUTH");
7367 smb_authType = SMB_AUTH_NONE;
7370 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
7371 * time prevents the failure of authentication when logged into Windows with an
7372 * external Kerberos principal mapped to a local account.
7374 else if ( smb_authType == SMB_AUTH_EXTENDED) {
7375 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
7376 * then the only option is NTLMSSP anyway; so just fallback.
7381 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7382 if (secBlobLength == 0) {
7383 smb_authType = SMB_AUTH_NTLM;
7384 afsi_log("Reverting to SMB AUTH NTLM");
7393 /* Now get ourselves a domain name. */
7394 /* For now we are using the local computer name as the domain name.
7395 * It is actually the domain for local logins, and we are acting as
7396 * a local SMB server.
7398 bufsize = sizeof(smb_ServerDomainName) - 1;
7399 GetComputerName(smb_ServerDomainName, &bufsize);
7400 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7401 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7404 /* Start listeners, waiters, servers, and daemons */
7406 for (i = 0; i < lana_list.length; i++) {
7407 if (lana_list.lana[i] == 255) continue;
7408 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7409 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7410 osi_assert(phandle != NULL);
7411 thrd_CloseHandle(phandle);
7415 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7416 NULL, 0, &lpid, "smb_ClientWaiter");
7417 osi_assert(phandle != NULL);
7418 thrd_CloseHandle(phandle);
7421 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7422 NULL, 0, &lpid, "smb_ServerWaiter");
7423 osi_assert(phandle != NULL);
7424 thrd_CloseHandle(phandle);
7426 for (i=0; i<nThreads; i++) {
7427 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7428 (void *) i, 0, &lpid, "smb_Server");
7429 osi_assert(phandle != NULL);
7430 thrd_CloseHandle(phandle);
7433 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7434 NULL, 0, &lpid, "smb_Daemon");
7435 osi_assert(phandle != NULL);
7436 thrd_CloseHandle(phandle);
7438 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7439 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7440 osi_assert(phandle != NULL);
7441 thrd_CloseHandle(phandle);
7450 void smb_Shutdown(void)
7459 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7461 /* setup the NCB system */
7464 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7467 /* Block new sessions by setting shutdown flag */
7468 smbShutdownFlag = 1;
7470 /* Hang up all sessions */
7471 memset((char *)ncbp, 0, sizeof(NCB));
7472 for (i = 1; i < numSessions; i++)
7474 if (dead_sessions[i])
7477 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7478 ncbp->ncb_command = NCBHANGUP;
7479 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7480 ncbp->ncb_lsn = LSNs[i];
7482 code = Netbios(ncbp);
7484 code = Netbios(ncbp, dos_ncb);
7486 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7487 if (code == 0) code = ncbp->ncb_retcode;
7489 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7490 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7494 /* Delete Netbios name */
7495 memset((char *)ncbp, 0, sizeof(NCB));
7496 for (i = 0; i < lana_list.length; i++) {
7497 if (lana_list.lana[i] == 255) continue;
7498 ncbp->ncb_command = NCBDELNAME;
7499 ncbp->ncb_lana_num = lana_list.lana[i];
7500 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7502 code = Netbios(ncbp);
7504 code = Netbios(ncbp, dos_ncb);
7506 if (code == 0) code = ncbp->ncb_retcode;
7508 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7509 ncbp->ncb_lana_num, code);
7515 /* Get the UNC \\<servername>\<sharename> prefix. */
7516 char *smb_GetSharename()
7520 /* Make sure we have been properly initialized. */
7521 if (smb_localNamep == NULL)
7524 /* Allocate space for \\<servername>\<sharename>, plus the
7527 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7528 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7534 void smb_LogPacket(smb_packet_t *packet)
7537 unsigned length, paramlen, datalen, i, j;
7539 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7543 osi_Log0(smb_logp, "*** SMB packet dump ***");
7545 vp = (BYTE *) packet->data;
7547 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7548 length = paramlen + 2 + datalen;
7551 for(i=0;i < length; i+=16)
7553 memset( buf, ' ', 80 );
7558 buf[strlen(buf)] = ' ';
7560 cp = (BYTE*) buf + 7;
7562 for(j=0;j < 16 && (i+j)<length; j++)
7564 *(cp++) = hex[vp[i+j] >> 4];
7565 *(cp++) = hex[vp[i+j] & 0xf];
7575 for(j=0;j < 16 && (i+j)<length;j++)
7577 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7588 osi_Log0( smb_logp, buf );
7591 osi_Log0(smb_logp, "*** End SMB packet dump ***");
7595 #endif /* NOTSERVICE */
7597 int smb_DumpVCP(FILE *outputFile, char *cookie)
7604 lock_ObtainRead(&smb_rctLock);
7606 sprintf(output, "begin dumping vcpsp\n");
7607 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7609 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7613 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7614 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7615 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7617 sprintf(output, "begin dumping fidsp\n");
7618 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7620 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7622 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",
7623 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
7624 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
7625 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7626 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7629 sprintf(output, "done dumping fidsp\n");
7630 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7633 sprintf(output, "done dumping vcpsp\n");
7634 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7636 lock_ReleaseRead(&smb_rctLock);