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 time_t 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 }};
208 char * myCrt_Dispatch(int i)
213 return "(00)ReceiveCoreMakeDir";
215 return "(01)ReceiveCoreRemoveDir";
217 return "(02)ReceiveCoreOpen";
219 return "(03)ReceiveCoreCreate";
221 return "(04)ReceiveCoreClose";
223 return "(05)ReceiveCoreFlush";
225 return "(06)ReceiveCoreUnlink";
227 return "(07)ReceiveCoreRename";
229 return "(08)ReceiveCoreGetFileAttributes";
231 return "(09)ReceiveCoreSetFileAttributes";
233 return "(0a)ReceiveCoreRead";
235 return "(0b)ReceiveCoreWrite";
237 return "(0c)ReceiveCoreLockRecord";
239 return "(0d)ReceiveCoreUnlockRecord";
241 return "(0e)SendCoreBadOp";
243 return "(0f)ReceiveCoreCreate";
245 return "(10)ReceiveCoreCheckPath";
247 return "(11)SendCoreBadOp";
249 return "(12)ReceiveCoreSeek";
251 return "(1a)ReceiveCoreReadRaw";
253 return "(1d)ReceiveCoreWriteRawDummy";
255 return "(22)ReceiveV3SetAttributes";
257 return "(23)ReceiveV3GetAttributes";
259 return "(24)ReceiveV3LockingX";
261 return "(25)ReceiveV3Trans";
263 return "(26)ReceiveV3Trans[aux]";
265 return "(29)SendCoreBadOp";
267 return "(2b)ReceiveCoreEcho";
269 return "(2d)ReceiveV3OpenX";
271 return "(2e)ReceiveV3ReadX";
273 return "(32)ReceiveV3Tran2A";
275 return "(33)ReceiveV3Tran2A[aux]";
277 return "(34)ReceiveV3FindClose";
279 return "(35)ReceiveV3FindNotifyClose";
281 return "(70)ReceiveCoreTreeConnect";
283 return "(71)ReceiveCoreTreeDisconnect";
285 return "(72)ReceiveNegotiate";
287 return "(73)ReceiveV3SessionSetupX";
289 return "(74)ReceiveV3UserLogoffX";
291 return "(75)ReceiveV3TreeConnectX";
293 return "(80)ReceiveCoreGetDiskAttributes";
295 return "(81)ReceiveCoreSearchDir";
299 return "(83)FindUnique";
301 return "(84)FindClose";
303 return "(A0)ReceiveNTTransact";
305 return "(A2)ReceiveNTCreateX";
307 return "(A4)ReceiveNTCancel";
309 return "(A5)ReceiveNTRename";
311 return "(C0)OpenPrintFile";
313 return "(C1)WritePrintFile";
315 return "(C2)ClosePrintFile";
317 return "(C3)GetPrintQueue";
319 return "(D8)ReadBulk";
321 return "(D9)WriteBulk";
323 return "(DA)WriteBulkData";
325 return "unknown SMB op";
329 char * myCrt_2Dispatch(int i)
334 return "unknown SMB op-2";
336 return "S(00)CreateFile";
338 return "S(01)FindFirst";
340 return "S(02)FindNext"; /* FindNext */
342 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
346 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
348 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
350 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
352 return "S(08)??_ReceiveTran2SetFileInfo";
354 return "S(09)??_ReceiveTran2FSCTL";
356 return "S(0a)_ReceiveTran2IOCTL";
358 return "S(0b)_ReceiveTran2FindNotifyFirst";
360 return "S(0c)_ReceiveTran2FindNotifyNext";
362 return "S(0d)_ReceiveTran2CreateDirectory";
364 return "S(0e)_ReceiveTran2SessionSetup";
368 char * myCrt_RapDispatch(int i)
373 return "unknown RAP OP";
375 return "RAP(0)NetShareEnum";
377 return "RAP(1)NetShareGetInfo";
379 return "RAP(13)NetServerGetInfo";
381 return "RAP(63)NetWkStaGetInfo";
385 /* scache must be locked */
386 unsigned int smb_Attributes(cm_scache_t *scp)
390 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
391 scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
393 attrs = SMB_ATTR_DIRECTORY;
394 #ifdef SPECIAL_FOLDERS
395 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
396 #endif /* SPECIAL_FOLDERS */
401 * We used to mark a file RO if it was in an RO volume, but that
402 * turns out to be impolitic in NT. See defect 10007.
405 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
407 if ((scp->unixModeBits & 0222) == 0)
408 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
413 /* Check if the named file/dir is a dotfile/dotdir */
414 /* String pointed to by lastComp can have leading slashes, but otherwise should have
415 no other patch components */
416 unsigned int smb_IsDotFile(char *lastComp) {
419 /* skip over slashes */
420 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
425 /* nulls, curdir and parent dir doesn't count */
431 if(*(s+1) == '.' && !*(s + 2))
438 static int ExtractBits(WORD bits, short start, short len)
445 num = bits << (16 - end);
446 num = num >> ((16 - end) + start);
452 void ShowUnixTime(char *FuncName, time_t unixTime)
457 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
459 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
460 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
462 int day, month, year, sec, min, hour;
465 day = ExtractBits(wDate, 0, 5);
466 month = ExtractBits(wDate, 5, 4);
467 year = ExtractBits(wDate, 9, 7) + 1980;
469 sec = ExtractBits(wTime, 0, 5);
470 min = ExtractBits(wTime, 5, 6);
471 hour = ExtractBits(wTime, 11, 5);
473 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
474 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
480 /* Determine if we are observing daylight savings time */
481 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
483 TIME_ZONE_INFORMATION timeZoneInformation;
484 SYSTEMTIME utc, local, localDST;
486 /* Get the time zone info. NT uses this to calc if we are in DST. */
487 GetTimeZoneInformation(&timeZoneInformation);
489 /* Return the daylight bias */
490 *pDstBias = timeZoneInformation.DaylightBias;
492 /* Return the bias */
493 *pBias = timeZoneInformation.Bias;
495 /* Now determine if DST is being observed */
497 /* Get the UTC (GMT) time */
500 /* Convert UTC time to local time using the time zone info. If we are
501 observing DST, the calculated local time will include this.
503 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
505 /* Set the daylight bias to 0. The daylight bias is the amount of change
506 * in time that we use for daylight savings time. By setting this to 0
507 * we cause there to be no change in time during daylight savings time.
509 timeZoneInformation.DaylightBias = 0;
511 /* Convert the utc time to local time again, but this time without any
512 adjustment for daylight savings time.
514 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
516 /* If the two times are different, then it means that the localDST that
517 we calculated includes the daylight bias, and therefore we are
518 observing daylight savings time.
520 *pDST = localDST.wHour != local.wHour;
523 /* Determine if we are observing daylight savings time */
524 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
530 *pDstBias = -60; /* where can this be different? */
536 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
538 BOOL dst; /* Will be TRUE if observing DST */
539 LONG dstBias; /* Offset from local time if observing DST */
540 LONG bias; /* Offset from GMT for local time */
543 * This function will adjust the last write time to compensate
544 * for two bugs in the smb client:
546 * 1) During Daylight Savings Time, the LastWriteTime is ahead
547 * in time by the DaylightBias (ignoring the sign - the
548 * DaylightBias is always stored as a negative number). If
549 * the DaylightBias is -60, then the LastWriteTime will be
550 * ahead by 60 minutes.
552 * 2) If the local time zone is a positive offset from GMT, then
553 * the LastWriteTime will be the correct local time plus the
554 * Bias (ignoring the sign - a positive offset from GMT is
555 * always stored as a negative Bias). If the Bias is -120,
556 * then the LastWriteTime will be ahead by 120 minutes.
558 * These bugs can occur at the same time.
561 GetTimeZoneInfo(&dst, &dstBias, &bias);
563 /* First adjust for DST */
565 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
567 /* Now adjust for a positive offset from GMT (a negative bias). */
569 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
573 * Calculate the difference (in seconds) between local time and GMT.
574 * This enables us to convert file times to kludge-GMT.
580 struct tm gmt_tm, local_tm;
581 int days, hours, minutes, seconds;
584 gmt_tm = *(gmtime(&t));
585 local_tm = *(localtime(&t));
587 days = local_tm.tm_yday - gmt_tm.tm_yday;
588 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
590 /* There is a problem with DST immediately after the time change
591 * which may continue to exist until the machine is rebooted
593 - (local_tm.tm_isdst ? 1 : 0)
596 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
597 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
603 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
608 time_t ersatz_unixTime;
611 * Must use kludge-GMT instead of real GMT.
612 * kludge-GMT is computed by adding time zone difference to localtime.
615 * ltp = gmtime(&unixTime);
617 ersatz_unixTime = unixTime - smb_NowTZ;
618 ltp = localtime(&ersatz_unixTime);
620 /* if we fail, make up something */
623 localJunk.tm_year = 89 - 20;
624 localJunk.tm_mon = 4;
625 localJunk.tm_mday = 12;
626 localJunk.tm_hour = 0;
627 localJunk.tm_min = 0;
628 localJunk.tm_sec = 0;
631 stm.wYear = ltp->tm_year + 1900;
632 stm.wMonth = ltp->tm_mon + 1;
633 stm.wDayOfWeek = ltp->tm_wday;
634 stm.wDay = ltp->tm_mday;
635 stm.wHour = ltp->tm_hour;
636 stm.wMinute = ltp->tm_min;
637 stm.wSecond = ltp->tm_sec;
638 stm.wMilliseconds = 0;
640 SystemTimeToFileTime(&stm, largeTimep);
643 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
645 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
646 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
647 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
649 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
651 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
652 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
654 *ft = LargeIntegerMultiplyByLong(*ft, 60);
655 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
658 ut = ConvertLongToLargeInteger(unixTime);
659 ut = LargeIntegerMultiplyByLong(ut, 10000000);
660 *ft = LargeIntegerAdd(*ft, ut);
665 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
671 FileTimeToSystemTime(largeTimep, &stm);
673 lt.tm_year = stm.wYear - 1900;
674 lt.tm_mon = stm.wMonth - 1;
675 lt.tm_wday = stm.wDayOfWeek;
676 lt.tm_mday = stm.wDay;
677 lt.tm_hour = stm.wHour;
678 lt.tm_min = stm.wMinute;
679 lt.tm_sec = stm.wSecond;
682 save_timezone = _timezone;
683 _timezone += smb_NowTZ;
684 *unixTimep = mktime(<);
685 _timezone = save_timezone;
688 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
690 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
691 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
692 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
696 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
697 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
698 a = LargeIntegerMultiplyByLong(a, 60);
699 a = LargeIntegerMultiplyByLong(a, 10000000);
701 /* subtract it from ft */
702 a = LargeIntegerSubtract(*ft, a);
704 /* divide down to seconds */
705 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
709 void smb_SearchTimeFromUnixTime(time_t *dosTimep, time_t unixTime)
717 ltp = localtime((time_t*) &t);
719 /* if we fail, make up something */
722 localJunk.tm_year = 89 - 20;
723 localJunk.tm_mon = 4;
724 localJunk.tm_mday = 12;
725 localJunk.tm_hour = 0;
726 localJunk.tm_min = 0;
727 localJunk.tm_sec = 0;
730 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
731 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
732 *dosTimep = (dosDate<<16) | dosTime;
735 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
737 unsigned short dosDate;
738 unsigned short dosTime;
741 dosDate = (unsigned short) (searchTime & 0xffff);
742 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
744 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
745 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
746 localTm.tm_mday = (dosDate) & 0x1f;
747 localTm.tm_hour = (dosTime>>11) & 0x1f;
748 localTm.tm_min = (dosTime >> 5) & 0x3f;
749 localTm.tm_sec = (dosTime & 0x1f) * 2;
750 localTm.tm_isdst = -1; /* compute whether DST in effect */
752 *unixTimep = mktime(&localTm);
755 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
757 *dosUTimep = unixTime - smb_localZero;
760 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
763 *unixTimep = dosTime + smb_localZero;
765 /* dosTime seems to be already adjusted for GMT */
766 *unixTimep = dosTime;
770 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
774 lock_ObtainWrite(&smb_rctLock);
775 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
776 if (lsn == vcp->lsn && lana == vcp->lana) {
781 if (!vcp && (flags & SMB_FLAG_CREATE)) {
782 vcp = malloc(sizeof(*vcp));
783 memset(vcp, 0, sizeof(*vcp));
784 vcp->vcID = numVCs++;
788 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
789 vcp->nextp = smb_allVCsp;
791 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
796 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
797 /* We must obtain a challenge for extended auth
798 * in case the client negotiates smb v3
801 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
802 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
805 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
807 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
814 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
816 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
817 LsaFreeReturnBuffer(lsaResp);
820 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
822 lock_ReleaseWrite(&smb_rctLock);
826 int smb_IsStarMask(char *maskp)
831 for(i=0; i<11; i++) {
833 if (tc == '?' || tc == '*' || tc == '>') return 1;
838 void smb_ReleaseVC(smb_vc_t *vcp)
840 lock_ObtainWrite(&smb_rctLock);
841 osi_assert(vcp->refCount-- > 0);
842 lock_ReleaseWrite(&smb_rctLock);
845 void smb_HoldVC(smb_vc_t *vcp)
847 lock_ObtainWrite(&smb_rctLock);
849 lock_ReleaseWrite(&smb_rctLock);
852 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
856 lock_ObtainWrite(&smb_rctLock);
857 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
858 if (tid == tidp->tid) {
863 if (!tidp && (flags & SMB_FLAG_CREATE)) {
864 tidp = malloc(sizeof(*tidp));
865 memset(tidp, 0, sizeof(*tidp));
866 tidp->nextp = vcp->tidsp;
871 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
874 lock_ReleaseWrite(&smb_rctLock);
878 void smb_ReleaseTID(smb_tid_t *tidp)
887 lock_ObtainWrite(&smb_rctLock);
888 osi_assert(tidp->refCount-- > 0);
889 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
890 ltpp = &tidp->vcp->tidsp;
891 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
892 if (tp == tidp) break;
894 osi_assert(tp != NULL);
896 lock_FinalizeMutex(&tidp->mx);
897 userp = tidp->userp; /* remember to drop ref later */
900 lock_ReleaseWrite(&smb_rctLock);
902 cm_ReleaseUser(userp);
909 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
911 smb_user_t *uidp = NULL;
913 lock_ObtainWrite(&smb_rctLock);
914 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
915 if (uid == uidp->userID) {
917 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
918 (int)vcp, uidp->userID,
919 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
923 if (!uidp && (flags & SMB_FLAG_CREATE)) {
924 uidp = malloc(sizeof(*uidp));
925 memset(uidp, 0, sizeof(*uidp));
926 uidp->nextp = vcp->usersp;
931 lock_InitializeMutex(&uidp->mx, "user_t mutex");
933 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 : ""));
935 lock_ReleaseWrite(&smb_rctLock);
939 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
941 smb_username_t *unp= NULL;
943 lock_ObtainWrite(&smb_rctLock);
944 for(unp = usernamesp; unp; unp = unp->nextp) {
945 if (stricmp(unp->name, usern) == 0 &&
946 stricmp(unp->machine, machine) == 0) {
951 if (!unp && (flags & SMB_FLAG_CREATE)) {
952 unp = malloc(sizeof(*unp));
953 memset(unp, 0, sizeof(*unp));
955 unp->nextp = usernamesp;
956 unp->name = strdup(usern);
957 unp->machine = strdup(machine);
959 lock_InitializeMutex(&unp->mx, "username_t mutex");
961 lock_ReleaseWrite(&smb_rctLock);
965 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
967 smb_user_t *uidp= NULL;
969 lock_ObtainWrite(&smb_rctLock);
970 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
973 if (stricmp(uidp->unp->name, usern) == 0) {
975 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
980 lock_ReleaseWrite(&smb_rctLock);
983 void smb_ReleaseUID(smb_user_t *uidp)
992 lock_ObtainWrite(&smb_rctLock);
993 osi_assert(uidp->refCount-- > 0);
994 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
995 lupp = &uidp->vcp->usersp;
996 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
997 if (up == uidp) break;
999 osi_assert(up != NULL);
1001 lock_FinalizeMutex(&uidp->mx);
1003 userp = uidp->unp->userp; /* remember to drop ref later */
1004 uidp->unp->userp = NULL;
1009 lock_ReleaseWrite(&smb_rctLock);
1011 cm_ReleaseUserVCRef(userp);
1012 cm_ReleaseUser(userp);
1019 /* retrieve a held reference to a user structure corresponding to an incoming
1021 * corresponding release function is cm_ReleaseUser.
1023 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1029 smbp = (smb_t *) inp;
1030 uidp = smb_FindUID(vcp, smbp->uid, 0);
1031 if ((!uidp) || (!uidp->unp))
1034 lock_ObtainMutex(&uidp->mx);
1035 up = uidp->unp->userp;
1037 lock_ReleaseMutex(&uidp->mx);
1039 smb_ReleaseUID(uidp);
1045 * Return a pointer to a pathname extracted from a TID structure. The
1046 * TID structure is not held; assume it won't go away.
1048 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1053 tidp = smb_FindTID(vcp, tid, 0);
1057 if(tidp->flags & SMB_TIDFLAG_IPC) {
1058 code = CM_ERROR_TIDIPC;
1059 /* tidp->pathname would be NULL, but that's fine */
1061 *treepath = tidp->pathname;
1062 smb_ReleaseTID(tidp);
1067 /* check to see if we have a chained fid, that is, a fid that comes from an
1068 * OpenAndX message that ran earlier in this packet. In this case, the fid
1069 * field in a read, for example, request, isn't set, since the value is
1070 * supposed to be inherited from the openAndX call.
1072 int smb_ChainFID(int fid, smb_packet_t *inp)
1074 if (inp->fid == 0 || inp->inCount == 0)
1080 /* are we a priv'd user? What does this mean on NT? */
1081 int smb_SUser(cm_user_t *userp)
1086 /* find a file ID. If we pass in 0 we select an used File ID.
1087 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1088 * smb_fid_t data structure if desired File ID cannot be found.
1090 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1095 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1098 lock_ObtainWrite(&smb_rctLock);
1099 /* figure out if we need to allocate a new file ID */
1102 fid = vcp->fidCounter;
1106 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1107 if (fid == fidp->fid) {
1118 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1119 char eventName[MAX_PATH];
1121 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1122 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1123 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1124 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1125 thrd_CloseHandle(event);
1132 fidp = malloc(sizeof(*fidp));
1133 memset(fidp, 0, sizeof(*fidp));
1134 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1138 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1140 fidp->curr_chunk = fidp->prev_chunk = -2;
1141 fidp->raw_write_event = event;
1143 vcp->fidCounter = fid+1;
1144 if (vcp->fidCounter == 0)
1145 vcp->fidCounter = 1;
1148 lock_ReleaseWrite(&smb_rctLock);
1152 void smb_ReleaseFID(smb_fid_t *fidp)
1155 smb_vc_t *vcp = NULL;
1156 smb_ioctl_t *ioctlp;
1162 lock_ObtainWrite(&smb_rctLock);
1163 osi_assert(fidp->refCount-- > 0);
1164 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1166 if (!(fidp->flags & SMB_FID_IOCTL))
1168 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1169 thrd_CloseHandle(fidp->raw_write_event);
1171 /* and see if there is ioctl stuff to free */
1172 ioctlp = fidp->ioctlp;
1174 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1175 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1176 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1182 /* do not call smb_ReleaseVC() because we already have the lock */
1185 lock_ReleaseWrite(&smb_rctLock);
1187 /* now release the scache structure */
1189 cm_ReleaseSCache(scp);
1193 * Case-insensitive search for one string in another;
1194 * used to find variable names in submount pathnames.
1196 static char *smb_stristr(char *str1, char *str2)
1200 for (cursor = str1; *cursor; cursor++)
1201 if (stricmp(cursor, str2) == 0)
1208 * Substitute a variable value for its name in a submount pathname. Variable
1209 * name has been identified by smb_stristr() and is in substr. Variable name
1210 * length (plus one) is in substr_size. Variable value is in newstr.
1212 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1217 strcpy(temp, substr + substr_size - 1);
1218 strcpy(substr, newstr);
1222 char VNUserName[] = "%USERNAME%";
1223 char VNLCUserName[] = "%LCUSERNAME%";
1224 char VNComputerName[] = "%COMPUTERNAME%";
1225 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1228 /* List available shares */
1229 int smb_ListShares()
1233 char shareBuf[4096];
1241 /*strcpy(shareNameList[num_shares], "all");
1242 strcpy(pathNameList[num_shares++], "/afs");*/
1243 fprintf(stderr, "The following shares are available:\n");
1244 fprintf(stderr, "Share Name (AFS Path)\n");
1245 fprintf(stderr, "---------------------\n");
1246 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1249 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1250 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1252 strcpy(sbmtpath, cm_confDir);
1254 strcat(sbmtpath, "/afsdsbmt.ini");
1255 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1256 shareBuf, sizeof(shareBuf),
1262 this_share = shareBuf;
1266 /*strcpy(shareNameList[num_shares], this_share);*/
1267 len = GetPrivateProfileString("AFS Submounts", this_share,
1274 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1277 if (*p == '\\') *p = '/'; /* change to / */
1281 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1282 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1285 while (*this_share != 0) this_share++; /* find next NUL */
1286 this_share++; /* skip past the NUL */
1287 } while (*this_share != 0); /* stop at final NUL */
1293 typedef struct smb_findShare_rock {
1297 } smb_findShare_rock_t;
1299 #define SMB_FINDSHARE_EXACT_MATCH 1
1300 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1302 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1306 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1307 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1308 if(!stricmp(dep->name, vrock->shareName))
1309 matchType = SMB_FINDSHARE_EXACT_MATCH;
1311 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1312 if(vrock->match) free(vrock->match);
1313 vrock->match = strdup(dep->name);
1314 vrock->matchType = matchType;
1316 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1317 return CM_ERROR_STOPNOW;
1323 /* find a shareName in the table of submounts */
1324 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1328 char pathName[1024];
1333 char sbmtpath[MAX_PATH];
1338 DWORD allSubmount = 1;
1340 /* if allSubmounts == 0, only return the //mountRoot/all share
1341 * if in fact it has been been created in the subMounts table.
1342 * This is to allow sites that want to restrict access to the
1345 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1346 0, KEY_QUERY_VALUE, &parmKey);
1347 if (code == ERROR_SUCCESS) {
1348 len = sizeof(allSubmount);
1349 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1350 (BYTE *) &allSubmount, &len);
1351 if (code != ERROR_SUCCESS) {
1354 RegCloseKey (parmKey);
1357 if (allSubmount && _stricmp(shareName, "all") == 0) {
1362 /* In case, the all share is disabled we need to still be able
1363 * to handle ioctl requests
1365 if (_stricmp(shareName, "ioctl$") == 0) {
1366 *pathNamep = strdup("/.__ioctl__");
1370 if (_stricmp(shareName, "IPC$") == 0 ||
1371 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1372 _stricmp(shareName, "DESKTOP.INI") == 0
1379 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1380 0, KEY_QUERY_VALUE, &parmKey);
1381 if (code == ERROR_SUCCESS) {
1382 len = sizeof(pathName);
1383 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1384 (BYTE *) pathName, &len);
1385 if (code != ERROR_SUCCESS)
1387 RegCloseKey (parmKey);
1392 strcpy(sbmtpath, cm_confDir);
1393 strcat(sbmtpath, "/afsdsbmt.ini");
1394 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1395 pathName, sizeof(pathName), sbmtpath);
1397 if (len != 0 && len != sizeof(pathName) - 1) {
1398 /* We can accept either unix or PC style AFS pathnames. Convert
1399 * Unix-style to PC style here for internal use.
1402 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1403 p += strlen(cm_mountRoot); /* skip mount path */
1406 if (*q == '/') *q = '\\'; /* change to \ */
1412 if (var = smb_stristr(p, VNUserName)) {
1413 if (uidp && uidp->unp)
1414 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1416 smb_subst(p, var, sizeof(VNUserName)," ");
1418 else if (var = smb_stristr(p, VNLCUserName))
1420 if (uidp && uidp->unp)
1421 strcpy(temp, uidp->unp->name);
1425 smb_subst(p, var, sizeof(VNLCUserName), temp);
1427 else if (var = smb_stristr(p, VNComputerName))
1429 sizeTemp = sizeof(temp);
1430 GetComputerName((LPTSTR)temp, &sizeTemp);
1431 smb_subst(p, var, sizeof(VNComputerName), temp);
1433 else if (var = smb_stristr(p, VNLCComputerName))
1435 sizeTemp = sizeof(temp);
1436 GetComputerName((LPTSTR)temp, &sizeTemp);
1438 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1443 *pathNamep = strdup(p);
1448 /* First lookup shareName in root.afs */
1450 smb_findShare_rock_t vrock;
1452 char * p = shareName;
1455 /* attempt to locate a partial match in root.afs. This is because
1456 when using the ANSI RAP calls, the share name is limited to 13 chars
1457 and hence is truncated. Of course we prefer exact matches. */
1459 thyper.HighPart = 0;
1462 vrock.shareName = shareName;
1464 vrock.matchType = 0;
1466 cm_HoldSCache(cm_rootSCachep);
1467 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1468 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1469 cm_ReleaseSCache(cm_rootSCachep);
1471 if (vrock.matchType) {
1472 sprintf(pathName,"/%s/",vrock.match);
1473 *pathNamep = strdup(strlwr(pathName));
1478 /* if we get here, there was no match for the share in root.afs */
1479 /* so try to create \\<netbiosName>\<cellname> */
1484 /* Get the full name for this cell */
1485 code = cm_SearchCellFile(p, temp, 0, 0);
1486 #ifdef AFS_AFSDB_ENV
1487 if (code && cm_dnsEnabled) {
1489 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1492 /* construct the path */
1494 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1495 *pathNamep = strdup(strlwr(pathName));
1504 /* Client-side offline caching policy types */
1505 #define CSC_POLICY_MANUAL 0
1506 #define CSC_POLICY_DOCUMENTS 1
1507 #define CSC_POLICY_PROGRAMS 2
1508 #define CSC_POLICY_DISABLE 3
1510 int smb_FindShareCSCPolicy(char *shareName)
1516 int retval = CSC_POLICY_MANUAL;
1518 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1519 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1522 REG_OPTION_NON_VOLATILE,
1528 len = sizeof(policy);
1529 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1531 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1533 else if (stricmp(policy, "documents") == 0)
1535 retval = CSC_POLICY_DOCUMENTS;
1537 else if (stricmp(policy, "programs") == 0)
1539 retval = CSC_POLICY_PROGRAMS;
1541 else if (stricmp(policy, "disable") == 0)
1543 retval = CSC_POLICY_DISABLE;
1546 RegCloseKey(hkCSCPolicy);
1550 /* find a dir search structure by cookie value, and return it held.
1551 * Must be called with smb_globalLock held.
1553 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1555 smb_dirSearch_t *dsp;
1557 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1558 if (dsp->cookie == cookie) {
1559 if (dsp != smb_firstDirSearchp) {
1560 /* move to head of LRU queue, too, if we're not already there */
1561 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1562 smb_lastDirSearchp = (smb_dirSearch_t *)
1564 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1565 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1566 if (!smb_lastDirSearchp)
1567 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1569 lock_ObtainMutex(&dsp->mx);
1571 lock_ReleaseMutex(&dsp->mx);
1578 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1580 lock_ObtainWrite(&smb_globalLock);
1581 lock_ObtainMutex(&dsp->mx);
1582 dsp->flags |= SMB_DIRSEARCH_DELETE;
1583 if (dsp->scp != NULL) {
1584 lock_ObtainMutex(&dsp->scp->mx);
1585 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1586 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1587 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1588 dsp->scp->bulkStatProgress = hones;
1590 lock_ReleaseMutex(&dsp->scp->mx);
1592 lock_ReleaseMutex(&dsp->mx);
1593 lock_ReleaseWrite(&smb_globalLock);
1596 /* Must be called with the smb_globalLock held */
1597 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1603 lock_ObtainMutex(&dsp->mx);
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_ReleaseMutex(&dsp->mx);
1610 lock_FinalizeMutex(&dsp->mx);
1614 lock_ReleaseMutex(&dsp->mx);
1616 /* do this now to avoid spurious locking hierarchy creation */
1617 if (scp) cm_ReleaseSCache(scp);
1620 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1622 lock_ObtainWrite(&smb_globalLock);
1623 smb_ReleaseDirSearchNoLock(dsp);
1624 lock_ReleaseWrite(&smb_globalLock);
1627 /* find a dir search structure by cookie value, and return it held */
1628 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1630 smb_dirSearch_t *dsp;
1632 lock_ObtainWrite(&smb_globalLock);
1633 dsp = smb_FindDirSearchNoLock(cookie);
1634 lock_ReleaseWrite(&smb_globalLock);
1638 /* GC some dir search entries, in the address space expected by the specific protocol.
1639 * Must be called with smb_globalLock held; release the lock temporarily.
1641 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1642 void smb_GCDirSearches(int isV3)
1644 smb_dirSearch_t *prevp;
1645 smb_dirSearch_t *tp;
1646 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1650 victimCount = 0; /* how many have we got so far */
1651 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1652 /* we'll move tp from queue, so
1655 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1656 /* if no one is using this guy, and we're either in the new protocol,
1657 * or we're in the old one and this is a small enough ID to be useful
1658 * to the old protocol, GC this guy.
1660 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1661 /* hold and delete */
1662 tp->flags |= SMB_DIRSEARCH_DELETE;
1663 victimsp[victimCount++] = tp;
1667 /* don't do more than this */
1668 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1672 /* now release them */
1673 for (i = 0; i < victimCount; i++) {
1674 smb_ReleaseDirSearchNoLock(victimsp[i]);
1678 /* function for allocating a dir search entry. We need these to remember enough context
1679 * since we don't get passed the path from call to call during a directory search.
1681 * Returns a held dir search structure, and bumps the reference count on the vnode,
1682 * since it saves a pointer to the vnode.
1684 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1686 smb_dirSearch_t *dsp;
1690 lock_ObtainWrite(&smb_globalLock);
1693 /* what's the biggest ID allowed in this version of the protocol */
1694 maxAllowed = isV3 ? 65535 : 255;
1697 /* twice so we have enough tries to find guys we GC after one pass;
1698 * 10 extra is just in case I mis-counted.
1700 if (++counter > 2*maxAllowed+10)
1701 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1703 if (smb_dirSearchCounter > maxAllowed) {
1704 smb_dirSearchCounter = 1;
1705 smb_GCDirSearches(isV3); /* GC some */
1707 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1709 /* don't need to watch for refcount zero and deleted, since
1710 * we haven't dropped the global lock.
1712 lock_ObtainMutex(&dsp->mx);
1714 lock_ReleaseMutex(&dsp->mx);
1715 ++smb_dirSearchCounter;
1719 dsp = malloc(sizeof(*dsp));
1720 memset(dsp, 0, sizeof(*dsp));
1721 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1722 if (!smb_lastDirSearchp)
1723 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1724 dsp->cookie = smb_dirSearchCounter;
1725 ++smb_dirSearchCounter;
1727 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1728 dsp->lastTime = osi_Time();
1731 lock_ReleaseWrite(&smb_globalLock);
1735 static smb_packet_t *GetPacket(void)
1739 unsigned int npar, seg, tb_sel;
1742 lock_ObtainWrite(&smb_globalLock);
1743 tbp = smb_packetFreeListp;
1745 smb_packetFreeListp = tbp->nextp;
1746 lock_ReleaseWrite(&smb_globalLock);
1749 tbp = calloc(65540,1);
1751 tbp = malloc(sizeof(smb_packet_t));
1753 tbp->magic = SMB_PACKETMAGIC;
1756 tbp->resumeCode = 0;
1762 tbp->ncb_length = 0;
1767 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1770 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1772 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1774 osi_panic("",__FILE__,__LINE__);
1777 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1782 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1783 tbp->dos_pkt_sel = tb_sel;
1786 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1791 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1795 memcpy(tbp, pkt, sizeof(smb_packet_t));
1796 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1800 static NCB *GetNCB(void)
1805 unsigned int npar, seg, tb_sel;
1808 lock_ObtainWrite(&smb_globalLock);
1809 tbp = smb_ncbFreeListp;
1811 smb_ncbFreeListp = tbp->nextp;
1812 lock_ReleaseWrite(&smb_globalLock);
1815 tbp = calloc(sizeof(*tbp),1);
1817 tbp = malloc(sizeof(*tbp));
1818 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1821 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1823 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1825 osi_panic("",__FILE__,__LINE__);
1827 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1832 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1833 tbp->dos_ncb_sel = tb_sel;
1835 tbp->magic = SMB_NCBMAGIC;
1838 osi_assert(tbp->magic == SMB_NCBMAGIC);
1840 memset(&tbp->ncb, 0, sizeof(NCB));
1843 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1848 void smb_FreePacket(smb_packet_t *tbp)
1850 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1852 lock_ObtainWrite(&smb_globalLock);
1853 tbp->nextp = smb_packetFreeListp;
1854 smb_packetFreeListp = tbp;
1855 tbp->magic = SMB_PACKETMAGIC;
1858 tbp->resumeCode = 0;
1864 tbp->ncb_length = 0;
1866 lock_ReleaseWrite(&smb_globalLock);
1869 static void FreeNCB(NCB *bufferp)
1873 tbp = (smb_ncb_t *) bufferp;
1874 osi_assert(tbp->magic == SMB_NCBMAGIC);
1876 lock_ObtainWrite(&smb_globalLock);
1877 tbp->nextp = smb_ncbFreeListp;
1878 smb_ncbFreeListp = tbp;
1879 lock_ReleaseWrite(&smb_globalLock);
1882 /* get a ptr to the data part of a packet, and its count */
1883 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1887 unsigned char *afterParmsp;
1889 parmBytes = *smbp->wctp << 1;
1890 afterParmsp = smbp->wctp + parmBytes + 1;
1892 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1893 if (nbytesp) *nbytesp = dataBytes;
1895 /* don't forget to skip the data byte count, since it follows
1896 * the parameters; that's where the "2" comes from below.
1898 return (unsigned char *) (afterParmsp + 2);
1901 /* must set all the returned parameters before playing around with the
1902 * data region, since the data region is located past the end of the
1903 * variable number of parameters.
1905 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1907 unsigned char *afterParmsp;
1909 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1911 *afterParmsp++ = dsize & 0xff;
1912 *afterParmsp = (dsize>>8) & 0xff;
1915 /* return the parm'th parameter in the smbp packet */
1916 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1919 unsigned char *parmDatap;
1921 parmCount = *smbp->wctp;
1923 if (parm >= parmCount) {
1928 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1930 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1931 parm, parmCount, smbp->ncb_length);
1934 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1935 1, smbp->ncb_length, ptbuf, smbp);
1936 DeregisterEventSource(h);
1938 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1939 osi_panic(s, __FILE__, __LINE__);
1941 parmDatap = smbp->wctp + (2*parm) + 1;
1943 return parmDatap[0] + (parmDatap[1] << 8);
1946 /* return the parm'th parameter in the smbp packet */
1947 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1950 unsigned char *parmDatap;
1952 parmCount = *smbp->wctp;
1954 if (parm * 2 + offset >= parmCount * 2) {
1959 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1961 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1962 parm, offset, parmCount, smbp->ncb_length);
1965 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1966 1, smbp->ncb_length, ptbuf, smbp);
1967 DeregisterEventSource(h);
1969 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1970 osi_panic(s, __FILE__, __LINE__);
1972 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1974 return parmDatap[0] + (parmDatap[1] << 8);
1977 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1981 /* make sure we have enough slots */
1982 if (*smbp->wctp <= slot)
1983 *smbp->wctp = slot+1;
1985 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1986 *parmDatap++ = parmValue & 0xff;
1987 *parmDatap = (parmValue>>8) & 0xff;
1990 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1994 /* make sure we have enough slots */
1995 if (*smbp->wctp <= slot)
1996 *smbp->wctp = slot+2;
1998 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1999 *parmDatap++ = parmValue & 0xff;
2000 *parmDatap++ = (parmValue>>8) & 0xff;
2001 *parmDatap++ = (parmValue>>16) & 0xff;
2002 *parmDatap++ = (parmValue>>24) & 0xff;
2005 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2010 /* make sure we have enough slots */
2011 if (*smbp->wctp <= slot)
2012 *smbp->wctp = slot+4;
2014 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2016 *parmDatap++ = *parmValuep++;
2019 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2023 /* make sure we have enough slots */
2024 if (*smbp->wctp <= slot) {
2025 if (smbp->oddByte) {
2027 *smbp->wctp = slot+1;
2032 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2033 *parmDatap++ = parmValue & 0xff;
2036 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2040 lastSlashp = strrchr(inPathp, '\\');
2042 *lastComponentp = lastSlashp;
2045 if (inPathp == lastSlashp)
2047 *outPathp++ = *inPathp++;
2056 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2061 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2066 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2072 tlen = inp[0] + (inp[1]<<8);
2073 inp += 2; /* skip length field */
2076 *chainpp = inp + tlen;
2085 /* format a packet as a response */
2086 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2091 outp = (smb_t *) op;
2093 /* zero the basic structure through the smb_wct field, and zero the data
2094 * size field, assuming that wct stays zero; otherwise, you have to
2095 * explicitly set the data size field, too.
2097 inSmbp = (smb_t *) inp;
2098 memset(outp, 0, sizeof(smb_t)+2);
2104 outp->com = inSmbp->com;
2105 outp->tid = inSmbp->tid;
2106 outp->pid = inSmbp->pid;
2107 outp->uid = inSmbp->uid;
2108 outp->mid = inSmbp->mid;
2109 outp->res[0] = inSmbp->res[0];
2110 outp->res[1] = inSmbp->res[1];
2111 op->inCom = inSmbp->com;
2113 outp->reb = 0x80; /* SERVER_RESP */
2114 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2116 /* copy fields in generic packet area */
2117 op->wctp = &outp->wct;
2120 /* send a (probably response) packet; vcp tells us to whom to send it.
2121 * we compute the length by looking at wct and bcc fields.
2123 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2140 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2143 memset((char *)ncbp, 0, sizeof(NCB));
2145 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2146 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2147 extra += tp[0] + (tp[1]<<8);
2148 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2149 extra += 3; /* wct and length fields */
2151 ncbp->ncb_length = extra; /* bytes to send */
2152 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2153 ncbp->ncb_lana_num = vcp->lana;
2154 ncbp->ncb_command = NCBSEND; /* op means send data */
2156 ncbp->ncb_buffer = (char *) inp;/* packet */
2157 code = Netbios(ncbp);
2159 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2160 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2162 /* copy header information from virtual to DOS address space */
2163 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2164 code = Netbios(ncbp, dos_ncb);
2168 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2174 void smb_MapNTError(long code, unsigned long *NTStatusp)
2176 unsigned long NTStatus;
2178 /* map CM_ERROR_* errors to NT 32-bit status codes */
2179 /* NT Status codes are listed in ntstatus.h not winerror.h */
2180 if (code == CM_ERROR_NOSUCHCELL) {
2181 NTStatus = 0xC000000FL; /* No such file */
2183 else if (code == CM_ERROR_NOSUCHVOLUME) {
2184 NTStatus = 0xC000000FL; /* No such file */
2186 else if (code == CM_ERROR_TIMEDOUT) {
2187 NTStatus = 0xC00000CFL; /* Sharing Paused */
2189 else if (code == CM_ERROR_RETRY) {
2190 NTStatus = 0xC000022DL; /* Retry */
2192 else if (code == CM_ERROR_NOACCESS) {
2193 NTStatus = 0xC0000022L; /* Access denied */
2195 else if (code == CM_ERROR_READONLY) {
2196 NTStatus = 0xC00000A2L; /* Write protected */
2198 else if (code == CM_ERROR_NOSUCHFILE) {
2199 NTStatus = 0xC000000FL; /* No such file */
2201 else if (code == CM_ERROR_NOSUCHPATH) {
2202 NTStatus = 0xC000003AL; /* Object path not found */
2204 else if (code == CM_ERROR_TOOBIG) {
2205 NTStatus = 0xC000007BL; /* Invalid image format */
2207 else if (code == CM_ERROR_INVAL) {
2208 NTStatus = 0xC000000DL; /* Invalid parameter */
2210 else if (code == CM_ERROR_BADFD) {
2211 NTStatus = 0xC0000008L; /* Invalid handle */
2213 else if (code == CM_ERROR_BADFDOP) {
2214 NTStatus = 0xC0000022L; /* Access denied */
2216 else if (code == CM_ERROR_EXISTS) {
2217 NTStatus = 0xC0000035L; /* Object name collision */
2219 else if (code == CM_ERROR_NOTEMPTY) {
2220 NTStatus = 0xC0000101L; /* Directory not empty */
2222 else if (code == CM_ERROR_CROSSDEVLINK) {
2223 NTStatus = 0xC00000D4L; /* Not same device */
2225 else if (code == CM_ERROR_NOTDIR) {
2226 NTStatus = 0xC0000103L; /* Not a directory */
2228 else if (code == CM_ERROR_ISDIR) {
2229 NTStatus = 0xC00000BAL; /* File is a directory */
2231 else if (code == CM_ERROR_BADOP) {
2233 /* I have no idea where this comes from */
2234 NTStatus = 0xC09820FFL; /* SMB no support */
2236 NTStatus = 0xC00000BBL; /* Not supported */
2237 #endif /* COMMENT */
2239 else if (code == CM_ERROR_BADSHARENAME) {
2240 NTStatus = 0xC00000CCL; /* Bad network name */
2242 else if (code == CM_ERROR_NOIPC) {
2244 NTStatus = 0xC0000022L; /* Access Denied */
2246 NTStatus = 0xC000013DL; /* Remote Resources */
2249 else if (code == CM_ERROR_CLOCKSKEW) {
2250 NTStatus = 0xC0000133L; /* Time difference at DC */
2252 else if (code == CM_ERROR_BADTID) {
2253 NTStatus = 0xC0982005L; /* SMB bad TID */
2255 else if (code == CM_ERROR_USESTD) {
2256 NTStatus = 0xC09820FBL; /* SMB use standard */
2258 else if (code == CM_ERROR_QUOTA) {
2260 NTStatus = 0xC0000044L; /* Quota exceeded */
2262 NTStatus = 0xC000007FL; /* Disk full */
2265 else if (code == CM_ERROR_SPACE) {
2266 NTStatus = 0xC000007FL; /* Disk full */
2268 else if (code == CM_ERROR_ATSYS) {
2269 NTStatus = 0xC0000033L; /* Object name invalid */
2271 else if (code == CM_ERROR_BADNTFILENAME) {
2272 NTStatus = 0xC0000033L; /* Object name invalid */
2274 else if (code == CM_ERROR_WOULDBLOCK) {
2275 NTStatus = 0xC0000055L; /* Lock not granted */
2277 else if (code == CM_ERROR_PARTIALWRITE) {
2278 NTStatus = 0xC000007FL; /* Disk full */
2280 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2281 NTStatus = 0xC0000023L; /* Buffer too small */
2283 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2284 NTStatus = 0xC0000035L; /* Object name collision */
2286 else if (code == CM_ERROR_BADPASSWORD) {
2287 NTStatus = 0xC000006DL; /* unknown username or bad password */
2289 else if (code == CM_ERROR_BADLOGONTYPE) {
2290 NTStatus = 0xC000015BL; /* logon type not granted */
2292 else if (code == CM_ERROR_GSSCONTINUE) {
2293 NTStatus = 0xC0000016L; /* more processing required */
2295 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2297 NTStatus = 0xC0000280L; /* reparse point not resolved */
2299 NTStatus = 0xC0000022L; /* Access Denied */
2303 NTStatus = 0xC0982001L; /* SMB non-specific error */
2306 *NTStatusp = NTStatus;
2307 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2310 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2311 unsigned char *classp)
2313 unsigned char class;
2314 unsigned short error;
2316 /* map CM_ERROR_* errors to SMB errors */
2317 if (code == CM_ERROR_NOSUCHCELL) {
2319 error = 3; /* bad path */
2321 else if (code == CM_ERROR_NOSUCHVOLUME) {
2323 error = 3; /* bad path */
2325 else if (code == CM_ERROR_TIMEDOUT) {
2327 error = 81; /* server is paused */
2329 else if (code == CM_ERROR_RETRY) {
2330 class = 2; /* shouldn't happen */
2333 else if (code == CM_ERROR_NOACCESS) {
2335 error = 4; /* bad access */
2337 else if (code == CM_ERROR_READONLY) {
2339 error = 19; /* read only */
2341 else if (code == CM_ERROR_NOSUCHFILE) {
2343 error = 2; /* ENOENT! */
2345 else if (code == CM_ERROR_NOSUCHPATH) {
2347 error = 3; /* Bad path */
2349 else if (code == CM_ERROR_TOOBIG) {
2351 error = 11; /* bad format */
2353 else if (code == CM_ERROR_INVAL) {
2354 class = 2; /* server non-specific error code */
2357 else if (code == CM_ERROR_BADFD) {
2359 error = 6; /* invalid file handle */
2361 else if (code == CM_ERROR_BADFDOP) {
2362 class = 1; /* invalid op on FD */
2365 else if (code == CM_ERROR_EXISTS) {
2367 error = 80; /* file already exists */
2369 else if (code == CM_ERROR_NOTEMPTY) {
2371 error = 5; /* delete directory not empty */
2373 else if (code == CM_ERROR_CROSSDEVLINK) {
2375 error = 17; /* EXDEV */
2377 else if (code == CM_ERROR_NOTDIR) {
2378 class = 1; /* bad path */
2381 else if (code == CM_ERROR_ISDIR) {
2382 class = 1; /* access denied; DOS doesn't have a good match */
2385 else if (code == CM_ERROR_BADOP) {
2389 else if (code == CM_ERROR_BADSHARENAME) {
2393 else if (code == CM_ERROR_NOIPC) {
2395 error = 4; /* bad access */
2397 else if (code == CM_ERROR_CLOCKSKEW) {
2398 class = 1; /* invalid function */
2401 else if (code == CM_ERROR_BADTID) {
2405 else if (code == CM_ERROR_USESTD) {
2409 else if (code == CM_ERROR_REMOTECONN) {
2413 else if (code == CM_ERROR_QUOTA) {
2414 if (vcp->flags & SMB_VCFLAG_USEV3) {
2416 error = 39; /* disk full */
2420 error = 5; /* access denied */
2423 else if (code == CM_ERROR_SPACE) {
2424 if (vcp->flags & SMB_VCFLAG_USEV3) {
2426 error = 39; /* disk full */
2430 error = 5; /* access denied */
2433 else if (code == CM_ERROR_PARTIALWRITE) {
2435 error = 39; /* disk full */
2437 else if (code == CM_ERROR_ATSYS) {
2439 error = 2; /* ENOENT */
2441 else if (code == CM_ERROR_WOULDBLOCK) {
2443 error = 33; /* lock conflict */
2445 else if (code == CM_ERROR_NOFILES) {
2447 error = 18; /* no files in search */
2449 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2451 error = 183; /* Samba uses this */
2453 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2454 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2456 error = 2; /* bad password */
2465 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2468 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2470 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2471 return CM_ERROR_BADOP;
2474 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2476 unsigned short EchoCount, i;
2477 char *data, *outdata;
2480 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2482 for (i=1; i<=EchoCount; i++) {
2483 data = smb_GetSMBData(inp, &dataSize);
2484 smb_SetSMBParm(outp, 0, i);
2485 smb_SetSMBDataLength(outp, dataSize);
2486 outdata = smb_GetSMBData(outp, NULL);
2487 memcpy(outdata, data, dataSize);
2488 smb_SendPacket(vcp, outp);
2494 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2497 long count, minCount, finalCount;
2501 cm_user_t *userp = NULL;
2505 char *rawBuf = NULL;
2507 dos_ptr rawBuf = NULL;
2514 fd = smb_GetSMBParm(inp, 0);
2515 count = smb_GetSMBParm(inp, 3);
2516 minCount = smb_GetSMBParm(inp, 4);
2517 offset.HighPart = 0; /* too bad */
2518 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2520 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2521 fd, offset.LowPart, count);
2523 fidp = smb_FindFID(vcp, fd, 0);
2527 lock_ObtainMutex(&smb_RawBufLock);
2529 /* Get a raw buf, from head of list */
2530 rawBuf = smb_RawBufs;
2532 smb_RawBufs = *(char **)smb_RawBufs;
2534 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2537 lock_ReleaseMutex(&smb_RawBufLock);
2541 if (fidp->flags & SMB_FID_IOCTL)
2544 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2546 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2549 /* Give back raw buffer */
2550 lock_ObtainMutex(&smb_RawBufLock);
2552 *((char **) rawBuf) = smb_RawBufs;
2554 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2557 smb_RawBufs = rawBuf;
2558 lock_ReleaseMutex(&smb_RawBufLock);
2561 smb_ReleaseFID(fidp);
2565 userp = smb_GetUser(vcp, inp);
2568 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2570 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2571 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2572 userp, &finalCount, TRUE /* rawFlag */);
2579 cm_ReleaseUser(userp);
2582 smb_ReleaseFID(fidp);
2587 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2589 memset((char *)ncbp, 0, sizeof(NCB));
2591 ncbp->ncb_length = (unsigned short) finalCount;
2592 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2593 ncbp->ncb_lana_num = vcp->lana;
2594 ncbp->ncb_command = NCBSEND;
2595 ncbp->ncb_buffer = rawBuf;
2598 code = Netbios(ncbp);
2600 code = Netbios(ncbp, dos_ncb);
2603 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2606 /* Give back raw buffer */
2607 lock_ObtainMutex(&smb_RawBufLock);
2609 *((char **) rawBuf) = smb_RawBufs;
2611 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2614 smb_RawBufs = rawBuf;
2615 lock_ReleaseMutex(&smb_RawBufLock);
2621 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2623 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2628 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2630 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2635 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2642 int protoIndex; /* index we're using */
2647 char protocol_array[10][1024]; /* protocol signature of the client */
2648 int caps; /* capabilities */
2651 TIME_ZONE_INFORMATION tzi;
2653 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2657 DWORD now = GetCurrentTime();
2658 if (now - last_msg_time >= 30000
2659 && now - last_msg_time <= 90000) {
2661 "Setting dead_vcp %x", active_vcp);
2663 smb_ReleaseVC(dead_vcp);
2665 "Previous dead_vcp %x", dead_vcp);
2667 smb_HoldVC(active_vcp);
2668 dead_vcp = active_vcp;
2669 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2674 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2676 namep = smb_GetSMBData(inp, &dbytes);
2679 coreProtoIndex = -1; /* not found */
2682 while(namex < dbytes) {
2683 osi_Log1(smb_logp, "Protocol %s",
2684 osi_LogSaveString(smb_logp, namep+1));
2685 strcpy(protocol_array[tcounter], namep+1);
2687 /* namep points at the first protocol, or really, a 0x02
2688 * byte preceding the null-terminated ASCII name.
2690 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2691 coreProtoIndex = tcounter;
2693 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2694 v3ProtoIndex = tcounter;
2696 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2697 NTProtoIndex = tcounter;
2700 /* compute size of protocol entry */
2701 entryLength = strlen(namep+1);
2702 entryLength += 2; /* 0x02 bytes and null termination */
2704 /* advance over this protocol entry */
2705 namex += entryLength;
2706 namep += entryLength;
2707 tcounter++; /* which proto entry we're looking at */
2710 if (NTProtoIndex != -1) {
2711 protoIndex = NTProtoIndex;
2712 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2714 else if (v3ProtoIndex != -1) {
2715 protoIndex = v3ProtoIndex;
2716 vcp->flags |= SMB_VCFLAG_USEV3;
2718 else if (coreProtoIndex != -1) {
2719 protoIndex = coreProtoIndex;
2720 vcp->flags |= SMB_VCFLAG_USECORE;
2722 else protoIndex = -1;
2724 if (protoIndex == -1)
2725 return CM_ERROR_INVAL;
2726 else if (NTProtoIndex != -1) {
2727 smb_SetSMBParm(outp, 0, protoIndex);
2728 if (smb_authType != SMB_AUTH_NONE) {
2729 smb_SetSMBParmByte(outp, 1,
2730 NEGOTIATE_SECURITY_USER_LEVEL |
2731 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2733 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2735 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2736 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2737 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2738 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2739 /* The session key is not a well documented field however most clients
2740 * will echo back the session key to the server. Currently we are using
2741 * the same value for all sessions. We should generate a random value
2742 * and store it into the vcp
2744 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2745 smb_SetSMBParm(outp, 8, 1);
2747 * Tried changing the capabilities to support for W2K - defect 117695
2748 * Maybe something else needs to be changed here?
2752 smb_SetSMBParmLong(outp, 9, 0x43fd);
2754 smb_SetSMBParmLong(outp, 9, 0x251);
2757 * 32-bit error codes *
2761 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2762 NTNEGOTIATE_CAPABILITY_NTFIND |
2763 NTNEGOTIATE_CAPABILITY_RAWMODE |
2764 NTNEGOTIATE_CAPABILITY_NTSMB;
2766 if ( smb_authType == SMB_AUTH_EXTENDED )
2767 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2769 smb_SetSMBParmLong(outp, 9, caps);
2771 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2772 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2773 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2775 GetTimeZoneInformation(&tzi);
2776 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2778 if (smb_authType == SMB_AUTH_NTLM) {
2779 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2780 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2781 /* paste in encryption key */
2782 datap = smb_GetSMBData(outp, NULL);
2783 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2784 /* and the faux domain name */
2785 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2786 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2790 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2792 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2794 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2796 datap = smb_GetSMBData(outp, NULL);
2797 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2800 datap += sizeof(smb_ServerGUID);
2801 memcpy(datap, secBlob, secBlobLength);
2805 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2806 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2809 else if (v3ProtoIndex != -1) {
2810 smb_SetSMBParm(outp, 0, protoIndex);
2812 /* NOTE: Extended authentication cannot be negotiated with v3
2813 * therefore we fail over to NTLM
2815 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2816 smb_SetSMBParm(outp, 1,
2817 NEGOTIATE_SECURITY_USER_LEVEL |
2818 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2820 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2822 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2823 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2824 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2825 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2826 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2827 smb_SetSMBParm(outp, 7, 1);
2829 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2830 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2831 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2833 GetTimeZoneInformation(&tzi);
2834 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2836 /* NOTE: Extended authentication cannot be negotiated with v3
2837 * therefore we fail over to NTLM
2839 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2840 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2841 smb_SetSMBParm(outp, 12, 0); /* resvd */
2842 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2843 datap = smb_GetSMBData(outp, NULL);
2844 /* paste in a new encryption key */
2845 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2846 /* and the faux domain name */
2847 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2849 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2850 smb_SetSMBParm(outp, 12, 0); /* resvd */
2851 smb_SetSMBDataLength(outp, 0);
2854 else if (coreProtoIndex != -1) { /* not really supported anymore */
2855 smb_SetSMBParm(outp, 0, protoIndex);
2856 smb_SetSMBDataLength(outp, 0);
2861 void smb_Daemon(void *parmp)
2863 afs_uint32 count = 0;
2868 if ((count % 72) == 0) { /* every five minutes */
2870 time_t old_localZero = smb_localZero;
2872 /* Initialize smb_localZero */
2873 myTime.tm_isdst = -1; /* compute whether on DST or not */
2874 myTime.tm_year = 70;
2880 smb_localZero = mktime(&myTime);
2882 smb_CalculateNowTZ();
2884 #ifdef AFS_FREELANCE
2885 if ( smb_localZero != old_localZero )
2886 cm_noteLocalMountPointChange();
2889 /* XXX GC dir search entries */
2893 void smb_WaitingLocksDaemon()
2895 smb_waitingLock_t *wL, *nwL;
2898 smb_packet_t *inp, *outp;
2903 lock_ObtainWrite(&smb_globalLock);
2904 nwL = smb_allWaitingLocks;
2906 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2915 lock_ObtainWrite(&smb_globalLock);
2917 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2918 lock_ReleaseWrite(&smb_globalLock);
2919 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2920 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2921 if (code == CM_ERROR_WOULDBLOCK) {
2923 if (wL->timeRemaining != 0xffffffff
2924 && (wL->timeRemaining -= 1000) < 0)
2933 ncbp->ncb_length = inp->ncb_length;
2934 inp->spacep = cm_GetSpace();
2936 /* Remove waitingLock from list */
2937 lock_ObtainWrite(&smb_globalLock);
2938 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2940 lock_ReleaseWrite(&smb_globalLock);
2942 /* Resume packet processing */
2944 smb_SetSMBDataLength(outp, 0);
2945 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2946 outp->resumeCode = code;
2948 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2951 cm_FreeSpace(inp->spacep);
2952 smb_FreePacket(inp);
2953 smb_FreePacket(outp);
2961 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2963 osi_Log0(smb_logp, "SMB receive get disk attributes");
2965 smb_SetSMBParm(outp, 0, 32000);
2966 smb_SetSMBParm(outp, 1, 64);
2967 smb_SetSMBParm(outp, 2, 1024);
2968 smb_SetSMBParm(outp, 3, 30000);
2969 smb_SetSMBParm(outp, 4, 0);
2970 smb_SetSMBDataLength(outp, 0);
2974 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2978 unsigned short newTid;
2979 char shareName[256];
2987 osi_Log0(smb_logp, "SMB receive tree connect");
2989 /* parse input parameters */
2990 tp = smb_GetSMBData(inp, NULL);
2991 pathp = smb_ParseASCIIBlock(tp, &tp);
2992 passwordp = smb_ParseASCIIBlock(tp, &tp);
2993 tp = strrchr(pathp, '\\');
2995 return CM_ERROR_BADSMB;
2996 strcpy(shareName, tp+1);
2998 userp = smb_GetUser(vcp, inp);
3000 lock_ObtainMutex(&vcp->mx);
3001 newTid = vcp->tidCounter++;
3002 lock_ReleaseMutex(&vcp->mx);
3004 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3005 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3006 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3008 smb_ReleaseUID(uidp);
3010 smb_ReleaseTID(tidp);
3011 return CM_ERROR_BADSHARENAME;
3013 lock_ObtainMutex(&tidp->mx);
3014 tidp->userp = userp;
3015 tidp->pathname = sharePath;
3016 lock_ReleaseMutex(&tidp->mx);
3017 smb_ReleaseTID(tidp);
3019 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3020 smb_SetSMBParm(rsp, 1, newTid);
3021 smb_SetSMBDataLength(rsp, 0);
3023 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3027 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3031 if (*inp++ != 0x1) return NULL;
3032 tlen = inp[0] + (inp[1]<<8);
3033 inp += 2; /* skip length field */
3036 *chainpp = inp + tlen;
3039 if (lengthp) *lengthp = tlen;
3044 /* set maskp to the mask part of the incoming path.
3045 * Mask is 11 bytes long (8.3 with the dot elided).
3046 * Returns true if succeeds with a valid name, otherwise it does
3047 * its best, but returns false.
3049 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3057 /* starts off valid */
3060 /* mask starts out all blanks */
3061 memset(maskp, ' ', 11);
3063 /* find last backslash, or use whole thing if there is none */
3064 tp = strrchr(pathp, '\\');
3065 if (!tp) tp = pathp;
3066 else tp++; /* skip slash */
3070 /* names starting with a dot are illegal */
3071 if (*tp == '.') valid8Dot3 = 0;
3075 if (tc == 0) return valid8Dot3;
3076 if (tc == '.' || tc == '"') break;
3077 if (i < 8) *up++ = tc;
3078 else valid8Dot3 = 0;
3081 /* if we get here, tp point after the dot */
3082 up = maskp+8; /* ext goes here */
3089 if (tc == '.' || tc == '"')
3092 /* copy extension if not too long */
3102 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3112 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3114 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3118 /* otherwise, we have a valid 8.3 name; see if we have a match,
3119 * treating '?' as a wildcard in maskp (but not in the file name).
3121 tp1 = umask; /* real name, in mask format */
3122 tp2 = maskp; /* mask, in mask format */
3123 for(i=0; i<11; i++) {
3124 tc1 = *tp1++; /* char from real name */
3125 tc2 = *tp2++; /* char from mask */
3126 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3127 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3130 if (tc2 == '?' && tc1 != ' ')
3137 /* we got a match */
3141 char *smb_FindMask(char *pathp)
3145 tp = strrchr(pathp, '\\'); /* find last slash */
3148 return tp+1; /* skip the slash */
3150 return pathp; /* no slash, return the entire path */
3153 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3155 unsigned char *pathp;
3157 unsigned char mask[11];
3158 unsigned char *statBlockp;
3159 unsigned char initStatBlock[21];
3162 osi_Log0(smb_logp, "SMB receive search volume");
3164 /* pull pathname and stat block out of request */
3165 tp = smb_GetSMBData(inp, NULL);
3166 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3167 osi_assert(pathp != NULL);
3168 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3169 osi_assert(statBlockp != NULL);
3171 statBlockp = initStatBlock;
3175 /* for returning to caller */
3176 smb_Get8Dot3MaskFromPath(mask, pathp);
3178 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3179 tp = smb_GetSMBData(outp, NULL);
3181 *tp++ = 43; /* bytes in a dir entry */
3182 *tp++ = 0; /* high byte in counter */
3184 /* now marshall the dir entry, starting with the search status */
3185 *tp++ = statBlockp[0]; /* Reserved */
3186 memcpy(tp, mask, 11); tp += 11; /* FileName */
3188 /* now pass back server use info, with 1st byte non-zero */
3190 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3192 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3194 *tp++ = 0x8; /* attribute: volume */
3204 /* 4 byte file size */
3210 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3211 memset(tp, ' ', 13);
3214 /* set the length of the data part of the packet to 43 + 3, for the dir
3215 * entry plus the 5 and the length fields.
3217 smb_SetSMBDataLength(outp, 46);
3221 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3222 cm_user_t *userp, cm_req_t *reqp)
3230 smb_dirListPatch_t *patchp;
3231 smb_dirListPatch_t *npatchp;
3233 for (patchp = *dirPatchespp; patchp; patchp =
3234 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3236 dptr = patchp->dptr;
3238 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3240 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3241 *dptr++ = SMB_ATTR_HIDDEN;
3244 lock_ObtainMutex(&scp->mx);
3245 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3246 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3248 lock_ReleaseMutex(&scp->mx);
3249 cm_ReleaseSCache(scp);
3250 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3251 *dptr++ = SMB_ATTR_HIDDEN;
3255 attr = smb_Attributes(scp);
3256 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3257 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3258 attr |= SMB_ATTR_HIDDEN;
3262 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3265 shortTemp = (unsigned short) (dosTime & 0xffff);
3266 *((u_short *)dptr) = shortTemp;
3269 /* and copy out date */
3270 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3271 *((u_short *)dptr) = shortTemp;
3274 /* copy out file length */
3275 *((u_long *)dptr) = scp->length.LowPart;
3277 lock_ReleaseMutex(&scp->mx);
3278 cm_ReleaseSCache(scp);
3281 /* now free the patches */
3282 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3283 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3287 /* and mark the list as empty */
3288 *dirPatchespp = NULL;
3293 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3302 smb_dirListPatch_t *dirListPatchesp;
3303 smb_dirListPatch_t *curPatchp;
3307 osi_hyper_t dirLength;
3308 osi_hyper_t bufferOffset;
3309 osi_hyper_t curOffset;
3311 unsigned char *inCookiep;
3312 smb_dirSearch_t *dsp;
3316 unsigned long clientCookie;
3317 cm_pageHeader_t *pageHeaderp;
3318 cm_user_t *userp = NULL;
3325 long nextEntryCookie;
3326 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3327 char resByte; /* reserved byte from the cookie */
3328 char *op; /* output data ptr */
3329 char *origOp; /* original value of op */
3330 cm_space_t *spacep; /* for pathname buffer */
3341 maxCount = smb_GetSMBParm(inp, 0);
3343 dirListPatchesp = NULL;
3345 caseFold = CM_FLAG_CASEFOLD;
3347 tp = smb_GetSMBData(inp, NULL);
3348 pathp = smb_ParseASCIIBlock(tp, &tp);
3349 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3351 /* bail out if request looks bad */
3352 if (!tp || !pathp) {
3353 return CM_ERROR_BADSMB;
3356 /* We can handle long names */
3357 if (vcp->flags & SMB_VCFLAG_USENT)
3358 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3360 /* make sure we got a whole search status */
3361 if (dataLength < 21) {
3362 nextCookie = 0; /* start at the beginning of the dir */
3365 attribute = smb_GetSMBParm(inp, 1);
3367 /* handle volume info in another function */
3368 if (attribute & 0x8)
3369 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3371 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3372 maxCount, osi_LogSaveString(smb_logp, pathp));
3374 if (*pathp == 0) { /* null pathp, treat as root dir */
3375 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3376 return CM_ERROR_NOFILES;
3380 dsp = smb_NewDirSearch(0);
3381 dsp->attribute = attribute;
3382 smb_Get8Dot3MaskFromPath(mask, pathp);
3383 memcpy(dsp->mask, mask, 11);
3385 /* track if this is likely to match a lot of entries */
3386 if (smb_IsStarMask(mask)) starPattern = 1;
3387 else starPattern = 0;
3390 /* pull the next cookie value out of the search status block */
3391 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3392 + (inCookiep[16]<<24);
3393 dsp = smb_FindDirSearch(inCookiep[12]);
3395 /* can't find dir search status; fatal error */
3396 return CM_ERROR_BADFD;
3398 attribute = dsp->attribute;
3399 resByte = inCookiep[0];
3401 /* copy out client cookie, in host byte order. Don't bother
3402 * interpreting it, since we're just passing it through, anyway.
3404 memcpy(&clientCookie, &inCookiep[17], 4);
3406 memcpy(mask, dsp->mask, 11);
3408 /* assume we're doing a star match if it has continued for more
3414 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3415 nextCookie, dsp->cookie, attribute);
3417 userp = smb_GetUser(vcp, inp);
3419 /* try to get the vnode for the path name next */
3420 lock_ObtainMutex(&dsp->mx);
3427 spacep = inp->spacep;
3428 smb_StripLastComponent(spacep->data, NULL, pathp);
3429 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3431 lock_ReleaseMutex(&dsp->mx);
3432 cm_ReleaseUser(userp);
3433 smb_DeleteDirSearch(dsp);
3434 smb_ReleaseDirSearch(dsp);
3435 return CM_ERROR_NOFILES;
3437 code = cm_NameI(cm_rootSCachep, spacep->data,
3438 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3441 cm_ReleaseSCache(dsp->scp);
3443 /* we need one hold for the entry we just stored into,
3444 * and one for our own processing. When we're done with this
3445 * function, we'll drop the one for our own processing.
3446 * We held it once from the namei call, and so we do another hold
3450 lock_ObtainMutex(&scp->mx);
3451 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3452 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3453 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3454 dsp->flags |= SMB_DIRSEARCH_BULKST;
3456 lock_ReleaseMutex(&scp->mx);
3459 lock_ReleaseMutex(&dsp->mx);
3461 cm_ReleaseUser(userp);
3462 smb_DeleteDirSearch(dsp);
3463 smb_ReleaseDirSearch(dsp);
3467 /* reserves space for parameter; we'll adjust it again later to the
3468 * real count of the # of entries we returned once we've actually
3469 * assembled the directory listing.
3471 smb_SetSMBParm(outp, 0, 0);
3473 /* get the directory size */
3474 lock_ObtainMutex(&scp->mx);
3475 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3476 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3478 lock_ReleaseMutex(&scp->mx);
3479 cm_ReleaseSCache(scp);
3480 cm_ReleaseUser(userp);
3481 smb_DeleteDirSearch(dsp);
3482 smb_ReleaseDirSearch(dsp);
3486 dirLength = scp->length;
3488 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3489 curOffset.HighPart = 0;
3490 curOffset.LowPart = nextCookie;
3491 origOp = op = smb_GetSMBData(outp, NULL);
3492 /* and write out the basic header */
3493 *op++ = 5; /* variable block */
3494 op += 2; /* skip vbl block length; we'll fill it in later */
3498 /* make sure that curOffset.LowPart doesn't point to the first
3499 * 32 bytes in the 2nd through last dir page, and that it doesn't
3500 * point at the first 13 32-byte chunks in the first dir page,
3501 * since those are dir and page headers, and don't contain useful
3504 temp = curOffset.LowPart & (2048-1);
3505 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3506 /* we're in the first page */
3507 if (temp < 13*32) temp = 13*32;
3510 /* we're in a later dir page */
3511 if (temp < 32) temp = 32;
3514 /* make sure the low order 5 bits are zero */
3517 /* now put temp bits back ito curOffset.LowPart */
3518 curOffset.LowPart &= ~(2048-1);
3519 curOffset.LowPart |= temp;
3521 /* check if we've returned all the names that will fit in the
3524 if (returnedNames >= maxCount)
3527 /* check if we've passed the dir's EOF */
3528 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3530 /* see if we can use the bufferp we have now; compute in which page
3531 * the current offset would be, and check whether that's the offset
3532 * of the buffer we have. If not, get the buffer.
3534 thyper.HighPart = curOffset.HighPart;
3535 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3536 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3539 buf_Release(bufferp);
3542 lock_ReleaseMutex(&scp->mx);
3543 lock_ObtainRead(&scp->bufCreateLock);
3544 code = buf_Get(scp, &thyper, &bufferp);
3545 lock_ReleaseRead(&scp->bufCreateLock);
3546 lock_ObtainMutex(&dsp->mx);
3548 /* now, if we're doing a star match, do bulk fetching of all of
3549 * the status info for files in the dir.
3552 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3553 lock_ObtainMutex(&scp->mx);
3554 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3555 LargeIntegerGreaterThanOrEqualTo(thyper,
3556 scp->bulkStatProgress)) {
3557 /* Don't bulk stat if risking timeout */
3558 int now = GetCurrentTime();
3559 if (now - req.startTime > 5000) {
3560 scp->bulkStatProgress = thyper;
3561 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3562 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3564 cm_TryBulkStat(scp, &thyper, userp, &req);
3567 lock_ObtainMutex(&scp->mx);
3569 lock_ReleaseMutex(&dsp->mx);
3573 bufferOffset = thyper;
3575 /* now get the data in the cache */
3577 code = cm_SyncOp(scp, bufferp, userp, &req,
3579 CM_SCACHESYNC_NEEDCALLBACK |
3580 CM_SCACHESYNC_READ);
3583 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3585 /* otherwise, load the buffer and try again */
3586 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3590 buf_Release(bufferp);
3594 } /* if (wrong buffer) ... */
3596 /* now we have the buffer containing the entry we're interested in; copy
3597 * it out if it represents a non-deleted entry.
3599 entryInDir = curOffset.LowPart & (2048-1);
3600 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3602 /* page header will help tell us which entries are free. Page header
3603 * can change more often than once per buffer, since AFS 3 dir page size
3604 * may be less than (but not more than a buffer package buffer.
3606 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3607 temp &= ~(2048 - 1); /* turn off intra-page bits */
3608 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3610 /* now determine which entry we're looking at in the page. If it is
3611 * free (there's a free bitmap at the start of the dir), we should
3612 * skip these 32 bytes.
3614 slotInPage = (entryInDir & 0x7e0) >> 5;
3615 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3616 /* this entry is free */
3617 numDirChunks = 1; /* only skip this guy */
3621 tp = bufferp->datap + entryInBuffer;
3622 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3624 /* while we're here, compute the next entry's location, too,
3625 * since we'll need it when writing out the cookie into the dir
3628 * XXXX Probably should do more sanity checking.
3630 numDirChunks = cm_NameEntries(dep->name, NULL);
3632 /* compute the offset of the cookie representing the next entry */
3633 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3635 /* Compute 8.3 name if necessary */
3636 actualName = dep->name;
3637 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3638 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3639 actualName = shortName;
3642 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3643 /* this is one of the entries to use: it is not deleted
3644 * and it matches the star pattern we're looking for.
3647 /* Eliminate entries that don't match requested
3650 /* no hidden files */
3651 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3654 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3656 /* We have already done the cm_TryBulkStat above */
3657 fid.cell = scp->fid.cell;
3658 fid.volume = scp->fid.volume;
3659 fid.vnode = ntohl(dep->fid.vnode);
3660 fid.unique = ntohl(dep->fid.unique);
3661 fileType = cm_FindFileType(&fid);
3662 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3663 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3665 if (fileType == CM_SCACHETYPE_DIRECTORY)
3670 memcpy(op, mask, 11); op += 11;
3671 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3672 *op++ = nextEntryCookie & 0xff;
3673 *op++ = (nextEntryCookie>>8) & 0xff;
3674 *op++ = (nextEntryCookie>>16) & 0xff;
3675 *op++ = (nextEntryCookie>>24) & 0xff;
3676 memcpy(op, &clientCookie, 4); op += 4;
3678 /* now we emit the attribute. This is sort of tricky,
3679 * since we need to really stat the file to find out
3680 * what type of entry we've got. Right now, we're
3681 * copying out data from a buffer, while holding the
3682 * scp locked, so it isn't really convenient to stat
3683 * something now. We'll put in a place holder now,
3684 * and make a second pass before returning this to get
3685 * the real attributes. So, we just skip the data for
3686 * now, and adjust it later. We allocate a patch
3687 * record to make it easy to find this point later.
3688 * The replay will happen at a time when it is safe to
3689 * unlock the directory.
3691 curPatchp = malloc(sizeof(*curPatchp));
3692 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3693 curPatchp->dptr = op;
3694 curPatchp->fid.cell = scp->fid.cell;
3695 curPatchp->fid.volume = scp->fid.volume;
3696 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3697 curPatchp->fid.unique = ntohl(dep->fid.unique);
3699 /* do hidden attribute here since name won't be around when applying
3703 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3704 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3706 curPatchp->flags = 0;
3708 op += 9; /* skip attr, time, date and size */
3710 /* zero out name area. The spec says to pad with
3711 * spaces, but Samba doesn't, and neither do we.
3715 /* finally, we get to copy out the name; we know that
3716 * it fits in 8.3 or the pattern wouldn't match, but it
3717 * never hurts to be sure.
3719 strncpy(op, actualName, 13);
3721 /* Uppercase if requested by client */
3722 if ((((smb_t *)inp)->flg2 & 1) == 0)
3727 /* now, adjust the # of entries copied */
3729 } /* if we're including this name */
3732 /* and adjust curOffset to be where the new cookie is */
3733 thyper.HighPart = 0;
3734 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3735 curOffset = LargeIntegerAdd(thyper, curOffset);
3736 } /* while copying data for dir listing */
3738 /* release the mutex */
3739 lock_ReleaseMutex(&scp->mx);
3740 if (bufferp) buf_Release(bufferp);
3742 /* apply and free last set of patches; if not doing a star match, this
3743 * will be empty, but better safe (and freeing everything) than sorry.
3745 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3747 /* special return code for unsuccessful search */
3748 if (code == 0 && dataLength < 21 && returnedNames == 0)
3749 code = CM_ERROR_NOFILES;
3751 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3752 returnedNames, code);
3755 smb_DeleteDirSearch(dsp);
3756 smb_ReleaseDirSearch(dsp);
3757 cm_ReleaseSCache(scp);
3758 cm_ReleaseUser(userp);
3762 /* finalize the output buffer */
3763 smb_SetSMBParm(outp, 0, returnedNames);
3764 temp = (long) (op - origOp);
3765 smb_SetSMBDataLength(outp, temp);
3767 /* the data area is a variable block, which has a 5 (already there)
3768 * followed by the length of the # of data bytes. We now know this to
3769 * be "temp," although that includes the 3 bytes of vbl block header.
3770 * Deduct for them and fill in the length field.
3772 temp -= 3; /* deduct vbl block info */
3773 osi_assert(temp == (43 * returnedNames));
3774 origOp[1] = temp & 0xff;
3775 origOp[2] = (temp>>8) & 0xff;
3776 if (returnedNames == 0)
3777 smb_DeleteDirSearch(dsp);
3778 smb_ReleaseDirSearch(dsp);
3779 cm_ReleaseSCache(scp);
3780 cm_ReleaseUser(userp);
3784 /* verify that this is a valid path to a directory. I don't know why they
3785 * don't use the get file attributes call.
3787 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3791 cm_scache_t *rootScp;
3792 cm_scache_t *newScp;
3801 pathp = smb_GetSMBData(inp, NULL);
3802 pathp = smb_ParseASCIIBlock(pathp, NULL);
3803 osi_Log1(smb_logp, "SMB receive check path %s",
3804 osi_LogSaveString(smb_logp, pathp));
3807 return CM_ERROR_BADFD;
3810 rootScp = cm_rootSCachep;
3812 userp = smb_GetUser(vcp, inp);
3814 caseFold = CM_FLAG_CASEFOLD;
3816 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3818 cm_ReleaseUser(userp);
3819 return CM_ERROR_NOSUCHPATH;
3821 code = cm_NameI(rootScp, pathp,
3822 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3823 userp, tidPathp, &req, &newScp);
3826 cm_ReleaseUser(userp);
3830 /* now lock the vnode with a callback; returns with newScp locked */
3831 lock_ObtainMutex(&newScp->mx);
3832 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3833 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3834 if (code && code != CM_ERROR_NOACCESS) {
3835 lock_ReleaseMutex(&newScp->mx);
3836 cm_ReleaseSCache(newScp);
3837 cm_ReleaseUser(userp);
3841 attrs = smb_Attributes(newScp);
3843 if (!(attrs & 0x10))
3844 code = CM_ERROR_NOTDIR;
3846 lock_ReleaseMutex(&newScp->mx);
3848 cm_ReleaseSCache(newScp);
3849 cm_ReleaseUser(userp);
3853 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3857 cm_scache_t *rootScp;
3858 unsigned short attribute;
3860 cm_scache_t *newScp;
3869 /* decode basic attributes we're passed */
3870 attribute = smb_GetSMBParm(inp, 0);
3871 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3873 pathp = smb_GetSMBData(inp, NULL);
3874 pathp = smb_ParseASCIIBlock(pathp, NULL);
3877 return CM_ERROR_BADSMB;
3880 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3881 dosTime, attribute);
3883 rootScp = cm_rootSCachep;
3885 userp = smb_GetUser(vcp, inp);
3887 caseFold = CM_FLAG_CASEFOLD;
3889 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3891 cm_ReleaseUser(userp);
3892 return CM_ERROR_NOSUCHFILE;
3894 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3895 tidPathp, &req, &newScp);
3898 cm_ReleaseUser(userp);
3902 /* now lock the vnode with a callback; returns with newScp locked; we
3903 * need the current status to determine what the new status is, in some
3906 lock_ObtainMutex(&newScp->mx);
3907 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3908 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3910 lock_ReleaseMutex(&newScp->mx);
3911 cm_ReleaseSCache(newScp);
3912 cm_ReleaseUser(userp);
3916 /* Check for RO volume */
3917 if (newScp->flags & CM_SCACHEFLAG_RO) {
3918 lock_ReleaseMutex(&newScp->mx);
3919 cm_ReleaseSCache(newScp);
3920 cm_ReleaseUser(userp);
3921 return CM_ERROR_READONLY;
3924 /* prepare for setattr call */
3927 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3928 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3930 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3931 /* we're told to make a writable file read-only */
3932 attr.unixModeBits = newScp->unixModeBits & ~0222;
3933 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3935 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3936 /* we're told to make a read-only file writable */
3937 attr.unixModeBits = newScp->unixModeBits | 0222;
3938 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3940 lock_ReleaseMutex(&newScp->mx);
3942 /* now call setattr */
3944 code = cm_SetAttr(newScp, &attr, userp, &req);
3948 cm_ReleaseSCache(newScp);
3949 cm_ReleaseUser(userp);
3954 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3958 cm_scache_t *rootScp;
3959 cm_scache_t *newScp, *dscp;
3971 pathp = smb_GetSMBData(inp, NULL);
3972 pathp = smb_ParseASCIIBlock(pathp, NULL);
3975 return CM_ERROR_BADSMB;
3978 if (*pathp == 0) /* null path */
3981 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3982 osi_LogSaveString(smb_logp, pathp));
3984 rootScp = cm_rootSCachep;
3986 userp = smb_GetUser(vcp, inp);
3988 /* we shouldn't need this for V3 requests, but we seem to */
3989 caseFold = CM_FLAG_CASEFOLD;
3991 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3993 cm_ReleaseUser(userp);
3994 return CM_ERROR_NOSUCHFILE;
3998 * XXX Strange hack XXX
4000 * As of Patch 5 (16 July 97), we are having the following problem:
4001 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4002 * requests to look up "desktop.ini" in all the subdirectories.
4003 * This can cause zillions of timeouts looking up non-existent cells
4004 * and volumes, especially in the top-level directory.
4006 * We have not found any way to avoid this or work around it except
4007 * to explicitly ignore the requests for mount points that haven't
4008 * yet been evaluated and for directories that haven't yet been
4011 * We should modify this hack to provide a fake desktop.ini file
4012 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4014 spacep = inp->spacep;
4015 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4016 #ifndef SPECIAL_FOLDERS
4017 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4018 code = cm_NameI(rootScp, spacep->data,
4019 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4020 userp, tidPathp, &req, &dscp);
4022 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT &&
4023 !dscp->mountRootFidp)
4024 code = CM_ERROR_NOSUCHFILE;
4025 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4026 cm_buf_t *bp = buf_Find(dscp, &hzero);
4030 code = CM_ERROR_NOSUCHFILE;
4032 cm_ReleaseSCache(dscp);
4034 cm_ReleaseUser(userp);
4039 #endif /* SPECIAL_FOLDERS */
4041 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4042 tidPathp, &req, &newScp);
4044 cm_ReleaseUser(userp);
4048 /* now lock the vnode with a callback; returns with newScp locked */
4049 lock_ObtainMutex(&newScp->mx);
4050 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4051 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4053 lock_ReleaseMutex(&newScp->mx);
4054 cm_ReleaseSCache(newScp);
4055 cm_ReleaseUser(userp);
4060 /* use smb_Attributes instead. Also the fact that a file is
4061 * in a readonly volume doesn't mean it shojuld be marked as RO
4063 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4064 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4065 attrs = SMB_ATTR_DIRECTORY;
4068 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4069 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4071 attrs = smb_Attributes(newScp);
4074 smb_SetSMBParm(outp, 0, attrs);
4076 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4077 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4078 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4079 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4080 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4081 smb_SetSMBParm(outp, 5, 0);
4082 smb_SetSMBParm(outp, 6, 0);
4083 smb_SetSMBParm(outp, 7, 0);
4084 smb_SetSMBParm(outp, 8, 0);
4085 smb_SetSMBParm(outp, 9, 0);
4086 smb_SetSMBDataLength(outp, 0);
4087 lock_ReleaseMutex(&newScp->mx);
4089 cm_ReleaseSCache(newScp);
4090 cm_ReleaseUser(userp);
4095 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4099 osi_Log0(smb_logp, "SMB receive tree disconnect");
4101 /* find the tree and free it */
4102 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4104 lock_ObtainMutex(&tidp->mx);
4105 tidp->flags |= SMB_TIDFLAG_DELETE;
4106 lock_ReleaseMutex(&tidp->mx);
4107 smb_ReleaseTID(tidp);
4113 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4131 pathp = smb_GetSMBData(inp, NULL);
4132 pathp = smb_ParseASCIIBlock(pathp, NULL);
4134 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4136 #ifdef DEBUG_VERBOSE
4140 hexpath = osi_HexifyString( pathp );
4141 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4146 share = smb_GetSMBParm(inp, 0);
4147 attribute = smb_GetSMBParm(inp, 1);
4149 spacep = inp->spacep;
4150 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4151 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4152 /* special case magic file name for receiving IOCTL requests
4153 * (since IOCTL calls themselves aren't getting through).
4155 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4156 smb_SetupIoctlFid(fidp, spacep);
4157 smb_SetSMBParm(outp, 0, fidp->fid);
4158 smb_SetSMBParm(outp, 1, 0); /* attrs */
4159 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4160 smb_SetSMBParm(outp, 3, 0);
4161 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4162 smb_SetSMBParm(outp, 5, 0x7fff);
4163 /* pass the open mode back */
4164 smb_SetSMBParm(outp, 6, (share & 0xf));
4165 smb_SetSMBDataLength(outp, 0);
4166 smb_ReleaseFID(fidp);
4170 userp = smb_GetUser(vcp, inp);
4172 caseFold = CM_FLAG_CASEFOLD;
4174 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4176 cm_ReleaseUser(userp);
4177 return CM_ERROR_NOSUCHPATH;
4179 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4180 tidPathp, &req, &scp);
4183 cm_ReleaseUser(userp);
4187 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4189 cm_ReleaseSCache(scp);
4190 cm_ReleaseUser(userp);
4194 /* don't need callback to check file type, since file types never
4195 * change, and namei and cm_Lookup all stat the object at least once on
4196 * a successful return.
4198 if (scp->fileType != CM_SCACHETYPE_FILE) {
4199 cm_ReleaseSCache(scp);
4200 cm_ReleaseUser(userp);
4201 return CM_ERROR_ISDIR;
4204 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4207 /* save a pointer to the vnode */
4210 if ((share & 0xf) == 0)
4211 fidp->flags |= SMB_FID_OPENREAD;
4212 else if ((share & 0xf) == 1)
4213 fidp->flags |= SMB_FID_OPENWRITE;
4215 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4217 lock_ObtainMutex(&scp->mx);
4218 smb_SetSMBParm(outp, 0, fidp->fid);
4219 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4220 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4221 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4222 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4223 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4224 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4225 /* pass the open mode back; XXXX add access checks */
4226 smb_SetSMBParm(outp, 6, (share & 0xf));
4227 smb_SetSMBDataLength(outp, 0);
4228 lock_ReleaseMutex(&scp->mx);
4231 cm_Open(scp, 0, userp);
4233 /* send and free packet */
4234 smb_ReleaseFID(fidp);
4235 cm_ReleaseUser(userp);
4236 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4240 typedef struct smb_unlinkRock {
4245 char *maskp; /* pointer to the star pattern */
4250 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4253 smb_unlinkRock_t *rockp;
4261 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4262 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4263 caseFold |= CM_FLAG_8DOT3;
4265 matchName = dep->name;
4266 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4268 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4269 !cm_Is8Dot3(dep->name)) {
4270 cm_Gen8Dot3Name(dep, shortName, NULL);
4271 matchName = shortName;
4272 /* 8.3 matches are always case insensitive */
4273 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4276 osi_Log1(smb_logp, "Unlinking %s",
4277 osi_LogSaveString(smb_logp, matchName));
4278 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4279 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4280 smb_NotifyChange(FILE_ACTION_REMOVED,
4281 FILE_NOTIFY_CHANGE_FILE_NAME,
4282 dscp, dep->name, NULL, TRUE);
4286 /* If we made a case sensitive exact match, we might as well quit now. */
4287 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4288 code = CM_ERROR_STOPNOW;
4296 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4305 smb_unlinkRock_t rock;
4314 attribute = smb_GetSMBParm(inp, 0);
4316 tp = smb_GetSMBData(inp, NULL);
4317 pathp = smb_ParseASCIIBlock(tp, &tp);
4319 osi_Log1(smb_logp, "SMB receive unlink %s",
4320 osi_LogSaveString(smb_logp, pathp));
4322 spacep = inp->spacep;
4323 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4325 userp = smb_GetUser(vcp, inp);
4327 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4329 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4331 cm_ReleaseUser(userp);
4332 return CM_ERROR_NOSUCHPATH;
4334 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4338 cm_ReleaseUser(userp);
4342 /* otherwise, scp points to the parent directory. */
4349 rock.maskp = smb_FindMask(pathp);
4350 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4353 thyper.HighPart = 0;
4359 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4360 * match. If that fails, we do a case insensitve match.
4362 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4363 !smb_IsStarMask(rock.maskp)) {
4364 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4367 thyper.HighPart = 0;
4368 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4373 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4375 if (code == CM_ERROR_STOPNOW)
4378 cm_ReleaseUser(userp);
4380 cm_ReleaseSCache(dscp);
4382 if (code == 0 && !rock.any)
4383 code = CM_ERROR_NOSUCHFILE;
4387 typedef struct smb_renameRock {
4388 cm_scache_t *odscp; /* old dir */
4389 cm_scache_t *ndscp; /* new dir */
4390 cm_user_t *userp; /* user */
4391 cm_req_t *reqp; /* request struct */
4392 smb_vc_t *vcp; /* virtual circuit */
4393 char *maskp; /* pointer to star pattern of old file name */
4394 int flags; /* tilde, casefold, etc */
4395 char *newNamep; /* ptr to the new file's name */
4398 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4401 smb_renameRock_t *rockp;
4406 rockp = (smb_renameRock_t *) vrockp;
4408 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4409 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4410 caseFold |= CM_FLAG_8DOT3;
4412 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4414 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4415 !cm_Is8Dot3(dep->name)) {
4416 cm_Gen8Dot3Name(dep, shortName, NULL);
4417 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4420 code = cm_Rename(rockp->odscp, dep->name,
4421 rockp->ndscp, rockp->newNamep, rockp->userp,
4423 /* if the call worked, stop doing the search now, since we
4424 * really only want to rename one file.
4427 code = CM_ERROR_STOPNOW;
4436 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4439 cm_space_t *spacep = NULL;
4440 smb_renameRock_t rock;
4441 cm_scache_t *oldDscp = NULL;
4442 cm_scache_t *newDscp = NULL;
4443 cm_scache_t *tmpscp= NULL;
4444 cm_scache_t *tmpscp2 = NULL;
4454 userp = smb_GetUser(vcp, inp);
4455 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4457 cm_ReleaseUser(userp);
4458 return CM_ERROR_NOSUCHPATH;
4462 spacep = inp->spacep;
4463 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4466 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4467 * what actually exists is foo/baz. I don't know why the code used to be
4468 * the way it was. 1/29/96
4470 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4472 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4474 * caseFold = CM_FLAG_CASEFOLD;
4476 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4477 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4478 userp, tidPathp, &req, &oldDscp);
4481 cm_ReleaseUser(userp);
4485 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4486 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4487 userp, tidPathp, &req, &newDscp);
4490 cm_ReleaseSCache(oldDscp);
4491 cm_ReleaseUser(userp);
4495 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4496 * next, get the component names, and lower case them.
4499 /* handle the old name first */
4501 oldLastNamep = oldPathp;
4505 /* and handle the new name, too */
4507 newLastNamep = newPathp;
4511 /* TODO: The old name could be a wildcard. The new name must not be */
4513 /* do the vnode call */
4514 rock.odscp = oldDscp;
4515 rock.ndscp = newDscp;
4519 rock.maskp = oldLastNamep;
4520 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4521 rock.newNamep = newLastNamep;
4523 /* Check if the file already exists; if so return error */
4524 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4525 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4526 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4527 osi_LogSaveString(afsd_logp, newLastNamep));
4529 /* Check if the old and the new names differ only in case. If so return
4530 * success, else return CM_ERROR_EXISTS
4532 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4534 /* This would be a success only if the old file is *as same as* the new file */
4535 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4537 if (tmpscp == tmpscp2)
4540 code = CM_ERROR_EXISTS;
4541 cm_ReleaseSCache(tmpscp2);
4544 code = CM_ERROR_NOSUCHFILE;
4547 /* file exist, do not rename, also fixes move */
4548 osi_Log0(smb_logp, "Can't rename. Target already exists");
4549 code = CM_ERROR_EXISTS;
4553 cm_ReleaseSCache(tmpscp);
4554 cm_ReleaseSCache(newDscp);
4555 cm_ReleaseSCache(oldDscp);
4556 cm_ReleaseUser(userp);
4560 /* Now search the directory for the pattern, and do the appropriate rename when found */
4561 thyper.LowPart = 0; /* search dir from here */
4562 thyper.HighPart = 0;
4564 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4566 if (code == CM_ERROR_STOPNOW)
4569 code = CM_ERROR_NOSUCHFILE;
4571 /* Handle Change Notification */
4573 * Being lazy, not distinguishing between files and dirs in this
4574 * filter, since we'd have to do a lookup.
4576 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4577 if (oldDscp == newDscp) {
4578 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4579 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4580 filter, oldDscp, oldLastNamep,
4581 newLastNamep, TRUE);
4583 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4584 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4585 filter, oldDscp, oldLastNamep,
4587 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4588 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4589 filter, newDscp, newLastNamep,
4594 cm_ReleaseSCache(tmpscp);
4595 cm_ReleaseUser(userp);
4596 cm_ReleaseSCache(oldDscp);
4597 cm_ReleaseSCache(newDscp);
4602 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4605 cm_space_t *spacep = NULL;
4606 cm_scache_t *oldDscp = NULL;
4607 cm_scache_t *newDscp = NULL;
4608 cm_scache_t *tmpscp= NULL;
4609 cm_scache_t *tmpscp2 = NULL;
4610 cm_scache_t *sscp = NULL;
4619 userp = smb_GetUser(vcp, inp);
4621 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4623 cm_ReleaseUser(userp);
4624 return CM_ERROR_NOSUCHPATH;
4629 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4631 spacep = inp->spacep;
4632 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4634 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4635 userp, tidPathp, &req, &oldDscp);
4637 cm_ReleaseUser(userp);
4641 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4642 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4643 userp, tidPathp, &req, &newDscp);
4645 cm_ReleaseSCache(oldDscp);
4646 cm_ReleaseUser(userp);
4650 /* Now, although we did two lookups for the two directories (because the same
4651 * directory can be referenced through different paths), we only allow hard links
4652 * within the same directory. */
4653 if (oldDscp != newDscp) {
4654 cm_ReleaseSCache(oldDscp);
4655 cm_ReleaseSCache(newDscp);
4656 cm_ReleaseUser(userp);
4657 return CM_ERROR_CROSSDEVLINK;
4660 /* handle the old name first */
4662 oldLastNamep = oldPathp;
4666 /* and handle the new name, too */
4668 newLastNamep = newPathp;
4672 /* now lookup the old name */
4673 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4674 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4676 cm_ReleaseSCache(oldDscp);
4677 cm_ReleaseSCache(newDscp);
4678 cm_ReleaseUser(userp);
4682 /* Check if the file already exists; if so return error */
4683 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4684 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4685 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4686 osi_LogSaveString(afsd_logp, newLastNamep));
4688 /* if the existing link is to the same file, then we return success */
4690 if(sscp == tmpscp) {
4693 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
4694 code = CM_ERROR_EXISTS;
4699 cm_ReleaseSCache(tmpscp);
4700 cm_ReleaseSCache(sscp);
4701 cm_ReleaseSCache(newDscp);
4702 cm_ReleaseSCache(oldDscp);
4703 cm_ReleaseUser(userp);
4707 /* now create the hardlink */
4708 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
4709 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
4710 osi_Log1(smb_logp," Link returns %d", code);
4712 /* Handle Change Notification */
4714 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
4715 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4716 smb_NotifyChange(FILE_ACTION_ADDED,
4717 filter, newDscp, newLastNamep,
4722 cm_ReleaseSCache(tmpscp);
4723 cm_ReleaseUser(userp);
4724 cm_ReleaseSCache(sscp);
4725 cm_ReleaseSCache(oldDscp);
4726 cm_ReleaseSCache(newDscp);
4731 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4737 tp = smb_GetSMBData(inp, NULL);
4738 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4739 newPathp = smb_ParseASCIIBlock(tp, &tp);
4741 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4742 osi_LogSaveString(smb_logp, oldPathp),
4743 osi_LogSaveString(smb_logp, newPathp));
4745 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
4750 typedef struct smb_rmdirRock {
4754 char *maskp; /* pointer to the star pattern */
4759 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4762 smb_rmdirRock_t *rockp;
4767 rockp = (smb_rmdirRock_t *) vrockp;
4769 matchName = dep->name;
4770 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4771 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4773 match = (strcmp(matchName, rockp->maskp) == 0);
4775 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4776 !cm_Is8Dot3(dep->name)) {
4777 cm_Gen8Dot3Name(dep, shortName, NULL);
4778 matchName = shortName;
4779 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4782 osi_Log1(smb_logp, "Removing directory %s",
4783 osi_LogSaveString(smb_logp, matchName));
4784 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4785 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4786 smb_NotifyChange(FILE_ACTION_REMOVED,
4787 FILE_NOTIFY_CHANGE_DIR_NAME,
4788 dscp, dep->name, NULL, TRUE);
4797 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4805 smb_rmdirRock_t rock;
4814 tp = smb_GetSMBData(inp, NULL);
4815 pathp = smb_ParseASCIIBlock(tp, &tp);
4817 spacep = inp->spacep;
4818 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4820 userp = smb_GetUser(vcp, inp);
4822 caseFold = CM_FLAG_CASEFOLD;
4824 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4826 cm_ReleaseUser(userp);
4827 return CM_ERROR_NOSUCHPATH;
4829 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4830 userp, tidPathp, &req, &dscp);
4833 cm_ReleaseUser(userp);
4837 /* otherwise, scp points to the parent directory. */
4844 rock.maskp = lastNamep;
4845 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4848 thyper.HighPart = 0;
4852 /* First do a case sensitive match, and if that fails, do a case insensitive match */
4853 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4854 if (code == 0 && !rock.any) {
4856 thyper.HighPart = 0;
4857 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4858 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4861 cm_ReleaseUser(userp);
4863 cm_ReleaseSCache(dscp);
4865 if (code == 0 && !rock.any)
4866 code = CM_ERROR_NOSUCHFILE;
4870 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4880 fid = smb_GetSMBParm(inp, 0);
4882 osi_Log1(smb_logp, "SMB flush fid %d", fid);
4884 fid = smb_ChainFID(fid, inp);
4885 fidp = smb_FindFID(vcp, fid, 0);
4886 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4888 smb_ReleaseFID(fidp);
4889 return CM_ERROR_BADFD;
4892 userp = smb_GetUser(vcp, inp);
4894 lock_ObtainMutex(&fidp->mx);
4895 if (fidp->flags & SMB_FID_OPENWRITE)
4896 code = cm_FSync(fidp->scp, userp, &req);
4899 lock_ReleaseMutex(&fidp->mx);
4901 smb_ReleaseFID(fidp);
4903 cm_ReleaseUser(userp);
4908 struct smb_FullNameRock {
4914 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4918 struct smb_FullNameRock *vrockp;
4920 vrockp = (struct smb_FullNameRock *)rockp;
4922 if (!cm_Is8Dot3(dep->name)) {
4923 cm_Gen8Dot3Name(dep, shortName, NULL);
4925 if (cm_stricmp(shortName, vrockp->name) == 0) {
4926 vrockp->fullName = strdup(dep->name);
4927 return CM_ERROR_STOPNOW;
4930 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
4931 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
4932 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4933 vrockp->fullName = strdup(dep->name);
4934 return CM_ERROR_STOPNOW;
4939 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4940 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4942 struct smb_FullNameRock rock;
4948 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
4949 if (code == CM_ERROR_STOPNOW)
4950 *newPathp = rock.fullName;
4952 *newPathp = strdup(pathp);
4955 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4966 fid = smb_GetSMBParm(inp, 0);
4967 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4969 osi_Log1(smb_logp, "SMB close fid %d", fid);
4971 fid = smb_ChainFID(fid, inp);
4972 fidp = smb_FindFID(vcp, fid, 0);
4974 return CM_ERROR_BADFD;
4977 userp = smb_GetUser(vcp, inp);
4979 lock_ObtainMutex(&fidp->mx);
4981 /* Don't jump the gun on an async raw write */
4982 while (fidp->raw_writers) {
4983 lock_ReleaseMutex(&fidp->mx);
4984 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4985 lock_ObtainMutex(&fidp->mx);
4988 fidp->flags |= SMB_FID_DELETE;
4990 /* watch for ioctl closes, and read-only opens */
4991 if (fidp->scp != NULL &&
4992 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4993 == SMB_FID_OPENWRITE) {
4994 if (dosTime != 0 && dosTime != -1) {
4995 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4996 /* This fixes defect 10958 */
4997 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4998 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5000 code = cm_FSync(fidp->scp, userp, &req);
5005 if (fidp->flags & SMB_FID_DELONCLOSE) {
5006 cm_scache_t *dscp = fidp->NTopen_dscp;
5007 char *pathp = fidp->NTopen_pathp;
5010 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5011 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5012 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5013 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5014 smb_NotifyChange(FILE_ACTION_REMOVED,
5015 FILE_NOTIFY_CHANGE_DIR_NAME,
5016 dscp, fullPathp, NULL, TRUE);
5020 code = cm_Unlink(dscp, fullPathp, userp, &req);
5021 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5022 smb_NotifyChange(FILE_ACTION_REMOVED,
5023 FILE_NOTIFY_CHANGE_FILE_NAME,
5024 dscp, fullPathp, NULL, TRUE);
5028 lock_ReleaseMutex(&fidp->mx);
5030 if (fidp->flags & SMB_FID_NTOPEN) {
5031 cm_ReleaseSCache(fidp->NTopen_dscp);
5032 free(fidp->NTopen_pathp);
5034 if (fidp->NTopen_wholepathp)
5035 free(fidp->NTopen_wholepathp);
5037 smb_ReleaseFID(fidp);
5038 cm_ReleaseUser(userp);
5043 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5046 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5047 cm_user_t *userp, long *readp)
5049 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5050 cm_user_t *userp, long *readp, int dosflag)
5057 osi_hyper_t fileLength;
5059 osi_hyper_t lastByte;
5060 osi_hyper_t bufferOffset;
5061 long bufIndex, nbytes;
5071 lock_ObtainMutex(&fidp->mx);
5073 lock_ObtainMutex(&scp->mx);
5075 if (offset.HighPart == 0) {
5076 chunk = offset.LowPart >> cm_logChunkSize;
5077 if (chunk != fidp->curr_chunk) {
5078 fidp->prev_chunk = fidp->curr_chunk;
5079 fidp->curr_chunk = chunk;
5081 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5085 /* start by looking up the file's end */
5086 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5087 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5088 if (code) goto done;
5090 /* now we have the entry locked, look up the length */
5091 fileLength = scp->length;
5093 /* adjust count down so that it won't go past EOF */
5094 thyper.LowPart = count;
5095 thyper.HighPart = 0;
5096 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5098 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5099 /* we'd read past EOF, so just stop at fileLength bytes.
5100 * Start by computing how many bytes remain in the file.
5102 thyper = LargeIntegerSubtract(fileLength, offset);
5104 /* if we are past EOF, read 0 bytes */
5105 if (LargeIntegerLessThanZero(thyper))
5108 count = thyper.LowPart;
5113 /* now, copy the data one buffer at a time,
5114 * until we've filled the request packet
5117 /* if we've copied all the data requested, we're done */
5118 if (count <= 0) break;
5120 /* otherwise, load up a buffer of data */
5121 thyper.HighPart = offset.HighPart;
5122 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5123 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5126 buf_Release(bufferp);
5129 lock_ReleaseMutex(&scp->mx);
5131 lock_ObtainRead(&scp->bufCreateLock);
5132 code = buf_Get(scp, &thyper, &bufferp);
5133 lock_ReleaseRead(&scp->bufCreateLock);
5135 lock_ObtainMutex(&scp->mx);
5136 if (code) goto done;
5137 bufferOffset = thyper;
5139 /* now get the data in the cache */
5141 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5142 CM_SCACHESYNC_NEEDCALLBACK |
5143 CM_SCACHESYNC_READ);
5144 if (code) goto done;
5146 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5148 /* otherwise, load the buffer and try again */
5149 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5153 buf_Release(bufferp);
5157 } /* if (wrong buffer) ... */
5159 /* now we have the right buffer loaded. Copy out the
5160 * data from here to the user's buffer.
5162 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5164 /* and figure out how many bytes we want from this buffer */
5165 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5166 if (nbytes > count) nbytes = count; /* don't go past EOF */
5168 /* now copy the data */
5171 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5174 memcpy(op, bufferp->datap + bufIndex, nbytes);
5176 /* adjust counters, pointers, etc. */
5179 thyper.LowPart = nbytes;
5180 thyper.HighPart = 0;
5181 offset = LargeIntegerAdd(thyper, offset);
5185 lock_ReleaseMutex(&scp->mx);
5186 lock_ReleaseMutex(&fidp->mx);
5188 buf_Release(bufferp);
5190 if (code == 0 && sequential)
5191 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5197 * smb_WriteData -- common code for Write and Raw Write
5200 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5201 cm_user_t *userp, long *writtenp)
5203 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5204 cm_user_t *userp, long *writtenp, int dosflag)
5211 osi_hyper_t fileLength; /* file's length at start of write */
5212 osi_hyper_t minLength; /* don't read past this */
5213 long nbytes; /* # of bytes to transfer this iteration */
5215 osi_hyper_t thyper; /* hyper tmp variable */
5216 osi_hyper_t bufferOffset;
5217 long bufIndex; /* index in buffer where our data is */
5219 osi_hyper_t writeBackOffset;/* offset of region to write back when
5224 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5225 fidp->fid, offsetp->LowPart, count);
5235 lock_ObtainMutex(&fidp->mx);
5237 lock_ObtainMutex(&scp->mx);
5239 /* start by looking up the file's end */
5240 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5242 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5243 CM_SCACHESYNC_NEEDCALLBACK
5244 | CM_SCACHESYNC_SETSTATUS
5245 | CM_SCACHESYNC_GETSTATUS);
5246 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5251 /* make sure we have a writable FD */
5252 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5253 code = CM_ERROR_BADFDOP;
5257 /* now we have the entry locked, look up the length */
5258 fileLength = scp->length;
5259 minLength = fileLength;
5260 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5261 minLength = scp->serverLength;
5263 /* adjust file length if we extend past EOF */
5264 thyper.LowPart = count;
5265 thyper.HighPart = 0;
5266 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5267 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5268 /* we'd write past EOF, so extend the file */
5269 scp->mask |= CM_SCACHEMASK_LENGTH;
5270 scp->length = thyper;
5271 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5273 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5275 /* now, if the new position (thyper) and the old (offset) are in
5276 * different storeback windows, remember to store back the previous
5277 * storeback window when we're done with the write.
5279 if ((thyper.LowPart & (-cm_chunkSize)) !=
5280 (offset.LowPart & (-cm_chunkSize))) {
5281 /* they're different */
5283 writeBackOffset.HighPart = offset.HighPart;
5284 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5289 /* now, copy the data one buffer at a time, until we've filled the
5292 /* if we've copied all the data requested, we're done */
5296 /* handle over quota or out of space */
5297 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5298 *writtenp = written;
5299 code = CM_ERROR_QUOTA;
5303 /* otherwise, load up a buffer of data */
5304 thyper.HighPart = offset.HighPart;
5305 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5306 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5309 lock_ReleaseMutex(&bufferp->mx);
5310 buf_Release(bufferp);
5313 lock_ReleaseMutex(&scp->mx);
5315 lock_ObtainRead(&scp->bufCreateLock);
5316 code = buf_Get(scp, &thyper, &bufferp);
5317 lock_ReleaseRead(&scp->bufCreateLock);
5319 lock_ObtainMutex(&bufferp->mx);
5320 lock_ObtainMutex(&scp->mx);
5321 if (code) goto done;
5323 bufferOffset = thyper;
5325 /* now get the data in the cache */
5327 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5329 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5330 CM_SCACHESYNC_NEEDCALLBACK
5331 | CM_SCACHESYNC_WRITE
5332 | CM_SCACHESYNC_BUFLOCKED);
5333 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5338 /* If we're overwriting the entire buffer, or
5339 * if we're writing at or past EOF, mark the
5340 * buffer as current so we don't call
5341 * cm_GetBuffer. This skips the fetch from the
5342 * server in those cases where we're going to
5343 * obliterate all the data in the buffer anyway,
5344 * or in those cases where there is no useful
5345 * data at the server to start with.
5347 * Use minLength instead of scp->length, since
5348 * the latter has already been updated by this
5351 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5352 || LargeIntegerEqualTo(offset, bufferp->offset)
5353 && (count >= buf_bufferSize
5354 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5355 ConvertLongToLargeInteger(count)),
5357 if (count < buf_bufferSize
5358 && bufferp->dataVersion == -1)
5359 memset(bufferp->datap, 0,
5361 bufferp->dataVersion = scp->dataVersion;
5364 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5366 /* otherwise, load the buffer and try again */
5367 lock_ReleaseMutex(&bufferp->mx);
5368 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5370 lock_ReleaseMutex(&scp->mx);
5371 lock_ObtainMutex(&bufferp->mx);
5372 lock_ObtainMutex(&scp->mx);
5376 lock_ReleaseMutex(&bufferp->mx);
5377 buf_Release(bufferp);
5381 } /* if (wrong buffer) ... */
5383 /* now we have the right buffer loaded. Copy out the
5384 * data from here to the user's buffer.
5386 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5388 /* and figure out how many bytes we want from this buffer */
5389 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5391 nbytes = count; /* don't go past end of request */
5393 /* now copy the data */
5396 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5399 memcpy(bufferp->datap + bufIndex, op, nbytes);
5400 buf_SetDirty(bufferp);
5402 /* and record the last writer */
5403 if (bufferp->userp != userp) {
5406 cm_ReleaseUser(bufferp->userp);
5407 bufferp->userp = userp;
5410 /* adjust counters, pointers, etc. */
5414 thyper.LowPart = nbytes;
5415 thyper.HighPart = 0;
5416 offset = LargeIntegerAdd(thyper, offset);
5420 lock_ReleaseMutex(&scp->mx);
5421 lock_ReleaseMutex(&fidp->mx);
5423 lock_ReleaseMutex(&bufferp->mx);
5424 buf_Release(bufferp);
5427 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5428 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5429 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5430 fidp->NTopen_dscp, fidp->NTopen_pathp,
5434 if (code == 0 && doWriteBack) {
5436 lock_ObtainMutex(&scp->mx);
5437 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5439 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5440 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5442 lock_ReleaseMutex(&scp->mx);
5443 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5444 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5447 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5448 fidp->fid, code, *writtenp);
5452 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5455 long count, written = 0, total_written = 0;
5460 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5462 int inDataBlockCount;
5464 fd = smb_GetSMBParm(inp, 0);
5465 count = smb_GetSMBParm(inp, 1);
5466 offset.HighPart = 0; /* too bad */
5467 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5469 op = smb_GetSMBData(inp, NULL);
5470 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5472 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5473 fd, offset.LowPart, count);
5475 fd = smb_ChainFID(fd, inp);
5476 fidp = smb_FindFID(vcp, fd, 0);
5478 return CM_ERROR_BADFD;
5481 if (fidp->flags & SMB_FID_IOCTL)
5482 return smb_IoctlWrite(fidp, vcp, inp, outp);
5484 userp = smb_GetUser(vcp, inp);
5486 /* special case: 0 bytes transferred means truncate to this position */
5492 truncAttr.mask = CM_ATTRMASK_LENGTH;
5493 truncAttr.length.LowPart = offset.LowPart;
5494 truncAttr.length.HighPart = 0;
5495 lock_ObtainMutex(&fidp->mx);
5496 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5497 lock_ReleaseMutex(&fidp->mx);
5498 smb_SetSMBParm(outp, 0, /* count */ 0);
5499 smb_SetSMBDataLength(outp, 0);
5500 fidp->flags |= SMB_FID_LENGTHSETDONE;
5505 * Work around bug in NT client
5507 * When copying a file, the NT client should first copy the data,
5508 * then copy the last write time. But sometimes the NT client does
5509 * these in the wrong order, so the data copies would inadvertently
5510 * cause the last write time to be overwritten. We try to detect this,
5511 * and don't set client mod time if we think that would go against the
5514 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5515 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5516 fidp->scp->clientModTime = time(NULL);
5520 while ( code == 0 && count > 0 ) {
5522 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5524 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5526 if (code == 0 && written == 0)
5527 code = CM_ERROR_PARTIALWRITE;
5529 offset.LowPart += written;
5531 total_written += written;
5535 /* set the packet data length to 3 bytes for the data block header,
5536 * plus the size of the data.
5538 smb_SetSMBParm(outp, 0, total_written);
5539 smb_SetSMBDataLength(outp, 0);
5542 smb_ReleaseFID(fidp);
5543 cm_ReleaseUser(userp);
5548 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5549 NCB *ncbp, raw_write_cont_t *rwcp)
5562 fd = smb_GetSMBParm(inp, 0);
5563 fidp = smb_FindFID(vcp, fd, 0);
5565 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5566 rwcp->offset.LowPart, rwcp->count);
5568 userp = smb_GetUser(vcp, inp);
5572 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5575 rawBuf = (dos_ptr) rwcp->buf;
5576 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5577 (unsigned char *) rawBuf, userp,
5581 if (rwcp->writeMode & 0x1) { /* synchronous */
5584 smb_FormatResponsePacket(vcp, inp, outp);
5585 op = (smb_t *) outp;
5586 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5587 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5588 smb_SetSMBDataLength(outp, 0);
5589 smb_SendPacket(vcp, outp);
5590 smb_FreePacket(outp);
5592 else { /* asynchronous */
5593 lock_ObtainMutex(&fidp->mx);
5594 fidp->raw_writers--;
5595 if (fidp->raw_writers == 0)
5596 thrd_SetEvent(fidp->raw_write_event);
5597 lock_ReleaseMutex(&fidp->mx);
5600 /* Give back raw buffer */
5601 lock_ObtainMutex(&smb_RawBufLock);
5603 *((char **)rawBuf) = smb_RawBufs;
5605 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5607 smb_RawBufs = rawBuf;
5608 lock_ReleaseMutex(&smb_RawBufLock);
5610 smb_ReleaseFID(fidp);
5611 cm_ReleaseUser(userp);
5614 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5619 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5622 long count, written = 0, total_written = 0;
5629 unsigned short writeMode;
5636 fd = smb_GetSMBParm(inp, 0);
5637 totalCount = smb_GetSMBParm(inp, 1);
5638 count = smb_GetSMBParm(inp, 10);
5639 offset.HighPart = 0; /* too bad */
5640 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5641 writeMode = smb_GetSMBParm(inp, 7);
5643 op = (char *) inp->data;
5644 op += smb_GetSMBParm(inp, 11);
5647 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5648 fd, offset.LowPart, count, writeMode);
5650 fd = smb_ChainFID(fd, inp);
5651 fidp = smb_FindFID(vcp, fd, 0);
5653 return CM_ERROR_BADFD;
5656 userp = smb_GetUser(vcp, inp);
5659 * Work around bug in NT client
5661 * When copying a file, the NT client should first copy the data,
5662 * then copy the last write time. But sometimes the NT client does
5663 * these in the wrong order, so the data copies would inadvertently
5664 * cause the last write time to be overwritten. We try to detect this,
5665 * and don't set client mod time if we think that would go against the
5668 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5669 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5670 fidp->scp->clientModTime = time(NULL);
5674 while ( code == 0 && count > 0 ) {
5676 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5678 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5680 if (code == 0 && written == 0)
5681 code = CM_ERROR_PARTIALWRITE;
5683 offset.LowPart += written;
5685 total_written += written;
5689 /* Get a raw buffer */
5692 lock_ObtainMutex(&smb_RawBufLock);
5694 /* Get a raw buf, from head of list */
5695 rawBuf = smb_RawBufs;
5697 smb_RawBufs = *(char **)smb_RawBufs;
5699 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5703 code = CM_ERROR_USESTD;
5705 lock_ReleaseMutex(&smb_RawBufLock);
5708 /* Don't allow a premature Close */
5709 if (code == 0 && (writeMode & 1) == 0) {
5710 lock_ObtainMutex(&fidp->mx);
5711 fidp->raw_writers++;
5712 thrd_ResetEvent(fidp->raw_write_event);
5713 lock_ReleaseMutex(&fidp->mx);
5716 smb_ReleaseFID(fidp);
5717 cm_ReleaseUser(userp);
5720 smb_SetSMBParm(outp, 0, total_written);
5721 smb_SetSMBDataLength(outp, 0);
5722 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5729 rwcp->offset.HighPart = 0;
5730 rwcp->offset.LowPart = offset.LowPart + count;
5731 rwcp->count = totalCount - count;
5732 rwcp->writeMode = writeMode;
5733 rwcp->alreadyWritten = total_written;
5735 /* set the packet data length to 3 bytes for the data block header,
5736 * plus the size of the data.
5738 smb_SetSMBParm(outp, 0, 0xffff);
5739 smb_SetSMBDataLength(outp, 0);
5744 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5747 long count, finalCount;
5754 fd = smb_GetSMBParm(inp, 0);
5755 count = smb_GetSMBParm(inp, 1);
5756 offset.HighPart = 0; /* too bad */
5757 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5759 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5760 fd, offset.LowPart, count);
5762 fd = smb_ChainFID(fd, inp);
5763 fidp = smb_FindFID(vcp, fd, 0);
5765 return CM_ERROR_BADFD;
5768 if (fidp->flags & SMB_FID_IOCTL) {
5769 return smb_IoctlRead(fidp, vcp, inp, outp);
5772 userp = smb_GetUser(vcp, inp);
5774 /* remember this for final results */
5775 smb_SetSMBParm(outp, 0, count);
5776 smb_SetSMBParm(outp, 1, 0);
5777 smb_SetSMBParm(outp, 2, 0);
5778 smb_SetSMBParm(outp, 3, 0);
5779 smb_SetSMBParm(outp, 4, 0);
5781 /* set the packet data length to 3 bytes for the data block header,
5782 * plus the size of the data.
5784 smb_SetSMBDataLength(outp, count+3);
5786 /* get op ptr after putting in the parms, since otherwise we don't
5787 * know where the data really is.
5789 op = smb_GetSMBData(outp, NULL);
5791 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5792 *op++ = 1; /* data block marker */
5793 *op++ = (unsigned char) (count & 0xff);
5794 *op++ = (unsigned char) ((count >> 8) & 0xff);
5797 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5799 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5802 /* fix some things up */
5803 smb_SetSMBParm(outp, 0, finalCount);
5804 smb_SetSMBDataLength(outp, finalCount+3);
5806 smb_ReleaseFID(fidp);
5808 cm_ReleaseUser(userp);
5812 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5819 cm_scache_t *dscp; /* dir we're dealing with */
5820 cm_scache_t *scp; /* file we're creating */
5822 int initialModeBits;
5832 /* compute initial mode bits based on read-only flag in attributes */
5833 initialModeBits = 0777;
5835 tp = smb_GetSMBData(inp, NULL);
5836 pathp = smb_ParseASCIIBlock(tp, &tp);
5838 if (strcmp(pathp, "\\") == 0)
5839 return CM_ERROR_EXISTS;
5841 spacep = inp->spacep;
5842 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5844 userp = smb_GetUser(vcp, inp);
5846 caseFold = CM_FLAG_CASEFOLD;
5848 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5850 cm_ReleaseUser(userp);
5851 return CM_ERROR_NOSUCHPATH;
5854 code = cm_NameI(cm_rootSCachep, spacep->data,
5855 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5856 userp, tidPathp, &req, &dscp);
5859 cm_ReleaseUser(userp);
5863 /* otherwise, scp points to the parent directory. Do a lookup, and
5864 * fail if we find it. Otherwise, we do the create.
5870 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5871 if (scp) cm_ReleaseSCache(scp);
5872 if (code != CM_ERROR_NOSUCHFILE) {
5873 if (code == 0) code = CM_ERROR_EXISTS;
5874 cm_ReleaseSCache(dscp);
5875 cm_ReleaseUser(userp);
5879 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5880 setAttr.clientModTime = time(NULL);
5881 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5882 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5883 smb_NotifyChange(FILE_ACTION_ADDED,
5884 FILE_NOTIFY_CHANGE_DIR_NAME,
5885 dscp, lastNamep, NULL, TRUE);
5887 /* we don't need this any longer */
5888 cm_ReleaseSCache(dscp);
5891 /* something went wrong creating or truncating the file */
5892 cm_ReleaseUser(userp);
5896 /* otherwise we succeeded */
5897 smb_SetSMBDataLength(outp, 0);
5898 cm_ReleaseUser(userp);
5903 BOOL smb_IsLegalFilename(char *filename)
5906 * Find the longest substring of filename that does not contain
5907 * any of the chars in illegalChars. If that substring is less
5908 * than the length of the whole string, then one or more of the
5909 * illegal chars is in filename.
5911 if (strcspn(filename, illegalChars) < strlen(filename))
5917 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5925 cm_scache_t *dscp; /* dir we're dealing with */
5926 cm_scache_t *scp; /* file we're creating */
5928 int initialModeBits;
5940 excl = (inp->inCom == 0x03)? 0 : 1;
5942 attributes = smb_GetSMBParm(inp, 0);
5943 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5945 /* compute initial mode bits based on read-only flag in attributes */
5946 initialModeBits = 0666;
5947 if (attributes & 1) initialModeBits &= ~0222;
5949 tp = smb_GetSMBData(inp, NULL);
5950 pathp = smb_ParseASCIIBlock(tp, &tp);
5952 spacep = inp->spacep;
5953 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5955 userp = smb_GetUser(vcp, inp);
5957 caseFold = CM_FLAG_CASEFOLD;
5959 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5961 cm_ReleaseUser(userp);
5962 return CM_ERROR_NOSUCHPATH;
5964 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5965 userp, tidPathp, &req, &dscp);
5968 cm_ReleaseUser(userp);
5972 /* otherwise, scp points to the parent directory. Do a lookup, and
5973 * truncate the file if we find it, otherwise we create the file.
5975 if (!lastNamep) lastNamep = pathp;
5978 if (!smb_IsLegalFilename(lastNamep))
5979 return CM_ERROR_BADNTFILENAME;
5981 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5982 #ifdef DEBUG_VERBOSE
5985 hexp = osi_HexifyString( lastNamep );
5986 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5991 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5992 if (code && code != CM_ERROR_NOSUCHFILE) {
5993 cm_ReleaseSCache(dscp);
5994 cm_ReleaseUser(userp);
5998 /* if we get here, if code is 0, the file exists and is represented by
5999 * scp. Otherwise, we have to create it.
6003 /* oops, file shouldn't be there */
6004 cm_ReleaseSCache(dscp);
6005 cm_ReleaseSCache(scp);
6006 cm_ReleaseUser(userp);
6007 return CM_ERROR_EXISTS;
6010 setAttr.mask = CM_ATTRMASK_LENGTH;
6011 setAttr.length.LowPart = 0;
6012 setAttr.length.HighPart = 0;
6013 code = cm_SetAttr(scp, &setAttr, userp, &req);
6016 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6017 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6018 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6020 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6021 smb_NotifyChange(FILE_ACTION_ADDED,
6022 FILE_NOTIFY_CHANGE_FILE_NAME,
6023 dscp, lastNamep, NULL, TRUE);
6024 if (!excl && code == CM_ERROR_EXISTS) {
6025 /* not an exclusive create, and someone else tried
6026 * creating it already, then we open it anyway. We
6027 * don't bother retrying after this, since if this next
6028 * fails, that means that the file was deleted after
6029 * we started this call.
6031 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6034 setAttr.mask = CM_ATTRMASK_LENGTH;
6035 setAttr.length.LowPart = 0;
6036 setAttr.length.HighPart = 0;
6037 code = cm_SetAttr(scp, &setAttr, userp, &req);
6042 /* we don't need this any longer */
6043 cm_ReleaseSCache(dscp);
6046 /* something went wrong creating or truncating the file */
6047 if (scp) cm_ReleaseSCache(scp);
6048 cm_ReleaseUser(userp);
6052 /* make sure we only open files */
6053 if (scp->fileType != CM_SCACHETYPE_FILE) {
6054 cm_ReleaseSCache(scp);
6055 cm_ReleaseUser(userp);
6056 return CM_ERROR_ISDIR;
6059 /* now all we have to do is open the file itself */
6060 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6063 /* save a pointer to the vnode */
6066 /* always create it open for read/write */
6067 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6069 smb_ReleaseFID(fidp);
6071 smb_SetSMBParm(outp, 0, fidp->fid);
6072 smb_SetSMBDataLength(outp, 0);
6074 cm_Open(scp, 0, userp);
6076 cm_ReleaseUser(userp);
6077 /* leave scp held since we put it in fidp->scp */
6081 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6094 fd = smb_GetSMBParm(inp, 0);
6095 whence = smb_GetSMBParm(inp, 1);
6096 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6098 /* try to find the file descriptor */
6099 fd = smb_ChainFID(fd, inp);
6100 fidp = smb_FindFID(vcp, fd, 0);
6101 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6102 return CM_ERROR_BADFD;
6105 userp = smb_GetUser(vcp, inp);
6107 lock_ObtainMutex(&fidp->mx);
6109 lock_ObtainMutex(&scp->mx);
6110 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6111 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6114 /* offset from current offset */
6115 offset += fidp->offset;
6117 else if (whence == 2) {
6118 /* offset from current EOF */
6119 offset += scp->length.LowPart;
6121 fidp->offset = offset;
6122 smb_SetSMBParm(outp, 0, offset & 0xffff);
6123 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6124 smb_SetSMBDataLength(outp, 0);
6126 lock_ReleaseMutex(&scp->mx);
6127 lock_ReleaseMutex(&fidp->mx);
6128 smb_ReleaseFID(fidp);
6129 cm_ReleaseUser(userp);
6133 /* dispatch all of the requests received in a packet. Due to chaining, this may
6134 * be more than one request.
6136 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6137 NCB *ncbp, raw_write_cont_t *rwcp)
6141 unsigned long code = 0;
6142 unsigned char *outWctp;
6143 int nparms; /* # of bytes of parameters */
6145 int nbytes; /* bytes of data, excluding count */
6148 unsigned short errCode;
6149 unsigned long NTStatus;
6151 unsigned char errClass;
6152 unsigned int oldGen;
6153 DWORD oldTime, newTime;
6155 /* get easy pointer to the data */
6156 smbp = (smb_t *) inp->data;
6158 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6159 /* setup the basic parms for the initial request in the packet */
6160 inp->inCom = smbp->com;
6161 inp->wctp = &smbp->wct;
6163 inp->ncb_length = ncbp->ncb_length;
6168 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6169 /* log it and discard it */
6174 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6175 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6177 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6178 1, ncbp->ncb_length, ptbuf, inp);
6179 DeregisterEventSource(h);
6181 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6186 /* We are an ongoing op */
6187 thrd_Increment(&ongoingOps);
6189 /* set up response packet for receiving output */
6190 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6191 smb_FormatResponsePacket(vcp, inp, outp);
6192 outWctp = outp->wctp;
6194 /* Remember session generation number and time */
6195 oldGen = sessionGen;
6196 oldTime = GetCurrentTime();
6198 while (inp->inCom != 0xff) {
6199 dp = &smb_dispatchTable[inp->inCom];
6201 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6202 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6203 code = outp->resumeCode;
6207 /* process each request in the packet; inCom, wctp and inCount
6208 * are already set up.
6210 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6213 /* now do the dispatch */
6214 /* start by formatting the response record a little, as a default */
6215 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6217 outWctp[1] = 0xff; /* no operation */
6218 outWctp[2] = 0; /* padding */
6223 /* not a chained request, this is a more reasonable default */
6224 outWctp[0] = 0; /* wct of zero */
6225 outWctp[1] = 0; /* and bcc (word) of zero */
6229 /* once set, stays set. Doesn't matter, since we never chain
6230 * "no response" calls.
6232 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6236 /* we have a recognized operation */
6238 if (inp->inCom == 0x1d)
6240 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6243 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6244 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
6245 code = (*(dp->procp)) (vcp, inp, outp);
6246 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6247 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6249 if ( code == CM_ERROR_BADSMB ||
6250 code == CM_ERROR_BADOP )
6252 #endif /* LOG_PACKET */
6255 if (oldGen != sessionGen) {
6260 newTime = GetCurrentTime();
6261 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6262 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6263 newTime - oldTime, ncbp->ncb_length);
6265 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6266 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6267 DeregisterEventSource(h);
6269 osi_Log1(smb_logp, "Pkt straddled session startup, "
6270 "ncb length %d", ncbp->ncb_length);
6274 /* bad opcode, fail the request, after displaying it */
6275 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6278 #endif /* LOG_PACKET */
6282 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6283 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6284 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6285 if (code == IDCANCEL)
6289 code = CM_ERROR_BADOP;
6292 /* catastrophic failure: log as much as possible */
6293 if (code == CM_ERROR_BADSMB) {
6300 "Invalid SMB, ncb_length %d",
6303 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6304 sprintf(s, "Invalid SMB message, length %d",
6307 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6308 1, ncbp->ncb_length, ptbuf, smbp);
6309 DeregisterEventSource(h);
6312 #endif /* LOG_PACKET */
6314 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6317 code = CM_ERROR_INVAL;
6320 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6321 thrd_Decrement(&ongoingOps);
6326 /* now, if we failed, turn the current response into an empty
6327 * one, and fill in the response packet's error code.
6330 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6331 smb_MapNTError(code, &NTStatus);
6332 outWctp = outp->wctp;
6333 smbp = (smb_t *) &outp->data;
6334 if (code != CM_ERROR_PARTIALWRITE
6335 && code != CM_ERROR_BUFFERTOOSMALL
6336 && code != CM_ERROR_GSSCONTINUE) {
6337 /* nuke wct and bcc. For a partial
6338 * write or an in-process authentication handshake,
6339 * assume they're OK.
6345 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6346 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6347 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6348 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6349 smbp->flg2 |= 0x4000;
6353 smb_MapCoreError(code, vcp, &errCode, &errClass);
6354 outWctp = outp->wctp;
6355 smbp = (smb_t *) &outp->data;
6356 if (code != CM_ERROR_PARTIALWRITE) {
6357 /* nuke wct and bcc. For a partial
6358 * write, assume they're OK.
6364 smbp->errLow = (unsigned char) (errCode & 0xff);
6365 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6366 smbp->rcls = errClass;
6369 } /* error occurred */
6371 /* if we're here, we've finished one request. Look to see if
6372 * this is a chained opcode. If it is, setup things to process
6373 * the chained request, and setup the output buffer to hold the
6374 * chained response. Start by finding the next input record.
6376 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6377 break; /* not a chained req */
6378 tp = inp->wctp; /* points to start of last request */
6379 /* in a chained request, the first two
6380 * parm fields are required, and are
6381 * AndXCommand/AndXReserved and
6383 if (tp[0] < 2) break;
6384 if (tp[1] == 0xff) break; /* no more chained opcodes */
6386 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6389 /* and now append the next output request to the end of this
6390 * last request. Begin by finding out where the last response
6391 * ends, since that's where we'll put our new response.
6393 outWctp = outp->wctp; /* ptr to out parameters */
6394 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6395 nparms = outWctp[0] << 1;
6396 tp = outWctp + nparms + 1; /* now points to bcc field */
6397 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6398 tp += 2 /* for the count itself */ + nbytes;
6399 /* tp now points to the new output record; go back and patch the
6400 * second parameter (off2) to point to the new record.
6402 temp = (unsigned int)tp - ((unsigned int) outp->data);
6403 outWctp[3] = (unsigned char) (temp & 0xff);
6404 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6405 outWctp[2] = 0; /* padding */
6406 outWctp[1] = inp->inCom; /* next opcode */
6408 /* finally, setup for the next iteration */
6411 } /* while loop over all requests in the packet */
6413 /* done logging out, turn off logging-out flag */
6414 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6415 vcp->justLoggedOut = NULL;
6418 free(loggedOutName);
6419 loggedOutName = NULL;
6420 smb_ReleaseUID(loggedOutUserp);
6421 loggedOutUserp = NULL;
6425 /* now send the output packet, and return */
6427 smb_SendPacket(vcp, outp);
6428 thrd_Decrement(&ongoingOps);
6430 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6432 smb_ReleaseVC(active_vcp);
6434 "Replacing active_vcp %x with %x", active_vcp, vcp);
6438 last_msg_time = GetCurrentTime();
6440 else if (active_vcp == vcp) {
6441 smb_ReleaseVC(active_vcp);
6449 /* Wait for Netbios() calls to return, and make the results available to server
6450 * threads. Note that server threads can't wait on the NCBevents array
6451 * themselves, because NCB events are manual-reset, and the servers would race
6452 * each other to reset them.
6454 void smb_ClientWaiter(void *parmp)
6460 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6462 if (code == WAIT_OBJECT_0) {
6463 if (smbShutdownFlag == 1)
6469 /* error checking */
6470 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6472 int abandonIdx = code - WAIT_ABANDONED_0;
6473 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6476 if (code == WAIT_IO_COMPLETION)
6478 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6482 if (code == WAIT_TIMEOUT)
6484 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6487 if (code == WAIT_FAILED)
6489 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6492 idx = code - WAIT_OBJECT_0;
6494 /* check idx range! */
6495 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6497 /* this is fatal - log as much as possible */
6498 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6502 thrd_ResetEvent(NCBevents[idx]);
6503 thrd_SetEvent(NCBreturns[0][idx]);
6509 * Try to have one NCBRECV request waiting for every live session. Not more
6510 * than one, because if there is more than one, it's hard to handle Write Raw.
6512 void smb_ServerWaiter(void *parmp)
6515 int idx_session, idx_NCB;
6523 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6525 if (code == WAIT_OBJECT_0) {
6526 if ( smbShutdownFlag == 1 )
6532 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6534 int abandonIdx = code - WAIT_ABANDONED_0;
6535 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6538 if (code == WAIT_IO_COMPLETION)
6540 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6544 if (code == WAIT_TIMEOUT)
6546 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6549 if (code == WAIT_FAILED)
6551 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6554 idx_session = code - WAIT_OBJECT_0;
6556 /* check idx range! */
6557 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6559 /* this is fatal - log as much as possible */
6560 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6566 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6568 if (code == WAIT_OBJECT_0) {
6569 if ( smbShutdownFlag == 1 )
6575 /* error checking */
6576 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6578 int abandonIdx = code - WAIT_ABANDONED_0;
6579 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6582 if (code == WAIT_IO_COMPLETION)
6584 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6588 if (code == WAIT_TIMEOUT)
6590 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6593 if (code == WAIT_FAILED)
6595 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6598 idx_NCB = code - WAIT_OBJECT_0;
6600 /* check idx range! */
6601 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6603 /* this is fatal - log as much as possible */
6604 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6608 /* Link them together */
6609 NCBsessions[idx_NCB] = idx_session;
6612 ncbp = NCBs[idx_NCB];
6613 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6614 ncbp->ncb_command = NCBRECV | ASYNCH;
6615 ncbp->ncb_lana_num = lanas[idx_session];
6617 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6618 ncbp->ncb_event = NCBevents[idx_NCB];
6619 ncbp->ncb_length = SMB_PACKETSIZE;
6622 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6623 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6624 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6625 ncbp->ncb_length = SMB_PACKETSIZE;
6626 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6627 Netbios(ncbp, dos_ncb);
6633 * The top level loop for handling SMB request messages. Each server thread
6634 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6635 * NCB and buffer for the incoming request are loaned to us.
6637 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6638 * to immediately send a request for the rest of the data. This must come
6639 * before any other traffic for that session, so we delay setting the session
6640 * event until that data has come in.
6642 void smb_Server(VOID *parmp)
6644 int myIdx = (int) parmp;
6648 smb_packet_t *outbufp;
6650 int idx_NCB, idx_session;
6652 smb_vc_t *vcp = NULL;
6659 outbufp = GetPacket();
6660 outbufp->ncbp = outncbp;
6663 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6666 /* terminate silently if shutdown flag is set */
6667 if (code == WAIT_OBJECT_0) {
6668 if (smbShutdownFlag == 1)
6674 /* error checking */
6675 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6677 int abandonIdx = code - WAIT_ABANDONED_0;
6678 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6681 if (code == WAIT_IO_COMPLETION)
6683 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6687 if (code == WAIT_TIMEOUT)
6689 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6692 if (code == WAIT_FAILED)
6694 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6697 idx_NCB = code - WAIT_OBJECT_0;
6699 /* check idx range! */
6700 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6702 /* this is fatal - log as much as possible */
6703 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6707 ncbp = NCBs[idx_NCB];
6709 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6711 idx_session = NCBsessions[idx_NCB];
6712 rc = ncbp->ncb_retcode;
6714 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6715 osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6718 case NRC_GOODRET: break;
6721 /* Can this happen? Or is it just my
6728 /* Client closed session */
6729 if (reportSessionStartups)
6731 osi_Log1(smb_logp, "session [ %d ] closed", idx_session);
6733 dead_sessions[idx_session] = TRUE;
6736 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6737 /* Should also release vcp. [done] 2004-05-11 jaltman
6739 * sanity check that all TID's are gone.
6741 * TODO: check if we could use LSNs[idx_session] instead,
6742 * also cleanup after dead vcp
6747 "dead_vcp already set, %x",
6749 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6751 "setting dead_vcp %x, user struct %x",
6755 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6757 if (vcp->justLoggedOut) {
6759 loggedOutTime = vcp->logoffTime;
6760 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
6761 loggedOutUserp = vcp->justLoggedOut;
6762 lock_ObtainWrite(&smb_rctLock);
6763 loggedOutUserp->refCount++;
6764 lock_ReleaseWrite(&smb_rctLock);
6770 /* Treat as transient error */
6777 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6778 sprintf(s, "SMB message incomplete, length %d",
6781 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6783 ncbp->ncb_length, ptbuf,
6785 DeregisterEventSource(h);
6788 "dispatch smb recv failed, message incomplete, ncb_length %d",
6791 "SMB message incomplete, "
6792 "length %d", ncbp->ncb_length);
6795 * We used to discard the packet.
6796 * Instead, try handling it normally.
6804 /* A weird error code. Log it, sleep, and
6806 if (vcp && vcp->errorCount++ > 3) {
6807 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6808 dead_sessions[idx_session] = TRUE;
6812 thrd_SetEvent(SessionEvents[idx_session]);
6817 /* Success, so now dispatch on all the data in the packet */
6819 smb_concurrentCalls++;
6820 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6821 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6825 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6827 * If at this point vcp is NULL (implies that packet was invalid)
6828 * then we are in big trouble. This means either :
6829 * a) we have the wrong NCB.
6830 * b) Netbios screwed up the call.
6831 * Obviously this implies that
6832 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6833 * lanas[idx_session] != ncbp->ncb_lana_num )
6834 * Either way, we can't do anything with this packet.
6835 * Log, sleep and resume.
6844 "LSNs[idx_session]=[%d],"
6845 "lanas[idx_session]=[%d],"
6846 "ncbp->ncb_lsn=[%d],"
6847 "ncbp->ncb_lana_num=[%d]",
6851 ncbp->ncb_lana_num);
6855 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6857 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6858 DeregisterEventSource(h);
6861 /* Also log in the trace log. */
6862 osi_Log4(smb_logp, "Server: BAD VCP!"
6863 "LSNs[idx_session]=[%d],"
6864 "lanas[idx_session]=[%d],"
6865 "ncbp->ncb_lsn=[%d],"
6866 "ncbp->ncb_lana_num=[%d]",
6870 ncbp->ncb_lana_num);
6872 /* thrd_Sleep(1000); Don't bother sleeping */
6873 thrd_SetEvent(SessionEvents[idx_session]);
6874 smb_concurrentCalls--;
6879 vcp->errorCount = 0;
6880 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6882 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6883 /* copy whole packet to virtual memory */
6884 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6886 bufp->dos_pkt / 16, bufp);*/
6888 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6890 smbp = (smb_t *)bufp->data;
6893 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6897 if (smbp->com == 0x1d) {
6898 /* Special handling for Write Raw */
6899 raw_write_cont_t rwc;
6900 EVENT_HANDLE rwevent;
6901 char eventName[MAX_PATH];
6903 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6904 if (rwc.code == 0) {
6905 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6906 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6907 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6908 ncbp->ncb_command = NCBRECV | ASYNCH;
6909 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6910 ncbp->ncb_lana_num = vcp->lana;
6911 ncbp->ncb_buffer = rwc.buf;
6912 ncbp->ncb_length = 65535;
6913 ncbp->ncb_event = rwevent;
6917 Netbios(ncbp, dos_ncb);
6919 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6920 thrd_CloseHandle(rwevent);
6922 thrd_SetEvent(SessionEvents[idx_session]);
6924 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6926 else if (smbp->com == 0xa0) {
6928 * Serialize the handling for NT Transact
6931 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6932 thrd_SetEvent(SessionEvents[idx_session]);
6934 thrd_SetEvent(SessionEvents[idx_session]);
6935 /* TODO: what else needs to be serialized? */
6936 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6938 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6940 __except( smb_ServerExceptionFilter() ) {
6944 smb_concurrentCalls--;
6947 thrd_SetEvent(NCBavails[idx_NCB]);
6954 * Exception filter for the server threads. If an exception occurs in the
6955 * dispatch routines, which is where exceptions are most common, then do a
6956 * force trace and give control to upstream exception handlers. Useful for
6959 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6960 DWORD smb_ServerExceptionFilter(void) {
6961 /* While this is not the best time to do a trace, if it succeeds, then
6962 * we have a trace (assuming tracing was enabled). Otherwise, this should
6963 * throw a second exception.
6968 ptbuf[0] = "Unhandled exception forcing trace";
6970 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6972 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6973 DeregisterEventSource(h);
6976 afsd_ForceTrace(TRUE);
6977 buf_ForceTrace(TRUE);
6978 return EXCEPTION_CONTINUE_SEARCH;
6983 * Create a new NCB and associated events, packet buffer, and "space" buffer.
6984 * If the number of server threads is M, and the number of live sessions is
6985 * N, then the number of NCB's in use at any time either waiting for, or
6986 * holding, received messages is M + N, so that is how many NCB's get created.
6988 void InitNCBslot(int idx)
6990 struct smb_packet *bufp;
6991 EVENT_HANDLE retHandle;
6993 char eventName[MAX_PATH];
6995 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6997 NCBs[idx] = GetNCB();
6998 sprintf(eventName,"NCBavails[%d]", idx);
6999 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7000 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7001 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7003 sprintf(eventName,"NCBevents[%d]", idx);
7004 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7005 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7006 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7008 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7009 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7010 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7011 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7012 for (i=0; i<smb_NumServerThreads; i++)
7013 NCBreturns[i][idx] = retHandle;
7015 bufp->spacep = cm_GetSpace();
7019 /* listen for new connections */
7020 void smb_Listener(void *parmp)
7028 char rname[NCBNAMSZ+1];
7029 char cname[MAX_COMPUTERNAME_LENGTH+1];
7030 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7035 int lana = (int) parmp;
7039 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7042 /* retrieve computer name */
7043 GetComputerName(cname, &cnamelen);
7047 memset(ncbp, 0, sizeof(NCB));
7050 ncbp->ncb_command = NCBLISTEN;
7051 ncbp->ncb_rto = 0; /* No receive timeout */
7052 ncbp->ncb_sto = 0; /* No send timeout */
7054 /* pad out with spaces instead of null termination */
7055 len = strlen(smb_localNamep);
7056 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7057 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7059 strcpy(ncbp->ncb_callname, "*");
7060 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7062 ncbp->ncb_lana_num = lana;
7065 code = Netbios(ncbp);
7067 code = Netbios(ncbp, dos_ncb);
7076 /* terminate silently if shutdown flag is set */
7077 if (smbShutdownFlag == 1) {
7086 "NCBLISTEN lana=%d failed with code %d",
7087 ncbp->ncb_lana_num, code);
7089 "Client exiting due to network failure. Please restart client.\n");
7093 "Client exiting due to network failure. Please restart client.\n"
7094 "NCBLISTEN lana=%d failed with code %d",
7095 ncbp->ncb_lana_num, code);
7097 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7098 MB_OK|MB_SERVICE_NOTIFICATION);
7099 osi_assert(tbuffer);
7102 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7103 ncbp->ncb_lana_num, code);
7104 fprintf(stderr, "\nClient exiting due to network failure "
7105 "(possibly due to power-saving mode)\n");
7106 fprintf(stderr, "Please restart client.\n");
7107 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7111 /* check for remote conns */
7112 /* first get remote name and insert null terminator */
7113 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7114 for (i=NCBNAMSZ; i>0; i--) {
7115 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7121 /* compare with local name */
7123 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7124 flags |= SMB_VCFLAG_REMOTECONN;
7126 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7128 lock_ObtainMutex(&smb_ListenerLock);
7130 /* New generation */
7133 /* Log session startup */
7135 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7137 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7138 #endif /* NOTSERVICE */
7139 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7140 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7142 if (reportSessionStartups) {
7148 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7149 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7151 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7153 DeregisterEventSource(h);
7156 fprintf(stderr, "%s: New session %d starting from host %s\n",
7157 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7161 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7162 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7165 /* now ncbp->ncb_lsn is the connection ID */
7166 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7167 vcp->flags |= flags;
7168 strcpy(vcp->rname, rname);
7170 /* Allocate slot in session arrays */
7171 /* Re-use dead session if possible, otherwise add one more */
7172 /* But don't look at session[0], it is reserved */
7173 for (i = 1; i < numSessions; i++) {
7174 if (dead_sessions[i]) {
7175 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7176 dead_sessions[i] = FALSE;
7181 /* assert that we do not exceed the maximum number of sessions or NCBs.
7182 * we should probably want to wait for a session to be freed in case
7186 osi_assert(i < Sessionmax - 1);
7187 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7189 LSNs[i] = ncbp->ncb_lsn;
7190 lanas[i] = ncbp->ncb_lana_num;
7192 if (i == numSessions) {
7193 /* Add new NCB for new session */
7194 char eventName[MAX_PATH];
7196 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7198 InitNCBslot(numNCBs);
7200 thrd_SetEvent(NCBavails[0]);
7201 thrd_SetEvent(NCBevents[0]);
7202 for (j = 0; j < smb_NumServerThreads; j++)
7203 thrd_SetEvent(NCBreturns[j][0]);
7204 /* Also add new session event */
7205 sprintf(eventName, "SessionEvents[%d]", i);
7206 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7207 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7208 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7210 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7211 thrd_SetEvent(SessionEvents[0]);
7213 thrd_SetEvent(SessionEvents[i]);
7216 lock_ReleaseMutex(&smb_ListenerLock);
7218 } /* dispatch while loop */
7221 /* initialize Netbios */
7222 void smb_NetbiosInit()
7228 int i, lana, code, l;
7230 int delname_tried=0;
7233 OSVERSIONINFO Version;
7235 /* AFAIK, this is the default for the ms loopback adapter.*/
7236 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
7237 /*******************************************************************/
7239 /* Get the version of Windows */
7240 memset(&Version, 0x00, sizeof(Version));
7241 Version.dwOSVersionInfoSize = sizeof(Version);
7242 GetVersionEx(&Version);
7244 /* setup the NCB system */
7247 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7251 if (smb_LANadapter == -1) {
7252 ncbp->ncb_command = NCBENUM;
7253 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7254 ncbp->ncb_length = sizeof(lana_list);
7255 code = Netbios(ncbp);
7257 sprintf(s, "Netbios NCBENUM error code %d", code);
7258 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7259 osi_panic(s, __FILE__, __LINE__);
7263 lana_list.length = 1;
7264 lana_list.lana[0] = smb_LANadapter;
7267 for (i = 0; i < lana_list.length; i++) {
7268 /* reset the adaptor: in Win32, this is required for every process, and
7269 * acts as an init call, not as a real hardware reset.
7271 ncbp->ncb_command = NCBRESET;
7272 ncbp->ncb_callname[0] = 100;
7273 ncbp->ncb_callname[2] = 100;
7274 ncbp->ncb_lana_num = lana_list.lana[i];
7275 code = Netbios(ncbp);
7277 code = ncbp->ncb_retcode;
7279 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7280 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7281 lana_list.lana[i] = 255; /* invalid lana */
7283 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7284 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7288 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7289 we will just fake the LANA list */
7290 if (smb_LANadapter == -1) {
7291 for (i = 0; i < 8; i++)
7292 lana_list.lana[i] = i;
7293 lana_list.length = 8;
7296 lana_list.length = 1;
7297 lana_list.lana[0] = smb_LANadapter;
7301 /* and declare our name so we can receive connections */
7302 memset(ncbp, 0, sizeof(*ncbp));
7303 len=lstrlen(smb_localNamep);
7304 memset(smb_sharename,' ',NCBNAMSZ);
7305 memcpy(smb_sharename,smb_localNamep,len);
7306 sprintf(s, "lana_list.length %d", lana_list.length);
7307 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7309 /* Keep the name so we can unregister it later */
7310 for (l = 0; l < lana_list.length; l++) {
7311 lana = lana_list.lana[l];
7313 ncbp->ncb_command = NCBADDNAME;
7314 ncbp->ncb_lana_num = lana;
7315 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7317 code = Netbios(ncbp);
7319 code = Netbios(ncbp, dos_ncb);
7322 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7323 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7325 char name[NCBNAMSZ+1];
7327 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7328 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7331 if (code == 0) code = ncbp->ncb_retcode;
7333 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7335 /* we only use one LANA with djgpp */
7336 lana_list.lana[0] = lana;
7337 lana_list.length = 1;
7341 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7342 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7343 if (code == NRC_BRIDGE) { /* invalid LANA num */
7344 lana_list.lana[l] = 255;
7347 else if (code == NRC_DUPNAME) {
7348 osi_Log0(smb_logp, "Name already exists; try to delete it");
7349 memset(ncbp, 0, sizeof(*ncbp));
7350 ncbp->ncb_command = NCBDELNAME;
7351 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7352 ncbp->ncb_lana_num = lana;
7354 code = Netbios(ncbp);
7356 code = Netbios(ncbp, dos_ncb);
7359 code = ncbp->ncb_retcode;
7361 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7362 osi_Log0(smb_logp, s);
7364 if (code != 0 || delname_tried) {
7365 lana_list.lana[l] = 255;
7367 else if (code == 0) {
7368 if (!delname_tried) {
7376 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7377 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7378 lana_list.lana[l] = 255; /* invalid lana */
7379 osi_panic(s, __FILE__, __LINE__);
7383 lana_found = 1; /* at least one worked */
7390 osi_assert(lana_list.length >= 0);
7392 sprintf(s, "No valid LANA numbers found!");
7393 osi_panic(s, __FILE__, __LINE__);
7396 /* we're done with the NCB now */
7400 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7417 EVENT_HANDLE retHandle;
7418 char eventName[MAX_PATH];
7421 smb_MBfunc = aMBfunc;
7425 smb_LANadapter = LANadapt;
7427 /* Initialize smb_localZero */
7428 myTime.tm_isdst = -1; /* compute whether on DST or not */
7429 myTime.tm_year = 70;
7435 smb_localZero = mktime(&myTime);
7437 /* Initialize kludge-GMT */
7438 smb_CalculateNowTZ();
7440 #ifdef AFS_FREELANCE_CLIENT
7441 /* Make sure the root.afs volume has the correct time */
7442 cm_noteLocalMountPointChange();
7445 /* initialize the remote debugging log */
7448 /* remember the name */
7449 len = strlen(snamep);
7450 smb_localNamep = malloc(len+1);
7451 strcpy(smb_localNamep, snamep);
7452 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7454 /* and the global lock */
7455 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7456 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7458 /* Raw I/O data structures */
7459 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7461 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7463 /* 4 Raw I/O buffers */
7465 smb_RawBufs = calloc(65536,1);
7466 *((char **)smb_RawBufs) = NULL;
7467 for (i=0; i<3; i++) {
7468 char *rawBuf = calloc(65536,1);
7469 *((char **)rawBuf) = smb_RawBufs;
7470 smb_RawBufs = rawBuf;
7473 npar = 65536 >> 4; /* number of paragraphs */
7474 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7476 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7478 osi_panic("",__FILE__,__LINE__);
7481 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7484 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7486 _farpokel(_dos_ds, smb_RawBufs, NULL);
7487 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7488 npar = 65536 >> 4; /* number of paragraphs */
7489 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7491 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7493 osi_panic("",__FILE__,__LINE__);
7496 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7499 rawBuf = (seg * 16) + 0; /* DOS physical address */
7500 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7501 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7502 smb_RawBufs = rawBuf;
7506 /* global free lists */
7507 smb_ncbFreeListp = NULL;
7508 smb_packetFreeListp = NULL;
7512 /* Initialize listener and server structures */
7514 memset(dead_sessions, 0, sizeof(dead_sessions));
7515 sprintf(eventName, "SessionEvents[0]");
7516 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7517 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7518 afsi_log("Event Object Already Exists: %s", eventName);
7520 smb_NumServerThreads = nThreads;
7521 sprintf(eventName, "NCBavails[0]");
7522 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7523 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7524 afsi_log("Event Object Already Exists: %s", eventName);
7525 sprintf(eventName, "NCBevents[0]");
7526 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7527 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7528 afsi_log("Event Object Already Exists: %s", eventName);
7529 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7530 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7531 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7532 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7533 afsi_log("Event Object Already Exists: %s", eventName);
7534 for (i = 0; i < smb_NumServerThreads; i++) {
7535 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7536 NCBreturns[i][0] = retHandle;
7538 for (i = 1; i <= nThreads; i++)
7540 numNCBs = nThreads + 1;
7542 /* Initialize dispatch table */
7543 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7544 /* Prepare the table for unknown operations */
7545 for(i=0; i<= SMB_NOPCODES; i++) {
7546 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7548 /* Fill in the ones we do know */
7549 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7550 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7551 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7552 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7553 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7554 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7555 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7556 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7557 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7558 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7559 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7560 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7561 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7562 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7563 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7564 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7565 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7566 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7567 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7568 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7569 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7570 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7571 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7572 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7573 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7574 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7575 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7576 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7577 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7578 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7579 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7580 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7581 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7582 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7583 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7584 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7585 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7586 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7587 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7588 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7589 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7590 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7591 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7592 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7593 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7594 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7595 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7596 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7597 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7598 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7599 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7600 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7601 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7602 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7603 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7604 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7605 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
7606 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
7607 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
7608 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7609 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7610 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7611 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7612 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7613 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
7614 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
7615 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
7616 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
7617 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
7618 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
7619 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
7620 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
7622 /* setup tran 2 dispatch table */
7623 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7624 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7625 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7626 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7627 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7628 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7629 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7630 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7631 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7632 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7633 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7634 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7635 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7636 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
7637 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
7638 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2GetDFSReferral;
7639 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2ReportDFSInconsistency;
7641 /* setup the rap dispatch table */
7642 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
7643 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
7644 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
7645 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
7646 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
7650 /* if we are doing SMB authentication we have register outselves as a logon process */
7651 if (smb_authType != SMB_AUTH_NONE) {
7653 LSA_STRING afsProcessName;
7654 LSA_OPERATIONAL_MODE dummy; /*junk*/
7656 afsProcessName.Buffer = "OpenAFSClientDaemon";
7657 afsProcessName.Length = strlen(afsProcessName.Buffer);
7658 afsProcessName.MaximumLength = afsProcessName.Length + 1;
7660 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7662 if (nts == STATUS_SUCCESS) {
7663 LSA_STRING packageName;
7664 /* we are registered. Find out the security package id */
7665 packageName.Buffer = MSV1_0_PACKAGE_NAME;
7666 packageName.Length = strlen(packageName.Buffer);
7667 packageName.MaximumLength = packageName.Length + 1;
7668 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7669 if (nts == STATUS_SUCCESS) {
7670 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7671 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7672 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7674 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7677 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7680 if (nts != STATUS_SUCCESS) {
7681 /* something went wrong. We report the error and revert back to no authentication
7682 because we can't perform any auth requests without a successful lsa handle
7683 or sec package id. */
7684 afsi_log("Reverting to NO SMB AUTH");
7685 smb_authType = SMB_AUTH_NONE;
7688 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
7689 * time prevents the failure of authentication when logged into Windows with an
7690 * external Kerberos principal mapped to a local account.
7692 else if ( smb_authType == SMB_AUTH_EXTENDED) {
7693 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
7694 * then the only option is NTLMSSP anyway; so just fallback.
7699 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7700 if (secBlobLength == 0) {
7701 smb_authType = SMB_AUTH_NTLM;
7702 afsi_log("Reverting to SMB AUTH NTLM");
7711 /* Now get ourselves a domain name. */
7712 /* For now we are using the local computer name as the domain name.
7713 * It is actually the domain for local logins, and we are acting as
7714 * a local SMB server.
7716 bufsize = sizeof(smb_ServerDomainName) - 1;
7717 GetComputerName(smb_ServerDomainName, &bufsize);
7718 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7719 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7722 /* Start listeners, waiters, servers, and daemons */
7724 for (i = 0; i < lana_list.length; i++) {
7725 if (lana_list.lana[i] == 255) continue;
7726 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7727 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7728 osi_assert(phandle != NULL);
7729 thrd_CloseHandle(phandle);
7733 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7734 NULL, 0, &lpid, "smb_ClientWaiter");
7735 osi_assert(phandle != NULL);
7736 thrd_CloseHandle(phandle);
7739 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7740 NULL, 0, &lpid, "smb_ServerWaiter");
7741 osi_assert(phandle != NULL);
7742 thrd_CloseHandle(phandle);
7744 for (i=0; i<nThreads; i++) {
7745 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7746 (void *) i, 0, &lpid, "smb_Server");
7747 osi_assert(phandle != NULL);
7748 thrd_CloseHandle(phandle);
7751 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7752 NULL, 0, &lpid, "smb_Daemon");
7753 osi_assert(phandle != NULL);
7754 thrd_CloseHandle(phandle);
7756 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7757 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7758 osi_assert(phandle != NULL);
7759 thrd_CloseHandle(phandle);
7768 void smb_Shutdown(void)
7777 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7779 /* setup the NCB system */
7782 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7785 /* Block new sessions by setting shutdown flag */
7786 smbShutdownFlag = 1;
7788 /* Hang up all sessions */
7789 memset((char *)ncbp, 0, sizeof(NCB));
7790 for (i = 1; i < numSessions; i++)
7792 if (dead_sessions[i])
7795 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7796 ncbp->ncb_command = NCBHANGUP;
7797 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7798 ncbp->ncb_lsn = LSNs[i];
7800 code = Netbios(ncbp);
7802 code = Netbios(ncbp, dos_ncb);
7804 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7805 if (code == 0) code = ncbp->ncb_retcode;
7807 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7808 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7812 /* Delete Netbios name */
7813 memset((char *)ncbp, 0, sizeof(NCB));
7814 for (i = 0; i < lana_list.length; i++) {
7815 if (lana_list.lana[i] == 255) continue;
7816 ncbp->ncb_command = NCBDELNAME;
7817 ncbp->ncb_lana_num = lana_list.lana[i];
7818 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7820 code = Netbios(ncbp);
7822 code = Netbios(ncbp, dos_ncb);
7825 code = ncbp->ncb_retcode;
7827 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7828 ncbp->ncb_lana_num, code);
7833 /* Trigger the shutdown of all SMB threads */
7834 for (i = 0; i < numSessions; i++)
7835 thrd_SetEvent(NCBreturns[i][0]);
7837 thrd_SetEvent(NCBevents[0]);
7838 thrd_SetEvent(SessionEvents[0]);
7839 thrd_SetEvent(NCBavails[0]);
7843 /* Get the UNC \\<servername>\<sharename> prefix. */
7844 char *smb_GetSharename()
7848 /* Make sure we have been properly initialized. */
7849 if (smb_localNamep == NULL)
7852 /* Allocate space for \\<servername>\<sharename>, plus the
7855 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7856 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7862 void smb_LogPacket(smb_packet_t *packet)
7865 unsigned length, paramlen, datalen, i, j;
7867 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7869 if (!packet) return;
7871 osi_Log0(smb_logp, "*** SMB packet dump ***");
7873 vp = (BYTE *) packet->data;
7875 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7876 length = paramlen + 2 + datalen;
7879 for (i=0;i < length; i+=16)
7881 memset( buf, ' ', 80 );
7886 buf[strlen(buf)] = ' ';
7888 cp = (BYTE*) buf + 7;
7890 for (j=0;j < 16 && (i+j)<length; j++)
7892 *(cp++) = hex[vp[i+j] >> 4];
7893 *(cp++) = hex[vp[i+j] & 0xf];
7903 for (j=0;j < 16 && (i+j)<length;j++)
7905 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7916 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
7919 osi_Log0(smb_logp, "*** End SMB packet dump ***");
7921 #endif /* LOG_PACKET */
7924 int smb_DumpVCP(FILE *outputFile, char *cookie)
7931 lock_ObtainRead(&smb_rctLock);
7933 sprintf(output, "begin dumping vcpsp\n");
7934 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7936 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7940 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7941 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7942 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7944 sprintf(output, "begin dumping fidsp\n");
7945 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7947 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7949 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",
7950 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
7951 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
7952 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7953 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7956 sprintf(output, "done dumping fidsp\n");
7957 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7960 sprintf(output, "done dumping vcpsp\n");
7961 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7963 lock_ReleaseRead(&smb_rctLock);