2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 //#define NOTSERVICE 1
13 #include <afs/param.h>
19 #include <sys/timeb.h>
35 #include "lanahelper.h"
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
49 int smbShutdownFlag = 0;
51 int smb_LogoffTokenTransfer;
52 time_t smb_LogoffTransferTimeout;
54 DWORD last_msg_time = 0;
58 unsigned int sessionGen = 0;
60 extern void afsi_log(char *pattern, ...);
61 extern HANDLE afsi_file;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
72 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
75 long smb_maxObsConcurrentCalls=0;
76 long smb_concurrentCalls=0;
78 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
80 smb_packet_t *smb_packetFreeListp;
81 smb_ncb_t *smb_ncbFreeListp;
83 int smb_NumServerThreads;
85 int numNCBs, numSessions, numVCs;
87 int smb_maxVCPerServer;
88 int smb_maxMpxRequests;
90 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
92 ULONG smb_lsaSecPackage;
93 LSA_STRING smb_lsaLogonOrigin;
95 #define NCBmax MAXIMUM_WAIT_OBJECTS
96 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
97 EVENT_HANDLE **NCBreturns;
98 DWORD NCBsessions[NCBmax];
100 struct smb_packet *bufs[NCBmax];
102 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
103 EVENT_HANDLE SessionEvents[Sessionmax];
104 unsigned short LSNs[Sessionmax];
105 int lanas[Sessionmax];
106 BOOL dead_sessions[Sessionmax];
110 osi_mutex_t smb_RawBufLock;
112 #define SMB_RAW_BUFS 4
114 int smb_RawBufSel[SMB_RAW_BUFS];
119 #define SMB_MASKFLAG_TILDE 1
120 #define SMB_MASKFLAG_CASEFOLD 2
122 #define RAWTIMEOUT INFINITE
125 typedef struct raw_write_cont {
138 /* dir search stuff */
139 long smb_dirSearchCounter = 1;
140 smb_dirSearch_t *smb_firstDirSearchp;
141 smb_dirSearch_t *smb_lastDirSearchp;
143 /* hide dot files? */
144 int smb_hideDotFiles;
146 /* global state about V3 protocols */
147 int smb_useV3; /* try to negotiate V3 */
150 static showErrors = 1;
151 /* MessageBox or something like it */
152 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
153 extern HANDLE WaitToTerminate;
157 * Time in Unix format of midnight, 1/1/1970 local time.
158 * When added to dosUTime, gives Unix (AFS) time.
160 long smb_localZero = 0;
162 /* Time difference for converting to kludge-GMT */
165 char *smb_localNamep = NULL;
167 smb_vc_t *smb_allVCsp;
169 smb_username_t *usernamesp = NULL;
171 smb_waitingLock_t *smb_allWaitingLocks;
174 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
175 NCB *ncbp, raw_write_cont_t *rwcp);
176 void smb_NetbiosInit();
178 #ifndef AFS_WIN95_ENV
179 DWORD smb_ServerExceptionFilter(void);
182 extern char cm_HostName[];
183 extern char cm_confDir[];
187 #define LPTSTR char *
188 #define GetComputerName(str, sizep) \
189 strcpy((str), cm_HostName); \
190 *(sizep) = strlen(cm_HostName)
194 void smb_LogPacket(smb_packet_t *packet);
195 #endif /* LOG_PACKET */
196 extern char AFSConfigKeyName[];
198 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
199 int smb_ServerDomainNameLength = 0;
200 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
201 int smb_ServerOSLength = sizeof(smb_ServerOS);
202 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
203 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
205 /* Faux server GUID. This is never checked. */
206 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
211 * To build an expiring version, comment out the definition of NOEXPIRE,
212 * and set the definition of EXPIREDATE to the desired value.
215 #define EXPIREDATE 834000000 /* Wed Jun 5 1996 */
218 char * myCrt_Dispatch(int i)
223 return "(00)ReceiveCoreMakeDir";
225 return "(01)ReceiveCoreRemoveDir";
227 return "(02)ReceiveCoreOpen";
229 return "(03)ReceiveCoreCreate";
231 return "(04)ReceiveCoreClose";
233 return "(05)ReceiveCoreFlush";
235 return "(06)ReceiveCoreUnlink";
237 return "(07)ReceiveCoreRename";
239 return "(08)ReceiveCoreGetFileAttributes";
241 return "(09)ReceiveCoreSetFileAttributes";
243 return "(0a)ReceiveCoreRead";
245 return "(0b)ReceiveCoreWrite";
247 return "(0c)ReceiveCoreLockRecord";
249 return "(0d)ReceiveCoreUnlockRecord";
251 return "(0e)SendCoreBadOp";
253 return "(0f)ReceiveCoreCreate";
255 return "(10)ReceiveCoreCheckPath";
257 return "(11)SendCoreBadOp";
259 return "(12)ReceiveCoreSeek";
261 return "(1a)ReceiveCoreReadRaw";
263 return "(1d)ReceiveCoreWriteRawDummy";
265 return "(22)ReceiveV3SetAttributes";
267 return "(23)ReceiveV3GetAttributes";
269 return "(24)ReceiveV3LockingX";
271 return "(25)ReceiveV3Trans";
273 return "(26)ReceiveV3Trans[aux]";
275 return "(29)SendCoreBadOp";
277 return "(2b)ReceiveCoreEcho";
279 return "(2d)ReceiveV3OpenX";
281 return "(2e)ReceiveV3ReadX";
283 return "(32)ReceiveV3Tran2A";
285 return "(33)ReceiveV3Tran2A[aux]";
287 return "(34)ReceiveV3FindClose";
289 return "(35)ReceiveV3FindNotifyClose";
291 return "(70)ReceiveCoreTreeConnect";
293 return "(71)ReceiveCoreTreeDisconnect";
295 return "(72)ReceiveNegotiate";
297 return "(73)ReceiveV3SessionSetupX";
299 return "(74)ReceiveV3UserLogoffX";
301 return "(75)ReceiveV3TreeConnectX";
303 return "(80)ReceiveCoreGetDiskAttributes";
305 return "(81)ReceiveCoreSearchDir";
309 return "(83)FindUnique";
311 return "(84)FindClose";
313 return "(A0)ReceiveNTTransact";
315 return "(A2)ReceiveNTCreateX";
317 return "(A4)ReceiveNTCancel";
319 return "(A5)ReceiveNTRename";
321 return "(C0)OpenPrintFile";
323 return "(C1)WritePrintFile";
325 return "(C2)ClosePrintFile";
327 return "(C3)GetPrintQueue";
329 return "(D8)ReadBulk";
331 return "(D9)WriteBulk";
333 return "(DA)WriteBulkData";
335 return "unknown SMB op";
339 char * myCrt_2Dispatch(int i)
344 return "unknown SMB op-2";
346 return "S(00)CreateFile";
348 return "S(01)FindFirst";
350 return "S(02)FindNext"; /* FindNext */
352 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
356 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
358 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
360 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
362 return "S(08)??_ReceiveTran2SetFileInfo";
364 return "S(09)??_ReceiveTran2FSCTL";
366 return "S(0a)_ReceiveTran2IOCTL";
368 return "S(0b)_ReceiveTran2FindNotifyFirst";
370 return "S(0c)_ReceiveTran2FindNotifyNext";
372 return "S(0d)_ReceiveTran2CreateDirectory";
374 return "S(0e)_ReceiveTran2SessionSetup";
378 char * myCrt_RapDispatch(int i)
383 return "unknown RAP OP";
385 return "RAP(0)NetShareEnum";
387 return "RAP(1)NetShareGetInfo";
389 return "RAP(13)NetServerGetInfo";
391 return "RAP(63)NetWkStaGetInfo";
395 /* scache must be locked */
396 unsigned int smb_Attributes(cm_scache_t *scp)
400 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
401 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
402 attrs = SMB_ATTR_DIRECTORY;
407 * We used to mark a file RO if it was in an RO volume, but that
408 * turns out to be impolitic in NT. See defect 10007.
411 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
413 if ((scp->unixModeBits & 0222) == 0)
414 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
419 /* Check if the named file/dir is a dotfile/dotdir */
420 /* String pointed to by lastComp can have leading slashes, but otherwise should have
421 no other patch components */
422 unsigned int smb_IsDotFile(char *lastComp) {
425 /* skip over slashes */
426 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
431 /* nulls, curdir and parent dir doesn't count */
434 if(!*(s + 1)) return 0;
435 if(*(s+1) == '.' && !*(s + 2)) return 0;
441 static int ExtractBits(WORD bits, short start, short len)
448 num = bits << (16 - end);
449 num = num >> ((16 - end) + start);
455 void ShowUnixTime(char *FuncName, time_t unixTime)
460 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
462 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
463 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
465 int day, month, year, sec, min, hour;
468 day = ExtractBits(wDate, 0, 5);
469 month = ExtractBits(wDate, 5, 4);
470 year = ExtractBits(wDate, 9, 7) + 1980;
472 sec = ExtractBits(wTime, 0, 5);
473 min = ExtractBits(wTime, 5, 6);
474 hour = ExtractBits(wTime, 11, 5);
476 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
477 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
483 /* Determine if we are observing daylight savings time */
484 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
486 TIME_ZONE_INFORMATION timeZoneInformation;
487 SYSTEMTIME utc, local, localDST;
489 /* Get the time zone info. NT uses this to calc if we are in DST. */
490 GetTimeZoneInformation(&timeZoneInformation);
492 /* Return the daylight bias */
493 *pDstBias = timeZoneInformation.DaylightBias;
495 /* Return the bias */
496 *pBias = timeZoneInformation.Bias;
498 /* Now determine if DST is being observed */
500 /* Get the UTC (GMT) time */
503 /* Convert UTC time to local time using the time zone info. If we are
504 observing DST, the calculated local time will include this.
506 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
508 /* Set the daylight bias to 0. The daylight bias is the amount of change
509 in time that we use for daylight savings time. By setting this to 0
510 we cause there to be no change in time during daylight savings time.
512 timeZoneInformation.DaylightBias = 0;
514 /* Convert the utc time to local time again, but this time without any
515 adjustment for daylight savings time.
517 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
519 /* If the two times are different, then it means that the localDST that
520 we calculated includes the daylight bias, and therefore we are
521 observing daylight savings time.
523 *pDST = localDST.wHour != local.wHour;
526 /* Determine if we are observing daylight savings time */
527 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
533 *pDstBias = -60; /* where can this be different? */
539 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
541 BOOL dst; /* Will be TRUE if observing DST */
542 LONG dstBias; /* Offset from local time if observing DST */
543 LONG bias; /* Offset from GMT for local time */
546 * This function will adjust the last write time to compensate
547 * for two bugs in the smb client:
549 * 1) During Daylight Savings Time, the LastWriteTime is ahead
550 * in time by the DaylightBias (ignoring the sign - the
551 * DaylightBias is always stored as a negative number). If
552 * the DaylightBias is -60, then the LastWriteTime will be
553 * ahead by 60 minutes.
555 * 2) If the local time zone is a positive offset from GMT, then
556 * the LastWriteTime will be the correct local time plus the
557 * Bias (ignoring the sign - a positive offset from GMT is
558 * always stored as a negative Bias). If the Bias is -120,
559 * then the LastWriteTime will be ahead by 120 minutes.
561 * These bugs can occur at the same time.
564 GetTimeZoneInfo(&dst, &dstBias, &bias);
566 /* First adjust for DST */
568 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
570 /* Now adjust for a positive offset from GMT (a negative bias). */
572 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
576 * Calculate the difference (in seconds) between local time and GMT.
577 * This enables us to convert file times to kludge-GMT.
583 struct tm gmt_tm, local_tm;
584 int days, hours, minutes, seconds;
587 gmt_tm = *(gmtime(&t));
588 local_tm = *(localtime(&t));
590 days = local_tm.tm_yday - gmt_tm.tm_yday;
591 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
593 /* There is a problem with DST immediately after the time change
594 * which may continue to exist until the machine is rebooted
596 - (local_tm.tm_isdst ? 1 : 0)
599 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
600 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
606 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
611 time_t ersatz_unixTime;
614 * Must use kludge-GMT instead of real GMT.
615 * kludge-GMT is computed by adding time zone difference to localtime.
618 * ltp = gmtime(&unixTime);
620 ersatz_unixTime = unixTime - smb_NowTZ;
621 ltp = localtime(&ersatz_unixTime);
623 /* if we fail, make up something */
626 localJunk.tm_year = 89 - 20;
627 localJunk.tm_mon = 4;
628 localJunk.tm_mday = 12;
629 localJunk.tm_hour = 0;
630 localJunk.tm_min = 0;
631 localJunk.tm_sec = 0;
634 stm.wYear = ltp->tm_year + 1900;
635 stm.wMonth = ltp->tm_mon + 1;
636 stm.wDayOfWeek = ltp->tm_wday;
637 stm.wDay = ltp->tm_mday;
638 stm.wHour = ltp->tm_hour;
639 stm.wMinute = ltp->tm_min;
640 stm.wSecond = ltp->tm_sec;
641 stm.wMilliseconds = 0;
643 SystemTimeToFileTime(&stm, largeTimep);
646 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
648 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
649 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
650 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
652 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
654 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
655 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
657 *ft = LargeIntegerMultiplyByLong(*ft, 60);
658 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
661 ut = ConvertLongToLargeInteger(unixTime);
662 ut = LargeIntegerMultiplyByLong(ut, 10000000);
663 *ft = LargeIntegerAdd(*ft, ut);
668 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
674 FileTimeToSystemTime(largeTimep, &stm);
676 lt.tm_year = stm.wYear - 1900;
677 lt.tm_mon = stm.wMonth - 1;
678 lt.tm_wday = stm.wDayOfWeek;
679 lt.tm_mday = stm.wDay;
680 lt.tm_hour = stm.wHour;
681 lt.tm_min = stm.wMinute;
682 lt.tm_sec = stm.wSecond;
685 save_timezone = _timezone;
686 _timezone += smb_NowTZ;
687 *unixTimep = mktime(<);
688 _timezone = save_timezone;
691 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
693 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
694 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
695 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
699 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
700 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
701 a = LargeIntegerMultiplyByLong(a, 60);
702 a = LargeIntegerMultiplyByLong(a, 10000000);
704 /* subtract it from ft */
705 a = LargeIntegerSubtract(*ft, a);
707 /* divide down to seconds */
708 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
712 void smb_SearchTimeFromUnixTime(long *dosTimep, time_t unixTime)
720 ltp = localtime((time_t*) &t);
722 /* if we fail, make up something */
725 localJunk.tm_year = 89 - 20;
726 localJunk.tm_mon = 4;
727 localJunk.tm_mday = 12;
728 localJunk.tm_hour = 0;
729 localJunk.tm_min = 0;
730 localJunk.tm_sec = 0;
733 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
734 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
735 *dosTimep = (dosDate<<16) | dosTime;
738 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
740 unsigned short dosDate;
741 unsigned short dosTime;
744 dosDate = searchTime & 0xffff;
745 dosTime = (searchTime >> 16) & 0xffff;
747 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
748 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
749 localTm.tm_mday = (dosDate) & 0x1f;
750 localTm.tm_hour = (dosTime>>11) & 0x1f;
751 localTm.tm_min = (dosTime >> 5) & 0x3f;
752 localTm.tm_sec = (dosTime & 0x1f) * 2;
753 localTm.tm_isdst = -1; /* compute whether DST in effect */
755 *unixTimep = mktime(&localTm);
758 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
760 *dosUTimep = unixTime - smb_localZero;
763 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
766 *unixTimep = dosTime + smb_localZero;
768 /* dosTime seems to be already adjusted for GMT */
769 *unixTimep = dosTime;
773 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
777 lock_ObtainWrite(&smb_rctLock);
778 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
779 if (lsn == vcp->lsn && lana == vcp->lana) {
784 if (!vcp && (flags & SMB_FLAG_CREATE)) {
785 vcp = malloc(sizeof(*vcp));
786 memset(vcp, 0, sizeof(*vcp));
787 vcp->vcID = numVCs++;
791 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
792 vcp->nextp = smb_allVCsp;
794 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
799 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
800 /* We must obtain a challenge for extended auth
801 * in case the client negotiates smb v3
804 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
805 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
808 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
810 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
817 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
819 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
820 LsaFreeReturnBuffer(lsaResp);
823 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
825 lock_ReleaseWrite(&smb_rctLock);
829 int smb_IsStarMask(char *maskp)
834 for(i=0; i<11; i++) {
836 if (tc == '?' || tc == '*' || tc == '>') return 1;
841 void smb_ReleaseVC(smb_vc_t *vcp)
843 lock_ObtainWrite(&smb_rctLock);
844 osi_assert(vcp->refCount-- > 0);
845 lock_ReleaseWrite(&smb_rctLock);
848 void smb_HoldVC(smb_vc_t *vcp)
850 lock_ObtainWrite(&smb_rctLock);
852 lock_ReleaseWrite(&smb_rctLock);
855 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
859 lock_ObtainWrite(&smb_rctLock);
860 for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
861 if (tid == tidp->tid) {
866 if (!tidp && (flags & SMB_FLAG_CREATE)) {
867 tidp = malloc(sizeof(*tidp));
868 memset(tidp, 0, sizeof(*tidp));
869 tidp->nextp = vcp->tidsp;
874 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
877 lock_ReleaseWrite(&smb_rctLock);
881 void smb_ReleaseTID(smb_tid_t *tidp)
890 lock_ObtainWrite(&smb_rctLock);
891 osi_assert(tidp->refCount-- > 0);
892 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
893 ltpp = &tidp->vcp->tidsp;
894 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
895 if (tp == tidp) break;
897 osi_assert(tp != NULL);
899 lock_FinalizeMutex(&tidp->mx);
900 userp = tidp->userp; /* remember to drop ref later */
903 lock_ReleaseWrite(&smb_rctLock);
905 cm_ReleaseUser(userp);
912 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
914 smb_user_t *uidp = NULL;
916 lock_ObtainWrite(&smb_rctLock);
917 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
918 if (uid == uidp->userID) {
920 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
921 (int)vcp, uidp->userID,
922 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
926 if (!uidp && (flags & SMB_FLAG_CREATE)) {
927 uidp = malloc(sizeof(*uidp));
928 memset(uidp, 0, sizeof(*uidp));
929 uidp->nextp = vcp->usersp;
934 lock_InitializeMutex(&uidp->mx, "user_t mutex");
936 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 : ""));
938 lock_ReleaseWrite(&smb_rctLock);
942 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
944 smb_username_t *unp= NULL;
946 lock_ObtainWrite(&smb_rctLock);
947 for(unp = usernamesp; unp; unp = unp->nextp) {
948 if (stricmp(unp->name, usern) == 0 &&
949 stricmp(unp->machine, machine) == 0) {
954 if (!unp && (flags & SMB_FLAG_CREATE)) {
955 unp = malloc(sizeof(*unp));
956 memset(unp, 0, sizeof(*unp));
958 unp->nextp = usernamesp;
959 unp->name = strdup(usern);
960 unp->machine = strdup(machine);
962 lock_InitializeMutex(&unp->mx, "username_t mutex");
964 lock_ReleaseWrite(&smb_rctLock);
968 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
970 smb_user_t *uidp= NULL;
972 lock_ObtainWrite(&smb_rctLock);
973 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
976 if (stricmp(uidp->unp->name, usern) == 0) {
978 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
983 lock_ReleaseWrite(&smb_rctLock);
986 void smb_ReleaseUID(smb_user_t *uidp)
995 lock_ObtainWrite(&smb_rctLock);
996 osi_assert(uidp->refCount-- > 0);
997 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
998 lupp = &uidp->vcp->usersp;
999 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1000 if (up == uidp) break;
1002 osi_assert(up != NULL);
1004 lock_FinalizeMutex(&uidp->mx);
1006 userp = uidp->unp->userp; /* remember to drop ref later */
1007 uidp->unp->userp = NULL;
1012 lock_ReleaseWrite(&smb_rctLock);
1014 cm_ReleaseUserVCRef(userp);
1015 cm_ReleaseUser(userp);
1022 /* retrieve a held reference to a user structure corresponding to an incoming
1024 * corresponding release function is cm_ReleaseUser.
1026 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1032 smbp = (smb_t *) inp;
1033 uidp = smb_FindUID(vcp, smbp->uid, 0);
1034 if ((!uidp) || (!uidp->unp))
1037 lock_ObtainMutex(&uidp->mx);
1038 up = uidp->unp->userp;
1040 lock_ReleaseMutex(&uidp->mx);
1042 smb_ReleaseUID(uidp);
1048 * Return a pointer to a pathname extracted from a TID structure. The
1049 * TID structure is not held; assume it won't go away.
1051 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1056 tidp = smb_FindTID(vcp, tid, 0);
1060 if(tidp->flags & SMB_TIDFLAG_IPC) {
1061 code = CM_ERROR_TIDIPC;
1062 /* tidp->pathname would be NULL, but that's fine */
1064 *treepath = tidp->pathname;
1065 smb_ReleaseTID(tidp);
1070 /* check to see if we have a chained fid, that is, a fid that comes from an
1071 * OpenAndX message that ran earlier in this packet. In this case, the fid
1072 * field in a read, for example, request, isn't set, since the value is
1073 * supposed to be inherited from the openAndX call.
1075 int smb_ChainFID(int fid, smb_packet_t *inp)
1077 if (inp->fid == 0 || inp->inCount == 0)
1083 /* are we a priv'd user? What does this mean on NT? */
1084 int smb_SUser(cm_user_t *userp)
1089 /* find a file ID. If we pass in 0 we select an used File ID.
1090 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1091 * smb_fid_t data structure if desired File ID cannot be found.
1093 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1098 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1101 lock_ObtainWrite(&smb_rctLock);
1102 /* figure out if we need to allocate a new file ID */
1105 fid = vcp->fidCounter;
1109 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1110 if (fid == fidp->fid) {
1121 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1122 char eventName[MAX_PATH];
1124 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1125 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1126 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1127 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1128 thrd_CloseHandle(event);
1135 fidp = malloc(sizeof(*fidp));
1136 memset(fidp, 0, sizeof(*fidp));
1137 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1141 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1143 fidp->curr_chunk = fidp->prev_chunk = -2;
1144 fidp->raw_write_event = event;
1146 vcp->fidCounter = fid+1;
1147 if (vcp->fidCounter == 0)
1148 vcp->fidCounter = 1;
1151 lock_ReleaseWrite(&smb_rctLock);
1155 void smb_ReleaseFID(smb_fid_t *fidp)
1158 smb_vc_t *vcp = NULL;
1159 smb_ioctl_t *ioctlp;
1165 lock_ObtainWrite(&smb_rctLock);
1166 osi_assert(fidp->refCount-- > 0);
1167 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1169 if (!(fidp->flags & SMB_FID_IOCTL))
1171 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1172 thrd_CloseHandle(fidp->raw_write_event);
1174 /* and see if there is ioctl stuff to free */
1175 ioctlp = fidp->ioctlp;
1177 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1178 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1179 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1185 /* do not call smb_ReleaseVC() because we already have the lock */
1188 lock_ReleaseWrite(&smb_rctLock);
1190 /* now release the scache structure */
1192 cm_ReleaseSCache(scp);
1196 * Case-insensitive search for one string in another;
1197 * used to find variable names in submount pathnames.
1199 static char *smb_stristr(char *str1, char *str2)
1203 for (cursor = str1; *cursor; cursor++)
1204 if (stricmp(cursor, str2) == 0)
1211 * Substitute a variable value for its name in a submount pathname. Variable
1212 * name has been identified by smb_stristr() and is in substr. Variable name
1213 * length (plus one) is in substr_size. Variable value is in newstr.
1215 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1220 strcpy(temp, substr + substr_size - 1);
1221 strcpy(substr, newstr);
1225 char VNUserName[] = "%USERNAME%";
1226 char VNLCUserName[] = "%LCUSERNAME%";
1227 char VNComputerName[] = "%COMPUTERNAME%";
1228 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1231 /* List available shares */
1232 int smb_ListShares()
1236 char shareBuf[4096];
1244 /*strcpy(shareNameList[num_shares], "all");
1245 strcpy(pathNameList[num_shares++], "/afs");*/
1246 fprintf(stderr, "The following shares are available:\n");
1247 fprintf(stderr, "Share Name (AFS Path)\n");
1248 fprintf(stderr, "---------------------\n");
1249 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1252 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1253 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1255 strcpy(sbmtpath, cm_confDir);
1257 strcat(sbmtpath, "/afsdsbmt.ini");
1258 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1259 shareBuf, sizeof(shareBuf),
1265 this_share = shareBuf;
1269 /*strcpy(shareNameList[num_shares], this_share);*/
1270 len = GetPrivateProfileString("AFS Submounts", this_share,
1277 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1280 if (*p == '\\') *p = '/'; /* change to / */
1284 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1285 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1288 while (*this_share != 0) this_share++; /* find next NUL */
1289 this_share++; /* skip past the NUL */
1290 } while (*this_share != 0); /* stop at final NUL */
1296 typedef struct smb_findShare_rock {
1300 } smb_findShare_rock_t;
1302 #define SMB_FINDSHARE_EXACT_MATCH 1
1303 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1305 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1309 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1310 if(!strnicmp(dep->name, vrock->shareName, 12)) {
1311 if(!stricmp(dep->name, vrock->shareName))
1312 matchType = SMB_FINDSHARE_EXACT_MATCH;
1314 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1315 if(vrock->match) free(vrock->match);
1316 vrock->match = strdup(dep->name);
1317 vrock->matchType = matchType;
1319 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1320 return CM_ERROR_STOPNOW;
1326 /* find a shareName in the table of submounts */
1327 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1331 char pathName[1024];
1336 char sbmtpath[MAX_PATH];
1341 DWORD allSubmount = 1;
1343 /* if allSubmounts == 0, only return the //mountRoot/all share
1344 * if in fact it has been been created in the subMounts table.
1345 * This is to allow sites that want to restrict access to the
1348 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1349 0, KEY_QUERY_VALUE, &parmKey);
1350 if (code == ERROR_SUCCESS) {
1351 len = sizeof(allSubmount);
1352 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1353 (BYTE *) &allSubmount, &len);
1354 if (code != ERROR_SUCCESS) {
1357 RegCloseKey (parmKey);
1360 if (allSubmount && _stricmp(shareName, "all") == 0) {
1365 /* In case, the all share is disabled we need to still be able
1366 * to handle ioctl requests
1368 if (_stricmp(shareName, "ioctl$") == 0) {
1369 *pathNamep = strdup("/.__ioctl__");
1373 if (_stricmp(shareName, "IPC$") == 0 ||
1374 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1375 _stricmp(shareName, "DESKTOP.INI") == 0
1382 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1383 0, KEY_QUERY_VALUE, &parmKey);
1384 if (code == ERROR_SUCCESS) {
1385 len = sizeof(pathName);
1386 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1387 (BYTE *) pathName, &len);
1388 if (code != ERROR_SUCCESS)
1390 RegCloseKey (parmKey);
1395 strcpy(sbmtpath, cm_confDir);
1396 strcat(sbmtpath, "/afsdsbmt.ini");
1397 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1398 pathName, sizeof(pathName), sbmtpath);
1400 if (len != 0 && len != sizeof(pathName) - 1) {
1401 /* We can accept either unix or PC style AFS pathnames. Convert
1402 * Unix-style to PC style here for internal use.
1405 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1406 p += strlen(cm_mountRoot); /* skip mount path */
1409 if (*q == '/') *q = '\\'; /* change to \ */
1415 if (var = smb_stristr(p, VNUserName)) {
1416 if (uidp && uidp->unp)
1417 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1419 smb_subst(p, var, sizeof(VNUserName)," ");
1421 else if (var = smb_stristr(p, VNLCUserName))
1423 if (uidp && uidp->unp)
1424 strcpy(temp, uidp->unp->name);
1428 smb_subst(p, var, sizeof(VNLCUserName), temp);
1430 else if (var = smb_stristr(p, VNComputerName))
1432 sizeTemp = sizeof(temp);
1433 GetComputerName((LPTSTR)temp, &sizeTemp);
1434 smb_subst(p, var, sizeof(VNComputerName), temp);
1436 else if (var = smb_stristr(p, VNLCComputerName))
1438 sizeTemp = sizeof(temp);
1439 GetComputerName((LPTSTR)temp, &sizeTemp);
1441 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1446 *pathNamep = strdup(p);
1451 /* First lookup shareName in root.afs */
1453 smb_findShare_rock_t vrock;
1455 char * p = shareName;
1458 /* attempt to locate a partial match in root.afs. This is because
1459 when using the ANSI RAP calls, the share name is limited to 13 chars
1460 and hence is truncated. Of course we prefer exact matches. */
1462 thyper.HighPart = 0;
1465 vrock.shareName = shareName;
1467 vrock.matchType = 0;
1469 cm_HoldSCache(cm_rootSCachep);
1470 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1471 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1472 cm_ReleaseSCache(cm_rootSCachep);
1474 if(vrock.matchType) {
1475 sprintf(pathName,"/%s/",vrock.match);
1476 *pathNamep = strdup(strlwr(pathName));
1481 /* if we get here, there was no match for the share in root.afs */
1482 /* so try to create \\<netbiosName>\<cellname> */
1487 /* Get the full name for this cell */
1488 code = cm_SearchCellFile(p, temp, 0, 0);
1489 #ifdef AFS_AFSDB_ENV
1490 if (code && cm_dnsEnabled) {
1492 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1495 /* construct the path */
1497 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1498 *pathNamep = strdup(strlwr(pathName));
1507 /* Client-side offline caching policy types */
1508 #define CSC_POLICY_MANUAL 0
1509 #define CSC_POLICY_DOCUMENTS 1
1510 #define CSC_POLICY_PROGRAMS 2
1511 #define CSC_POLICY_DISABLE 3
1513 int smb_FindShareCSCPolicy(char *shareName)
1519 int retval = CSC_POLICY_MANUAL;
1521 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1522 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1525 REG_OPTION_NON_VOLATILE,
1531 len = sizeof(policy);
1532 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1534 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1536 else if (stricmp(policy, "documents") == 0)
1538 retval = CSC_POLICY_DOCUMENTS;
1540 else if (stricmp(policy, "programs") == 0)
1542 retval = CSC_POLICY_PROGRAMS;
1544 else if (stricmp(policy, "disable") == 0)
1546 retval = CSC_POLICY_DISABLE;
1549 RegCloseKey(hkCSCPolicy);
1553 /* find a dir search structure by cookie value, and return it held.
1554 * Must be called with smb_globalLock held.
1556 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1558 smb_dirSearch_t *dsp;
1560 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1561 if (dsp->cookie == cookie) {
1562 if (dsp != smb_firstDirSearchp) {
1563 /* move to head of LRU queue, too, if we're not already there */
1564 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1565 smb_lastDirSearchp = (smb_dirSearch_t *)
1567 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1568 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1569 if (!smb_lastDirSearchp)
1570 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1579 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1581 lock_ObtainWrite(&smb_globalLock);
1582 dsp->flags |= SMB_DIRSEARCH_DELETE;
1583 lock_ReleaseWrite(&smb_globalLock);
1584 lock_ObtainMutex(&dsp->mx);
1585 if(dsp->scp != NULL) {
1586 lock_ObtainMutex(&dsp->scp->mx);
1587 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1588 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1589 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1590 dsp->scp->bulkStatProgress = hones;
1592 lock_ReleaseMutex(&dsp->scp->mx);
1594 lock_ReleaseMutex(&dsp->mx);
1597 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1603 lock_ObtainWrite(&smb_globalLock);
1604 osi_assert(dsp->refCount-- > 0);
1605 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1606 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1607 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1608 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1609 lock_FinalizeMutex(&dsp->mx);
1613 lock_ReleaseWrite(&smb_globalLock);
1615 /* do this now to avoid spurious locking hierarchy creation */
1616 if (scp) cm_ReleaseSCache(scp);
1619 /* find a dir search structure by cookie value, and return it held */
1620 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1622 smb_dirSearch_t *dsp;
1624 lock_ObtainWrite(&smb_globalLock);
1625 dsp = smb_FindDirSearchNL(cookie);
1626 lock_ReleaseWrite(&smb_globalLock);
1630 /* GC some dir search entries, in the address space expected by the specific protocol.
1631 * Must be called with smb_globalLock held; release the lock temporarily.
1633 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1634 void smb_GCDirSearches(int isV3)
1636 smb_dirSearch_t *prevp;
1637 smb_dirSearch_t *tp;
1638 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1642 victimCount = 0; /* how many have we got so far */
1643 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1644 /* we'll move tp from queue, so
1647 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1648 /* if no one is using this guy, and we're either in the new protocol,
1649 * or we're in the old one and this is a small enough ID to be useful
1650 * to the old protocol, GC this guy.
1652 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1653 /* hold and delete */
1654 tp->flags |= SMB_DIRSEARCH_DELETE;
1655 victimsp[victimCount++] = tp;
1659 /* don't do more than this */
1660 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1663 /* now release them */
1664 lock_ReleaseWrite(&smb_globalLock);
1665 for(i = 0; i < victimCount; i++) {
1666 smb_ReleaseDirSearch(victimsp[i]);
1668 lock_ObtainWrite(&smb_globalLock);
1671 /* function for allocating a dir search entry. We need these to remember enough context
1672 * since we don't get passed the path from call to call during a directory search.
1674 * Returns a held dir search structure, and bumps the reference count on the vnode,
1675 * since it saves a pointer to the vnode.
1677 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1679 smb_dirSearch_t *dsp;
1683 lock_ObtainWrite(&smb_globalLock);
1686 /* what's the biggest ID allowed in this version of the protocol */
1687 if (isV3) maxAllowed = 65535;
1688 else maxAllowed = 255;
1691 /* twice so we have enough tries to find guys we GC after one pass;
1692 * 10 extra is just in case I mis-counted.
1694 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1695 __FILE__, __LINE__);
1696 if (smb_dirSearchCounter > maxAllowed) {
1697 smb_dirSearchCounter = 1;
1698 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1700 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1702 /* don't need to watch for refcount zero and deleted, since
1703 * we haven't dropped the global lock.
1706 ++smb_dirSearchCounter;
1710 dsp = malloc(sizeof(*dsp));
1711 memset(dsp, 0, sizeof(*dsp));
1712 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1713 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1714 dsp->cookie = smb_dirSearchCounter;
1715 ++smb_dirSearchCounter;
1717 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1718 dsp->lastTime = osi_Time();
1721 lock_ReleaseWrite(&smb_globalLock);
1725 static smb_packet_t *GetPacket(void)
1729 unsigned int npar, seg, tb_sel;
1732 lock_ObtainWrite(&smb_globalLock);
1733 tbp = smb_packetFreeListp;
1735 smb_packetFreeListp = tbp->nextp;
1736 lock_ReleaseWrite(&smb_globalLock);
1739 tbp = calloc(65540,1);
1741 tbp = malloc(sizeof(smb_packet_t));
1743 tbp->magic = SMB_PACKETMAGIC;
1746 tbp->resumeCode = 0;
1752 tbp->ncb_length = 0;
1757 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1760 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1762 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1764 osi_panic("",__FILE__,__LINE__);
1767 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1772 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1773 tbp->dos_pkt_sel = tb_sel;
1776 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1781 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1785 memcpy(tbp, pkt, sizeof(smb_packet_t));
1786 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1790 static NCB *GetNCB(void)
1795 unsigned int npar, seg, tb_sel;
1798 lock_ObtainWrite(&smb_globalLock);
1799 tbp = smb_ncbFreeListp;
1801 smb_ncbFreeListp = tbp->nextp;
1802 lock_ReleaseWrite(&smb_globalLock);
1805 tbp = calloc(sizeof(*tbp),1);
1807 tbp = malloc(sizeof(*tbp));
1808 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1811 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1813 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1815 osi_panic("",__FILE__,__LINE__);
1817 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1822 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1823 tbp->dos_ncb_sel = tb_sel;
1825 tbp->magic = SMB_NCBMAGIC;
1828 osi_assert(tbp->magic == SMB_NCBMAGIC);
1830 memset(&tbp->ncb, 0, sizeof(NCB));
1833 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1838 void smb_FreePacket(smb_packet_t *tbp)
1840 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1842 lock_ObtainWrite(&smb_globalLock);
1843 tbp->nextp = smb_packetFreeListp;
1844 smb_packetFreeListp = tbp;
1845 tbp->magic = SMB_PACKETMAGIC;
1848 tbp->resumeCode = 0;
1854 tbp->ncb_length = 0;
1856 lock_ReleaseWrite(&smb_globalLock);
1859 static void FreeNCB(NCB *bufferp)
1863 tbp = (smb_ncb_t *) bufferp;
1864 osi_assert(tbp->magic == SMB_NCBMAGIC);
1866 lock_ObtainWrite(&smb_globalLock);
1867 tbp->nextp = smb_ncbFreeListp;
1868 smb_ncbFreeListp = tbp;
1869 lock_ReleaseWrite(&smb_globalLock);
1872 /* get a ptr to the data part of a packet, and its count */
1873 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1877 unsigned char *afterParmsp;
1879 parmBytes = *smbp->wctp << 1;
1880 afterParmsp = smbp->wctp + parmBytes + 1;
1882 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1883 if (nbytesp) *nbytesp = dataBytes;
1885 /* don't forget to skip the data byte count, since it follows
1886 * the parameters; that's where the "2" comes from below.
1888 return (unsigned char *) (afterParmsp + 2);
1891 /* must set all the returned parameters before playing around with the
1892 * data region, since the data region is located past the end of the
1893 * variable number of parameters.
1895 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1897 unsigned char *afterParmsp;
1899 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1901 *afterParmsp++ = dsize & 0xff;
1902 *afterParmsp = (dsize>>8) & 0xff;
1905 /* return the parm'th parameter in the smbp packet */
1906 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1909 unsigned char *parmDatap;
1911 parmCount = *smbp->wctp;
1913 if (parm >= parmCount) {
1918 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1920 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1921 parm, parmCount, smbp->ncb_length);
1924 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1925 1, smbp->ncb_length, ptbuf, smbp);
1926 DeregisterEventSource(h);
1928 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1929 osi_panic(s, __FILE__, __LINE__);
1931 parmDatap = smbp->wctp + (2*parm) + 1;
1933 return parmDatap[0] + (parmDatap[1] << 8);
1936 /* return the parm'th parameter in the smbp packet */
1937 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1940 unsigned char *parmDatap;
1942 parmCount = *smbp->wctp;
1944 if (parm * 2 + offset >= parmCount * 2) {
1949 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1951 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1952 parm, offset, parmCount, smbp->ncb_length);
1955 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1956 1, smbp->ncb_length, ptbuf, smbp);
1957 DeregisterEventSource(h);
1959 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1960 osi_panic(s, __FILE__, __LINE__);
1962 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1964 return parmDatap[0] + (parmDatap[1] << 8);
1967 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1971 /* make sure we have enough slots */
1972 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1974 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1975 *parmDatap++ = parmValue & 0xff;
1976 *parmDatap = (parmValue>>8) & 0xff;
1979 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1983 /* make sure we have enough slots */
1984 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1986 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1987 *parmDatap++ = parmValue & 0xff;
1988 *parmDatap++ = (parmValue>>8) & 0xff;
1989 *parmDatap++ = (parmValue>>16) & 0xff;
1990 *parmDatap++ = (parmValue>>24) & 0xff;
1993 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1998 /* make sure we have enough slots */
1999 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
2001 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2003 *parmDatap++ = *parmValuep++;
2006 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2010 /* make sure we have enough slots */
2011 if (*smbp->wctp <= slot) {
2012 if (smbp->oddByte) {
2014 *smbp->wctp = slot+1;
2019 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2020 *parmDatap++ = parmValue & 0xff;
2023 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2027 lastSlashp = strrchr(inPathp, '\\');
2029 *lastComponentp = lastSlashp;
2032 if (inPathp == lastSlashp)
2034 *outPathp++ = *inPathp++;
2043 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2048 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2053 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2059 tlen = inp[0] + (inp[1]<<8);
2060 inp += 2; /* skip length field */
2063 *chainpp = inp + tlen;
2072 /* format a packet as a response */
2073 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2078 outp = (smb_t *) op;
2080 /* zero the basic structure through the smb_wct field, and zero the data
2081 * size field, assuming that wct stays zero; otherwise, you have to
2082 * explicitly set the data size field, too.
2084 inSmbp = (smb_t *) inp;
2085 memset(outp, 0, sizeof(smb_t)+2);
2091 outp->com = inSmbp->com;
2092 outp->tid = inSmbp->tid;
2093 outp->pid = inSmbp->pid;
2094 outp->uid = inSmbp->uid;
2095 outp->mid = inSmbp->mid;
2096 outp->res[0] = inSmbp->res[0];
2097 outp->res[1] = inSmbp->res[1];
2098 op->inCom = inSmbp->com;
2100 outp->reb = 0x80; /* SERVER_RESP */
2101 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2103 /* copy fields in generic packet area */
2104 op->wctp = &outp->wct;
2107 /* send a (probably response) packet; vcp tells us to whom to send it.
2108 * we compute the length by looking at wct and bcc fields.
2110 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2127 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2130 memset((char *)ncbp, 0, sizeof(NCB));
2132 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2133 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2134 extra += tp[0] + (tp[1]<<8);
2135 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2136 extra += 3; /* wct and length fields */
2138 ncbp->ncb_length = extra; /* bytes to send */
2139 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2140 ncbp->ncb_lana_num = vcp->lana;
2141 ncbp->ncb_command = NCBSEND; /* op means send data */
2143 ncbp->ncb_buffer = (char *) inp;/* packet */
2144 code = Netbios(ncbp);
2146 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2147 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2149 /* copy header information from virtual to DOS address space */
2150 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2151 code = Netbios(ncbp, dos_ncb);
2155 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2161 void smb_MapNTError(long code, unsigned long *NTStatusp)
2163 unsigned long NTStatus;
2165 /* map CM_ERROR_* errors to NT 32-bit status codes */
2166 /* NT Status codes are listed in ntstatus.h not winerror.h */
2167 if (code == CM_ERROR_NOSUCHCELL) {
2168 NTStatus = 0xC000000FL; /* No such file */
2170 else if (code == CM_ERROR_NOSUCHVOLUME) {
2171 NTStatus = 0xC000000FL; /* No such file */
2173 else if (code == CM_ERROR_TIMEDOUT) {
2174 NTStatus = 0xC00000CFL; /* Sharing Paused */
2176 else if (code == CM_ERROR_RETRY) {
2177 NTStatus = 0xC000022DL; /* Retry */
2179 else if (code == CM_ERROR_NOACCESS) {
2180 NTStatus = 0xC0000022L; /* Access denied */
2182 else if (code == CM_ERROR_READONLY) {
2183 NTStatus = 0xC00000A2L; /* Write protected */
2185 else if (code == CM_ERROR_NOSUCHFILE) {
2186 NTStatus = 0xC000000FL; /* No such file */
2188 else if (code == CM_ERROR_NOSUCHPATH) {
2189 NTStatus = 0xC000003AL; /* Object path not found */
2191 else if (code == CM_ERROR_TOOBIG) {
2192 NTStatus = 0xC000007BL; /* Invalid image format */
2194 else if (code == CM_ERROR_INVAL) {
2195 NTStatus = 0xC000000DL; /* Invalid parameter */
2197 else if (code == CM_ERROR_BADFD) {
2198 NTStatus = 0xC0000008L; /* Invalid handle */
2200 else if (code == CM_ERROR_BADFDOP) {
2201 NTStatus = 0xC0000022L; /* Access denied */
2203 else if (code == CM_ERROR_EXISTS) {
2204 NTStatus = 0xC0000035L; /* Object name collision */
2206 else if (code == CM_ERROR_NOTEMPTY) {
2207 NTStatus = 0xC0000101L; /* Directory not empty */
2209 else if (code == CM_ERROR_CROSSDEVLINK) {
2210 NTStatus = 0xC00000D4L; /* Not same device */
2212 else if (code == CM_ERROR_NOTDIR) {
2213 NTStatus = 0xC0000103L; /* Not a directory */
2215 else if (code == CM_ERROR_ISDIR) {
2216 NTStatus = 0xC00000BAL; /* File is a directory */
2218 else if (code == CM_ERROR_BADOP) {
2220 /* I have no idea where this comes from */
2221 NTStatus = 0xC09820FFL; /* SMB no support */
2223 NTStatus = 0xC00000BBL; /* Not supported */
2224 #endif /* COMMENT */
2226 else if (code == CM_ERROR_BADSHARENAME) {
2227 NTStatus = 0xC00000CCL; /* Bad network name */
2229 else if (code == CM_ERROR_NOIPC) {
2231 NTStatus = 0xC0000022L; /* Access Denied */
2233 NTStatus = 0xC000013DL; /* Remote Resources */
2236 else if (code == CM_ERROR_CLOCKSKEW) {
2237 NTStatus = 0xC0000133L; /* Time difference at DC */
2239 else if (code == CM_ERROR_BADTID) {
2240 NTStatus = 0xC0982005L; /* SMB bad TID */
2242 else if (code == CM_ERROR_USESTD) {
2243 NTStatus = 0xC09820FBL; /* SMB use standard */
2245 else if (code == CM_ERROR_QUOTA) {
2246 NTStatus = 0xC0000044L; /* Quota exceeded */
2248 else if (code == CM_ERROR_SPACE) {
2249 NTStatus = 0xC000007FL; /* Disk full */
2251 else if (code == CM_ERROR_ATSYS) {
2252 NTStatus = 0xC0000033L; /* Object name invalid */
2254 else if (code == CM_ERROR_BADNTFILENAME) {
2255 NTStatus = 0xC0000033L; /* Object name invalid */
2257 else if (code == CM_ERROR_WOULDBLOCK) {
2258 NTStatus = 0xC0000055L; /* Lock not granted */
2260 else if (code == CM_ERROR_PARTIALWRITE) {
2261 NTStatus = 0xC000007FL; /* Disk full */
2263 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2264 NTStatus = 0xC0000023L; /* Buffer too small */
2266 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2267 NTStatus = 0xC0000035L; /* Object name collision */
2269 else if (code == CM_ERROR_BADPASSWORD) {
2270 NTStatus = 0xC000006DL; /* unknown username or bad password */
2272 else if (code == CM_ERROR_BADLOGONTYPE) {
2273 NTStatus = 0xC000015BL; /* logon type not granted */
2275 else if (code == CM_ERROR_GSSCONTINUE) {
2276 NTStatus = 0xC0000016L; /* more processing required */
2279 NTStatus = 0xC0982001L; /* SMB non-specific error */
2282 *NTStatusp = NTStatus;
2283 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2286 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2287 unsigned char *classp)
2289 unsigned char class;
2290 unsigned short error;
2292 /* map CM_ERROR_* errors to SMB errors */
2293 if (code == CM_ERROR_NOSUCHCELL) {
2295 error = 3; /* bad path */
2297 else if (code == CM_ERROR_NOSUCHVOLUME) {
2299 error = 3; /* bad path */
2301 else if (code == CM_ERROR_TIMEDOUT) {
2303 error = 81; /* server is paused */
2305 else if (code == CM_ERROR_RETRY) {
2306 class = 2; /* shouldn't happen */
2309 else if (code == CM_ERROR_NOACCESS) {
2311 error = 4; /* bad access */
2313 else if (code == CM_ERROR_READONLY) {
2315 error = 19; /* read only */
2317 else if (code == CM_ERROR_NOSUCHFILE) {
2319 error = 2; /* ENOENT! */
2321 else if (code == CM_ERROR_NOSUCHPATH) {
2323 error = 3; /* Bad path */
2325 else if (code == CM_ERROR_TOOBIG) {
2327 error = 11; /* bad format */
2329 else if (code == CM_ERROR_INVAL) {
2330 class = 2; /* server non-specific error code */
2333 else if (code == CM_ERROR_BADFD) {
2335 error = 6; /* invalid file handle */
2337 else if (code == CM_ERROR_BADFDOP) {
2338 class = 1; /* invalid op on FD */
2341 else if (code == CM_ERROR_EXISTS) {
2343 error = 80; /* file already exists */
2345 else if (code == CM_ERROR_NOTEMPTY) {
2347 error = 5; /* delete directory not empty */
2349 else if (code == CM_ERROR_CROSSDEVLINK) {
2351 error = 17; /* EXDEV */
2353 else if (code == CM_ERROR_NOTDIR) {
2354 class = 1; /* bad path */
2357 else if (code == CM_ERROR_ISDIR) {
2358 class = 1; /* access denied; DOS doesn't have a good match */
2361 else if (code == CM_ERROR_BADOP) {
2365 else if (code == CM_ERROR_BADSHARENAME) {
2369 else if (code == CM_ERROR_NOIPC) {
2371 error = 4; /* bad access */
2373 else if (code == CM_ERROR_CLOCKSKEW) {
2374 class = 1; /* invalid function */
2377 else if (code == CM_ERROR_BADTID) {
2381 else if (code == CM_ERROR_USESTD) {
2385 else if (code == CM_ERROR_REMOTECONN) {
2389 else if (code == CM_ERROR_QUOTA) {
2390 if (vcp->flags & SMB_VCFLAG_USEV3) {
2392 error = 39; /* disk full */
2396 error = 5; /* access denied */
2399 else if (code == CM_ERROR_SPACE) {
2400 if (vcp->flags & SMB_VCFLAG_USEV3) {
2402 error = 39; /* disk full */
2406 error = 5; /* access denied */
2409 else if (code == CM_ERROR_PARTIALWRITE) {
2411 error = 39; /* disk full */
2413 else if (code == CM_ERROR_ATSYS) {
2415 error = 2; /* ENOENT */
2417 else if (code == CM_ERROR_WOULDBLOCK) {
2419 error = 33; /* lock conflict */
2421 else if (code == CM_ERROR_NOFILES) {
2423 error = 18; /* no files in search */
2425 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2427 error = 183; /* Samba uses this */
2429 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2430 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2432 error = 2; /* bad password */
2441 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2444 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2446 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2447 return CM_ERROR_BADOP;
2450 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2452 unsigned short EchoCount, i;
2453 char *data, *outdata;
2456 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2458 for (i=1; i<=EchoCount; i++) {
2459 data = smb_GetSMBData(inp, &dataSize);
2460 smb_SetSMBParm(outp, 0, i);
2461 smb_SetSMBDataLength(outp, dataSize);
2462 outdata = smb_GetSMBData(outp, NULL);
2463 memcpy(outdata, data, dataSize);
2464 smb_SendPacket(vcp, outp);
2470 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2473 long count, minCount, finalCount;
2477 cm_user_t *userp = NULL;
2481 char *rawBuf = NULL;
2483 dos_ptr rawBuf = NULL;
2490 fd = smb_GetSMBParm(inp, 0);
2491 count = smb_GetSMBParm(inp, 3);
2492 minCount = smb_GetSMBParm(inp, 4);
2493 offset.HighPart = 0; /* too bad */
2494 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2496 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2497 fd, offset.LowPart, count);
2499 fidp = smb_FindFID(vcp, fd, 0);
2503 lock_ObtainMutex(&smb_RawBufLock);
2505 /* Get a raw buf, from head of list */
2506 rawBuf = smb_RawBufs;
2508 smb_RawBufs = *(char **)smb_RawBufs;
2510 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2513 lock_ReleaseMutex(&smb_RawBufLock);
2517 if (fidp->flags & SMB_FID_IOCTL)
2520 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2522 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2525 /* Give back raw buffer */
2526 lock_ObtainMutex(&smb_RawBufLock);
2528 *((char **) rawBuf) = smb_RawBufs;
2530 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2533 smb_RawBufs = rawBuf;
2534 lock_ReleaseMutex(&smb_RawBufLock);
2537 smb_ReleaseFID(fidp);
2541 userp = smb_GetUser(vcp, inp);
2544 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2546 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2547 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2548 userp, &finalCount, TRUE /* rawFlag */);
2555 cm_ReleaseUser(userp);
2558 smb_ReleaseFID(fidp);
2563 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2565 memset((char *)ncbp, 0, sizeof(NCB));
2567 ncbp->ncb_length = (unsigned short) finalCount;
2568 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2569 ncbp->ncb_lana_num = vcp->lana;
2570 ncbp->ncb_command = NCBSEND;
2571 ncbp->ncb_buffer = rawBuf;
2574 code = Netbios(ncbp);
2576 code = Netbios(ncbp, dos_ncb);
2579 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2582 /* Give back raw buffer */
2583 lock_ObtainMutex(&smb_RawBufLock);
2585 *((char **) rawBuf) = smb_RawBufs;
2587 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2590 smb_RawBufs = rawBuf;
2591 lock_ReleaseMutex(&smb_RawBufLock);
2597 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2602 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2607 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2614 int protoIndex; /* index we're using */
2619 char protocol_array[10][1024]; /* protocol signature of the client */
2620 int caps; /* capabilities */
2623 TIME_ZONE_INFORMATION tzi;
2625 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2629 DWORD now = GetCurrentTime();
2630 if (now - last_msg_time >= 30000
2631 && now - last_msg_time <= 90000) {
2633 "Setting dead_vcp %x", active_vcp);
2635 smb_ReleaseVC(dead_vcp);
2637 "Previous dead_vcp %x", dead_vcp);
2639 smb_HoldVC(active_vcp);
2640 dead_vcp = active_vcp;
2641 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2646 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2648 namep = smb_GetSMBData(inp, &dbytes);
2651 coreProtoIndex = -1; /* not found */
2654 while(namex < dbytes) {
2655 osi_Log1(smb_logp, "Protocol %s",
2656 osi_LogSaveString(smb_logp, namep+1));
2657 strcpy(protocol_array[tcounter], namep+1);
2659 /* namep points at the first protocol, or really, a 0x02
2660 * byte preceding the null-terminated ASCII name.
2662 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2663 coreProtoIndex = tcounter;
2665 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2666 v3ProtoIndex = tcounter;
2668 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2669 NTProtoIndex = tcounter;
2672 /* compute size of protocol entry */
2673 entryLength = strlen(namep+1);
2674 entryLength += 2; /* 0x02 bytes and null termination */
2676 /* advance over this protocol entry */
2677 namex += entryLength;
2678 namep += entryLength;
2679 tcounter++; /* which proto entry we're looking at */
2682 if (NTProtoIndex != -1) {
2683 protoIndex = NTProtoIndex;
2684 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2686 else if (v3ProtoIndex != -1) {
2687 protoIndex = v3ProtoIndex;
2688 vcp->flags |= SMB_VCFLAG_USEV3;
2690 else if (coreProtoIndex != -1) {
2691 protoIndex = coreProtoIndex;
2692 vcp->flags |= SMB_VCFLAG_USECORE;
2694 else protoIndex = -1;
2696 if (protoIndex == -1)
2697 return CM_ERROR_INVAL;
2698 else if (NTProtoIndex != -1) {
2699 smb_SetSMBParm(outp, 0, protoIndex);
2700 if (smb_authType != SMB_AUTH_NONE) {
2701 smb_SetSMBParmByte(outp, 1,
2702 NEGOTIATE_SECURITY_USER_LEVEL |
2703 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2705 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2707 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2708 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2709 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2710 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2711 /* The session key is not a well documented field however most clients
2712 * will echo back the session key to the server. Currently we are using
2713 * the same value for all sessions. We should generate a random value
2714 * and store it into the vcp
2716 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2717 smb_SetSMBParm(outp, 8, 1);
2719 * Tried changing the capabilities to support for W2K - defect 117695
2720 * Maybe something else needs to be changed here?
2724 smb_SetSMBParmLong(outp, 9, 0x43fd);
2726 smb_SetSMBParmLong(outp, 9, 0x251);
2729 * 32-bit error codes *
2733 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2734 NTNEGOTIATE_CAPABILITY_NTFIND |
2735 NTNEGOTIATE_CAPABILITY_RAWMODE |
2736 NTNEGOTIATE_CAPABILITY_NTSMB;
2738 if ( smb_authType == SMB_AUTH_EXTENDED )
2739 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2741 smb_SetSMBParmLong(outp, 9, caps);
2743 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2744 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2745 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2747 GetTimeZoneInformation(&tzi);
2748 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2750 if (smb_authType == SMB_AUTH_NTLM) {
2751 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2752 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2753 /* paste in encryption key */
2754 datap = smb_GetSMBData(outp, NULL);
2755 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2756 /* and the faux domain name */
2757 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2758 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2762 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2764 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2766 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2768 datap = smb_GetSMBData(outp, NULL);
2769 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2772 datap += sizeof(smb_ServerGUID);
2773 memcpy(datap, secBlob, secBlobLength);
2777 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2778 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2781 else if (v3ProtoIndex != -1) {
2782 smb_SetSMBParm(outp, 0, protoIndex);
2784 /* NOTE: Extended authentication cannot be negotiated with v3
2785 * therefore we fail over to NTLM
2787 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2788 smb_SetSMBParm(outp, 1,
2789 NEGOTIATE_SECURITY_USER_LEVEL |
2790 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2792 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2794 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2795 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2796 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2797 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2798 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2799 smb_SetSMBParm(outp, 7, 1);
2801 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2802 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2803 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2805 GetTimeZoneInformation(&tzi);
2806 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2808 /* NOTE: Extended authentication cannot be negotiated with v3
2809 * therefore we fail over to NTLM
2811 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2812 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2813 smb_SetSMBParm(outp, 12, 0); /* resvd */
2814 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2815 datap = smb_GetSMBData(outp, NULL);
2816 /* paste in a new encryption key */
2817 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2818 /* and the faux domain name */
2819 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2821 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2822 smb_SetSMBParm(outp, 12, 0); /* resvd */
2823 smb_SetSMBDataLength(outp, 0);
2826 else if (coreProtoIndex != -1) { /* not really supported anymore */
2827 smb_SetSMBParm(outp, 0, protoIndex);
2828 smb_SetSMBDataLength(outp, 0);
2833 void smb_Daemon(void *parmp)
2835 afs_uint32 count = 0;
2840 if ((count % 72) == 0) { /* every five minutes */
2842 long old_localZero = smb_localZero;
2844 /* Initialize smb_localZero */
2845 myTime.tm_isdst = -1; /* compute whether on DST or not */
2846 myTime.tm_year = 70;
2852 smb_localZero = mktime(&myTime);
2854 smb_CalculateNowTZ();
2856 #ifdef AFS_FREELANCE
2857 if ( smb_localZero != old_localZero )
2858 cm_noteLocalMountPointChange();
2861 /* XXX GC dir search entries */
2865 void smb_WaitingLocksDaemon()
2867 smb_waitingLock_t *wL, *nwL;
2870 smb_packet_t *inp, *outp;
2875 lock_ObtainWrite(&smb_globalLock);
2876 nwL = smb_allWaitingLocks;
2878 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2887 lock_ObtainWrite(&smb_globalLock);
2889 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2890 lock_ReleaseWrite(&smb_globalLock);
2891 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2892 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2893 if (code == CM_ERROR_WOULDBLOCK) {
2895 if (wL->timeRemaining != 0xffffffff
2896 && (wL->timeRemaining -= 1000) < 0)
2905 ncbp->ncb_length = inp->ncb_length;
2906 inp->spacep = cm_GetSpace();
2908 /* Remove waitingLock from list */
2909 lock_ObtainWrite(&smb_globalLock);
2910 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2912 lock_ReleaseWrite(&smb_globalLock);
2914 /* Resume packet processing */
2916 smb_SetSMBDataLength(outp, 0);
2917 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2918 outp->resumeCode = code;
2920 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2923 cm_FreeSpace(inp->spacep);
2924 smb_FreePacket(inp);
2925 smb_FreePacket(outp);
2933 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2935 osi_Log0(smb_logp, "SMB receive get disk attributes");
2937 smb_SetSMBParm(outp, 0, 32000);
2938 smb_SetSMBParm(outp, 1, 64);
2939 smb_SetSMBParm(outp, 2, 1024);
2940 smb_SetSMBParm(outp, 3, 30000);
2941 smb_SetSMBParm(outp, 4, 0);
2942 smb_SetSMBDataLength(outp, 0);
2946 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2950 unsigned short newTid;
2951 char shareName[256];
2959 osi_Log0(smb_logp, "SMB receive tree connect");
2961 /* parse input parameters */
2962 tp = smb_GetSMBData(inp, NULL);
2963 pathp = smb_ParseASCIIBlock(tp, &tp);
2964 passwordp = smb_ParseASCIIBlock(tp, &tp);
2965 tp = strrchr(pathp, '\\');
2967 return CM_ERROR_BADSMB;
2968 strcpy(shareName, tp+1);
2970 userp = smb_GetUser(vcp, inp);
2972 lock_ObtainMutex(&vcp->mx);
2973 newTid = vcp->tidCounter++;
2974 lock_ReleaseMutex(&vcp->mx);
2976 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2977 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2978 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2980 smb_ReleaseUID(uidp);
2982 smb_ReleaseTID(tidp);
2983 return CM_ERROR_BADSHARENAME;
2985 lock_ObtainMutex(&tidp->mx);
2986 tidp->userp = userp;
2987 tidp->pathname = sharePath;
2988 lock_ReleaseMutex(&tidp->mx);
2989 smb_ReleaseTID(tidp);
2991 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2992 smb_SetSMBParm(rsp, 1, newTid);
2993 smb_SetSMBDataLength(rsp, 0);
2995 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2999 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3003 if (*inp++ != 0x1) return NULL;
3004 tlen = inp[0] + (inp[1]<<8);
3005 inp += 2; /* skip length field */
3008 *chainpp = inp + tlen;
3011 if (lengthp) *lengthp = tlen;
3016 /* set maskp to the mask part of the incoming path.
3017 * Mask is 11 bytes long (8.3 with the dot elided).
3018 * Returns true if succeeds with a valid name, otherwise it does
3019 * its best, but returns false.
3021 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3029 /* starts off valid */
3032 /* mask starts out all blanks */
3033 memset(maskp, ' ', 11);
3035 /* find last backslash, or use whole thing if there is none */
3036 tp = strrchr(pathp, '\\');
3037 if (!tp) tp = pathp;
3038 else tp++; /* skip slash */
3042 /* names starting with a dot are illegal */
3043 if (*tp == '.') valid8Dot3 = 0;
3047 if (tc == 0) return valid8Dot3;
3048 if (tc == '.' || tc == '"') break;
3049 if (i < 8) *up++ = tc;
3050 else valid8Dot3 = 0;
3053 /* if we get here, tp point after the dot */
3054 up = maskp+8; /* ext goes here */
3061 if (tc == '.' || tc == '"')
3064 /* copy extension if not too long */
3074 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3084 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3086 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3090 /* otherwise, we have a valid 8.3 name; see if we have a match,
3091 * treating '?' as a wildcard in maskp (but not in the file name).
3093 tp1 = umask; /* real name, in mask format */
3094 tp2 = maskp; /* mask, in mask format */
3095 for(i=0; i<11; i++) {
3096 tc1 = *tp1++; /* char from real name */
3097 tc2 = *tp2++; /* char from mask */
3098 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3099 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3102 if (tc2 == '?' && tc1 != ' ')
3109 /* we got a match */
3113 char *smb_FindMask(char *pathp)
3117 tp = strrchr(pathp, '\\'); /* find last slash */
3120 return tp+1; /* skip the slash */
3122 return pathp; /* no slash, return the entire path */
3125 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3127 unsigned char *pathp;
3129 unsigned char mask[11];
3130 unsigned char *statBlockp;
3131 unsigned char initStatBlock[21];
3134 osi_Log0(smb_logp, "SMB receive search volume");
3136 /* pull pathname and stat block out of request */
3137 tp = smb_GetSMBData(inp, NULL);
3138 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3139 osi_assert(pathp != NULL);
3140 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3141 osi_assert(statBlockp != NULL);
3143 statBlockp = initStatBlock;
3147 /* for returning to caller */
3148 smb_Get8Dot3MaskFromPath(mask, pathp);
3150 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3151 tp = smb_GetSMBData(outp, NULL);
3153 *tp++ = 43; /* bytes in a dir entry */
3154 *tp++ = 0; /* high byte in counter */
3156 /* now marshall the dir entry, starting with the search status */
3157 *tp++ = statBlockp[0]; /* Reserved */
3158 memcpy(tp, mask, 11); tp += 11; /* FileName */
3160 /* now pass back server use info, with 1st byte non-zero */
3162 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3164 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3166 *tp++ = 0x8; /* attribute: volume */
3176 /* 4 byte file size */
3182 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3183 memset(tp, ' ', 13);
3186 /* set the length of the data part of the packet to 43 + 3, for the dir
3187 * entry plus the 5 and the length fields.
3189 smb_SetSMBDataLength(outp, 46);
3193 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3194 cm_user_t *userp, cm_req_t *reqp)
3202 smb_dirListPatch_t *patchp;
3203 smb_dirListPatch_t *npatchp;
3205 for(patchp = *dirPatchespp; patchp; patchp =
3206 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3208 dptr = patchp->dptr;
3210 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3212 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3213 *dptr++ = SMB_ATTR_HIDDEN;
3216 lock_ObtainMutex(&scp->mx);
3217 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3218 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3220 lock_ReleaseMutex(&scp->mx);
3221 cm_ReleaseSCache(scp);
3222 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3223 *dptr++ = SMB_ATTR_HIDDEN;
3227 attr = smb_Attributes(scp);
3228 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3229 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3230 attr |= SMB_ATTR_HIDDEN;
3234 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3237 shortTemp = dosTime & 0xffff;
3238 *((u_short *)dptr) = shortTemp;
3241 /* and copy out date */
3242 shortTemp = (dosTime>>16) & 0xffff;
3243 *((u_short *)dptr) = shortTemp;
3246 /* copy out file length */
3247 *((u_long *)dptr) = scp->length.LowPart;
3249 lock_ReleaseMutex(&scp->mx);
3250 cm_ReleaseSCache(scp);
3253 /* now free the patches */
3254 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3255 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3259 /* and mark the list as empty */
3260 *dirPatchespp = NULL;
3265 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3274 smb_dirListPatch_t *dirListPatchesp;
3275 smb_dirListPatch_t *curPatchp;
3279 osi_hyper_t dirLength;
3280 osi_hyper_t bufferOffset;
3281 osi_hyper_t curOffset;
3283 unsigned char *inCookiep;
3284 smb_dirSearch_t *dsp;
3288 unsigned long clientCookie;
3289 cm_pageHeader_t *pageHeaderp;
3290 cm_user_t *userp = NULL;
3297 long nextEntryCookie;
3298 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3299 char resByte; /* reserved byte from the cookie */
3300 char *op; /* output data ptr */
3301 char *origOp; /* original value of op */
3302 cm_space_t *spacep; /* for pathname buffer */
3313 maxCount = smb_GetSMBParm(inp, 0);
3315 dirListPatchesp = NULL;
3317 caseFold = CM_FLAG_CASEFOLD;
3319 tp = smb_GetSMBData(inp, NULL);
3320 pathp = smb_ParseASCIIBlock(tp, &tp);
3321 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3323 /* bail out if request looks bad */
3324 if (!tp || !pathp) {
3325 return CM_ERROR_BADSMB;
3328 /* We can handle long names */
3329 if (vcp->flags & SMB_VCFLAG_USENT)
3330 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3332 /* make sure we got a whole search status */
3333 if (dataLength < 21) {
3334 nextCookie = 0; /* start at the beginning of the dir */
3337 attribute = smb_GetSMBParm(inp, 1);
3339 /* handle volume info in another function */
3340 if (attribute & 0x8)
3341 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3343 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3344 maxCount, osi_LogSaveString(smb_logp, pathp));
3346 if (*pathp == 0) { /* null pathp, treat as root dir */
3347 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3348 return CM_ERROR_NOFILES;
3352 dsp = smb_NewDirSearch(0);
3353 dsp->attribute = attribute;
3354 smb_Get8Dot3MaskFromPath(mask, pathp);
3355 memcpy(dsp->mask, mask, 11);
3357 /* track if this is likely to match a lot of entries */
3358 if (smb_IsStarMask(mask)) starPattern = 1;
3359 else starPattern = 0;
3362 /* pull the next cookie value out of the search status block */
3363 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3364 + (inCookiep[16]<<24);
3365 dsp = smb_FindDirSearch(inCookiep[12]);
3367 /* can't find dir search status; fatal error */
3368 return CM_ERROR_BADFD;
3370 attribute = dsp->attribute;
3371 resByte = inCookiep[0];
3373 /* copy out client cookie, in host byte order. Don't bother
3374 * interpreting it, since we're just passing it through, anyway.
3376 memcpy(&clientCookie, &inCookiep[17], 4);
3378 memcpy(mask, dsp->mask, 11);
3380 /* assume we're doing a star match if it has continued for more
3386 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3387 nextCookie, dsp->cookie, attribute);
3389 userp = smb_GetUser(vcp, inp);
3391 /* try to get the vnode for the path name next */
3392 lock_ObtainMutex(&dsp->mx);
3399 spacep = inp->spacep;
3400 smb_StripLastComponent(spacep->data, NULL, pathp);
3401 lock_ReleaseMutex(&dsp->mx);
3402 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3404 lock_ReleaseMutex(&dsp->mx);
3405 cm_ReleaseUser(userp);
3406 smb_DeleteDirSearch(dsp);
3407 smb_ReleaseDirSearch(dsp);
3408 return CM_ERROR_NOFILES;
3410 code = cm_NameI(cm_rootSCachep, spacep->data,
3411 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3412 lock_ObtainMutex(&dsp->mx);
3414 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3416 /* we need one hold for the entry we just stored into,
3417 * and one for our own processing. When we're done with this
3418 * function, we'll drop the one for our own processing.
3419 * We held it once from the namei call, and so we do another hold
3423 lock_ObtainMutex(&scp->mx);
3424 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3425 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3426 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3427 dsp->flags |= SMB_DIRSEARCH_BULKST;
3429 lock_ReleaseMutex(&scp->mx);
3432 lock_ReleaseMutex(&dsp->mx);
3434 cm_ReleaseUser(userp);
3435 smb_DeleteDirSearch(dsp);
3436 smb_ReleaseDirSearch(dsp);
3440 /* reserves space for parameter; we'll adjust it again later to the
3441 * real count of the # of entries we returned once we've actually
3442 * assembled the directory listing.
3444 smb_SetSMBParm(outp, 0, 0);
3446 /* get the directory size */
3447 lock_ObtainMutex(&scp->mx);
3448 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3449 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3451 lock_ReleaseMutex(&scp->mx);
3452 cm_ReleaseSCache(scp);
3453 cm_ReleaseUser(userp);
3454 smb_DeleteDirSearch(dsp);
3455 smb_ReleaseDirSearch(dsp);
3459 dirLength = scp->length;
3461 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3462 curOffset.HighPart = 0;
3463 curOffset.LowPart = nextCookie;
3464 origOp = op = smb_GetSMBData(outp, NULL);
3465 /* and write out the basic header */
3466 *op++ = 5; /* variable block */
3467 op += 2; /* skip vbl block length; we'll fill it in later */
3471 /* make sure that curOffset.LowPart doesn't point to the first
3472 * 32 bytes in the 2nd through last dir page, and that it doesn't
3473 * point at the first 13 32-byte chunks in the first dir page,
3474 * since those are dir and page headers, and don't contain useful
3477 temp = curOffset.LowPart & (2048-1);
3478 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3479 /* we're in the first page */
3480 if (temp < 13*32) temp = 13*32;
3483 /* we're in a later dir page */
3484 if (temp < 32) temp = 32;
3487 /* make sure the low order 5 bits are zero */
3490 /* now put temp bits back ito curOffset.LowPart */
3491 curOffset.LowPart &= ~(2048-1);
3492 curOffset.LowPart |= temp;
3494 /* check if we've returned all the names that will fit in the
3497 if (returnedNames >= maxCount)
3500 /* check if we've passed the dir's EOF */
3501 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3503 /* see if we can use the bufferp we have now; compute in which page
3504 * the current offset would be, and check whether that's the offset
3505 * of the buffer we have. If not, get the buffer.
3507 thyper.HighPart = curOffset.HighPart;
3508 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3509 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3512 buf_Release(bufferp);
3515 lock_ReleaseMutex(&scp->mx);
3516 lock_ObtainRead(&scp->bufCreateLock);
3517 code = buf_Get(scp, &thyper, &bufferp);
3518 lock_ReleaseRead(&scp->bufCreateLock);
3520 /* now, if we're doing a star match, do bulk fetching of all of
3521 * the status info for files in the dir.
3524 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3526 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3527 && LargeIntegerGreaterThanOrEqualTo(thyper,
3528 scp->bulkStatProgress)) {
3529 /* Don't bulk stat if risking timeout */
3530 int now = GetCurrentTime();
3531 if (now - req.startTime > 5000) {
3532 scp->bulkStatProgress = thyper;
3533 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3534 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3536 cm_TryBulkStat(scp, &thyper, userp, &req);
3540 lock_ObtainMutex(&scp->mx);
3543 bufferOffset = thyper;
3545 /* now get the data in the cache */
3547 code = cm_SyncOp(scp, bufferp, userp, &req,
3549 CM_SCACHESYNC_NEEDCALLBACK
3550 | CM_SCACHESYNC_READ);
3553 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3555 /* otherwise, load the buffer and try again */
3556 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3561 buf_Release(bufferp);
3565 } /* if (wrong buffer) ... */
3567 /* now we have the buffer containing the entry we're interested in; copy
3568 * it out if it represents a non-deleted entry.
3570 entryInDir = curOffset.LowPart & (2048-1);
3571 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3573 /* page header will help tell us which entries are free. Page header
3574 * can change more often than once per buffer, since AFS 3 dir page size
3575 * may be less than (but not more than a buffer package buffer.
3577 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3578 temp &= ~(2048 - 1); /* turn off intra-page bits */
3579 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3581 /* now determine which entry we're looking at in the page. If it is
3582 * free (there's a free bitmap at the start of the dir), we should
3583 * skip these 32 bytes.
3585 slotInPage = (entryInDir & 0x7e0) >> 5;
3586 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3587 /* this entry is free */
3588 numDirChunks = 1; /* only skip this guy */
3592 tp = bufferp->datap + entryInBuffer;
3593 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3595 /* while we're here, compute the next entry's location, too,
3596 * since we'll need it when writing out the cookie into the dir
3599 * XXXX Probably should do more sanity checking.
3601 numDirChunks = cm_NameEntries(dep->name, NULL);
3603 /* compute the offset of the cookie representing the next entry */
3604 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3606 /* Compute 8.3 name if necessary */
3607 actualName = dep->name;
3608 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3609 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3610 actualName = shortName;
3613 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3614 /* this is one of the entries to use: it is not deleted
3615 * and it matches the star pattern we're looking for.
3618 /* Eliminate entries that don't match requested
3621 /* no hidden files */
3622 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3625 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3627 /* We have already done the cm_TryBulkStat above */
3628 fid.cell = scp->fid.cell;
3629 fid.volume = scp->fid.volume;
3630 fid.vnode = ntohl(dep->fid.vnode);
3631 fid.unique = ntohl(dep->fid.unique);
3632 fileType = cm_FindFileType(&fid);
3633 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3634 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3636 if (fileType == CM_SCACHETYPE_DIRECTORY)
3641 memcpy(op, mask, 11); op += 11;
3642 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3643 *op++ = nextEntryCookie & 0xff;
3644 *op++ = (nextEntryCookie>>8) & 0xff;
3645 *op++ = (nextEntryCookie>>16) & 0xff;
3646 *op++ = (nextEntryCookie>>24) & 0xff;
3647 memcpy(op, &clientCookie, 4); op += 4;
3649 /* now we emit the attribute. This is sort of tricky,
3650 * since we need to really stat the file to find out
3651 * what type of entry we've got. Right now, we're
3652 * copying out data from a buffer, while holding the
3653 * scp locked, so it isn't really convenient to stat
3654 * something now. We'll put in a place holder now,
3655 * and make a second pass before returning this to get
3656 * the real attributes. So, we just skip the data for
3657 * now, and adjust it later. We allocate a patch
3658 * record to make it easy to find this point later.
3659 * The replay will happen at a time when it is safe to
3660 * unlock the directory.
3662 curPatchp = malloc(sizeof(*curPatchp));
3663 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3664 curPatchp->dptr = op;
3665 curPatchp->fid.cell = scp->fid.cell;
3666 curPatchp->fid.volume = scp->fid.volume;
3667 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3668 curPatchp->fid.unique = ntohl(dep->fid.unique);
3670 /* do hidden attribute here since name won't be around when applying
3674 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3675 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3677 curPatchp->flags = 0;
3679 op += 9; /* skip attr, time, date and size */
3681 /* zero out name area. The spec says to pad with
3682 * spaces, but Samba doesn't, and neither do we.
3686 /* finally, we get to copy out the name; we know that
3687 * it fits in 8.3 or the pattern wouldn't match, but it
3688 * never hurts to be sure.
3690 strncpy(op, actualName, 13);
3692 /* Uppercase if requested by client */
3693 if ((((smb_t *)inp)->flg2 & 1) == 0)
3698 /* now, adjust the # of entries copied */
3700 } /* if we're including this name */
3703 /* and adjust curOffset to be where the new cookie is */
3704 thyper.HighPart = 0;
3705 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3706 curOffset = LargeIntegerAdd(thyper, curOffset);
3707 } /* while copying data for dir listing */
3709 /* release the mutex */
3710 lock_ReleaseMutex(&scp->mx);
3711 if (bufferp) buf_Release(bufferp);
3713 /* apply and free last set of patches; if not doing a star match, this
3714 * will be empty, but better safe (and freeing everything) than sorry.
3716 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3718 /* special return code for unsuccessful search */
3719 if (code == 0 && dataLength < 21 && returnedNames == 0)
3720 code = CM_ERROR_NOFILES;
3722 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3723 returnedNames, code);
3726 smb_DeleteDirSearch(dsp);
3727 smb_ReleaseDirSearch(dsp);
3728 cm_ReleaseSCache(scp);
3729 cm_ReleaseUser(userp);
3733 /* finalize the output buffer */
3734 smb_SetSMBParm(outp, 0, returnedNames);
3735 temp = (long) (op - origOp);
3736 smb_SetSMBDataLength(outp, temp);
3738 /* the data area is a variable block, which has a 5 (already there)
3739 * followed by the length of the # of data bytes. We now know this to
3740 * be "temp," although that includes the 3 bytes of vbl block header.
3741 * Deduct for them and fill in the length field.
3743 temp -= 3; /* deduct vbl block info */
3744 osi_assert(temp == (43 * returnedNames));
3745 origOp[1] = temp & 0xff;
3746 origOp[2] = (temp>>8) & 0xff;
3747 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3748 smb_ReleaseDirSearch(dsp);
3749 cm_ReleaseSCache(scp);
3750 cm_ReleaseUser(userp);
3754 /* verify that this is a valid path to a directory. I don't know why they
3755 * don't use the get file attributes call.
3757 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3761 cm_scache_t *rootScp;
3762 cm_scache_t *newScp;
3771 pathp = smb_GetSMBData(inp, NULL);
3772 pathp = smb_ParseASCIIBlock(pathp, NULL);
3773 osi_Log1(smb_logp, "SMB receive check path %s",
3774 osi_LogSaveString(smb_logp, pathp));
3777 return CM_ERROR_BADFD;
3780 rootScp = cm_rootSCachep;
3782 userp = smb_GetUser(vcp, inp);
3784 caseFold = CM_FLAG_CASEFOLD;
3786 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3788 cm_ReleaseUser(userp);
3789 return CM_ERROR_NOSUCHPATH;
3791 code = cm_NameI(rootScp, pathp,
3792 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3793 userp, tidPathp, &req, &newScp);
3796 cm_ReleaseUser(userp);
3800 /* now lock the vnode with a callback; returns with newScp locked */
3801 lock_ObtainMutex(&newScp->mx);
3802 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3803 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3804 if (code && code != CM_ERROR_NOACCESS) {
3805 lock_ReleaseMutex(&newScp->mx);
3806 cm_ReleaseSCache(newScp);
3807 cm_ReleaseUser(userp);
3811 attrs = smb_Attributes(newScp);
3813 if (!(attrs & 0x10))
3814 code = CM_ERROR_NOTDIR;
3816 lock_ReleaseMutex(&newScp->mx);
3818 cm_ReleaseSCache(newScp);
3819 cm_ReleaseUser(userp);
3823 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3827 cm_scache_t *rootScp;
3828 unsigned short attribute;
3830 cm_scache_t *newScp;
3839 /* decode basic attributes we're passed */
3840 attribute = smb_GetSMBParm(inp, 0);
3841 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3843 pathp = smb_GetSMBData(inp, NULL);
3844 pathp = smb_ParseASCIIBlock(pathp, NULL);
3847 return CM_ERROR_BADSMB;
3850 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3851 dosTime, attribute);
3853 rootScp = cm_rootSCachep;
3855 userp = smb_GetUser(vcp, inp);
3857 caseFold = CM_FLAG_CASEFOLD;
3859 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3861 cm_ReleaseUser(userp);
3862 return CM_ERROR_NOSUCHFILE;
3864 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3865 tidPathp, &req, &newScp);
3868 cm_ReleaseUser(userp);
3872 /* now lock the vnode with a callback; returns with newScp locked; we
3873 * need the current status to determine what the new status is, in some
3876 lock_ObtainMutex(&newScp->mx);
3877 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3878 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3880 lock_ReleaseMutex(&newScp->mx);
3881 cm_ReleaseSCache(newScp);
3882 cm_ReleaseUser(userp);
3886 /* Check for RO volume */
3887 if (newScp->flags & CM_SCACHEFLAG_RO) {
3888 lock_ReleaseMutex(&newScp->mx);
3889 cm_ReleaseSCache(newScp);
3890 cm_ReleaseUser(userp);
3891 return CM_ERROR_READONLY;
3894 /* prepare for setattr call */
3897 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3898 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3900 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3901 /* we're told to make a writable file read-only */
3902 attr.unixModeBits = newScp->unixModeBits & ~0222;
3903 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3905 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3906 /* we're told to make a read-only file writable */
3907 attr.unixModeBits = newScp->unixModeBits | 0222;
3908 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3910 lock_ReleaseMutex(&newScp->mx);
3912 /* now call setattr */
3914 code = cm_SetAttr(newScp, &attr, userp, &req);
3918 cm_ReleaseSCache(newScp);
3919 cm_ReleaseUser(userp);
3924 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3928 cm_scache_t *rootScp;
3929 cm_scache_t *newScp, *dscp;
3941 pathp = smb_GetSMBData(inp, NULL);
3942 pathp = smb_ParseASCIIBlock(pathp, NULL);
3945 return CM_ERROR_BADSMB;
3948 if (*pathp == 0) /* null path */
3951 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3952 osi_LogSaveString(smb_logp, pathp));
3954 rootScp = cm_rootSCachep;
3956 userp = smb_GetUser(vcp, inp);
3958 /* we shouldn't need this for V3 requests, but we seem to */
3959 caseFold = CM_FLAG_CASEFOLD;
3961 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3963 cm_ReleaseUser(userp);
3964 return CM_ERROR_NOSUCHFILE;
3968 * XXX Strange hack XXX
3970 * As of Patch 5 (16 July 97), we are having the following problem:
3971 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3972 * requests to look up "desktop.ini" in all the subdirectories.
3973 * This can cause zillions of timeouts looking up non-existent cells
3974 * and volumes, especially in the top-level directory.
3976 * We have not found any way to avoid this or work around it except
3977 * to explicitly ignore the requests for mount points that haven't
3978 * yet been evaluated and for directories that haven't yet been
3981 * We should modify this hack to provide a fake desktop.ini file
3982 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3984 spacep = inp->spacep;
3985 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3986 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3987 code = cm_NameI(rootScp, spacep->data,
3988 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3989 userp, tidPathp, &req, &dscp);
3991 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3992 && !dscp->mountRootFidp)
3993 code = CM_ERROR_NOSUCHFILE;
3994 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3995 cm_buf_t *bp = buf_Find(dscp, &hzero);
3999 code = CM_ERROR_NOSUCHFILE;
4001 cm_ReleaseSCache(dscp);
4003 cm_ReleaseUser(userp);
4009 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4010 tidPathp, &req, &newScp);
4013 cm_ReleaseUser(userp);
4017 /* now lock the vnode with a callback; returns with newScp locked */
4018 lock_ObtainMutex(&newScp->mx);
4019 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4020 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4022 lock_ReleaseMutex(&newScp->mx);
4023 cm_ReleaseSCache(newScp);
4024 cm_ReleaseUser(userp);
4029 /* use smb_Attributes instead. Also the fact that a file is
4030 * in a readonly volume doesn't mean it shojuld be marked as RO
4032 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
4033 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4034 attrs = SMB_ATTR_DIRECTORY;
4037 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4038 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4040 attrs = smb_Attributes(newScp);
4043 smb_SetSMBParm(outp, 0, attrs);
4045 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4046 smb_SetSMBParm(outp, 1, dosTime & 0xffff);
4047 smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
4048 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4049 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4050 smb_SetSMBParm(outp, 5, 0);
4051 smb_SetSMBParm(outp, 6, 0);
4052 smb_SetSMBParm(outp, 7, 0);
4053 smb_SetSMBParm(outp, 8, 0);
4054 smb_SetSMBParm(outp, 9, 0);
4055 smb_SetSMBDataLength(outp, 0);
4056 lock_ReleaseMutex(&newScp->mx);
4058 cm_ReleaseSCache(newScp);
4059 cm_ReleaseUser(userp);
4064 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4068 osi_Log0(smb_logp, "SMB receive tree disconnect");
4070 /* find the tree and free it */
4071 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4073 lock_ObtainMutex(&tidp->mx);
4074 tidp->flags |= SMB_TIDFLAG_DELETE;
4075 lock_ReleaseMutex(&tidp->mx);
4076 smb_ReleaseTID(tidp);
4082 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4100 pathp = smb_GetSMBData(inp, NULL);
4101 pathp = smb_ParseASCIIBlock(pathp, NULL);
4103 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4105 #ifdef DEBUG_VERBOSE
4109 hexpath = osi_HexifyString( pathp );
4110 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4115 share = smb_GetSMBParm(inp, 0);
4116 attribute = smb_GetSMBParm(inp, 1);
4118 spacep = inp->spacep;
4119 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4120 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4121 /* special case magic file name for receiving IOCTL requests
4122 * (since IOCTL calls themselves aren't getting through).
4124 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4125 smb_SetupIoctlFid(fidp, spacep);
4126 smb_SetSMBParm(outp, 0, fidp->fid);
4127 smb_SetSMBParm(outp, 1, 0); /* attrs */
4128 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4129 smb_SetSMBParm(outp, 3, 0);
4130 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4131 smb_SetSMBParm(outp, 5, 0x7fff);
4132 /* pass the open mode back */
4133 smb_SetSMBParm(outp, 6, (share & 0xf));
4134 smb_SetSMBDataLength(outp, 0);
4135 smb_ReleaseFID(fidp);
4139 userp = smb_GetUser(vcp, inp);
4141 caseFold = CM_FLAG_CASEFOLD;
4143 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4145 cm_ReleaseUser(userp);
4146 return CM_ERROR_NOSUCHPATH;
4148 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4149 tidPathp, &req, &scp);
4152 cm_ReleaseUser(userp);
4156 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4158 cm_ReleaseSCache(scp);
4159 cm_ReleaseUser(userp);
4163 /* don't need callback to check file type, since file types never
4164 * change, and namei and cm_Lookup all stat the object at least once on
4165 * a successful return.
4167 if (scp->fileType != CM_SCACHETYPE_FILE) {
4168 cm_ReleaseSCache(scp);
4169 cm_ReleaseUser(userp);
4170 return CM_ERROR_ISDIR;
4173 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4176 /* save a pointer to the vnode */
4179 if ((share & 0xf) == 0)
4180 fidp->flags |= SMB_FID_OPENREAD;
4181 else if ((share & 0xf) == 1)
4182 fidp->flags |= SMB_FID_OPENWRITE;
4184 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4186 lock_ObtainMutex(&scp->mx);
4187 smb_SetSMBParm(outp, 0, fidp->fid);
4188 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4189 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4190 smb_SetSMBParm(outp, 2, dosTime & 0xffff);
4191 smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
4192 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4193 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4194 /* pass the open mode back; XXXX add access checks */
4195 smb_SetSMBParm(outp, 6, (share & 0xf));
4196 smb_SetSMBDataLength(outp, 0);
4197 lock_ReleaseMutex(&scp->mx);
4200 cm_Open(scp, 0, userp);
4202 /* send and free packet */
4203 smb_ReleaseFID(fidp);
4204 cm_ReleaseUser(userp);
4205 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4209 typedef struct smb_unlinkRock {
4214 char *maskp; /* pointer to the star pattern */
4219 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4222 smb_unlinkRock_t *rockp;
4230 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4231 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4232 caseFold |= CM_FLAG_8DOT3;
4234 matchName = dep->name;
4235 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4237 && (rockp->flags & SMB_MASKFLAG_TILDE)
4238 && !cm_Is8Dot3(dep->name)) {
4239 cm_Gen8Dot3Name(dep, shortName, NULL);
4240 matchName = shortName;
4241 /* 8.3 matches are always case insensitive */
4242 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4245 osi_Log1(smb_logp, "Unlinking %s",
4246 osi_LogSaveString(smb_logp, matchName));
4247 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4248 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4249 smb_NotifyChange(FILE_ACTION_REMOVED,
4250 FILE_NOTIFY_CHANGE_FILE_NAME,
4251 dscp, dep->name, NULL, TRUE);
4254 /* If we made a case sensitive exact match, we might as well quit now. */
4255 if(!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4256 code = CM_ERROR_STOPNOW;
4264 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4273 smb_unlinkRock_t rock;
4282 attribute = smb_GetSMBParm(inp, 0);
4284 tp = smb_GetSMBData(inp, NULL);
4285 pathp = smb_ParseASCIIBlock(tp, &tp);
4287 osi_Log1(smb_logp, "SMB receive unlink %s",
4288 osi_LogSaveString(smb_logp, pathp));
4290 spacep = inp->spacep;
4291 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4293 userp = smb_GetUser(vcp, inp);
4295 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4297 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4299 cm_ReleaseUser(userp);
4300 return CM_ERROR_NOSUCHPATH;
4302 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4306 cm_ReleaseUser(userp);
4310 /* otherwise, scp points to the parent directory. */
4317 rock.maskp = smb_FindMask(pathp);
4318 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4321 thyper.HighPart = 0;
4327 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4328 * match. If that fails, we do a case insensitve match.
4330 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4331 !smb_IsStarMask(rock.maskp)) {
4332 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4335 thyper.HighPart = 0;
4336 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4341 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4343 if (code == CM_ERROR_STOPNOW)
4346 cm_ReleaseUser(userp);
4348 cm_ReleaseSCache(dscp);
4350 if (code == 0 && !rock.any)
4351 code = CM_ERROR_NOSUCHFILE;
4355 typedef struct smb_renameRock {
4356 cm_scache_t *odscp; /* old dir */
4357 cm_scache_t *ndscp; /* new dir */
4358 cm_user_t *userp; /* user */
4359 cm_req_t *reqp; /* request struct */
4360 smb_vc_t *vcp; /* virtual circuit */
4361 char *maskp; /* pointer to star pattern of old file name */
4362 int flags; /* tilde, casefold, etc */
4363 char *newNamep; /* ptr to the new file's name */
4366 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4369 smb_renameRock_t *rockp;
4374 rockp = (smb_renameRock_t *) vrockp;
4376 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4377 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4378 caseFold |= CM_FLAG_8DOT3;
4380 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4382 && (rockp->flags & SMB_MASKFLAG_TILDE)
4383 && !cm_Is8Dot3(dep->name)) {
4384 cm_Gen8Dot3Name(dep, shortName, NULL);
4385 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4388 code = cm_Rename(rockp->odscp, dep->name,
4389 rockp->ndscp, rockp->newNamep, rockp->userp,
4391 /* if the call worked, stop doing the search now, since we
4392 * really only want to rename one file.
4395 code = CM_ERROR_STOPNOW;
4404 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4407 cm_space_t *spacep = NULL;
4408 smb_renameRock_t rock;
4409 cm_scache_t *oldDscp = NULL;
4410 cm_scache_t *newDscp = NULL;
4411 cm_scache_t *tmpscp= NULL;
4412 cm_scache_t *tmpscp2 = NULL;
4422 userp = smb_GetUser(vcp, inp);
4423 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4425 cm_ReleaseUser(userp);
4426 return CM_ERROR_NOSUCHPATH;
4430 spacep = inp->spacep;
4431 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4434 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4435 * what actually exists is foo/baz. I don't know why the code used to be
4436 * the way it was. 1/29/96
4438 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4440 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4442 * caseFold = CM_FLAG_CASEFOLD;
4444 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4445 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4446 userp, tidPathp, &req, &oldDscp);
4449 cm_ReleaseUser(userp);
4453 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4454 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4455 userp, tidPathp, &req, &newDscp);
4458 cm_ReleaseSCache(oldDscp);
4459 cm_ReleaseUser(userp);
4463 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4464 * next, get the component names, and lower case them.
4467 /* handle the old name first */
4469 oldLastNamep = oldPathp;
4473 /* and handle the new name, too */
4475 newLastNamep = newPathp;
4479 /* TODO: The old name could be a wildcard. The new name must not be */
4481 /* do the vnode call */
4482 rock.odscp = oldDscp;
4483 rock.ndscp = newDscp;
4487 rock.maskp = oldLastNamep;
4488 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4489 rock.newNamep = newLastNamep;
4491 /* Check if the file already exists; if so return error */
4492 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4493 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4494 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4495 osi_LogSaveString(afsd_logp, newLastNamep));
4497 /* Check if the old and the new names differ only in case. If so return
4498 * success, else return CM_ERROR_EXISTS
4500 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4502 /* This would be a success only if the old file is *as same as* the new file */
4503 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4505 if (tmpscp == tmpscp2)
4508 code = CM_ERROR_EXISTS;
4509 cm_ReleaseSCache(tmpscp2);
4512 code = CM_ERROR_NOSUCHFILE;
4515 /* file exist, do not rename, also fixes move */
4516 osi_Log0(smb_logp, "Can't rename. Target already exists");
4517 code = CM_ERROR_EXISTS;
4521 cm_ReleaseSCache(tmpscp);
4522 cm_ReleaseSCache(newDscp);
4523 cm_ReleaseSCache(oldDscp);
4524 cm_ReleaseUser(userp);
4528 /* Now search the directory for the pattern, and do the appropriate rename when found */
4529 thyper.LowPart = 0; /* search dir from here */
4530 thyper.HighPart = 0;
4532 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4534 if (code == CM_ERROR_STOPNOW)
4537 code = CM_ERROR_NOSUCHFILE;
4539 /* Handle Change Notification */
4541 * Being lazy, not distinguishing between files and dirs in this
4542 * filter, since we'd have to do a lookup.
4544 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4545 if (oldDscp == newDscp) {
4546 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4547 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4548 filter, oldDscp, oldLastNamep,
4549 newLastNamep, TRUE);
4551 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4552 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4553 filter, oldDscp, oldLastNamep,
4555 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4556 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4557 filter, newDscp, newLastNamep,
4562 cm_ReleaseSCache(tmpscp);
4563 cm_ReleaseUser(userp);
4564 cm_ReleaseSCache(oldDscp);
4565 cm_ReleaseSCache(newDscp);
4570 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4573 cm_space_t *spacep = NULL;
4574 cm_scache_t *oldDscp = NULL;
4575 cm_scache_t *newDscp = NULL;
4576 cm_scache_t *tmpscp= NULL;
4577 cm_scache_t *tmpscp2 = NULL;
4578 cm_scache_t *sscp = NULL;
4587 userp = smb_GetUser(vcp, inp);
4589 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4591 cm_ReleaseUser(userp);
4592 return CM_ERROR_NOSUCHPATH;
4597 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4599 spacep = inp->spacep;
4600 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4602 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4603 userp, tidPathp, &req, &oldDscp);
4605 cm_ReleaseUser(userp);
4609 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4610 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4611 userp, tidPathp, &req, &newDscp);
4613 cm_ReleaseSCache(oldDscp);
4614 cm_ReleaseUser(userp);
4618 /* Now, although we did two lookups for the two directories (because the same
4619 * directory can be referenced through different paths), we only allow hard links
4620 * within the same directory. */
4621 if (oldDscp != newDscp) {
4622 cm_ReleaseSCache(oldDscp);
4623 cm_ReleaseSCache(newDscp);
4624 cm_ReleaseUser(userp);
4625 return CM_ERROR_CROSSDEVLINK;
4628 /* handle the old name first */
4630 oldLastNamep = oldPathp;
4634 /* and handle the new name, too */
4636 newLastNamep = newPathp;
4640 /* now lookup the old name */
4641 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4642 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4644 cm_ReleaseSCache(oldDscp);
4645 cm_ReleaseSCache(newDscp);
4646 cm_ReleaseUser(userp);
4650 /* Check if the file already exists; if so return error */
4651 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4652 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4653 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4654 osi_LogSaveString(afsd_logp, newLastNamep));
4656 /* if the existing link is to the same file, then we return success */
4658 if(sscp == tmpscp) {
4661 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
4662 code = CM_ERROR_EXISTS;
4667 cm_ReleaseSCache(tmpscp);
4668 cm_ReleaseSCache(sscp);
4669 cm_ReleaseSCache(newDscp);
4670 cm_ReleaseSCache(oldDscp);
4671 cm_ReleaseUser(userp);
4675 /* now create the hardlink */
4676 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
4677 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
4678 osi_Log1(smb_logp," Link returns %d", code);
4680 /* Handle Change Notification */
4682 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
4683 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4684 smb_NotifyChange(FILE_ACTION_ADDED,
4685 filter, newDscp, newLastNamep,
4690 cm_ReleaseSCache(tmpscp);
4691 cm_ReleaseUser(userp);
4692 cm_ReleaseSCache(sscp);
4693 cm_ReleaseSCache(oldDscp);
4694 cm_ReleaseSCache(newDscp);
4699 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4705 tp = smb_GetSMBData(inp, NULL);
4706 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4707 newPathp = smb_ParseASCIIBlock(tp, &tp);
4709 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4710 osi_LogSaveString(smb_logp, oldPathp),
4711 osi_LogSaveString(smb_logp, newPathp));
4713 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
4718 typedef struct smb_rmdirRock {
4722 char *maskp; /* pointer to the star pattern */
4727 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4730 smb_rmdirRock_t *rockp;
4735 rockp = (smb_rmdirRock_t *) vrockp;
4737 matchName = dep->name;
4738 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4739 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4741 match = (strcmp(matchName, rockp->maskp) == 0);
4743 && (rockp->flags & SMB_MASKFLAG_TILDE)
4744 && !cm_Is8Dot3(dep->name)) {
4745 cm_Gen8Dot3Name(dep, shortName, NULL);
4746 matchName = shortName;
4747 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4750 osi_Log1(smb_logp, "Removing directory %s",
4751 osi_LogSaveString(smb_logp, matchName));
4752 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4753 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4754 smb_NotifyChange(FILE_ACTION_REMOVED,
4755 FILE_NOTIFY_CHANGE_DIR_NAME,
4756 dscp, dep->name, NULL, TRUE);
4765 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4773 smb_rmdirRock_t rock;
4782 tp = smb_GetSMBData(inp, NULL);
4783 pathp = smb_ParseASCIIBlock(tp, &tp);
4785 spacep = inp->spacep;
4786 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4788 userp = smb_GetUser(vcp, inp);
4790 caseFold = CM_FLAG_CASEFOLD;
4792 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4794 cm_ReleaseUser(userp);
4795 return CM_ERROR_NOSUCHPATH;
4797 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4798 userp, tidPathp, &req, &dscp);
4801 cm_ReleaseUser(userp);
4805 /* otherwise, scp points to the parent directory. */
4812 rock.maskp = lastNamep;
4813 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4816 thyper.HighPart = 0;
4820 /* First do a case sensitive match, and if that fails, do a case insensitive match */
4821 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4822 if (code == 0 && !rock.any) {
4824 thyper.HighPart = 0;
4825 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4826 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4829 cm_ReleaseUser(userp);
4831 cm_ReleaseSCache(dscp);
4833 if (code == 0 && !rock.any)
4834 code = CM_ERROR_NOSUCHFILE;
4838 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4848 fid = smb_GetSMBParm(inp, 0);
4850 osi_Log1(smb_logp, "SMB flush fid %d", fid);
4852 fid = smb_ChainFID(fid, inp);
4853 fidp = smb_FindFID(vcp, fid, 0);
4854 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4856 smb_ReleaseFID(fidp);
4857 return CM_ERROR_BADFD;
4860 userp = smb_GetUser(vcp, inp);
4862 lock_ObtainMutex(&fidp->mx);
4863 if (fidp->flags & SMB_FID_OPENWRITE)
4864 code = cm_FSync(fidp->scp, userp, &req);
4867 lock_ReleaseMutex(&fidp->mx);
4869 smb_ReleaseFID(fidp);
4871 cm_ReleaseUser(userp);
4876 struct smb_FullNameRock {
4882 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4886 struct smb_FullNameRock *vrockp;
4888 vrockp = (struct smb_FullNameRock *)rockp;
4890 if (!cm_Is8Dot3(dep->name)) {
4891 cm_Gen8Dot3Name(dep, shortName, NULL);
4893 if (cm_stricmp(shortName, vrockp->name) == 0) {
4894 vrockp->fullName = strdup(dep->name);
4895 return CM_ERROR_STOPNOW;
4898 if (cm_stricmp(dep->name, vrockp->name) == 0
4899 && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
4900 && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4901 vrockp->fullName = strdup(dep->name);
4902 return CM_ERROR_STOPNOW;
4907 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4908 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4910 struct smb_FullNameRock rock;
4916 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL,
4918 if (code == CM_ERROR_STOPNOW)
4919 *newPathp = rock.fullName;
4921 *newPathp = strdup(pathp);
4924 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4935 fid = smb_GetSMBParm(inp, 0);
4936 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4938 osi_Log1(smb_logp, "SMB close fid %d", fid);
4940 fid = smb_ChainFID(fid, inp);
4941 fidp = smb_FindFID(vcp, fid, 0);
4943 return CM_ERROR_BADFD;
4946 userp = smb_GetUser(vcp, inp);
4948 lock_ObtainMutex(&fidp->mx);
4950 /* Don't jump the gun on an async raw write */
4951 while (fidp->raw_writers) {
4952 lock_ReleaseMutex(&fidp->mx);
4953 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4954 lock_ObtainMutex(&fidp->mx);
4957 fidp->flags |= SMB_FID_DELETE;
4959 /* watch for ioctl closes, and read-only opens */
4960 if (fidp->scp != NULL
4961 && (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4962 == SMB_FID_OPENWRITE) {
4963 if (dosTime != 0 && dosTime != -1) {
4964 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4965 /* This fixes defect 10958 */
4966 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4967 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
4969 code = cm_FSync(fidp->scp, userp, &req);
4974 if (fidp->flags & SMB_FID_DELONCLOSE) {
4975 cm_scache_t *dscp = fidp->NTopen_dscp;
4976 char *pathp = fidp->NTopen_pathp;
4979 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
4980 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
4981 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
4982 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4983 smb_NotifyChange(FILE_ACTION_REMOVED,
4984 FILE_NOTIFY_CHANGE_DIR_NAME,
4985 dscp, fullPathp, NULL, TRUE);
4989 code = cm_Unlink(dscp, fullPathp, userp, &req);
4990 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4991 smb_NotifyChange(FILE_ACTION_REMOVED,
4992 FILE_NOTIFY_CHANGE_FILE_NAME,
4993 dscp, fullPathp, NULL, TRUE);
4997 lock_ReleaseMutex(&fidp->mx);
4999 if (fidp->flags & SMB_FID_NTOPEN) {
5000 cm_ReleaseSCache(fidp->NTopen_dscp);
5001 free(fidp->NTopen_pathp);
5003 if (fidp->NTopen_wholepathp)
5004 free(fidp->NTopen_wholepathp);
5006 smb_ReleaseFID(fidp);
5007 cm_ReleaseUser(userp);
5012 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5015 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5016 cm_user_t *userp, long *readp)
5018 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5019 cm_user_t *userp, long *readp, int dosflag)
5026 osi_hyper_t fileLength;
5028 osi_hyper_t lastByte;
5029 osi_hyper_t bufferOffset;
5030 long bufIndex, nbytes;
5040 lock_ObtainMutex(&fidp->mx);
5042 lock_ObtainMutex(&scp->mx);
5044 if (offset.HighPart == 0) {
5045 chunk = offset.LowPart >> cm_logChunkSize;
5046 if (chunk != fidp->curr_chunk) {
5047 fidp->prev_chunk = fidp->curr_chunk;
5048 fidp->curr_chunk = chunk;
5050 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5054 /* start by looking up the file's end */
5055 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5056 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5057 if (code) goto done;
5059 /* now we have the entry locked, look up the length */
5060 fileLength = scp->length;
5062 /* adjust count down so that it won't go past EOF */
5063 thyper.LowPart = count;
5064 thyper.HighPart = 0;
5065 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5067 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5068 /* we'd read past EOF, so just stop at fileLength bytes.
5069 * Start by computing how many bytes remain in the file.
5071 thyper = LargeIntegerSubtract(fileLength, offset);
5073 /* if we are past EOF, read 0 bytes */
5074 if (LargeIntegerLessThanZero(thyper))
5077 count = thyper.LowPart;
5082 /* now, copy the data one buffer at a time,
5083 * until we've filled the request packet
5086 /* if we've copied all the data requested, we're done */
5087 if (count <= 0) break;
5089 /* otherwise, load up a buffer of data */
5090 thyper.HighPart = offset.HighPart;
5091 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5092 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5095 buf_Release(bufferp);
5098 lock_ReleaseMutex(&scp->mx);
5100 lock_ObtainRead(&scp->bufCreateLock);
5101 code = buf_Get(scp, &thyper, &bufferp);
5102 lock_ReleaseRead(&scp->bufCreateLock);
5104 lock_ObtainMutex(&scp->mx);
5105 if (code) goto done;
5106 bufferOffset = thyper;
5108 /* now get the data in the cache */
5110 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5111 CM_SCACHESYNC_NEEDCALLBACK
5112 | CM_SCACHESYNC_READ);
5113 if (code) goto done;
5115 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5117 /* otherwise, load the buffer and try again */
5118 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5122 buf_Release(bufferp);
5126 } /* if (wrong buffer) ... */
5128 /* now we have the right buffer loaded. Copy out the
5129 * data from here to the user's buffer.
5131 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5133 /* and figure out how many bytes we want from this buffer */
5134 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5135 if (nbytes > count) nbytes = count; /* don't go past EOF */
5137 /* now copy the data */
5140 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5143 memcpy(op, bufferp->datap + bufIndex, nbytes);
5145 /* adjust counters, pointers, etc. */
5148 thyper.LowPart = nbytes;
5149 thyper.HighPart = 0;
5150 offset = LargeIntegerAdd(thyper, offset);
5154 lock_ReleaseMutex(&scp->mx);
5155 lock_ReleaseMutex(&fidp->mx);
5157 buf_Release(bufferp);
5159 if (code == 0 && sequential)
5160 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5166 * smb_WriteData -- common code for Write and Raw Write
5169 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5170 cm_user_t *userp, long *writtenp)
5172 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5173 cm_user_t *userp, long *writtenp, int dosflag)
5180 osi_hyper_t fileLength; /* file's length at start of write */
5181 osi_hyper_t minLength; /* don't read past this */
5182 long nbytes; /* # of bytes to transfer this iteration */
5184 osi_hyper_t thyper; /* hyper tmp variable */
5185 osi_hyper_t bufferOffset;
5186 long bufIndex; /* index in buffer where our data is */
5188 osi_hyper_t writeBackOffset; /* offset of region to write back when
5193 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5194 fidp->fid, offsetp->LowPart, count);
5202 lock_ObtainMutex(&fidp->mx);
5204 lock_ObtainMutex(&scp->mx);
5206 /* start by looking up the file's end */
5207 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5209 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5210 CM_SCACHESYNC_NEEDCALLBACK
5211 | CM_SCACHESYNC_SETSTATUS
5212 | CM_SCACHESYNC_GETSTATUS);
5213 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5218 /* make sure we have a writable FD */
5219 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5220 code = CM_ERROR_BADFDOP;
5224 /* now we have the entry locked, look up the length */
5225 fileLength = scp->length;
5226 minLength = fileLength;
5227 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5228 minLength = scp->serverLength;
5230 /* adjust file length if we extend past EOF */
5231 thyper.LowPart = count;
5232 thyper.HighPart = 0;
5233 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5234 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5235 /* we'd write past EOF, so extend the file */
5236 scp->mask |= CM_SCACHEMASK_LENGTH;
5237 scp->length = thyper;
5238 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5240 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5242 /* now, if the new position (thyper) and the old (offset) are in
5243 * different storeback windows, remember to store back the previous
5244 * storeback window when we're done with the write.
5246 if ((thyper.LowPart & (-cm_chunkSize)) !=
5247 (offset.LowPart & (-cm_chunkSize))) {
5248 /* they're different */
5250 writeBackOffset.HighPart = offset.HighPart;
5251 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5256 /* now, copy the data one buffer at a time, until we've filled the
5259 /* if we've copied all the data requested, we're done */
5260 if (count <= 0) break;
5262 /* handle over quota or out of space */
5263 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5264 *writtenp = written;
5268 /* otherwise, load up a buffer of data */
5269 thyper.HighPart = offset.HighPart;
5270 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5271 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5274 lock_ReleaseMutex(&bufferp->mx);
5275 buf_Release(bufferp);
5278 lock_ReleaseMutex(&scp->mx);
5280 lock_ObtainRead(&scp->bufCreateLock);
5281 code = buf_Get(scp, &thyper, &bufferp);
5282 lock_ReleaseRead(&scp->bufCreateLock);
5284 lock_ObtainMutex(&bufferp->mx);
5285 lock_ObtainMutex(&scp->mx);
5286 if (code) goto done;
5288 bufferOffset = thyper;
5290 /* now get the data in the cache */
5292 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5294 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5295 CM_SCACHESYNC_NEEDCALLBACK
5296 | CM_SCACHESYNC_WRITE
5297 | CM_SCACHESYNC_BUFLOCKED);
5298 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5303 /* If we're overwriting the entire buffer, or
5304 * if we're writing at or past EOF, mark the
5305 * buffer as current so we don't call
5306 * cm_GetBuffer. This skips the fetch from the
5307 * server in those cases where we're going to
5308 * obliterate all the data in the buffer anyway,
5309 * or in those cases where there is no useful
5310 * data at the server to start with.
5312 * Use minLength instead of scp->length, since
5313 * the latter has already been updated by this
5316 if (LargeIntegerGreaterThanOrEqualTo(
5317 bufferp->offset, minLength)
5318 || LargeIntegerEqualTo(offset, bufferp->offset)
5319 && (count >= buf_bufferSize
5320 || LargeIntegerGreaterThanOrEqualTo(
5321 LargeIntegerAdd(offset,
5322 ConvertLongToLargeInteger(count)),
5324 if (count < buf_bufferSize
5325 && bufferp->dataVersion == -1)
5326 memset(bufferp->datap, 0,
5328 bufferp->dataVersion = scp->dataVersion;
5331 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5333 /* otherwise, load the buffer and try again */
5334 lock_ReleaseMutex(&bufferp->mx);
5335 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5337 lock_ReleaseMutex(&scp->mx);
5338 lock_ObtainMutex(&bufferp->mx);
5339 lock_ObtainMutex(&scp->mx);
5343 lock_ReleaseMutex(&bufferp->mx);
5344 buf_Release(bufferp);
5348 } /* if (wrong buffer) ... */
5350 /* now we have the right buffer loaded. Copy out the
5351 * data from here to the user's buffer.
5353 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5355 /* and figure out how many bytes we want from this buffer */
5356 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5358 nbytes = count; /* don't go past end of request */
5360 /* now copy the data */
5363 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5366 memcpy(bufferp->datap + bufIndex, op, nbytes);
5367 buf_SetDirty(bufferp);
5369 /* and record the last writer */
5370 if (bufferp->userp != userp) {
5373 cm_ReleaseUser(bufferp->userp);
5374 bufferp->userp = userp;
5377 /* adjust counters, pointers, etc. */
5381 thyper.LowPart = nbytes;
5382 thyper.HighPart = 0;
5383 offset = LargeIntegerAdd(thyper, offset);
5387 lock_ReleaseMutex(&scp->mx);
5388 lock_ReleaseMutex(&fidp->mx);
5390 lock_ReleaseMutex(&bufferp->mx);
5391 buf_Release(bufferp);
5394 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5395 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5396 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5397 fidp->NTopen_dscp, fidp->NTopen_pathp,
5401 if (code == 0 && doWriteBack) {
5403 lock_ObtainMutex(&scp->mx);
5404 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5406 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5407 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5409 lock_ReleaseMutex(&scp->mx);
5410 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5411 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5414 osi_Log2(smb_logp, "smb_WriteData fid %d returns %d",
5419 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5422 long count, written = 0;
5427 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5429 int inDataBlockCount;
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 op = smb_GetSMBData(inp, NULL);
5437 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5439 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5440 fd, offset.LowPart, count);
5442 fd = smb_ChainFID(fd, inp);
5443 fidp = smb_FindFID(vcp, fd, 0);
5445 return CM_ERROR_BADFD;
5448 if (fidp->flags & SMB_FID_IOCTL)
5449 return smb_IoctlWrite(fidp, vcp, inp, outp);
5451 userp = smb_GetUser(vcp, inp);
5453 /* special case: 0 bytes transferred means truncate to this position */
5459 truncAttr.mask = CM_ATTRMASK_LENGTH;
5460 truncAttr.length.LowPart = offset.LowPart;
5461 truncAttr.length.HighPart = 0;
5462 lock_ObtainMutex(&fidp->mx);
5463 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5464 lock_ReleaseMutex(&fidp->mx);
5465 smb_SetSMBParm(outp, 0, /* count */ 0);
5466 smb_SetSMBDataLength(outp, 0);
5467 fidp->flags |= SMB_FID_LENGTHSETDONE;
5472 * Work around bug in NT client
5474 * When copying a file, the NT client should first copy the data,
5475 * then copy the last write time. But sometimes the NT client does
5476 * these in the wrong order, so the data copies would inadvertently
5477 * cause the last write time to be overwritten. We try to detect this,
5478 * and don't set client mod time if we think that would go against the
5481 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5482 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5483 fidp->scp->clientModTime = time(NULL);
5487 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5489 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5491 if (code == 0 && written < count)
5492 code = CM_ERROR_PARTIALWRITE;
5494 /* set the packet data length to 3 bytes for the data block header,
5495 * plus the size of the data.
5497 smb_SetSMBParm(outp, 0, written);
5498 smb_SetSMBDataLength(outp, 0);
5501 smb_ReleaseFID(fidp);
5502 cm_ReleaseUser(userp);
5507 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5508 NCB *ncbp, raw_write_cont_t *rwcp)
5521 fd = smb_GetSMBParm(inp, 0);
5522 fidp = smb_FindFID(vcp, fd, 0);
5524 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5525 rwcp->offset.LowPart, rwcp->count);
5527 userp = smb_GetUser(vcp, inp);
5531 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5534 rawBuf = (dos_ptr) rwcp->buf;
5535 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5536 (unsigned char *) rawBuf, userp,
5540 if (rwcp->writeMode & 0x1) { /* synchronous */
5543 smb_FormatResponsePacket(vcp, inp, outp);
5544 op = (smb_t *) outp;
5545 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5546 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5547 smb_SetSMBDataLength(outp, 0);
5548 smb_SendPacket(vcp, outp);
5549 smb_FreePacket(outp);
5551 else { /* asynchronous */
5552 lock_ObtainMutex(&fidp->mx);
5553 fidp->raw_writers--;
5554 if (fidp->raw_writers == 0)
5555 thrd_SetEvent(fidp->raw_write_event);
5556 lock_ReleaseMutex(&fidp->mx);
5559 /* Give back raw buffer */
5560 lock_ObtainMutex(&smb_RawBufLock);
5562 *((char **)rawBuf) = smb_RawBufs;
5564 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5566 smb_RawBufs = rawBuf;
5567 lock_ReleaseMutex(&smb_RawBufLock);
5569 smb_ReleaseFID(fidp);
5570 cm_ReleaseUser(userp);
5573 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5578 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5581 long count, written = 0;
5588 unsigned short writeMode;
5595 fd = smb_GetSMBParm(inp, 0);
5596 totalCount = smb_GetSMBParm(inp, 1);
5597 count = smb_GetSMBParm(inp, 10);
5598 offset.HighPart = 0; /* too bad */
5599 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5600 writeMode = smb_GetSMBParm(inp, 7);
5602 op = (char *) inp->data;
5603 op += smb_GetSMBParm(inp, 11);
5606 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5607 fd, offset.LowPart, count, writeMode);
5609 fd = smb_ChainFID(fd, inp);
5610 fidp = smb_FindFID(vcp, fd, 0);
5612 return CM_ERROR_BADFD;
5615 userp = smb_GetUser(vcp, inp);
5618 * Work around bug in NT client
5620 * When copying a file, the NT client should first copy the data,
5621 * then copy the last write time. But sometimes the NT client does
5622 * these in the wrong order, so the data copies would inadvertently
5623 * cause the last write time to be overwritten. We try to detect this,
5624 * and don't set client mod time if we think that would go against the
5627 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5628 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5629 fidp->scp->clientModTime = time(NULL);
5633 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5635 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5637 if (code == 0 && written < count)
5638 code = CM_ERROR_PARTIALWRITE;
5640 /* Get a raw buffer */
5643 lock_ObtainMutex(&smb_RawBufLock);
5645 /* Get a raw buf, from head of list */
5646 rawBuf = smb_RawBufs;
5648 smb_RawBufs = *(char **)smb_RawBufs;
5650 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5654 code = CM_ERROR_USESTD;
5656 lock_ReleaseMutex(&smb_RawBufLock);
5659 /* Don't allow a premature Close */
5660 if (code == 0 && (writeMode & 1) == 0) {
5661 lock_ObtainMutex(&fidp->mx);
5662 fidp->raw_writers++;
5663 thrd_ResetEvent(fidp->raw_write_event);
5664 lock_ReleaseMutex(&fidp->mx);
5667 smb_ReleaseFID(fidp);
5668 cm_ReleaseUser(userp);
5671 smb_SetSMBParm(outp, 0, written);
5672 smb_SetSMBDataLength(outp, 0);
5673 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5680 rwcp->offset.HighPart = 0;
5681 rwcp->offset.LowPart = offset.LowPart + count;
5682 rwcp->count = totalCount - count;
5683 rwcp->writeMode = writeMode;
5684 rwcp->alreadyWritten = written;
5686 /* set the packet data length to 3 bytes for the data block header,
5687 * plus the size of the data.
5689 smb_SetSMBParm(outp, 0, 0xffff);
5690 smb_SetSMBDataLength(outp, 0);
5695 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5698 long count, finalCount;
5705 fd = smb_GetSMBParm(inp, 0);
5706 count = smb_GetSMBParm(inp, 1);
5707 offset.HighPart = 0; /* too bad */
5708 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5710 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5711 fd, offset.LowPart, count);
5713 fd = smb_ChainFID(fd, inp);
5714 fidp = smb_FindFID(vcp, fd, 0);
5716 return CM_ERROR_BADFD;
5719 if (fidp->flags & SMB_FID_IOCTL) {
5720 return smb_IoctlRead(fidp, vcp, inp, outp);
5723 userp = smb_GetUser(vcp, inp);
5725 /* remember this for final results */
5726 smb_SetSMBParm(outp, 0, count);
5727 smb_SetSMBParm(outp, 1, 0);
5728 smb_SetSMBParm(outp, 2, 0);
5729 smb_SetSMBParm(outp, 3, 0);
5730 smb_SetSMBParm(outp, 4, 0);
5732 /* set the packet data length to 3 bytes for the data block header,
5733 * plus the size of the data.
5735 smb_SetSMBDataLength(outp, count+3);
5737 /* get op ptr after putting in the parms, since otherwise we don't
5738 * know where the data really is.
5740 op = smb_GetSMBData(outp, NULL);
5742 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5743 *op++ = 1; /* data block marker */
5744 *op++ = (unsigned char) (count & 0xff);
5745 *op++ = (unsigned char) ((count >> 8) & 0xff);
5748 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5750 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5753 /* fix some things up */
5754 smb_SetSMBParm(outp, 0, finalCount);
5755 smb_SetSMBDataLength(outp, finalCount+3);
5757 smb_ReleaseFID(fidp);
5759 cm_ReleaseUser(userp);
5763 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5770 cm_scache_t *dscp; /* dir we're dealing with */
5771 cm_scache_t *scp; /* file we're creating */
5773 int initialModeBits;
5783 /* compute initial mode bits based on read-only flag in attributes */
5784 initialModeBits = 0777;
5786 tp = smb_GetSMBData(inp, NULL);
5787 pathp = smb_ParseASCIIBlock(tp, &tp);
5789 if (strcmp(pathp, "\\") == 0)
5790 return CM_ERROR_EXISTS;
5792 spacep = inp->spacep;
5793 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5795 userp = smb_GetUser(vcp, inp);
5797 caseFold = CM_FLAG_CASEFOLD;
5799 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5801 cm_ReleaseUser(userp);
5802 return CM_ERROR_NOSUCHPATH;
5805 code = cm_NameI(cm_rootSCachep, spacep->data,
5806 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5807 userp, tidPathp, &req, &dscp);
5810 cm_ReleaseUser(userp);
5814 /* otherwise, scp points to the parent directory. Do a lookup, and
5815 * fail if we find it. Otherwise, we do the create.
5821 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5822 if (scp) cm_ReleaseSCache(scp);
5823 if (code != CM_ERROR_NOSUCHFILE) {
5824 if (code == 0) code = CM_ERROR_EXISTS;
5825 cm_ReleaseSCache(dscp);
5826 cm_ReleaseUser(userp);
5830 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5831 setAttr.clientModTime = time(NULL);
5832 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5833 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5834 smb_NotifyChange(FILE_ACTION_ADDED,
5835 FILE_NOTIFY_CHANGE_DIR_NAME,
5836 dscp, lastNamep, NULL, TRUE);
5838 /* we don't need this any longer */
5839 cm_ReleaseSCache(dscp);
5842 /* something went wrong creating or truncating the file */
5843 cm_ReleaseUser(userp);
5847 /* otherwise we succeeded */
5848 smb_SetSMBDataLength(outp, 0);
5849 cm_ReleaseUser(userp);
5854 BOOL smb_IsLegalFilename(char *filename)
5857 * Find the longest substring of filename that does not contain
5858 * any of the chars in illegalChars. If that substring is less
5859 * than the length of the whole string, then one or more of the
5860 * illegal chars is in filename.
5862 if (strcspn(filename, illegalChars) < strlen(filename))
5868 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5876 cm_scache_t *dscp; /* dir we're dealing with */
5877 cm_scache_t *scp; /* file we're creating */
5879 int initialModeBits;
5891 excl = (inp->inCom == 0x03)? 0 : 1;
5893 attributes = smb_GetSMBParm(inp, 0);
5894 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5896 /* compute initial mode bits based on read-only flag in attributes */
5897 initialModeBits = 0666;
5898 if (attributes & 1) initialModeBits &= ~0222;
5900 tp = smb_GetSMBData(inp, NULL);
5901 pathp = smb_ParseASCIIBlock(tp, &tp);
5903 spacep = inp->spacep;
5904 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5906 userp = smb_GetUser(vcp, inp);
5908 caseFold = CM_FLAG_CASEFOLD;
5910 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5912 cm_ReleaseUser(userp);
5913 return CM_ERROR_NOSUCHPATH;
5915 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5916 userp, tidPathp, &req, &dscp);
5919 cm_ReleaseUser(userp);
5923 /* otherwise, scp points to the parent directory. Do a lookup, and
5924 * truncate the file if we find it, otherwise we create the file.
5926 if (!lastNamep) lastNamep = pathp;
5929 if (!smb_IsLegalFilename(lastNamep))
5930 return CM_ERROR_BADNTFILENAME;
5932 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5933 #ifdef DEBUG_VERBOSE
5936 hexp = osi_HexifyString( lastNamep );
5937 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5942 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5943 if (code && code != CM_ERROR_NOSUCHFILE) {
5944 cm_ReleaseSCache(dscp);
5945 cm_ReleaseUser(userp);
5949 /* if we get here, if code is 0, the file exists and is represented by
5950 * scp. Otherwise, we have to create it.
5954 /* oops, file shouldn't be there */
5955 cm_ReleaseSCache(dscp);
5956 cm_ReleaseSCache(scp);
5957 cm_ReleaseUser(userp);
5958 return CM_ERROR_EXISTS;
5961 setAttr.mask = CM_ATTRMASK_LENGTH;
5962 setAttr.length.LowPart = 0;
5963 setAttr.length.HighPart = 0;
5964 code = cm_SetAttr(scp, &setAttr, userp, &req);
5967 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5968 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5969 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5971 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5972 smb_NotifyChange(FILE_ACTION_ADDED,
5973 FILE_NOTIFY_CHANGE_FILE_NAME,
5974 dscp, lastNamep, NULL, TRUE);
5975 if (!excl && code == CM_ERROR_EXISTS) {
5976 /* not an exclusive create, and someone else tried
5977 * creating it already, then we open it anyway. We
5978 * don't bother retrying after this, since if this next
5979 * fails, that means that the file was deleted after
5980 * we started this call.
5982 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
5985 setAttr.mask = CM_ATTRMASK_LENGTH;
5986 setAttr.length.LowPart = 0;
5987 setAttr.length.HighPart = 0;
5988 code = cm_SetAttr(scp, &setAttr, userp, &req);
5993 /* we don't need this any longer */
5994 cm_ReleaseSCache(dscp);
5997 /* something went wrong creating or truncating the file */
5998 if (scp) cm_ReleaseSCache(scp);
5999 cm_ReleaseUser(userp);
6003 /* make sure we only open files */
6004 if (scp->fileType != CM_SCACHETYPE_FILE) {
6005 cm_ReleaseSCache(scp);
6006 cm_ReleaseUser(userp);
6007 return CM_ERROR_ISDIR;
6010 /* now all we have to do is open the file itself */
6011 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6014 /* save a pointer to the vnode */
6017 /* always create it open for read/write */
6018 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6020 smb_ReleaseFID(fidp);
6022 smb_SetSMBParm(outp, 0, fidp->fid);
6023 smb_SetSMBDataLength(outp, 0);
6025 cm_Open(scp, 0, userp);
6027 cm_ReleaseUser(userp);
6028 /* leave scp held since we put it in fidp->scp */
6032 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6045 fd = smb_GetSMBParm(inp, 0);
6046 whence = smb_GetSMBParm(inp, 1);
6047 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6049 /* try to find the file descriptor */
6050 fd = smb_ChainFID(fd, inp);
6051 fidp = smb_FindFID(vcp, fd, 0);
6052 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6053 return CM_ERROR_BADFD;
6056 userp = smb_GetUser(vcp, inp);
6058 lock_ObtainMutex(&fidp->mx);
6060 lock_ObtainMutex(&scp->mx);
6061 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6062 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6065 /* offset from current offset */
6066 offset += fidp->offset;
6068 else if (whence == 2) {
6069 /* offset from current EOF */
6070 offset += scp->length.LowPart;
6072 fidp->offset = offset;
6073 smb_SetSMBParm(outp, 0, offset & 0xffff);
6074 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6075 smb_SetSMBDataLength(outp, 0);
6077 lock_ReleaseMutex(&scp->mx);
6078 lock_ReleaseMutex(&fidp->mx);
6079 smb_ReleaseFID(fidp);
6080 cm_ReleaseUser(userp);
6084 /* dispatch all of the requests received in a packet. Due to chaining, this may
6085 * be more than one request.
6087 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6088 NCB *ncbp, raw_write_cont_t *rwcp)
6092 unsigned long code = 0;
6093 unsigned char *outWctp;
6094 int nparms; /* # of bytes of parameters */
6096 int nbytes; /* bytes of data, excluding count */
6099 unsigned short errCode;
6100 unsigned long NTStatus;
6102 unsigned char errClass;
6103 unsigned int oldGen;
6104 DWORD oldTime, newTime;
6106 /* get easy pointer to the data */
6107 smbp = (smb_t *) inp->data;
6109 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6110 /* setup the basic parms for the initial request in the packet */
6111 inp->inCom = smbp->com;
6112 inp->wctp = &smbp->wct;
6114 inp->ncb_length = ncbp->ncb_length;
6119 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6120 /* log it and discard it */
6125 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6126 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6128 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6129 1, ncbp->ncb_length, ptbuf, inp);
6130 DeregisterEventSource(h);
6132 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6137 /* We are an ongoing op */
6138 thrd_Increment(&ongoingOps);
6140 /* set up response packet for receiving output */
6141 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6142 smb_FormatResponsePacket(vcp, inp, outp);
6143 outWctp = outp->wctp;
6145 /* Remember session generation number and time */
6146 oldGen = sessionGen;
6147 oldTime = GetCurrentTime();
6149 while (inp->inCom != 0xff) {
6150 dp = &smb_dispatchTable[inp->inCom];
6152 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6153 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6154 code = outp->resumeCode;
6158 /* process each request in the packet; inCom, wctp and inCount
6159 * are already set up.
6161 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6164 /* now do the dispatch */
6165 /* start by formatting the response record a little, as a default */
6166 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6168 outWctp[1] = 0xff; /* no operation */
6169 outWctp[2] = 0; /* padding */
6174 /* not a chained request, this is a more reasonable default */
6175 outWctp[0] = 0; /* wct of zero */
6176 outWctp[1] = 0; /* and bcc (word) of zero */
6180 /* once set, stays set. Doesn't matter, since we never chain
6181 * "no response" calls.
6183 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6187 /* we have a recognized operation */
6189 if (inp->inCom == 0x1d)
6191 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6194 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6195 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
6196 code = (*(dp->procp)) (vcp, inp, outp);
6197 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6198 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6200 if ( code == CM_ERROR_BADSMB ||
6201 code == CM_ERROR_BADOP )
6203 #endif /* LOG_PACKET */
6206 if (oldGen != sessionGen) {
6211 newTime = GetCurrentTime();
6212 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6213 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6214 newTime - oldTime, ncbp->ncb_length);
6216 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6217 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6218 DeregisterEventSource(h);
6220 osi_Log1(smb_logp, "Pkt straddled session startup, "
6221 "ncb length %d", ncbp->ncb_length);
6225 /* bad opcode, fail the request, after displaying it */
6226 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6229 #endif /* LOG_PACKET */
6233 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6234 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6235 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6236 if (code == IDCANCEL)
6240 code = CM_ERROR_BADOP;
6243 /* catastrophic failure: log as much as possible */
6244 if (code == CM_ERROR_BADSMB) {
6251 "Invalid SMB, ncb_length %d",
6254 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6255 sprintf(s, "Invalid SMB message, length %d",
6258 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6259 1, ncbp->ncb_length, ptbuf, smbp);
6260 DeregisterEventSource(h);
6263 #endif /* LOG_PACKET */
6265 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6268 code = CM_ERROR_INVAL;
6271 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6272 thrd_Decrement(&ongoingOps);
6277 /* now, if we failed, turn the current response into an empty
6278 * one, and fill in the response packet's error code.
6281 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6282 smb_MapNTError(code, &NTStatus);
6283 outWctp = outp->wctp;
6284 smbp = (smb_t *) &outp->data;
6285 if (code != CM_ERROR_PARTIALWRITE
6286 && code != CM_ERROR_BUFFERTOOSMALL
6287 && code != CM_ERROR_GSSCONTINUE) {
6288 /* nuke wct and bcc. For a partial
6289 * write or an in-process authentication handshake,
6290 * assume they're OK.
6296 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6297 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6298 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6299 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6300 smbp->flg2 |= 0x4000;
6304 smb_MapCoreError(code, vcp, &errCode, &errClass);
6305 outWctp = outp->wctp;
6306 smbp = (smb_t *) &outp->data;
6307 if (code != CM_ERROR_PARTIALWRITE) {
6308 /* nuke wct and bcc. For a partial
6309 * write, assume they're OK.
6315 smbp->errLow = (unsigned char) (errCode & 0xff);
6316 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6317 smbp->rcls = errClass;
6320 } /* error occurred */
6322 /* if we're here, we've finished one request. Look to see if
6323 * this is a chained opcode. If it is, setup things to process
6324 * the chained request, and setup the output buffer to hold the
6325 * chained response. Start by finding the next input record.
6327 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6328 break; /* not a chained req */
6329 tp = inp->wctp; /* points to start of last request */
6330 /* in a chained request, the first two
6331 * parm fields are required, and are
6332 * AndXCommand/AndXReserved and
6334 if (tp[0] < 2) break;
6335 if (tp[1] == 0xff) break; /* no more chained opcodes */
6337 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6340 /* and now append the next output request to the end of this
6341 * last request. Begin by finding out where the last response
6342 * ends, since that's where we'll put our new response.
6344 outWctp = outp->wctp; /* ptr to out parameters */
6345 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6346 nparms = outWctp[0] << 1;
6347 tp = outWctp + nparms + 1; /* now points to bcc field */
6348 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6349 tp += 2 /* for the count itself */ + nbytes;
6350 /* tp now points to the new output record; go back and patch the
6351 * second parameter (off2) to point to the new record.
6353 temp = (unsigned int)tp - ((unsigned int) outp->data);
6354 outWctp[3] = (unsigned char) (temp & 0xff);
6355 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6356 outWctp[2] = 0; /* padding */
6357 outWctp[1] = inp->inCom; /* next opcode */
6359 /* finally, setup for the next iteration */
6362 } /* while loop over all requests in the packet */
6364 /* done logging out, turn off logging-out flag */
6365 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6366 vcp->justLoggedOut = NULL;
6369 free(loggedOutName);
6370 loggedOutName = NULL;
6371 smb_ReleaseUID(loggedOutUserp);
6372 loggedOutUserp = NULL;
6376 /* now send the output packet, and return */
6378 smb_SendPacket(vcp, outp);
6379 thrd_Decrement(&ongoingOps);
6381 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6383 smb_ReleaseVC(active_vcp);
6385 "Replacing active_vcp %x with %x", active_vcp, vcp);
6389 last_msg_time = GetCurrentTime();
6391 else if (active_vcp == vcp) {
6392 smb_ReleaseVC(active_vcp);
6400 /* Wait for Netbios() calls to return, and make the results available to server
6401 * threads. Note that server threads can't wait on the NCBevents array
6402 * themselves, because NCB events are manual-reset, and the servers would race
6403 * each other to reset them.
6405 void smb_ClientWaiter(void *parmp)
6411 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6413 if (code == WAIT_OBJECT_0)
6416 /* error checking */
6417 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6419 int abandonIdx = code - WAIT_ABANDONED_0;
6420 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6423 if (code == WAIT_IO_COMPLETION)
6425 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6429 if (code == WAIT_TIMEOUT)
6431 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6434 if (code == WAIT_FAILED)
6436 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6439 idx = code - WAIT_OBJECT_0;
6441 /* check idx range! */
6442 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6444 /* this is fatal - log as much as possible */
6445 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6449 thrd_ResetEvent(NCBevents[idx]);
6450 thrd_SetEvent(NCBreturns[0][idx]);
6456 * Try to have one NCBRECV request waiting for every live session. Not more
6457 * than one, because if there is more than one, it's hard to handle Write Raw.
6459 void smb_ServerWaiter(void *parmp)
6462 int idx_session, idx_NCB;
6470 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6472 if (code == WAIT_OBJECT_0)
6475 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6477 int abandonIdx = code - WAIT_ABANDONED_0;
6478 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6481 if (code == WAIT_IO_COMPLETION)
6483 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6487 if (code == WAIT_TIMEOUT)
6489 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6492 if (code == WAIT_FAILED)
6494 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6497 idx_session = code - WAIT_OBJECT_0;
6499 /* check idx range! */
6500 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6502 /* this is fatal - log as much as possible */
6503 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6509 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6511 if (code == WAIT_OBJECT_0)
6514 /* error checking */
6515 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6517 int abandonIdx = code - WAIT_ABANDONED_0;
6518 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6521 if (code == WAIT_IO_COMPLETION)
6523 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6527 if (code == WAIT_TIMEOUT)
6529 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6532 if (code == WAIT_FAILED)
6534 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6537 idx_NCB = code - WAIT_OBJECT_0;
6539 /* check idx range! */
6540 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6542 /* this is fatal - log as much as possible */
6543 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6547 /* Link them together */
6548 NCBsessions[idx_NCB] = idx_session;
6551 ncbp = NCBs[idx_NCB];
6553 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6555 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6556 ncbp->ncb_command = NCBRECV | ASYNCH;
6557 ncbp->ncb_lana_num = lanas[idx_session];
6559 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6560 ncbp->ncb_event = NCBevents[idx_NCB];
6561 ncbp->ncb_length = SMB_PACKETSIZE;
6564 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6565 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6566 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6567 ncbp->ncb_length = SMB_PACKETSIZE;
6568 Netbios(ncbp, dos_ncb);
6574 * The top level loop for handling SMB request messages. Each server thread
6575 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6576 * NCB and buffer for the incoming request are loaned to us.
6578 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6579 * to immediately send a request for the rest of the data. This must come
6580 * before any other traffic for that session, so we delay setting the session
6581 * event until that data has come in.
6583 void smb_Server(VOID *parmp)
6585 int myIdx = (int) parmp;
6589 smb_packet_t *outbufp;
6591 int idx_NCB, idx_session;
6593 smb_vc_t *vcp = NULL;
6600 outbufp = GetPacket();
6601 outbufp->ncbp = outncbp;
6605 /* check for demo expiration */
6607 unsigned long tod = time((void *) 0);
6608 if (tod > EXPIREDATE) {
6609 (*smb_MBfunc)(NULL, "AFS demo expiration",
6611 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6615 #endif /* !NOEXPIRE */
6617 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6619 if (code == WAIT_OBJECT_0) {
6623 /* error checking */
6624 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6626 int abandonIdx = code - WAIT_ABANDONED_0;
6627 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6630 if (code == WAIT_IO_COMPLETION)
6632 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6636 if (code == WAIT_TIMEOUT)
6638 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6641 if (code == WAIT_FAILED)
6643 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6646 idx_NCB = code - WAIT_OBJECT_0;
6648 /* check idx range! */
6649 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6651 /* this is fatal - log as much as possible */
6652 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6656 ncbp = NCBs[idx_NCB];
6658 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6660 idx_session = NCBsessions[idx_NCB];
6661 rc = ncbp->ncb_retcode;
6663 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6664 osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6667 case NRC_GOODRET: break;
6670 /* Can this happen? Or is it just my
6677 /* Client closed session */
6678 if (reportSessionStartups)
6680 osi_Log1(smb_logp, "session [ %d ] closed", idx_session);
6682 dead_sessions[idx_session] = TRUE;
6685 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6686 /* Should also release vcp. [done] 2004-05-11 jaltman
6688 * sanity check that all TID's are gone.
6690 * TODO: check if we could use LSNs[idx_session] instead,
6691 * also cleanup after dead vcp
6696 "dead_vcp already set, %x",
6698 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6700 "setting dead_vcp %x, user struct %x",
6704 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6706 if (vcp->justLoggedOut) {
6708 loggedOutTime = vcp->logoffTime;
6710 strdup(vcp->justLoggedOut->unp->name);
6711 loggedOutUserp = vcp->justLoggedOut;
6712 lock_ObtainWrite(&smb_rctLock);
6713 loggedOutUserp->refCount++;
6714 lock_ReleaseWrite(&smb_rctLock);
6720 /* Treat as transient error */
6727 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6728 sprintf(s, "SMB message incomplete, length %d",
6731 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6733 ncbp->ncb_length, ptbuf,
6735 DeregisterEventSource(h);
6738 "dispatch smb recv failed, message incomplete, ncb_length %d",
6741 "SMB message incomplete, "
6742 "length %d", ncbp->ncb_length);
6745 * We used to discard the packet.
6746 * Instead, try handling it normally.
6754 /* A weird error code. Log it, sleep, and
6756 if (vcp && vcp->errorCount++ > 3) {
6757 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6758 dead_sessions[idx_session] = TRUE;
6762 thrd_SetEvent(SessionEvents[idx_session]);
6767 /* Success, so now dispatch on all the data in the packet */
6769 smb_concurrentCalls++;
6770 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6771 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6775 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6777 * If at this point vcp is NULL (implies that packet was invalid)
6778 * then we are in big trouble. This means either :
6779 * a) we have the wrong NCB.
6780 * b) Netbios screwed up the call.
6781 * Obviously this implies that
6782 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6783 * lanas[idx_session] != ncbp->ncb_lana_num )
6784 * Either way, we can't do anything with this packet.
6785 * Log, sleep and resume.
6794 "LSNs[idx_session]=[%d],"
6795 "lanas[idx_session]=[%d],"
6796 "ncbp->ncb_lsn=[%d],"
6797 "ncbp->ncb_lana_num=[%d]",
6801 ncbp->ncb_lana_num);
6805 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6807 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6808 DeregisterEventSource(h);
6811 /* Also log in the trace log. */
6812 osi_Log4(smb_logp, "Server: BAD VCP!"
6813 "LSNs[idx_session]=[%d],"
6814 "lanas[idx_session]=[%d],"
6815 "ncbp->ncb_lsn=[%d],"
6816 "ncbp->ncb_lana_num=[%d]",
6820 ncbp->ncb_lana_num);
6822 /* thrd_Sleep(1000); Don't bother sleeping */
6823 thrd_SetEvent(SessionEvents[idx_session]);
6824 smb_concurrentCalls--;
6829 vcp->errorCount = 0;
6830 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6832 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6833 /* copy whole packet to virtual memory */
6834 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6836 bufp->dos_pkt / 16, bufp);*/
6838 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6840 smbp = (smb_t *)bufp->data;
6843 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6847 if (smbp->com == 0x1d) {
6848 /* Special handling for Write Raw */
6849 raw_write_cont_t rwc;
6850 EVENT_HANDLE rwevent;
6851 char eventName[MAX_PATH];
6853 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6854 if (rwc.code == 0) {
6855 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6856 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6857 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6858 ncbp->ncb_command = NCBRECV | ASYNCH;
6859 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6860 ncbp->ncb_lana_num = vcp->lana;
6861 ncbp->ncb_buffer = rwc.buf;
6862 ncbp->ncb_length = 65535;
6863 ncbp->ncb_event = rwevent;
6867 Netbios(ncbp, dos_ncb);
6869 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6870 thrd_CloseHandle(rwevent);
6872 thrd_SetEvent(SessionEvents[idx_session]);
6874 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6875 } else if (smbp->com == 0xa0) {
6877 * Serialize the handling for NT Transact
6880 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6881 thrd_SetEvent(SessionEvents[idx_session]);
6883 thrd_SetEvent(SessionEvents[idx_session]);
6884 /* TODO: what else needs to be serialized? */
6885 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6887 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6889 __except( smb_ServerExceptionFilter() ) {
6893 smb_concurrentCalls--;
6896 thrd_SetEvent(NCBavails[idx_NCB]);
6903 * Exception filter for the server threads. If an exception occurs in the
6904 * dispatch routines, which is where exceptions are most common, then do a
6905 * force trace and give control to upstream exception handlers. Useful for
6908 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6909 DWORD smb_ServerExceptionFilter(void) {
6910 /* While this is not the best time to do a trace, if it succeeds, then
6911 * we have a trace (assuming tracing was enabled). Otherwise, this should
6912 * throw a second exception.
6917 ptbuf[0] = "Unhandled exception forcing trace";
6919 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6921 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6922 DeregisterEventSource(h);
6925 afsd_ForceTrace(TRUE);
6926 return EXCEPTION_CONTINUE_SEARCH;
6931 * Create a new NCB and associated events, packet buffer, and "space" buffer.
6932 * If the number of server threads is M, and the number of live sessions is
6933 * N, then the number of NCB's in use at any time either waiting for, or
6934 * holding, received messages is M + N, so that is how many NCB's get created.
6936 void InitNCBslot(int idx)
6938 struct smb_packet *bufp;
6939 EVENT_HANDLE retHandle;
6941 char eventName[MAX_PATH];
6943 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6945 NCBs[idx] = GetNCB();
6946 sprintf(eventName,"NCBavails[%d]", idx);
6947 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6948 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6949 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6951 sprintf(eventName,"NCBevents[%d]", idx);
6952 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
6953 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6954 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6956 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
6957 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6958 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6959 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6960 for (i=0; i<smb_NumServerThreads; i++)
6961 NCBreturns[i][idx] = retHandle;
6963 bufp->spacep = cm_GetSpace();
6967 /* listen for new connections */
6968 void smb_Listener(void *parmp)
6976 char rname[NCBNAMSZ+1];
6977 char cname[MAX_COMPUTERNAME_LENGTH+1];
6978 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
6983 int lana = (int) parmp;
6987 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6990 /* retrieve computer name */
6991 GetComputerName(cname, &cnamelen);
6995 memset(ncbp, 0, sizeof(NCB));
6999 /* check for demo expiration */
7001 unsigned long tod = time((void *) 0);
7002 if (tod > EXPIREDATE) {
7003 (*smb_MBfunc)(NULL, "AFS demo expiration",
7005 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
7013 #endif /* !NOEXPIRE */
7015 ncbp->ncb_command = NCBLISTEN;
7016 ncbp->ncb_rto = 0; /* No receive timeout */
7017 ncbp->ncb_sto = 0; /* No send timeout */
7019 /* pad out with spaces instead of null termination */
7020 len = strlen(smb_localNamep);
7021 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7022 for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7024 strcpy(ncbp->ncb_callname, "*");
7025 for(i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7027 ncbp->ncb_lana_num = lana;
7030 code = Netbios(ncbp);
7032 code = Netbios(ncbp, dos_ncb);
7041 /* terminate silently if shutdown flag is set */
7042 if (smbShutdownFlag == 1) {
7051 "NCBLISTEN lana=%d failed with code %d",
7052 ncbp->ncb_lana_num, code);
7054 "Client exiting due to network failure. Please restart client.\n");
7058 "Client exiting due to network failure. Please restart client.\n"
7059 "NCBLISTEN lana=%d failed with code %d",
7060 ncbp->ncb_lana_num, code);
7062 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7063 MB_OK|MB_SERVICE_NOTIFICATION);
7064 osi_assert(tbuffer);
7067 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7068 ncbp->ncb_lana_num, code);
7069 fprintf(stderr, "\nClient exiting due to network failure "
7070 "(possibly due to power-saving mode)\n");
7071 fprintf(stderr, "Please restart client.\n");
7072 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7076 /* check for remote conns */
7077 /* first get remote name and insert null terminator */
7078 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7079 for (i=NCBNAMSZ; i>0; i--) {
7080 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7086 /* compare with local name */
7088 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7089 flags |= SMB_VCFLAG_REMOTECONN;
7091 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7093 lock_ObtainMutex(&smb_ListenerLock);
7095 /* New generation */
7098 /* Log session startup */
7100 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7102 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7103 #endif /* NOTSERVICE */
7104 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7105 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7107 if (reportSessionStartups) {
7113 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7114 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7116 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7118 DeregisterEventSource(h);
7121 fprintf(stderr, "%s: New session %d starting from host %s\n",
7122 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7126 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7127 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7130 /* now ncbp->ncb_lsn is the connection ID */
7131 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7132 vcp->flags |= flags;
7133 strcpy(vcp->rname, rname);
7135 /* Allocate slot in session arrays */
7136 /* Re-use dead session if possible, otherwise add one more */
7137 /* But don't look at session[0], it is reserved */
7138 for (i = 1; i < numSessions; i++) {
7139 if (dead_sessions[i]) {
7140 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7141 dead_sessions[i] = FALSE;
7146 /* assert that we do not exceed the maximum number of sessions or NCBs.
7147 * we should probably want to wait for a session to be freed in case
7151 osi_assert(i < Sessionmax - 1);
7152 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7154 LSNs[i] = ncbp->ncb_lsn;
7155 lanas[i] = ncbp->ncb_lana_num;
7157 if (i == numSessions) {
7158 /* Add new NCB for new session */
7159 char eventName[MAX_PATH];
7161 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7163 InitNCBslot(numNCBs);
7165 thrd_SetEvent(NCBavails[0]);
7166 thrd_SetEvent(NCBevents[0]);
7167 for (j = 0; j < smb_NumServerThreads; j++)
7168 thrd_SetEvent(NCBreturns[j][0]);
7169 /* Also add new session event */
7170 sprintf(eventName, "SessionEvents[%d]", i);
7171 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7172 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7173 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7175 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7176 thrd_SetEvent(SessionEvents[0]);
7178 thrd_SetEvent(SessionEvents[i]);
7181 lock_ReleaseMutex(&smb_ListenerLock);
7183 } /* dispatch while loop */
7186 /* initialize Netbios */
7187 void smb_NetbiosInit()
7193 int i, lana, code, l;
7195 int delname_tried=0;
7198 OSVERSIONINFO Version;
7200 /* AFAIK, this is the default for the ms loopback adapter.*/
7201 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
7202 /*******************************************************************/
7204 /* Get the version of Windows */
7205 memset(&Version, 0x00, sizeof(Version));
7206 Version.dwOSVersionInfoSize = sizeof(Version);
7207 GetVersionEx(&Version);
7209 /* setup the NCB system */
7212 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7216 if (smb_LANadapter == -1) {
7217 ncbp->ncb_command = NCBENUM;
7218 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7219 ncbp->ncb_length = sizeof(lana_list);
7220 code = Netbios(ncbp);
7222 sprintf(s, "Netbios NCBENUM error code %d", code);
7223 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7224 osi_panic(s, __FILE__, __LINE__);
7228 lana_list.length = 1;
7229 lana_list.lana[0] = smb_LANadapter;
7232 for (i = 0; i < lana_list.length; i++) {
7233 /* reset the adaptor: in Win32, this is required for every process, and
7234 * acts as an init call, not as a real hardware reset.
7236 ncbp->ncb_command = NCBRESET;
7237 ncbp->ncb_callname[0] = 100;
7238 ncbp->ncb_callname[2] = 100;
7239 ncbp->ncb_lana_num = lana_list.lana[i];
7240 code = Netbios(ncbp);
7242 code = ncbp->ncb_retcode;
7244 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7245 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7246 lana_list.lana[i] = 255; /* invalid lana */
7248 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7249 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7253 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7254 we will just fake the LANA list */
7255 if (smb_LANadapter == -1) {
7256 for (i = 0; i < 8; i++)
7257 lana_list.lana[i] = i;
7258 lana_list.length = 8;
7261 lana_list.length = 1;
7262 lana_list.lana[0] = smb_LANadapter;
7266 /* and declare our name so we can receive connections */
7267 memset(ncbp, 0, sizeof(*ncbp));
7268 len=lstrlen(smb_localNamep);
7269 memset(smb_sharename,' ',NCBNAMSZ);
7270 memcpy(smb_sharename,smb_localNamep,len);
7271 sprintf(s, "lana_list.length %d", lana_list.length);
7272 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7274 /* Keep the name so we can unregister it later */
7275 for (l = 0; l < lana_list.length; l++) {
7276 lana = lana_list.lana[l];
7278 ncbp->ncb_command = NCBADDNAME;
7279 ncbp->ncb_lana_num = lana;
7280 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7282 code = Netbios(ncbp);
7284 code = Netbios(ncbp, dos_ncb);
7287 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7288 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7290 char name[NCBNAMSZ+1];
7292 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7293 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7296 if (code == 0) code = ncbp->ncb_retcode;
7298 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7300 /* we only use one LANA with djgpp */
7301 lana_list.lana[0] = lana;
7302 lana_list.length = 1;
7306 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7307 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7308 if (code == NRC_BRIDGE) { /* invalid LANA num */
7309 lana_list.lana[l] = 255;
7312 else if (code == NRC_DUPNAME) {
7313 osi_Log0(smb_logp, "Name already exists; try to delete it");
7314 memset(ncbp, 0, sizeof(*ncbp));
7315 ncbp->ncb_command = NCBDELNAME;
7316 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7317 ncbp->ncb_lana_num = lana;
7319 code = Netbios(ncbp);
7321 code = Netbios(ncbp, dos_ncb);
7323 if (code == 0) code = ncbp->ncb_retcode;
7325 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7326 osi_Log0(smb_logp, s);
7328 if (code != 0 || delname_tried) {
7329 lana_list.lana[l] = 255;
7331 else if (code == 0) {
7332 if (!delname_tried) {
7340 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7341 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7342 lana_list.lana[l] = 255; /* invalid lana */
7343 osi_panic(s, __FILE__, __LINE__);
7347 lana_found = 1; /* at least one worked */
7354 osi_assert(lana_list.length >= 0);
7356 sprintf(s, "No valid LANA numbers found!");
7357 osi_panic(s, __FILE__, __LINE__);
7360 /* we're done with the NCB now */
7364 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7381 EVENT_HANDLE retHandle;
7382 char eventName[MAX_PATH];
7385 smb_MBfunc = aMBfunc;
7389 /* check for demo expiration */
7391 unsigned long tod = time((void *) 0);
7392 if (tod > EXPIREDATE) {
7394 (*smb_MBfunc)(NULL, "AFS demo expiration", "afsd",
7395 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
7398 fprintf(stderr, "AFS demo expiration\n");
7403 #endif /* !NOEXPIRE */
7406 smb_LANadapter = LANadapt;
7408 /* Initialize smb_localZero */
7409 myTime.tm_isdst = -1; /* compute whether on DST or not */
7410 myTime.tm_year = 70;
7416 smb_localZero = mktime(&myTime);
7418 /* Initialize kludge-GMT */
7419 smb_CalculateNowTZ();
7421 #ifdef AFS_FREELANCE_CLIENT
7422 /* Make sure the root.afs volume has the correct time */
7423 cm_noteLocalMountPointChange();
7426 /* initialize the remote debugging log */
7429 /* remember the name */
7430 len = strlen(snamep);
7431 smb_localNamep = malloc(len+1);
7432 strcpy(smb_localNamep, snamep);
7433 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7435 /* and the global lock */
7436 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7437 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7439 /* Raw I/O data structures */
7440 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7442 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7444 /* 4 Raw I/O buffers */
7446 smb_RawBufs = calloc(65536,1);
7447 *((char **)smb_RawBufs) = NULL;
7448 for (i=0; i<3; i++) {
7449 char *rawBuf = calloc(65536,1);
7450 *((char **)rawBuf) = smb_RawBufs;
7451 smb_RawBufs = rawBuf;
7454 npar = 65536 >> 4; /* number of paragraphs */
7455 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7457 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7459 osi_panic("",__FILE__,__LINE__);
7462 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7465 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7467 _farpokel(_dos_ds, smb_RawBufs, NULL);
7468 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7469 npar = 65536 >> 4; /* number of paragraphs */
7470 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7472 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7474 osi_panic("",__FILE__,__LINE__);
7477 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7480 rawBuf = (seg * 16) + 0; /* DOS physical address */
7481 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7482 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7483 smb_RawBufs = rawBuf;
7487 /* global free lists */
7488 smb_ncbFreeListp = NULL;
7489 smb_packetFreeListp = NULL;
7493 /* Initialize listener and server structures */
7495 memset(dead_sessions, 0, sizeof(dead_sessions));
7496 sprintf(eventName, "SessionEvents[0]");
7497 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7498 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7499 afsi_log("Event Object Already Exists: %s", eventName);
7501 smb_NumServerThreads = nThreads;
7502 sprintf(eventName, "NCBavails[0]");
7503 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7504 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7505 afsi_log("Event Object Already Exists: %s", eventName);
7506 sprintf(eventName, "NCBevents[0]");
7507 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7508 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7509 afsi_log("Event Object Already Exists: %s", eventName);
7510 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7511 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7512 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7513 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7514 afsi_log("Event Object Already Exists: %s", eventName);
7515 for (i = 0; i < smb_NumServerThreads; i++) {
7516 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7517 NCBreturns[i][0] = retHandle;
7519 for (i = 1; i <= nThreads; i++)
7521 numNCBs = nThreads + 1;
7523 /* Initialize dispatch table */
7524 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7525 /* Prepare the table for unknown operations */
7526 for(i=0; i<= SMB_NOPCODES; i++) {
7527 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7529 /* Fill in the ones we do know */
7530 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7531 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7532 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7533 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7534 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7535 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7536 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7537 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7538 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7539 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7540 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7541 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7542 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7543 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7544 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7545 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7546 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7547 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7548 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7549 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7550 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7551 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7552 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7553 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7554 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7555 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7556 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7557 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7558 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7559 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7560 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7561 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7562 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7563 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7564 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7565 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7566 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7567 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7568 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7569 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7570 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7571 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7572 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7573 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7574 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7575 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7576 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7577 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7578 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7579 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7580 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7581 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7582 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7583 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7584 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7585 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7586 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
7587 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
7588 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
7589 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7590 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7591 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7592 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7593 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7594 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
7595 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
7596 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
7597 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
7598 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
7599 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
7600 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
7601 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
7603 /* setup tran 2 dispatch table */
7604 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7605 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7606 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7607 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7608 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7609 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7610 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7611 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7612 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7613 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7614 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7615 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7616 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7617 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
7618 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
7619 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2GetDFSReferral;
7620 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2ReportDFSInconsistency;
7622 /* setup the rap dispatch table */
7623 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
7624 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
7625 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
7626 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
7627 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
7631 /* if we are doing SMB authentication we have register outselves as a logon process */
7632 if (smb_authType != SMB_AUTH_NONE) {
7634 LSA_STRING afsProcessName;
7635 LSA_OPERATIONAL_MODE dummy; /*junk*/
7637 afsProcessName.Buffer = "OpenAFSClientDaemon";
7638 afsProcessName.Length = strlen(afsProcessName.Buffer);
7639 afsProcessName.MaximumLength = afsProcessName.Length + 1;
7641 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7643 if (nts == STATUS_SUCCESS) {
7644 LSA_STRING packageName;
7645 /* we are registered. Find out the security package id */
7646 packageName.Buffer = MSV1_0_PACKAGE_NAME;
7647 packageName.Length = strlen(packageName.Buffer);
7648 packageName.MaximumLength = packageName.Length + 1;
7649 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7650 if (nts == STATUS_SUCCESS) {
7651 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7652 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7653 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7655 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7658 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7661 if (nts != STATUS_SUCCESS) {
7662 /* something went wrong. We report the error and revert back to no authentication
7663 because we can't perform any auth requests without a successful lsa handle
7664 or sec package id. */
7665 afsi_log("Reverting to NO SMB AUTH");
7666 smb_authType = SMB_AUTH_NONE;
7669 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
7670 * time prevents the failure of authentication when logged into Windows with an
7671 * external Kerberos principal mapped to a local account.
7673 else if ( smb_authType == SMB_AUTH_EXTENDED) {
7674 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
7675 * then the only option is NTLMSSP anyway; so just fallback.
7680 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7681 if (secBlobLength == 0) {
7682 smb_authType = SMB_AUTH_NTLM;
7683 afsi_log("Reverting to SMB AUTH NTLM");
7692 /* Now get ourselves a domain name. */
7693 /* For now we are using the local computer name as the domain name.
7694 * It is actually the domain for local logins, and we are acting as
7695 * a local SMB server.
7697 bufsize = sizeof(smb_ServerDomainName) - 1;
7698 GetComputerName(smb_ServerDomainName, &bufsize);
7699 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7700 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7703 /* Start listeners, waiters, servers, and daemons */
7705 for (i = 0; i < lana_list.length; i++) {
7706 if (lana_list.lana[i] == 255) continue;
7707 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7708 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7709 osi_assert(phandle != NULL);
7710 thrd_CloseHandle(phandle);
7714 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7715 NULL, 0, &lpid, "smb_ClientWaiter");
7716 osi_assert(phandle != NULL);
7717 thrd_CloseHandle(phandle);
7720 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7721 NULL, 0, &lpid, "smb_ServerWaiter");
7722 osi_assert(phandle != NULL);
7723 thrd_CloseHandle(phandle);
7725 for (i=0; i<nThreads; i++) {
7726 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7727 (void *) i, 0, &lpid, "smb_Server");
7728 osi_assert(phandle != NULL);
7729 thrd_CloseHandle(phandle);
7732 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7733 NULL, 0, &lpid, "smb_Daemon");
7734 osi_assert(phandle != NULL);
7735 thrd_CloseHandle(phandle);
7737 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7738 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7739 osi_assert(phandle != NULL);
7740 thrd_CloseHandle(phandle);
7749 void smb_Shutdown(void)
7758 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7760 /* setup the NCB system */
7763 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7766 /* Block new sessions by setting shutdown flag */
7767 smbShutdownFlag = 1;
7769 /* Hang up all sessions */
7770 memset((char *)ncbp, 0, sizeof(NCB));
7771 for (i = 1; i < numSessions; i++)
7773 if (dead_sessions[i])
7776 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7777 ncbp->ncb_command = NCBHANGUP;
7778 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7779 ncbp->ncb_lsn = LSNs[i];
7781 code = Netbios(ncbp);
7783 code = Netbios(ncbp, dos_ncb);
7785 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7786 if (code == 0) code = ncbp->ncb_retcode;
7788 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7789 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7793 /* Delete Netbios name */
7794 memset((char *)ncbp, 0, sizeof(NCB));
7795 for (i = 0; i < lana_list.length; i++) {
7796 if (lana_list.lana[i] == 255) continue;
7797 ncbp->ncb_command = NCBDELNAME;
7798 ncbp->ncb_lana_num = lana_list.lana[i];
7799 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7801 code = Netbios(ncbp);
7803 code = Netbios(ncbp, dos_ncb);
7805 if (code == 0) code = ncbp->ncb_retcode;
7807 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7808 ncbp->ncb_lana_num, code);
7814 /* Get the UNC \\<servername>\<sharename> prefix. */
7815 char *smb_GetSharename()
7819 /* Make sure we have been properly initialized. */
7820 if (smb_localNamep == NULL)
7823 /* Allocate space for \\<servername>\<sharename>, plus the
7826 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7827 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7833 void smb_LogPacket(smb_packet_t *packet)
7836 unsigned length, paramlen, datalen, i, j;
7838 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7842 osi_Log0(smb_logp, "*** SMB packet dump ***");
7844 vp = (BYTE *) packet->data;
7846 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7847 length = paramlen + 2 + datalen;
7850 for(i=0;i < length; i+=16)
7852 memset( buf, ' ', 80 );
7857 buf[strlen(buf)] = ' ';
7859 cp = (BYTE*) buf + 7;
7861 for(j=0;j < 16 && (i+j)<length; j++)
7863 *(cp++) = hex[vp[i+j] >> 4];
7864 *(cp++) = hex[vp[i+j] & 0xf];
7874 for(j=0;j < 16 && (i+j)<length;j++)
7876 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7887 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
7890 osi_Log0(smb_logp, "*** End SMB packet dump ***");
7893 #endif /* LOG_PACKET */
7896 int smb_DumpVCP(FILE *outputFile, char *cookie)
7903 lock_ObtainRead(&smb_rctLock);
7905 sprintf(output, "begin dumping vcpsp\n");
7906 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7908 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7912 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7913 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7914 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7916 sprintf(output, "begin dumping fidsp\n");
7917 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7919 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7921 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",
7922 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
7923 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
7924 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7925 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7928 sprintf(output, "done dumping fidsp\n");
7929 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7932 sprintf(output, "done dumping vcpsp\n");
7933 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7935 lock_ReleaseRead(&smb_rctLock);