2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 /* These characters are illegal in Windows filenames */
35 static char *illegalChars = "\\/:*?\"<>|";
37 static int smbShutdownFlag = 0;
38 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
40 int smb_LogoffTokenTransfer;
41 time_t smb_LogoffTransferTimeout;
43 int smb_StoreAnsiFilenames = 0;
45 DWORD last_msg_time = 0;
49 unsigned int sessionGen = 0;
51 extern void afsi_log(char *pattern, ...);
52 extern HANDLE afsi_file;
53 extern int powerStateSuspended;
55 osi_hyper_t hzero = {0, 0};
56 osi_hyper_t hones = {0xFFFFFFFF, -1};
59 osi_rwlock_t smb_globalLock;
60 osi_rwlock_t smb_rctLock;
61 osi_mutex_t smb_ListenerLock;
62 osi_mutex_t smb_StartedLock;
64 unsigned char smb_LANadapter = LANA_INVALID;
65 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
66 int smb_LanAdapterChangeDetected = 0;
68 BOOL isGateway = FALSE;
71 long smb_maxObsConcurrentCalls=0;
72 long smb_concurrentCalls=0;
74 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
76 smb_packet_t *smb_packetFreeListp;
77 smb_ncb_t *smb_ncbFreeListp;
79 int smb_NumServerThreads;
81 int numNCBs, numSessions, numVCs;
83 int smb_maxVCPerServer;
84 int smb_maxMpxRequests;
86 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
88 ULONG smb_lsaSecPackage;
89 LSA_STRING smb_lsaLogonOrigin;
91 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
92 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
93 EVENT_HANDLE **NCBreturns;
94 EVENT_HANDLE **NCBShutdown;
95 EVENT_HANDLE *smb_ServerShutdown;
96 EVENT_HANDLE ListenerShutdown[256];
97 DWORD NCBsessions[NCB_MAX];
99 struct smb_packet *bufs[NCB_MAX];
101 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
102 EVENT_HANDLE SessionEvents[SESSION_MAX];
103 unsigned short LSNs[SESSION_MAX];
104 int lanas[SESSION_MAX];
105 BOOL dead_sessions[SESSION_MAX];
108 osi_mutex_t smb_RawBufLock;
111 #define SMB_MASKFLAG_TILDE 1
112 #define SMB_MASKFLAG_CASEFOLD 2
114 #define RAWTIMEOUT INFINITE
117 typedef struct raw_write_cont {
126 /* dir search stuff */
127 long smb_dirSearchCounter = 1;
128 smb_dirSearch_t *smb_firstDirSearchp;
129 smb_dirSearch_t *smb_lastDirSearchp;
131 /* hide dot files? */
132 int smb_hideDotFiles;
134 /* global state about V3 protocols */
135 int smb_useV3; /* try to negotiate V3 */
137 static showErrors = 0;
138 /* MessageBox or something like it */
139 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
142 * Time in Unix format of midnight, 1/1/1970 local time.
143 * When added to dosUTime, gives Unix (AFS) time.
145 time_t smb_localZero = 0;
147 #define USE_NUMERIC_TIME_CONV 1
149 #ifndef USE_NUMERIC_TIME_CONV
150 /* Time difference for converting to kludge-GMT */
151 afs_uint32 smb_NowTZ;
152 #endif /* USE_NUMERIC_TIME_CONV */
154 char *smb_localNamep = NULL;
156 smb_vc_t *smb_allVCsp;
157 smb_vc_t *smb_deadVCsp;
159 smb_username_t *usernamesp = NULL;
161 smb_waitingLockRequest_t *smb_allWaitingLocks;
163 DWORD smb_TlsRequestSlot = -1;
166 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
167 NCB *ncbp, raw_write_cont_t *rwcp);
168 int smb_NetbiosInit(int);
171 void smb_LogPacket(smb_packet_t *packet);
172 #endif /* LOG_PACKET */
174 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
175 int smb_ServerDomainNameLength = 0;
176 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
177 int smb_ServerOSLength = sizeof(smb_ServerOS);
178 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
179 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
181 /* Faux server GUID. This is never checked. */
182 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
184 void smb_ResetServerPriority()
186 void * p = TlsGetValue(smb_TlsRequestSlot);
189 TlsSetValue(smb_TlsRequestSlot, NULL);
190 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
194 void smb_SetRequestStartTime()
196 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
198 tp = malloc(sizeof(time_t));
202 if (!TlsSetValue(smb_TlsRequestSlot, tp))
207 void smb_UpdateServerPriority()
209 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
212 time_t now = osi_Time();
214 /* Give one priority boost for each 15 seconds */
215 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
220 const char * ncb_error_string(int code)
224 case 0x01: s = "llegal buffer length"; break;
225 case 0x03: s = "illegal command"; break;
226 case 0x05: s = "command timed out"; break;
227 case 0x06: s = "message incomplete, issue another command"; break;
228 case 0x07: s = "illegal buffer address"; break;
229 case 0x08: s = "session number out of range"; break;
230 case 0x09: s = "no resource available"; break;
231 case 0x0a: s = "session closed"; break;
232 case 0x0b: s = "command cancelled"; break;
233 case 0x0d: s = "duplicate name"; break;
234 case 0x0e: s = "name table full"; break;
235 case 0x0f: s = "no deletions, name has active sessions"; break;
236 case 0x11: s = "local session table full"; break;
237 case 0x12: s = "remote session table full"; break;
238 case 0x13: s = "illegal name number"; break;
239 case 0x14: s = "no callname"; break;
240 case 0x15: s = "cannot put * in NCB_NAME"; break;
241 case 0x16: s = "name in use on remote adapter"; break;
242 case 0x17: s = "name deleted"; break;
243 case 0x18: s = "session ended abnormally"; break;
244 case 0x19: s = "name conflict detected"; break;
245 case 0x21: s = "interface busy, IRET before retrying"; break;
246 case 0x22: s = "too many commands outstanding, retry later";break;
247 case 0x23: s = "ncb_lana_num field invalid"; break;
248 case 0x24: s = "command completed while cancel occurring "; break;
249 case 0x26: s = "command not valid to cancel"; break;
250 case 0x30: s = "name defined by anther local process"; break;
251 case 0x34: s = "environment undefined. RESET required"; break;
252 case 0x35: s = "required OS resources exhausted"; break;
253 case 0x36: s = "max number of applications exceeded"; break;
254 case 0x37: s = "no saps available for netbios"; break;
255 case 0x38: s = "requested resources are not available"; break;
256 case 0x39: s = "invalid ncb address or length > segment"; break;
257 case 0x3B: s = "invalid NCB DDID"; break;
258 case 0x3C: s = "lock of user area failed"; break;
259 case 0x3f: s = "NETBIOS not loaded"; break;
260 case 0x40: s = "system error"; break;
261 default: s = "unknown error";
267 char * myCrt_Dispatch(int i)
272 return "(00)ReceiveCoreMakeDir";
274 return "(01)ReceiveCoreRemoveDir";
276 return "(02)ReceiveCoreOpen";
278 return "(03)ReceiveCoreCreate";
280 return "(04)ReceiveCoreClose";
282 return "(05)ReceiveCoreFlush";
284 return "(06)ReceiveCoreUnlink";
286 return "(07)ReceiveCoreRename";
288 return "(08)ReceiveCoreGetFileAttributes";
290 return "(09)ReceiveCoreSetFileAttributes";
292 return "(0a)ReceiveCoreRead";
294 return "(0b)ReceiveCoreWrite";
296 return "(0c)ReceiveCoreLockRecord";
298 return "(0d)ReceiveCoreUnlockRecord";
300 return "(0e)SendCoreBadOp";
302 return "(0f)ReceiveCoreCreate";
304 return "(10)ReceiveCoreCheckPath";
306 return "(11)SendCoreBadOp";
308 return "(12)ReceiveCoreSeek";
310 return "(1a)ReceiveCoreReadRaw";
312 return "(1d)ReceiveCoreWriteRawDummy";
314 return "(22)ReceiveV3SetAttributes";
316 return "(23)ReceiveV3GetAttributes";
318 return "(24)ReceiveV3LockingX";
320 return "(25)ReceiveV3Trans";
322 return "(26)ReceiveV3Trans[aux]";
324 return "(29)SendCoreBadOp";
326 return "(2b)ReceiveCoreEcho";
328 return "(2d)ReceiveV3OpenX";
330 return "(2e)ReceiveV3ReadX";
332 return "(2f)ReceiveV3WriteX";
334 return "(32)ReceiveV3Tran2A";
336 return "(33)ReceiveV3Tran2A[aux]";
338 return "(34)ReceiveV3FindClose";
340 return "(35)ReceiveV3FindNotifyClose";
342 return "(70)ReceiveCoreTreeConnect";
344 return "(71)ReceiveCoreTreeDisconnect";
346 return "(72)ReceiveNegotiate";
348 return "(73)ReceiveV3SessionSetupX";
350 return "(74)ReceiveV3UserLogoffX";
352 return "(75)ReceiveV3TreeConnectX";
354 return "(80)ReceiveCoreGetDiskAttributes";
356 return "(81)ReceiveCoreSearchDir";
360 return "(83)FindUnique";
362 return "(84)FindClose";
364 return "(A0)ReceiveNTTransact";
366 return "(A2)ReceiveNTCreateX";
368 return "(A4)ReceiveNTCancel";
370 return "(A5)ReceiveNTRename";
372 return "(C0)OpenPrintFile";
374 return "(C1)WritePrintFile";
376 return "(C2)ClosePrintFile";
378 return "(C3)GetPrintQueue";
380 return "(D8)ReadBulk";
382 return "(D9)WriteBulk";
384 return "(DA)WriteBulkData";
386 return "unknown SMB op";
390 char * myCrt_2Dispatch(int i)
395 return "unknown SMB op-2";
397 return "S(00)CreateFile_ReceiveTran2Open";
399 return "S(01)FindFirst_ReceiveTran2SearchDir";
401 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
403 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
405 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
407 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
409 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
411 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
413 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
415 return "S(09)_ReceiveTran2FSCTL";
417 return "S(0a)_ReceiveTran2IOCTL";
419 return "S(0b)_ReceiveTran2FindNotifyFirst";
421 return "S(0c)_ReceiveTran2FindNotifyNext";
423 return "S(0d)_ReceiveTran2CreateDirectory";
425 return "S(0e)_ReceiveTran2SessionSetup";
427 return "S(0f)_QueryFileSystemInformationFid";
429 return "S(10)_ReceiveTran2GetDfsReferral";
431 return "S(11)_ReceiveTran2ReportDfsInconsistency";
435 char * myCrt_RapDispatch(int i)
440 return "unknown RAP OP";
442 return "RAP(0)NetShareEnum";
444 return "RAP(1)NetShareGetInfo";
446 return "RAP(13)NetServerGetInfo";
448 return "RAP(63)NetWkStaGetInfo";
452 /* scache must be locked */
453 unsigned int smb_Attributes(cm_scache_t *scp)
457 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
458 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
459 scp->fileType == CM_SCACHETYPE_INVALID)
461 attrs = SMB_ATTR_DIRECTORY;
462 #ifdef SPECIAL_FOLDERS
463 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
464 #endif /* SPECIAL_FOLDERS */
465 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
466 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
471 * We used to mark a file RO if it was in an RO volume, but that
472 * turns out to be impolitic in NT. See defect 10007.
475 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
476 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
478 if ((scp->unixModeBits & 0222) == 0)
479 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
485 /* Check if the named file/dir is a dotfile/dotdir */
486 /* String pointed to by lastComp can have leading slashes, but otherwise should have
487 no other patch components */
488 unsigned int smb_IsDotFile(char *lastComp) {
491 /* skip over slashes */
492 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
497 /* nulls, curdir and parent dir doesn't count */
503 if(*(s+1) == '.' && !*(s + 2))
510 static int ExtractBits(WORD bits, short start, short len)
517 num = bits << (16 - end);
518 num = num >> ((16 - end) + start);
523 void ShowUnixTime(char *FuncName, time_t unixTime)
528 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
530 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
531 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
533 int day, month, year, sec, min, hour;
536 day = ExtractBits(wDate, 0, 5);
537 month = ExtractBits(wDate, 5, 4);
538 year = ExtractBits(wDate, 9, 7) + 1980;
540 sec = ExtractBits(wTime, 0, 5);
541 min = ExtractBits(wTime, 5, 6);
542 hour = ExtractBits(wTime, 11, 5);
544 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
545 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
549 /* Determine if we are observing daylight savings time */
550 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
552 TIME_ZONE_INFORMATION timeZoneInformation;
553 SYSTEMTIME utc, local, localDST;
555 /* Get the time zone info. NT uses this to calc if we are in DST. */
556 GetTimeZoneInformation(&timeZoneInformation);
558 /* Return the daylight bias */
559 *pDstBias = timeZoneInformation.DaylightBias;
561 /* Return the bias */
562 *pBias = timeZoneInformation.Bias;
564 /* Now determine if DST is being observed */
566 /* Get the UTC (GMT) time */
569 /* Convert UTC time to local time using the time zone info. If we are
570 observing DST, the calculated local time will include this.
572 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
574 /* Set the daylight bias to 0. The daylight bias is the amount of change
575 * in time that we use for daylight savings time. By setting this to 0
576 * we cause there to be no change in time during daylight savings time.
578 timeZoneInformation.DaylightBias = 0;
580 /* Convert the utc time to local time again, but this time without any
581 adjustment for daylight savings time.
583 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
585 /* If the two times are different, then it means that the localDST that
586 we calculated includes the daylight bias, and therefore we are
587 observing daylight savings time.
589 *pDST = localDST.wHour != local.wHour;
593 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
595 BOOL dst; /* Will be TRUE if observing DST */
596 LONG dstBias; /* Offset from local time if observing DST */
597 LONG bias; /* Offset from GMT for local time */
600 * This function will adjust the last write time to compensate
601 * for two bugs in the smb client:
603 * 1) During Daylight Savings Time, the LastWriteTime is ahead
604 * in time by the DaylightBias (ignoring the sign - the
605 * DaylightBias is always stored as a negative number). If
606 * the DaylightBias is -60, then the LastWriteTime will be
607 * ahead by 60 minutes.
609 * 2) If the local time zone is a positive offset from GMT, then
610 * the LastWriteTime will be the correct local time plus the
611 * Bias (ignoring the sign - a positive offset from GMT is
612 * always stored as a negative Bias). If the Bias is -120,
613 * then the LastWriteTime will be ahead by 120 minutes.
615 * These bugs can occur at the same time.
618 GetTimeZoneInfo(&dst, &dstBias, &bias);
620 /* First adjust for DST */
622 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
624 /* Now adjust for a positive offset from GMT (a negative bias). */
626 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
629 #ifndef USE_NUMERIC_TIME_CONV
631 * Calculate the difference (in seconds) between local time and GMT.
632 * This enables us to convert file times to kludge-GMT.
638 struct tm gmt_tm, local_tm;
639 int days, hours, minutes, seconds;
642 gmt_tm = *(gmtime(&t));
643 local_tm = *(localtime(&t));
645 days = local_tm.tm_yday - gmt_tm.tm_yday;
646 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
647 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
648 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
652 #endif /* USE_NUMERIC_TIME_CONV */
654 #ifdef USE_NUMERIC_TIME_CONV
655 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
657 // Note that LONGLONG is a 64-bit value
660 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
661 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
662 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
665 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
670 time_t ersatz_unixTime;
673 * Must use kludge-GMT instead of real GMT.
674 * kludge-GMT is computed by adding time zone difference to localtime.
677 * ltp = gmtime(&unixTime);
679 ersatz_unixTime = unixTime - smb_NowTZ;
680 ltp = localtime(&ersatz_unixTime);
682 /* if we fail, make up something */
685 localJunk.tm_year = 89 - 20;
686 localJunk.tm_mon = 4;
687 localJunk.tm_mday = 12;
688 localJunk.tm_hour = 0;
689 localJunk.tm_min = 0;
690 localJunk.tm_sec = 0;
693 stm.wYear = ltp->tm_year + 1900;
694 stm.wMonth = ltp->tm_mon + 1;
695 stm.wDayOfWeek = ltp->tm_wday;
696 stm.wDay = ltp->tm_mday;
697 stm.wHour = ltp->tm_hour;
698 stm.wMinute = ltp->tm_min;
699 stm.wSecond = ltp->tm_sec;
700 stm.wMilliseconds = 0;
702 SystemTimeToFileTime(&stm, largeTimep);
704 #endif /* USE_NUMERIC_TIME_CONV */
706 #ifdef USE_NUMERIC_TIME_CONV
707 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
709 // Note that LONGLONG is a 64-bit value
712 ll = largeTimep->dwHighDateTime;
714 ll += largeTimep->dwLowDateTime;
716 ll -= 116444736000000000;
719 *unixTimep = (DWORD)ll;
721 #else /* USE_NUMERIC_TIME_CONV */
722 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
728 FileTimeToSystemTime(largeTimep, &stm);
730 lt.tm_year = stm.wYear - 1900;
731 lt.tm_mon = stm.wMonth - 1;
732 lt.tm_wday = stm.wDayOfWeek;
733 lt.tm_mday = stm.wDay;
734 lt.tm_hour = stm.wHour;
735 lt.tm_min = stm.wMinute;
736 lt.tm_sec = stm.wSecond;
739 save_timezone = _timezone;
740 _timezone += smb_NowTZ;
741 *unixTimep = mktime(<);
742 _timezone = save_timezone;
744 #endif /* USE_NUMERIC_TIME_CONV */
746 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
756 /* if we fail, make up something */
759 localJunk.tm_year = 89 - 20;
760 localJunk.tm_mon = 4;
761 localJunk.tm_mday = 12;
762 localJunk.tm_hour = 0;
763 localJunk.tm_min = 0;
764 localJunk.tm_sec = 0;
767 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
768 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
769 *searchTimep = (dosDate<<16) | dosTime;
772 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
774 unsigned short dosDate;
775 unsigned short dosTime;
778 dosDate = (unsigned short) (searchTime & 0xffff);
779 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
781 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
782 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
783 localTm.tm_mday = (dosDate) & 0x1f;
784 localTm.tm_hour = (dosTime>>11) & 0x1f;
785 localTm.tm_min = (dosTime >> 5) & 0x3f;
786 localTm.tm_sec = (dosTime & 0x1f) * 2;
787 localTm.tm_isdst = -1; /* compute whether DST in effect */
789 *unixTimep = mktime(&localTm);
792 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
794 time_t diff_t = unixTime - smb_localZero;
795 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
796 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
798 *dosUTimep = (afs_uint32)diff_t;
801 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
803 *unixTimep = dosTime + smb_localZero;
806 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
810 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
811 lock_ObtainWrite(&smb_rctLock);
812 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
813 if (vcp->magic != SMB_VC_MAGIC)
814 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
817 if (lsn == vcp->lsn && lana == vcp->lana &&
818 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
819 smb_HoldVCNoLock(vcp);
823 if (!vcp && (flags & SMB_FLAG_CREATE)) {
824 vcp = malloc(sizeof(*vcp));
825 memset(vcp, 0, sizeof(*vcp));
826 vcp->vcID = ++numVCs;
827 vcp->magic = SMB_VC_MAGIC;
828 vcp->refCount = 2; /* smb_allVCsp and caller */
831 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
832 vcp->nextp = smb_allVCsp;
834 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
839 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
840 /* We must obtain a challenge for extended auth
841 * in case the client negotiates smb v3
843 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
844 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
845 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
846 ULONG lsaRespSize = 0;
848 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
850 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
857 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
858 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
859 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
860 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
861 nts, ntsEx, lsaRespSize);
863 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
865 if (ntsEx == STATUS_SUCCESS) {
866 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
867 LsaFreeReturnBuffer(lsaResp);
870 * This will cause the subsequent authentication to fail but
871 * that is better than us dereferencing a NULL pointer and
874 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
878 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
880 if (numVCs >= CM_SESSION_RESERVED) {
882 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
885 lock_ReleaseWrite(&smb_rctLock);
886 lock_ReleaseWrite(&smb_globalLock);
890 int smb_IsStarMask(char *maskp)
895 for(i=0; i<11; i++) {
897 if (tc == '?' || tc == '*' || tc == '>')
903 void smb_ReleaseVCInternal(smb_vc_t *vcp)
910 if (vcp->refCount == 0) {
911 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
912 /* remove VCP from smb_deadVCsp */
913 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
919 lock_FinalizeMutex(&vcp->mx);
920 memset(vcp,0,sizeof(smb_vc_t));
923 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
927 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
928 avcp?"not ":"",vcp, vcp->refCount);
930 GenerateMiniDump(NULL);
932 /* This is a wrong. However, I suspect that there is an undercount
933 * and I don't want to release 1.4.1 in a state that will allow
934 * smb_vc_t objects to be deallocated while still in the
935 * smb_allVCsp list. The list is supposed to keep a reference
936 * to the smb_vc_t. Put it back.
943 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
945 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
946 smb_ReleaseVCInternal(vcp);
949 void smb_ReleaseVC(smb_vc_t *vcp)
951 lock_ObtainWrite(&smb_rctLock);
952 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
953 smb_ReleaseVCInternal(vcp);
954 lock_ReleaseWrite(&smb_rctLock);
957 void smb_HoldVCNoLock(smb_vc_t *vcp)
960 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
963 void smb_HoldVC(smb_vc_t *vcp)
965 lock_ObtainWrite(&smb_rctLock);
967 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
968 lock_ReleaseWrite(&smb_rctLock);
971 void smb_CleanupDeadVC(smb_vc_t *vcp)
979 smb_user_t *uidpIter;
980 smb_user_t *uidpNext;
984 lock_ObtainMutex(&vcp->mx);
985 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
986 lock_ReleaseMutex(&vcp->mx);
987 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
990 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
991 lock_ReleaseMutex(&vcp->mx);
992 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
994 lock_ObtainWrite(&smb_rctLock);
995 /* remove VCP from smb_allVCsp */
996 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
997 if ((*vcpp)->magic != SMB_VC_MAGIC)
998 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1002 vcp->nextp = smb_deadVCsp;
1004 /* Hold onto the reference until we are done with this function */
1009 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1010 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1012 if (fidpIter->delete)
1015 fid = fidpIter->fid;
1016 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1018 smb_HoldFIDNoLock(fidpIter);
1019 lock_ReleaseWrite(&smb_rctLock);
1021 smb_CloseFID(vcp, fidpIter, NULL, 0);
1022 smb_ReleaseFID(fidpIter);
1024 lock_ObtainWrite(&smb_rctLock);
1025 fidpNext = vcp->fidsp;
1028 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1029 tidpNext = tidpIter->nextp;
1030 if (tidpIter->delete)
1032 tidpIter->delete = 1;
1034 tid = tidpIter->tid;
1035 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1037 smb_HoldTIDNoLock(tidpIter);
1038 lock_ReleaseWrite(&smb_rctLock);
1040 smb_ReleaseTID(tidpIter);
1042 lock_ObtainWrite(&smb_rctLock);
1043 tidpNext = vcp->tidsp;
1046 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1047 uidpNext = uidpIter->nextp;
1048 if (uidpIter->delete)
1050 uidpIter->delete = 1;
1052 /* do not add an additional reference count for the smb_user_t
1053 * as the smb_vc_t already is holding a reference */
1054 lock_ReleaseWrite(&smb_rctLock);
1056 smb_ReleaseUID(uidpIter);
1058 lock_ObtainWrite(&smb_rctLock);
1059 uidpNext = vcp->usersp;
1062 /* The vcp is now on the deadVCsp list. We intentionally drop the
1063 * reference so that the refcount can reach 0 and we can delete it */
1064 smb_ReleaseVCNoLock(vcp);
1066 lock_ReleaseWrite(&smb_rctLock);
1067 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1070 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1074 lock_ObtainWrite(&smb_rctLock);
1076 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1077 if (tidp->refCount == 0 && tidp->delete) {
1079 lock_ReleaseWrite(&smb_rctLock);
1080 smb_ReleaseTID(tidp);
1081 lock_ObtainWrite(&smb_rctLock);
1085 if (tid == tidp->tid) {
1090 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1091 tidp = malloc(sizeof(*tidp));
1092 memset(tidp, 0, sizeof(*tidp));
1093 tidp->nextp = vcp->tidsp;
1096 smb_HoldVCNoLock(vcp);
1098 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1101 lock_ReleaseWrite(&smb_rctLock);
1105 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1110 void smb_ReleaseTID(smb_tid_t *tidp)
1117 lock_ObtainWrite(&smb_rctLock);
1118 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1119 if (tidp->refCount == 0 && (tidp->delete)) {
1120 ltpp = &tidp->vcp->tidsp;
1121 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1125 osi_assertx(tp != NULL, "null smb_tid_t");
1127 lock_FinalizeMutex(&tidp->mx);
1128 userp = tidp->userp; /* remember to drop ref later */
1130 smb_ReleaseVCNoLock(tidp->vcp);
1133 lock_ReleaseWrite(&smb_rctLock);
1135 cm_ReleaseUser(userp);
1138 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1140 smb_user_t *uidp = NULL;
1142 lock_ObtainWrite(&smb_rctLock);
1143 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1144 if (uid == uidp->userID) {
1146 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1148 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1152 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1153 uidp = malloc(sizeof(*uidp));
1154 memset(uidp, 0, sizeof(*uidp));
1155 uidp->nextp = vcp->usersp;
1156 uidp->refCount = 2; /* one for the vcp and one for the caller */
1158 smb_HoldVCNoLock(vcp);
1160 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1162 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1164 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1166 lock_ReleaseWrite(&smb_rctLock);
1170 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1172 smb_username_t *unp= NULL;
1174 lock_ObtainWrite(&smb_rctLock);
1175 for(unp = usernamesp; unp; unp = unp->nextp) {
1176 if (stricmp(unp->name, usern) == 0 &&
1177 stricmp(unp->machine, machine) == 0) {
1182 if (!unp && (flags & SMB_FLAG_CREATE)) {
1183 unp = malloc(sizeof(*unp));
1184 memset(unp, 0, sizeof(*unp));
1186 unp->nextp = usernamesp;
1187 unp->name = strdup(usern);
1188 unp->machine = strdup(machine);
1190 lock_InitializeMutex(&unp->mx, "username_t mutex");
1191 if (flags & SMB_FLAG_AFSLOGON)
1192 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1195 lock_ReleaseWrite(&smb_rctLock);
1199 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1201 smb_user_t *uidp= NULL;
1203 lock_ObtainWrite(&smb_rctLock);
1204 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1207 if (stricmp(uidp->unp->name, usern) == 0) {
1209 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1210 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1215 lock_ReleaseWrite(&smb_rctLock);
1219 void smb_ReleaseUsername(smb_username_t *unp)
1222 smb_username_t **lupp;
1223 cm_user_t *userp = NULL;
1224 time_t now = osi_Time();
1226 lock_ObtainWrite(&smb_rctLock);
1227 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1228 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1229 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1231 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1235 osi_assertx(up != NULL, "null smb_username_t");
1237 up->nextp = NULL; /* do not remove this */
1238 lock_FinalizeMutex(&unp->mx);
1244 lock_ReleaseWrite(&smb_rctLock);
1247 cm_ReleaseUser(userp);
1251 void smb_HoldUIDNoLock(smb_user_t *uidp)
1256 void smb_ReleaseUID(smb_user_t *uidp)
1260 smb_username_t *unp = NULL;
1262 lock_ObtainWrite(&smb_rctLock);
1263 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1264 if (uidp->refCount == 0) {
1265 lupp = &uidp->vcp->usersp;
1266 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1270 osi_assertx(up != NULL, "null smb_user_t");
1272 lock_FinalizeMutex(&uidp->mx);
1274 smb_ReleaseVCNoLock(uidp->vcp);
1278 lock_ReleaseWrite(&smb_rctLock);
1282 cm_ReleaseUserVCRef(unp->userp);
1283 smb_ReleaseUsername(unp);
1287 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1289 cm_user_t *up = NULL;
1294 lock_ObtainMutex(&uidp->mx);
1296 up = uidp->unp->userp;
1299 lock_ReleaseMutex(&uidp->mx);
1305 /* retrieve a held reference to a user structure corresponding to an incoming
1307 * corresponding release function is cm_ReleaseUser.
1309 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1312 cm_user_t *up = NULL;
1315 smbp = (smb_t *) inp;
1316 uidp = smb_FindUID(vcp, smbp->uid, 0);
1320 up = smb_GetUserFromUID(uidp);
1322 smb_ReleaseUID(uidp);
1327 * Return a pointer to a pathname extracted from a TID structure. The
1328 * TID structure is not held; assume it won't go away.
1330 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1335 tidp = smb_FindTID(vcp, tid, 0);
1339 if (tidp->flags & SMB_TIDFLAG_IPC) {
1340 code = CM_ERROR_TIDIPC;
1341 /* tidp->pathname would be NULL, but that's fine */
1343 *treepath = tidp->pathname;
1344 smb_ReleaseTID(tidp);
1349 /* check to see if we have a chained fid, that is, a fid that comes from an
1350 * OpenAndX message that ran earlier in this packet. In this case, the fid
1351 * field in a read, for example, request, isn't set, since the value is
1352 * supposed to be inherited from the openAndX call.
1354 int smb_ChainFID(int fid, smb_packet_t *inp)
1356 if (inp->fid == 0 || inp->inCount == 0)
1362 /* are we a priv'd user? What does this mean on NT? */
1363 int smb_SUser(cm_user_t *userp)
1368 /* find a file ID. If we pass in 0 we select an unused File ID.
1369 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1370 * smb_fid_t data structure if desired File ID cannot be found.
1372 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1377 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1380 lock_ObtainWrite(&smb_rctLock);
1381 /* figure out if we need to allocate a new file ID */
1384 fid = vcp->fidCounter;
1388 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1389 if (fidp->refCount == 0 && fidp->delete) {
1391 lock_ReleaseWrite(&smb_rctLock);
1392 smb_ReleaseFID(fidp);
1393 lock_ObtainWrite(&smb_rctLock);
1396 if (fid == fidp->fid) {
1399 if (fid == 0xFFFF) {
1401 "New FID number wraps on vcp 0x%x", vcp);
1411 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1412 char eventName[MAX_PATH];
1414 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1415 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1416 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1417 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1418 thrd_CloseHandle(event);
1420 if (fid == 0xFFFF) {
1421 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1427 fidp = malloc(sizeof(*fidp));
1428 memset(fidp, 0, sizeof(*fidp));
1429 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1432 smb_HoldVCNoLock(vcp);
1433 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1435 fidp->curr_chunk = fidp->prev_chunk = -2;
1436 fidp->raw_write_event = event;
1438 vcp->fidCounter = fid+1;
1439 if (vcp->fidCounter == 0xFFFF) {
1440 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1442 vcp->fidCounter = 1;
1447 lock_ReleaseWrite(&smb_rctLock);
1451 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1453 smb_fid_t *fidp = NULL;
1459 lock_ObtainWrite(&smb_rctLock);
1460 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1461 if (scp == fidp->scp) {
1466 lock_ReleaseWrite(&smb_rctLock);
1470 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1476 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1477 /* the sm_fid_t->mx and smb_rctLock must not be held */
1478 void smb_ReleaseFID(smb_fid_t *fidp)
1480 cm_scache_t *scp = NULL;
1481 cm_user_t *userp = NULL;
1482 smb_vc_t *vcp = NULL;
1483 smb_ioctl_t *ioctlp;
1485 lock_ObtainMutex(&fidp->mx);
1486 lock_ObtainWrite(&smb_rctLock);
1487 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1488 if (fidp->refCount == 0 && (fidp->delete)) {
1491 scp = fidp->scp; /* release after lock is released */
1493 lock_ObtainMutex(&scp->mx);
1494 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1495 lock_ReleaseMutex(&scp->mx);
1496 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1499 userp = fidp->userp;
1503 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1504 thrd_CloseHandle(fidp->raw_write_event);
1506 /* and see if there is ioctl stuff to free */
1507 ioctlp = fidp->ioctlp;
1510 cm_FreeSpace(ioctlp->prefix);
1511 if (ioctlp->inAllocp)
1512 free(ioctlp->inAllocp);
1513 if (ioctlp->outAllocp)
1514 free(ioctlp->outAllocp);
1517 lock_ReleaseMutex(&fidp->mx);
1518 lock_FinalizeMutex(&fidp->mx);
1522 smb_ReleaseVCNoLock(vcp);
1524 lock_ReleaseMutex(&fidp->mx);
1526 lock_ReleaseWrite(&smb_rctLock);
1528 /* now release the scache structure */
1530 cm_ReleaseSCache(scp);
1533 cm_ReleaseUser(userp);
1537 * Case-insensitive search for one string in another;
1538 * used to find variable names in submount pathnames.
1540 static char *smb_stristr(char *str1, char *str2)
1544 for (cursor = str1; *cursor; cursor++)
1545 if (stricmp(cursor, str2) == 0)
1552 * Substitute a variable value for its name in a submount pathname. Variable
1553 * name has been identified by smb_stristr() and is in substr. Variable name
1554 * length (plus one) is in substr_size. Variable value is in newstr.
1556 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1561 strcpy(temp, substr + substr_size - 1);
1562 strcpy(substr, newstr);
1566 char VNUserName[] = "%USERNAME%";
1567 char VNLCUserName[] = "%LCUSERNAME%";
1568 char VNComputerName[] = "%COMPUTERNAME%";
1569 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1572 typedef struct smb_findShare_rock {
1576 } smb_findShare_rock_t;
1578 #define SMB_FINDSHARE_EXACT_MATCH 1
1579 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1581 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1585 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1586 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1587 if(!stricmp(dep->name, vrock->shareName))
1588 matchType = SMB_FINDSHARE_EXACT_MATCH;
1590 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1591 if(vrock->match) free(vrock->match);
1592 vrock->match = strdup(dep->name);
1593 vrock->matchType = matchType;
1595 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1596 return CM_ERROR_STOPNOW;
1602 /* find a shareName in the table of submounts */
1603 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1607 char pathName[1024];
1614 DWORD allSubmount = 1;
1616 /* if allSubmounts == 0, only return the //mountRoot/all share
1617 * if in fact it has been been created in the subMounts table.
1618 * This is to allow sites that want to restrict access to the
1621 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1622 0, KEY_QUERY_VALUE, &parmKey);
1623 if (code == ERROR_SUCCESS) {
1624 len = sizeof(allSubmount);
1625 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1626 (BYTE *) &allSubmount, &len);
1627 if (code != ERROR_SUCCESS) {
1630 RegCloseKey (parmKey);
1633 if (allSubmount && _stricmp(shareName, "all") == 0) {
1638 /* In case, the all share is disabled we need to still be able
1639 * to handle ioctl requests
1641 if (_stricmp(shareName, "ioctl$") == 0) {
1642 *pathNamep = strdup("/.__ioctl__");
1646 if (_stricmp(shareName, "IPC$") == 0 ||
1647 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1648 _stricmp(shareName, "DESKTOP.INI") == 0
1654 /* Check for volume references
1656 * They look like <cell>{%,#}<volume>
1658 if (strchr(shareName, '%') != NULL ||
1659 strchr(shareName, '#') != NULL) {
1660 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1661 /* make room for '/@vol:' + mountchar + NULL terminator*/
1663 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1664 osi_LogSaveString(smb_logp, shareName));
1666 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1667 "/" CM_PREFIX_VOL "%s", shareName);
1668 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1669 len = strlen(pathstr) + 1;
1671 *pathNamep = malloc(len);
1673 strcpy(*pathNamep, pathstr);
1675 osi_Log1(smb_logp, " returning pathname [%s]",
1676 osi_LogSaveString(smb_logp, *pathNamep));
1684 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1685 0, KEY_QUERY_VALUE, &parmKey);
1686 if (code == ERROR_SUCCESS) {
1687 len = sizeof(pathName);
1688 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1689 (BYTE *) pathName, &len);
1690 if (code != ERROR_SUCCESS)
1692 RegCloseKey (parmKey);
1696 if (len != 0 && len != sizeof(pathName) - 1) {
1697 /* We can accept either unix or PC style AFS pathnames. Convert
1698 * Unix-style to PC style here for internal use.
1701 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1702 p += strlen(cm_mountRoot); /* skip mount path */
1705 if (*q == '/') *q = '\\'; /* change to \ */
1711 if (var = smb_stristr(p, VNUserName)) {
1712 if (uidp && uidp->unp)
1713 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1715 smb_subst(p, var, sizeof(VNUserName)," ");
1717 else if (var = smb_stristr(p, VNLCUserName))
1719 if (uidp && uidp->unp)
1720 strcpy(temp, uidp->unp->name);
1724 smb_subst(p, var, sizeof(VNLCUserName), temp);
1726 else if (var = smb_stristr(p, VNComputerName))
1728 sizeTemp = sizeof(temp);
1729 GetComputerName((LPTSTR)temp, &sizeTemp);
1730 smb_subst(p, var, sizeof(VNComputerName), temp);
1732 else if (var = smb_stristr(p, VNLCComputerName))
1734 sizeTemp = sizeof(temp);
1735 GetComputerName((LPTSTR)temp, &sizeTemp);
1737 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1742 *pathNamep = strdup(p);
1747 /* First lookup shareName in root.afs */
1749 smb_findShare_rock_t vrock;
1751 char * p = shareName;
1754 /* attempt to locate a partial match in root.afs. This is because
1755 when using the ANSI RAP calls, the share name is limited to 13 chars
1756 and hence is truncated. Of course we prefer exact matches. */
1758 thyper.HighPart = 0;
1761 vrock.shareName = shareName;
1763 vrock.matchType = 0;
1765 cm_HoldSCache(cm_data.rootSCachep);
1766 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1767 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1768 cm_ReleaseSCache(cm_data.rootSCachep);
1770 if (vrock.matchType) {
1771 sprintf(pathName,"/%s/",vrock.match);
1772 *pathNamep = strdup(strlwr(pathName));
1777 /* if we get here, there was no match for the share in root.afs */
1778 /* so try to create \\<netbiosName>\<cellname> */
1783 /* Get the full name for this cell */
1784 code = cm_SearchCellFile(p, temp, 0, 0);
1785 #ifdef AFS_AFSDB_ENV
1786 if (code && cm_dnsEnabled) {
1788 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1791 /* construct the path */
1793 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1794 *pathNamep = strdup(strlwr(pathName));
1803 /* Client-side offline caching policy types */
1804 #define CSC_POLICY_MANUAL 0
1805 #define CSC_POLICY_DOCUMENTS 1
1806 #define CSC_POLICY_PROGRAMS 2
1807 #define CSC_POLICY_DISABLE 3
1809 int smb_FindShareCSCPolicy(char *shareName)
1815 int retval = CSC_POLICY_MANUAL;
1817 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1818 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1821 REG_OPTION_NON_VOLATILE,
1827 len = sizeof(policy);
1828 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1830 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1832 else if (stricmp(policy, "documents") == 0)
1834 retval = CSC_POLICY_DOCUMENTS;
1836 else if (stricmp(policy, "programs") == 0)
1838 retval = CSC_POLICY_PROGRAMS;
1840 else if (stricmp(policy, "disable") == 0)
1842 retval = CSC_POLICY_DISABLE;
1845 RegCloseKey(hkCSCPolicy);
1849 /* find a dir search structure by cookie value, and return it held.
1850 * Must be called with smb_globalLock held.
1852 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1854 smb_dirSearch_t *dsp;
1856 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1857 if (dsp->cookie == cookie) {
1858 if (dsp != smb_firstDirSearchp) {
1859 /* move to head of LRU queue, too, if we're not already there */
1860 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1861 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1862 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1863 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1864 if (!smb_lastDirSearchp)
1865 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1867 lock_ObtainMutex(&dsp->mx);
1869 lock_ReleaseMutex(&dsp->mx);
1875 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1876 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1877 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1883 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1885 lock_ObtainWrite(&smb_globalLock);
1886 lock_ObtainMutex(&dsp->mx);
1887 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1888 dsp->cookie, dsp, dsp->scp);
1889 dsp->flags |= SMB_DIRSEARCH_DELETE;
1890 if (dsp->scp != NULL) {
1891 lock_ObtainMutex(&dsp->scp->mx);
1892 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1893 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1894 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1895 dsp->scp->bulkStatProgress = hzero;
1897 lock_ReleaseMutex(&dsp->scp->mx);
1899 lock_ReleaseMutex(&dsp->mx);
1900 lock_ReleaseWrite(&smb_globalLock);
1903 /* Must be called with the smb_globalLock held */
1904 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1906 cm_scache_t *scp = NULL;
1908 lock_ObtainMutex(&dsp->mx);
1909 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1910 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1911 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1912 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1913 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1914 lock_ReleaseMutex(&dsp->mx);
1915 lock_FinalizeMutex(&dsp->mx);
1917 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1918 dsp->cookie, dsp, scp);
1921 lock_ReleaseMutex(&dsp->mx);
1923 /* do this now to avoid spurious locking hierarchy creation */
1925 cm_ReleaseSCache(scp);
1928 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1930 lock_ObtainWrite(&smb_globalLock);
1931 smb_ReleaseDirSearchNoLock(dsp);
1932 lock_ReleaseWrite(&smb_globalLock);
1935 /* find a dir search structure by cookie value, and return it held */
1936 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1938 smb_dirSearch_t *dsp;
1940 lock_ObtainWrite(&smb_globalLock);
1941 dsp = smb_FindDirSearchNoLock(cookie);
1942 lock_ReleaseWrite(&smb_globalLock);
1946 /* GC some dir search entries, in the address space expected by the specific protocol.
1947 * Must be called with smb_globalLock held; release the lock temporarily.
1949 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1950 void smb_GCDirSearches(int isV3)
1952 smb_dirSearch_t *prevp;
1953 smb_dirSearch_t *tp;
1954 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1958 victimCount = 0; /* how many have we got so far */
1959 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1960 /* we'll move tp from queue, so
1963 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1964 /* if no one is using this guy, and we're either in the new protocol,
1965 * or we're in the old one and this is a small enough ID to be useful
1966 * to the old protocol, GC this guy.
1968 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1969 /* hold and delete */
1970 lock_ObtainMutex(&tp->mx);
1971 tp->flags |= SMB_DIRSEARCH_DELETE;
1972 lock_ReleaseMutex(&tp->mx);
1973 victimsp[victimCount++] = tp;
1977 /* don't do more than this */
1978 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1982 /* now release them */
1983 for (i = 0; i < victimCount; i++) {
1984 smb_ReleaseDirSearchNoLock(victimsp[i]);
1988 /* function for allocating a dir search entry. We need these to remember enough context
1989 * since we don't get passed the path from call to call during a directory search.
1991 * Returns a held dir search structure, and bumps the reference count on the vnode,
1992 * since it saves a pointer to the vnode.
1994 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1996 smb_dirSearch_t *dsp;
2002 lock_ObtainWrite(&smb_globalLock);
2005 /* what's the biggest ID allowed in this version of the protocol */
2006 /* TODO: do we really want a non v3 dir search request to wrap
2007 smb_dirSearchCounter? */
2008 maxAllowed = isV3 ? 65535 : 255;
2009 if (smb_dirSearchCounter > maxAllowed)
2010 smb_dirSearchCounter = 1;
2012 start = smb_dirSearchCounter;
2015 /* twice so we have enough tries to find guys we GC after one pass;
2016 * 10 extra is just in case I mis-counted.
2018 if (++counter > 2*maxAllowed+10)
2019 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2021 if (smb_dirSearchCounter > maxAllowed) {
2022 smb_dirSearchCounter = 1;
2024 if (smb_dirSearchCounter == start) {
2026 smb_GCDirSearches(isV3);
2029 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2031 /* don't need to watch for refcount zero and deleted, since
2032 * we haven't dropped the global lock.
2034 lock_ObtainMutex(&dsp->mx);
2036 lock_ReleaseMutex(&dsp->mx);
2037 ++smb_dirSearchCounter;
2041 dsp = malloc(sizeof(*dsp));
2042 memset(dsp, 0, sizeof(*dsp));
2043 dsp->cookie = smb_dirSearchCounter;
2044 ++smb_dirSearchCounter;
2046 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2047 dsp->lastTime = osi_Time();
2048 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2049 if (!smb_lastDirSearchp)
2050 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2052 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2056 lock_ReleaseWrite(&smb_globalLock);
2060 static smb_packet_t *GetPacket(void)
2064 lock_ObtainWrite(&smb_globalLock);
2065 tbp = smb_packetFreeListp;
2067 smb_packetFreeListp = tbp->nextp;
2068 lock_ReleaseWrite(&smb_globalLock);
2070 tbp = calloc(65540,1);
2071 tbp->magic = SMB_PACKETMAGIC;
2074 tbp->resumeCode = 0;
2080 tbp->ncb_length = 0;
2085 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2090 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2094 memcpy(tbp, pkt, sizeof(smb_packet_t));
2095 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2097 smb_HoldVC(tbp->vcp);
2101 static NCB *GetNCB(void)
2106 lock_ObtainWrite(&smb_globalLock);
2107 tbp = smb_ncbFreeListp;
2109 smb_ncbFreeListp = tbp->nextp;
2110 lock_ReleaseWrite(&smb_globalLock);
2112 tbp = calloc(sizeof(*tbp),1);
2113 tbp->magic = SMB_NCBMAGIC;
2116 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2118 memset(&tbp->ncb, 0, sizeof(NCB));
2123 void smb_FreePacket(smb_packet_t *tbp)
2125 smb_vc_t * vcp = NULL;
2126 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2128 lock_ObtainWrite(&smb_globalLock);
2129 tbp->nextp = smb_packetFreeListp;
2130 smb_packetFreeListp = tbp;
2131 tbp->magic = SMB_PACKETMAGIC;
2135 tbp->resumeCode = 0;
2141 tbp->ncb_length = 0;
2143 lock_ReleaseWrite(&smb_globalLock);
2149 static void FreeNCB(NCB *bufferp)
2153 tbp = (smb_ncb_t *) bufferp;
2154 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2156 lock_ObtainWrite(&smb_globalLock);
2157 tbp->nextp = smb_ncbFreeListp;
2158 smb_ncbFreeListp = tbp;
2159 lock_ReleaseWrite(&smb_globalLock);
2162 /* get a ptr to the data part of a packet, and its count */
2163 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2167 unsigned char *afterParmsp;
2169 parmBytes = *smbp->wctp << 1;
2170 afterParmsp = smbp->wctp + parmBytes + 1;
2172 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2173 if (nbytesp) *nbytesp = dataBytes;
2175 /* don't forget to skip the data byte count, since it follows
2176 * the parameters; that's where the "2" comes from below.
2178 return (unsigned char *) (afterParmsp + 2);
2181 /* must set all the returned parameters before playing around with the
2182 * data region, since the data region is located past the end of the
2183 * variable number of parameters.
2185 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2187 unsigned char *afterParmsp;
2189 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2191 *afterParmsp++ = dsize & 0xff;
2192 *afterParmsp = (dsize>>8) & 0xff;
2195 /* return the parm'th parameter in the smbp packet */
2196 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2199 unsigned char *parmDatap;
2201 parmCount = *smbp->wctp;
2203 if (parm >= parmCount) {
2206 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2207 parm, parmCount, smbp->ncb_length);
2208 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2209 parm, parmCount, smbp->ncb_length);
2210 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2211 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2212 osi_panic(s, __FILE__, __LINE__);
2214 parmDatap = smbp->wctp + (2*parm) + 1;
2216 return parmDatap[0] + (parmDatap[1] << 8);
2219 /* return the parm'th parameter in the smbp packet */
2220 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2223 unsigned char *parmDatap;
2225 parmCount = *smbp->wctp;
2227 if (parm >= parmCount) {
2230 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2231 parm, parmCount, smbp->ncb_length);
2232 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2233 parm, parmCount, smbp->ncb_length);
2234 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2235 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2236 osi_panic(s, __FILE__, __LINE__);
2238 parmDatap = smbp->wctp + (2*parm) + 1;
2240 return parmDatap[0];
2243 /* return the parm'th parameter in the smbp packet */
2244 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2247 unsigned char *parmDatap;
2249 parmCount = *smbp->wctp;
2251 if (parm + 1 >= parmCount) {
2254 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2255 parm, parmCount, smbp->ncb_length);
2256 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2257 parm, parmCount, smbp->ncb_length);
2258 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2259 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2260 osi_panic(s, __FILE__, __LINE__);
2262 parmDatap = smbp->wctp + (2*parm) + 1;
2264 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2267 /* return the parm'th parameter in the smbp packet */
2268 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2271 unsigned char *parmDatap;
2273 parmCount = *smbp->wctp;
2275 if (parm * 2 + offset >= parmCount * 2) {
2278 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2279 parm, offset, parmCount, smbp->ncb_length);
2280 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2281 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2282 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2283 parm, offset, parmCount, smbp->ncb_length);
2284 osi_panic(s, __FILE__, __LINE__);
2286 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2288 return parmDatap[0] + (parmDatap[1] << 8);
2291 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2295 /* make sure we have enough slots */
2296 if (*smbp->wctp <= slot)
2297 *smbp->wctp = slot+1;
2299 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2300 *parmDatap++ = parmValue & 0xff;
2301 *parmDatap = (parmValue>>8) & 0xff;
2304 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2308 /* make sure we have enough slots */
2309 if (*smbp->wctp <= slot)
2310 *smbp->wctp = slot+2;
2312 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2313 *parmDatap++ = parmValue & 0xff;
2314 *parmDatap++ = (parmValue>>8) & 0xff;
2315 *parmDatap++ = (parmValue>>16) & 0xff;
2316 *parmDatap = (parmValue>>24) & 0xff;
2319 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2324 /* make sure we have enough slots */
2325 if (*smbp->wctp <= slot)
2326 *smbp->wctp = slot+4;
2328 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2330 *parmDatap++ = *parmValuep++;
2333 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2337 /* make sure we have enough slots */
2338 if (*smbp->wctp <= slot) {
2339 if (smbp->oddByte) {
2341 *smbp->wctp = slot+1;
2346 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2347 *parmDatap++ = parmValue & 0xff;
2350 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2354 lastSlashp = strrchr(inPathp, '\\');
2356 *lastComponentp = lastSlashp;
2359 if (inPathp == lastSlashp)
2361 *outPathp++ = *inPathp++;
2370 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2375 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2380 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2386 tlen = inp[0] + (inp[1]<<8);
2387 inp += 2; /* skip length field */
2390 *chainpp = inp + tlen;
2399 /* format a packet as a response */
2400 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2405 outp = (smb_t *) op;
2407 /* zero the basic structure through the smb_wct field, and zero the data
2408 * size field, assuming that wct stays zero; otherwise, you have to
2409 * explicitly set the data size field, too.
2411 inSmbp = (smb_t *) inp;
2412 memset(outp, 0, sizeof(smb_t)+2);
2418 outp->com = inSmbp->com;
2419 outp->tid = inSmbp->tid;
2420 outp->pid = inSmbp->pid;
2421 outp->uid = inSmbp->uid;
2422 outp->mid = inSmbp->mid;
2423 outp->res[0] = inSmbp->res[0];
2424 outp->res[1] = inSmbp->res[1];
2425 op->inCom = inSmbp->com;
2427 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2428 #ifdef SEND_CANONICAL_PATHNAMES
2429 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2431 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2433 /* copy fields in generic packet area */
2434 op->wctp = &outp->wct;
2437 /* send a (probably response) packet; vcp tells us to whom to send it.
2438 * we compute the length by looking at wct and bcc fields.
2440 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2454 memset((char *)ncbp, 0, sizeof(NCB));
2456 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2457 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2458 extra += tp[0] + (tp[1]<<8);
2459 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2460 extra += 3; /* wct and length fields */
2462 ncbp->ncb_length = extra; /* bytes to send */
2463 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2464 ncbp->ncb_lana_num = vcp->lana;
2465 ncbp->ncb_command = NCBSEND; /* op means send data */
2466 ncbp->ncb_buffer = (char *) inp;/* packet */
2467 code = Netbios(ncbp);
2470 const char * s = ncb_error_string(code);
2471 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2472 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2474 lock_ObtainMutex(&vcp->mx);
2475 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2476 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2478 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2479 lock_ReleaseMutex(&vcp->mx);
2480 lock_ObtainWrite(&smb_globalLock);
2481 dead_sessions[vcp->session] = TRUE;
2482 lock_ReleaseWrite(&smb_globalLock);
2483 smb_CleanupDeadVC(vcp);
2485 lock_ReleaseMutex(&vcp->mx);
2493 void smb_MapNTError(long code, unsigned long *NTStatusp)
2495 unsigned long NTStatus;
2497 /* map CM_ERROR_* errors to NT 32-bit status codes */
2498 /* NT Status codes are listed in ntstatus.h not winerror.h */
2499 if (code == CM_ERROR_NOSUCHCELL) {
2500 NTStatus = 0xC000000FL; /* No such file */
2502 else if (code == CM_ERROR_NOSUCHVOLUME) {
2503 NTStatus = 0xC000000FL; /* No such file */
2505 else if (code == CM_ERROR_TIMEDOUT) {
2507 NTStatus = 0xC00000CFL; /* Sharing Paused */
2509 NTStatus = 0x00000102L; /* Timeout */
2512 else if (code == CM_ERROR_RETRY) {
2513 NTStatus = 0xC000022DL; /* Retry */
2515 else if (code == CM_ERROR_NOACCESS) {
2516 NTStatus = 0xC0000022L; /* Access denied */
2518 else if (code == CM_ERROR_READONLY) {
2519 NTStatus = 0xC00000A2L; /* Write protected */
2521 else if (code == CM_ERROR_NOSUCHFILE ||
2522 code == CM_ERROR_BPLUS_NOMATCH) {
2523 NTStatus = 0xC000000FL; /* No such file */
2525 else if (code == CM_ERROR_NOSUCHPATH) {
2526 NTStatus = 0xC000003AL; /* Object path not found */
2528 else if (code == CM_ERROR_TOOBIG) {
2529 NTStatus = 0xC000007BL; /* Invalid image format */
2531 else if (code == CM_ERROR_INVAL) {
2532 NTStatus = 0xC000000DL; /* Invalid parameter */
2534 else if (code == CM_ERROR_BADFD) {
2535 NTStatus = 0xC0000008L; /* Invalid handle */
2537 else if (code == CM_ERROR_BADFDOP) {
2538 NTStatus = 0xC0000022L; /* Access denied */
2540 else if (code == CM_ERROR_EXISTS) {
2541 NTStatus = 0xC0000035L; /* Object name collision */
2543 else if (code == CM_ERROR_NOTEMPTY) {
2544 NTStatus = 0xC0000101L; /* Directory not empty */
2546 else if (code == CM_ERROR_CROSSDEVLINK) {
2547 NTStatus = 0xC00000D4L; /* Not same device */
2549 else if (code == CM_ERROR_NOTDIR) {
2550 NTStatus = 0xC0000103L; /* Not a directory */
2552 else if (code == CM_ERROR_ISDIR) {
2553 NTStatus = 0xC00000BAL; /* File is a directory */
2555 else if (code == CM_ERROR_BADOP) {
2557 /* I have no idea where this comes from */
2558 NTStatus = 0xC09820FFL; /* SMB no support */
2560 NTStatus = 0xC00000BBL; /* Not supported */
2561 #endif /* COMMENT */
2563 else if (code == CM_ERROR_BADSHARENAME) {
2564 NTStatus = 0xC00000CCL; /* Bad network name */
2566 else if (code == CM_ERROR_NOIPC) {
2568 NTStatus = 0xC0000022L; /* Access Denied */
2570 NTStatus = 0xC000013DL; /* Remote Resources */
2573 else if (code == CM_ERROR_CLOCKSKEW) {
2574 NTStatus = 0xC0000133L; /* Time difference at DC */
2576 else if (code == CM_ERROR_BADTID) {
2577 NTStatus = 0xC0982005L; /* SMB bad TID */
2579 else if (code == CM_ERROR_USESTD) {
2580 NTStatus = 0xC09820FBL; /* SMB use standard */
2582 else if (code == CM_ERROR_QUOTA) {
2584 NTStatus = 0xC0000044L; /* Quota exceeded */
2586 NTStatus = 0xC000007FL; /* Disk full */
2589 else if (code == CM_ERROR_SPACE) {
2590 NTStatus = 0xC000007FL; /* Disk full */
2592 else if (code == CM_ERROR_ATSYS) {
2593 NTStatus = 0xC0000033L; /* Object name invalid */
2595 else if (code == CM_ERROR_BADNTFILENAME) {
2596 NTStatus = 0xC0000033L; /* Object name invalid */
2598 else if (code == CM_ERROR_WOULDBLOCK) {
2599 NTStatus = 0xC0000055L; /* Lock not granted */
2601 else if (code == CM_ERROR_SHARING_VIOLATION) {
2602 NTStatus = 0xC0000043L; /* Sharing violation */
2604 else if (code == CM_ERROR_LOCK_CONFLICT) {
2605 NTStatus = 0xC0000054L; /* Lock conflict */
2607 else if (code == CM_ERROR_PARTIALWRITE) {
2608 NTStatus = 0xC000007FL; /* Disk full */
2610 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2611 NTStatus = 0xC0000023L; /* Buffer too small */
2613 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2614 NTStatus = 0xC0000035L; /* Object name collision */
2616 else if (code == CM_ERROR_BADPASSWORD) {
2617 NTStatus = 0xC000006DL; /* unknown username or bad password */
2619 else if (code == CM_ERROR_BADLOGONTYPE) {
2620 NTStatus = 0xC000015BL; /* logon type not granted */
2622 else if (code == CM_ERROR_GSSCONTINUE) {
2623 NTStatus = 0xC0000016L; /* more processing required */
2625 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2627 NTStatus = 0xC0000280L; /* reparse point not resolved */
2629 NTStatus = 0xC0000022L; /* Access Denied */
2632 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2633 NTStatus = 0xC0000257L; /* Path Not Covered */
2635 else if (code == CM_ERROR_ALLBUSY) {
2636 NTStatus = 0xC000022DL; /* Retry */
2638 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2639 NTStatus = 0xC00000BEL; /* Bad Network Path */
2641 else if (code == RXKADUNKNOWNKEY) {
2642 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2644 else if (code == CM_ERROR_BAD_LEVEL) {
2645 NTStatus = 0xC0000148L; /* Invalid Level */
2647 NTStatus = 0xC0982001L; /* SMB non-specific error */
2650 *NTStatusp = NTStatus;
2651 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2654 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2655 unsigned char *classp)
2657 unsigned char class;
2658 unsigned short error;
2660 /* map CM_ERROR_* errors to SMB errors */
2661 if (code == CM_ERROR_NOSUCHCELL) {
2663 error = 3; /* bad path */
2665 else if (code == CM_ERROR_NOSUCHVOLUME) {
2667 error = 3; /* bad path */
2669 else if (code == CM_ERROR_TIMEDOUT) {
2671 error = 81; /* server is paused */
2673 else if (code == CM_ERROR_RETRY) {
2674 class = 2; /* shouldn't happen */
2677 else if (code == CM_ERROR_NOACCESS) {
2679 error = 4; /* bad access */
2681 else if (code == CM_ERROR_READONLY) {
2683 error = 19; /* read only */
2685 else if (code == CM_ERROR_NOSUCHFILE ||
2686 code == CM_ERROR_BPLUS_NOMATCH) {
2688 error = 2; /* ENOENT! */
2690 else if (code == CM_ERROR_NOSUCHPATH) {
2692 error = 3; /* Bad path */
2694 else if (code == CM_ERROR_TOOBIG) {
2696 error = 11; /* bad format */
2698 else if (code == CM_ERROR_INVAL) {
2699 class = 2; /* server non-specific error code */
2702 else if (code == CM_ERROR_BADFD) {
2704 error = 6; /* invalid file handle */
2706 else if (code == CM_ERROR_BADFDOP) {
2707 class = 1; /* invalid op on FD */
2710 else if (code == CM_ERROR_EXISTS) {
2712 error = 80; /* file already exists */
2714 else if (code == CM_ERROR_NOTEMPTY) {
2716 error = 5; /* delete directory not empty */
2718 else if (code == CM_ERROR_CROSSDEVLINK) {
2720 error = 17; /* EXDEV */
2722 else if (code == CM_ERROR_NOTDIR) {
2723 class = 1; /* bad path */
2726 else if (code == CM_ERROR_ISDIR) {
2727 class = 1; /* access denied; DOS doesn't have a good match */
2730 else if (code == CM_ERROR_BADOP) {
2734 else if (code == CM_ERROR_BADSHARENAME) {
2738 else if (code == CM_ERROR_NOIPC) {
2740 error = 4; /* bad access */
2742 else if (code == CM_ERROR_CLOCKSKEW) {
2743 class = 1; /* invalid function */
2746 else if (code == CM_ERROR_BADTID) {
2750 else if (code == CM_ERROR_USESTD) {
2754 else if (code == CM_ERROR_REMOTECONN) {
2758 else if (code == CM_ERROR_QUOTA) {
2759 if (vcp->flags & SMB_VCFLAG_USEV3) {
2761 error = 39; /* disk full */
2765 error = 5; /* access denied */
2768 else if (code == CM_ERROR_SPACE) {
2769 if (vcp->flags & SMB_VCFLAG_USEV3) {
2771 error = 39; /* disk full */
2775 error = 5; /* access denied */
2778 else if (code == CM_ERROR_PARTIALWRITE) {
2780 error = 39; /* disk full */
2782 else if (code == CM_ERROR_ATSYS) {
2784 error = 2; /* ENOENT */
2786 else if (code == CM_ERROR_WOULDBLOCK) {
2788 error = 33; /* lock conflict */
2790 else if (code == CM_ERROR_LOCK_CONFLICT) {
2792 error = 33; /* lock conflict */
2794 else if (code == CM_ERROR_SHARING_VIOLATION) {
2796 error = 33; /* lock conflict */
2798 else if (code == CM_ERROR_NOFILES) {
2800 error = 18; /* no files in search */
2802 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2804 error = 183; /* Samba uses this */
2806 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2807 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2809 error = 2; /* bad password */
2811 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2813 error = 3; /* bad path */
2822 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2825 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2827 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2828 return CM_ERROR_BADOP;
2831 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2833 unsigned short EchoCount, i;
2834 char *data, *outdata;
2837 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2839 for (i=1; i<=EchoCount; i++) {
2840 data = smb_GetSMBData(inp, &dataSize);
2841 smb_SetSMBParm(outp, 0, i);
2842 smb_SetSMBDataLength(outp, dataSize);
2843 outdata = smb_GetSMBData(outp, NULL);
2844 memcpy(outdata, data, dataSize);
2845 smb_SendPacket(vcp, outp);
2851 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2854 long count, minCount, finalCount;
2859 cm_user_t *userp = NULL;
2862 char *rawBuf = NULL;
2867 fd = smb_GetSMBParm(inp, 0);
2868 count = smb_GetSMBParm(inp, 3);
2869 minCount = smb_GetSMBParm(inp, 4);
2870 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2872 if (*inp->wctp == 10) {
2873 /* we were sent a request with 64-bit file offsets */
2874 #ifdef AFS_LARGEFILES
2875 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2877 if (LargeIntegerLessThanZero(offset)) {
2878 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2882 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2883 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2886 offset.HighPart = 0;
2890 /* we were sent a request with 32-bit file offsets */
2891 offset.HighPart = 0;
2894 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2895 fd, offset.HighPart, offset.LowPart, count);
2897 fidp = smb_FindFID(vcp, fd, 0);
2901 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2902 smb_CloseFID(vcp, fidp, NULL, 0);
2903 code = CM_ERROR_NOSUCHFILE;
2908 pid = ((smb_t *) inp)->pid;
2910 LARGE_INTEGER LOffset, LLength;
2913 key = cm_GenerateKey(vcp->vcID, pid, fd);
2915 LOffset.HighPart = offset.HighPart;
2916 LOffset.LowPart = offset.LowPart;
2917 LLength.HighPart = 0;
2918 LLength.LowPart = count;
2920 lock_ObtainMutex(&fidp->scp->mx);
2921 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2922 lock_ReleaseMutex(&fidp->scp->mx);
2928 lock_ObtainMutex(&smb_RawBufLock);
2930 /* Get a raw buf, from head of list */
2931 rawBuf = smb_RawBufs;
2932 smb_RawBufs = *(char **)smb_RawBufs;
2934 lock_ReleaseMutex(&smb_RawBufLock);
2938 lock_ObtainMutex(&fidp->mx);
2939 if (fidp->flags & SMB_FID_IOCTL)
2941 lock_ReleaseMutex(&fidp->mx);
2942 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2944 /* Give back raw buffer */
2945 lock_ObtainMutex(&smb_RawBufLock);
2946 *((char **) rawBuf) = smb_RawBufs;
2948 smb_RawBufs = rawBuf;
2949 lock_ReleaseMutex(&smb_RawBufLock);
2952 smb_ReleaseFID(fidp);
2955 lock_ReleaseMutex(&fidp->mx);
2957 userp = smb_GetUserFromVCP(vcp, inp);
2959 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2965 cm_ReleaseUser(userp);
2968 smb_ReleaseFID(fidp);
2972 memset((char *)ncbp, 0, sizeof(NCB));
2974 ncbp->ncb_length = (unsigned short) finalCount;
2975 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2976 ncbp->ncb_lana_num = vcp->lana;
2977 ncbp->ncb_command = NCBSEND;
2978 ncbp->ncb_buffer = rawBuf;
2980 code = Netbios(ncbp);
2982 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2985 /* Give back raw buffer */
2986 lock_ObtainMutex(&smb_RawBufLock);
2987 *((char **) rawBuf) = smb_RawBufs;
2989 smb_RawBufs = rawBuf;
2990 lock_ReleaseMutex(&smb_RawBufLock);
2996 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2998 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3003 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3005 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3010 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3017 int VistaProtoIndex;
3018 int protoIndex; /* index we're using */
3023 char protocol_array[10][1024]; /* protocol signature of the client */
3024 int caps; /* capabilities */
3027 TIME_ZONE_INFORMATION tzi;
3029 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3032 namep = smb_GetSMBData(inp, &dbytes);
3035 coreProtoIndex = -1; /* not found */
3038 VistaProtoIndex = -1;
3039 while(namex < dbytes) {
3040 osi_Log1(smb_logp, "Protocol %s",
3041 osi_LogSaveString(smb_logp, namep+1));
3042 strcpy(protocol_array[tcounter], namep+1);
3044 /* namep points at the first protocol, or really, a 0x02
3045 * byte preceding the null-terminated ASCII name.
3047 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3048 coreProtoIndex = tcounter;
3050 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3051 v3ProtoIndex = tcounter;
3053 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3054 NTProtoIndex = tcounter;
3056 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3057 VistaProtoIndex = tcounter;
3060 /* compute size of protocol entry */
3061 entryLength = (int)strlen(namep+1);
3062 entryLength += 2; /* 0x02 bytes and null termination */
3064 /* advance over this protocol entry */
3065 namex += entryLength;
3066 namep += entryLength;
3067 tcounter++; /* which proto entry we're looking at */
3070 lock_ObtainMutex(&vcp->mx);
3072 if (VistaProtoIndex != -1) {
3073 protoIndex = VistaProtoIndex;
3074 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3077 if (NTProtoIndex != -1) {
3078 protoIndex = NTProtoIndex;
3079 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3081 else if (v3ProtoIndex != -1) {
3082 protoIndex = v3ProtoIndex;
3083 vcp->flags |= SMB_VCFLAG_USEV3;
3085 else if (coreProtoIndex != -1) {
3086 protoIndex = coreProtoIndex;
3087 vcp->flags |= SMB_VCFLAG_USECORE;
3089 else protoIndex = -1;
3090 lock_ReleaseMutex(&vcp->mx);
3092 if (protoIndex == -1)
3093 return CM_ERROR_INVAL;
3094 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3095 smb_SetSMBParm(outp, 0, protoIndex);
3096 if (smb_authType != SMB_AUTH_NONE) {
3097 smb_SetSMBParmByte(outp, 1,
3098 NEGOTIATE_SECURITY_USER_LEVEL |
3099 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3101 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3103 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3104 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3105 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3106 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3107 /* The session key is not a well documented field however most clients
3108 * will echo back the session key to the server. Currently we are using
3109 * the same value for all sessions. We should generate a random value
3110 * and store it into the vcp
3112 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3113 smb_SetSMBParm(outp, 8, 1);
3115 * Tried changing the capabilities to support for W2K - defect 117695
3116 * Maybe something else needs to be changed here?
3120 smb_SetSMBParmLong(outp, 9, 0x43fd);
3122 smb_SetSMBParmLong(outp, 9, 0x251);
3125 * 32-bit error codes *
3130 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3132 NTNEGOTIATE_CAPABILITY_DFS |
3134 #ifdef AFS_LARGEFILES
3135 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3137 NTNEGOTIATE_CAPABILITY_NTFIND |
3138 NTNEGOTIATE_CAPABILITY_RAWMODE |
3139 NTNEGOTIATE_CAPABILITY_NTSMB;
3141 if ( smb_authType == SMB_AUTH_EXTENDED )
3142 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3144 smb_SetSMBParmLong(outp, 9, caps);
3146 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3147 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3148 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3150 GetTimeZoneInformation(&tzi);
3151 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3153 if (smb_authType == SMB_AUTH_NTLM) {
3154 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3155 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3156 /* paste in encryption key */
3157 datap = smb_GetSMBData(outp, NULL);
3158 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3159 /* and the faux domain name */
3160 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3161 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3165 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3167 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3169 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3171 datap = smb_GetSMBData(outp, NULL);
3172 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3175 datap += sizeof(smb_ServerGUID);
3176 memcpy(datap, secBlob, secBlobLength);
3180 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3181 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3184 else if (v3ProtoIndex != -1) {
3185 smb_SetSMBParm(outp, 0, protoIndex);
3187 /* NOTE: Extended authentication cannot be negotiated with v3
3188 * therefore we fail over to NTLM
3190 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3191 smb_SetSMBParm(outp, 1,
3192 NEGOTIATE_SECURITY_USER_LEVEL |
3193 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3195 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3197 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3198 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3199 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3200 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3201 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3202 smb_SetSMBParm(outp, 7, 1);
3204 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3205 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3206 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3208 GetTimeZoneInformation(&tzi);
3209 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3211 /* NOTE: Extended authentication cannot be negotiated with v3
3212 * therefore we fail over to NTLM
3214 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3215 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3216 smb_SetSMBParm(outp, 12, 0); /* resvd */
3217 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3218 datap = smb_GetSMBData(outp, NULL);
3219 /* paste in a new encryption key */
3220 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3221 /* and the faux domain name */
3222 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3224 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3225 smb_SetSMBParm(outp, 12, 0); /* resvd */
3226 smb_SetSMBDataLength(outp, 0);
3229 else if (coreProtoIndex != -1) { /* not really supported anymore */
3230 smb_SetSMBParm(outp, 0, protoIndex);
3231 smb_SetSMBDataLength(outp, 0);
3236 void smb_CheckVCs(void)
3238 smb_vc_t * vcp, *nextp;
3239 smb_packet_t * outp = GetPacket();
3242 lock_ObtainWrite(&smb_rctLock);
3243 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3245 if (vcp->magic != SMB_VC_MAGIC)
3246 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3247 __FILE__, __LINE__);
3251 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3254 smb_HoldVCNoLock(vcp);
3256 smb_HoldVCNoLock(nextp);
3257 smb_FormatResponsePacket(vcp, NULL, outp);
3258 smbp = (smb_t *)outp;
3259 outp->inCom = smbp->com = 0x2b /* Echo */;
3267 smb_SetSMBParm(outp, 0, 0);
3268 smb_SetSMBDataLength(outp, 0);
3269 lock_ReleaseWrite(&smb_rctLock);
3271 smb_SendPacket(vcp, outp);
3273 lock_ObtainWrite(&smb_rctLock);
3274 smb_ReleaseVCNoLock(vcp);
3276 smb_ReleaseVCNoLock(nextp);
3278 lock_ReleaseWrite(&smb_rctLock);
3279 smb_FreePacket(outp);
3282 void smb_Daemon(void *parmp)
3284 afs_uint32 count = 0;
3285 smb_username_t **unpp;
3288 while(smbShutdownFlag == 0) {
3292 if (smbShutdownFlag == 1)
3295 if ((count % 72) == 0) { /* every five minutes */
3297 time_t old_localZero = smb_localZero;
3299 /* Initialize smb_localZero */
3300 myTime.tm_isdst = -1; /* compute whether on DST or not */
3301 myTime.tm_year = 70;
3307 smb_localZero = mktime(&myTime);
3309 #ifndef USE_NUMERIC_TIME_CONV
3310 smb_CalculateNowTZ();
3311 #endif /* USE_NUMERIC_TIME_CONV */
3312 #ifdef AFS_FREELANCE
3313 if ( smb_localZero != old_localZero )
3314 cm_noteLocalMountPointChange();
3320 /* GC smb_username_t objects that will no longer be used */
3322 lock_ObtainWrite(&smb_rctLock);
3323 for ( unpp=&usernamesp; *unpp; ) {
3325 smb_username_t *unp;
3327 lock_ObtainMutex(&(*unpp)->mx);
3328 if ( (*unpp)->refCount > 0 ||
3329 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3330 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3332 else if (!smb_LogoffTokenTransfer ||
3333 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3335 lock_ReleaseMutex(&(*unpp)->mx);
3343 lock_FinalizeMutex(&unp->mx);
3349 lock_ReleaseWrite(&smb_rctLock);
3350 cm_ReleaseUser(userp);
3351 lock_ObtainWrite(&smb_rctLock);
3354 unpp = &(*unpp)->nextp;
3357 lock_ReleaseWrite(&smb_rctLock);
3359 /* XXX GC dir search entries */
3363 void smb_WaitingLocksDaemon()
3365 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3366 smb_waitingLock_t *wl, *wlNext;
3369 smb_packet_t *inp, *outp;
3373 while (smbShutdownFlag == 0) {
3374 lock_ObtainWrite(&smb_globalLock);
3375 nwlRequest = smb_allWaitingLocks;
3376 if (nwlRequest == NULL) {
3377 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3382 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3389 lock_ObtainWrite(&smb_globalLock);
3391 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3393 wlRequest = nwlRequest;
3394 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3395 lock_ReleaseWrite(&smb_globalLock);
3399 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3400 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3403 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3405 /* wl->state is either _DONE or _WAITING. _ERROR
3406 would no longer be on the queue. */
3407 code = cm_RetryLock( wl->lockp,
3408 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3411 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3412 } else if (code != CM_ERROR_WOULDBLOCK) {
3413 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3418 if (code == CM_ERROR_WOULDBLOCK) {
3421 if (wlRequest->timeRemaining != 0xffffffff
3422 && (wlRequest->timeRemaining -= 1000) < 0)
3434 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3437 scp = wlRequest->scp;
3438 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3442 lock_ObtainMutex(&scp->mx);
3444 for (wl = wlRequest->locks; wl; wl = wlNext) {
3445 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3447 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3448 wl->LLength, wl->key, NULL, &req);
3450 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3455 lock_ReleaseMutex(&scp->mx);
3459 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3462 for (wl = wlRequest->locks; wl; wl = wlNext) {
3463 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3464 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3469 vcp = wlRequest->vcp;
3470 inp = wlRequest->inp;
3471 outp = wlRequest->outp;
3473 ncbp->ncb_length = inp->ncb_length;
3474 inp->spacep = cm_GetSpace();
3476 /* Remove waitingLock from list */
3477 lock_ObtainWrite(&smb_globalLock);
3478 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3480 lock_ReleaseWrite(&smb_globalLock);
3482 /* Resume packet processing */
3484 smb_SetSMBDataLength(outp, 0);
3485 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3486 outp->resumeCode = code;
3488 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3491 cm_FreeSpace(inp->spacep);
3492 smb_FreePacket(inp);
3493 smb_FreePacket(outp);
3495 cm_ReleaseSCache(wlRequest->scp);
3498 } while (nwlRequest && smbShutdownFlag == 0);
3503 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3505 osi_Log0(smb_logp, "SMB receive get disk attributes");
3507 smb_SetSMBParm(outp, 0, 32000);
3508 smb_SetSMBParm(outp, 1, 64);
3509 smb_SetSMBParm(outp, 2, 1024);
3510 smb_SetSMBParm(outp, 3, 30000);
3511 smb_SetSMBParm(outp, 4, 0);
3512 smb_SetSMBDataLength(outp, 0);
3516 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3520 unsigned short newTid;
3521 char shareName[AFSPATHMAX];
3529 osi_Log0(smb_logp, "SMB receive tree connect");
3531 /* parse input parameters */
3532 tp = smb_GetSMBData(inp, NULL);
3533 pathp = smb_ParseASCIIBlock(tp, &tp);
3534 if (smb_StoreAnsiFilenames)
3535 OemToChar(pathp,pathp);
3536 passwordp = smb_ParseASCIIBlock(tp, &tp);
3537 tp = strrchr(pathp, '\\');
3539 return CM_ERROR_BADSMB;
3540 strcpy(shareName, tp+1);
3542 lock_ObtainMutex(&vcp->mx);
3543 newTid = vcp->tidCounter++;
3544 lock_ReleaseMutex(&vcp->mx);
3546 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3547 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3548 userp = smb_GetUserFromUID(uidp);
3549 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3551 smb_ReleaseUID(uidp);
3553 smb_ReleaseTID(tidp);
3554 return CM_ERROR_BADSHARENAME;
3556 lock_ObtainMutex(&tidp->mx);
3557 tidp->userp = userp;
3558 tidp->pathname = sharePath;
3559 lock_ReleaseMutex(&tidp->mx);
3560 smb_ReleaseTID(tidp);
3562 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3563 smb_SetSMBParm(rsp, 1, newTid);
3564 smb_SetSMBDataLength(rsp, 0);
3566 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3570 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3574 if (*inp++ != 0x1) return NULL;
3575 tlen = inp[0] + (inp[1]<<8);
3576 inp += 2; /* skip length field */
3579 *chainpp = inp + tlen;
3582 if (lengthp) *lengthp = tlen;
3587 /* set maskp to the mask part of the incoming path.
3588 * Mask is 11 bytes long (8.3 with the dot elided).
3589 * Returns true if succeeds with a valid name, otherwise it does
3590 * its best, but returns false.
3592 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3600 /* starts off valid */
3603 /* mask starts out all blanks */
3604 memset(maskp, ' ', 11);
3607 /* find last backslash, or use whole thing if there is none */
3608 tp = strrchr(pathp, '\\');
3612 tp++; /* skip slash */
3616 /* names starting with a dot are illegal */
3624 if (tc == '.' || tc == '"')
3632 /* if we get here, tp point after the dot */
3633 up = maskp+8; /* ext goes here */
3640 if (tc == '.' || tc == '"')
3643 /* copy extension if not too long */
3653 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3663 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3665 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3669 /* otherwise, we have a valid 8.3 name; see if we have a match,
3670 * treating '?' as a wildcard in maskp (but not in the file name).
3672 tp1 = umask; /* real name, in mask format */
3673 tp2 = maskp; /* mask, in mask format */
3674 for(i=0; i<11; i++) {
3675 tc1 = *tp1++; /* char from real name */
3676 tc2 = *tp2++; /* char from mask */
3677 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3678 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3681 if (tc2 == '?' && tc1 != ' ')
3688 /* we got a match */
3692 char *smb_FindMask(char *pathp)
3696 tp = strrchr(pathp, '\\'); /* find last slash */
3699 return tp+1; /* skip the slash */
3701 return pathp; /* no slash, return the entire path */
3704 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3706 unsigned char *pathp;
3708 unsigned char mask[12];
3709 unsigned char *statBlockp;
3710 unsigned char initStatBlock[21];
3713 osi_Log0(smb_logp, "SMB receive search volume");
3715 /* pull pathname and stat block out of request */
3716 tp = smb_GetSMBData(inp, NULL);
3717 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3718 osi_assertx(pathp != NULL, "null path");
3719 if (smb_StoreAnsiFilenames)
3720 OemToChar(pathp,pathp);
3721 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3722 osi_assertx(statBlockp != NULL, "null statBlock");
3724 statBlockp = initStatBlock;
3728 /* for returning to caller */
3729 smb_Get8Dot3MaskFromPath(mask, pathp);
3731 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3732 tp = smb_GetSMBData(outp, NULL);
3734 *tp++ = 43; /* bytes in a dir entry */
3735 *tp++ = 0; /* high byte in counter */
3737 /* now marshall the dir entry, starting with the search status */
3738 *tp++ = statBlockp[0]; /* Reserved */
3739 memcpy(tp, mask, 11); tp += 11; /* FileName */
3741 /* now pass back server use info, with 1st byte non-zero */
3743 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3745 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3747 *tp++ = 0x8; /* attribute: volume */
3757 /* 4 byte file size */
3763 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3764 memset(tp, ' ', 13);
3767 /* set the length of the data part of the packet to 43 + 3, for the dir
3768 * entry plus the 5 and the length fields.
3770 smb_SetSMBDataLength(outp, 46);
3775 smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3776 char * tidPathp, char * relPathp,
3777 cm_user_t *userp, cm_req_t *reqp)
3785 smb_dirListPatch_t *patchp;
3786 smb_dirListPatch_t *npatchp;
3787 char path[AFSPATHMAX];
3789 for (patchp = *dirPatchespp; patchp; patchp =
3790 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3792 dptr = patchp->dptr;
3794 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
3795 reqp->relPathp = path;
3796 reqp->tidPathp = tidPathp;
3798 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3799 reqp->relPathp = reqp->tidPathp = NULL;
3802 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3803 *dptr++ = SMB_ATTR_HIDDEN;
3806 lock_ObtainMutex(&scp->mx);
3807 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3808 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3810 lock_ReleaseMutex(&scp->mx);
3811 cm_ReleaseSCache(scp);
3812 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3813 *dptr++ = SMB_ATTR_HIDDEN;
3817 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3819 attr = smb_Attributes(scp);
3820 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3821 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3822 attr |= SMB_ATTR_HIDDEN;
3826 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3829 shortTemp = (unsigned short) (dosTime & 0xffff);
3830 *((u_short *)dptr) = shortTemp;
3833 /* and copy out date */
3834 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3835 *((u_short *)dptr) = shortTemp;
3838 /* copy out file length */
3839 *((u_long *)dptr) = scp->length.LowPart;
3841 lock_ReleaseMutex(&scp->mx);
3842 cm_ReleaseSCache(scp);
3845 /* now free the patches */
3846 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3847 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3851 /* and mark the list as empty */
3852 *dirPatchespp = NULL;
3857 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3864 cm_dirEntry_t *dep = 0;
3866 smb_dirListPatch_t *dirListPatchesp;
3867 smb_dirListPatch_t *curPatchp;
3871 osi_hyper_t dirLength;
3872 osi_hyper_t bufferOffset;
3873 osi_hyper_t curOffset;
3875 unsigned char *inCookiep;
3876 smb_dirSearch_t *dsp;
3880 unsigned long clientCookie;
3881 cm_pageHeader_t *pageHeaderp;
3882 cm_user_t *userp = NULL;
3889 long nextEntryCookie;
3890 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3891 char resByte; /* reserved byte from the cookie */
3892 char *op; /* output data ptr */
3893 char *origOp; /* original value of op */
3894 cm_space_t *spacep; /* for pathname buffer */
3905 maxCount = smb_GetSMBParm(inp, 0);
3907 dirListPatchesp = NULL;
3909 caseFold = CM_FLAG_CASEFOLD;
3911 tp = smb_GetSMBData(inp, NULL);
3912 pathp = smb_ParseASCIIBlock(tp, &tp);
3913 if (smb_StoreAnsiFilenames)
3914 OemToChar(pathp,pathp);
3915 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3917 /* bail out if request looks bad */
3918 if (!tp || !pathp) {
3919 return CM_ERROR_BADSMB;
3922 /* We can handle long names */
3923 if (vcp->flags & SMB_VCFLAG_USENT)
3924 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3926 /* make sure we got a whole search status */
3927 if (dataLength < 21) {
3928 nextCookie = 0; /* start at the beginning of the dir */
3931 attribute = smb_GetSMBParm(inp, 1);
3933 /* handle volume info in another function */
3934 if (attribute & 0x8)
3935 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3937 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3938 maxCount, osi_LogSaveString(smb_logp, pathp));
3940 if (*pathp == 0) { /* null pathp, treat as root dir */
3941 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3942 return CM_ERROR_NOFILES;
3946 dsp = smb_NewDirSearch(0);
3947 dsp->attribute = attribute;
3948 smb_Get8Dot3MaskFromPath(mask, pathp);
3949 memcpy(dsp->mask, mask, 12);
3951 /* track if this is likely to match a lot of entries */
3952 if (smb_IsStarMask(mask))
3957 /* pull the next cookie value out of the search status block */
3958 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3959 + (inCookiep[16]<<24);
3960 dsp = smb_FindDirSearch(inCookiep[12]);
3962 /* can't find dir search status; fatal error */
3963 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3964 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3965 return CM_ERROR_BADFD;
3967 attribute = dsp->attribute;
3968 resByte = inCookiep[0];
3970 /* copy out client cookie, in host byte order. Don't bother
3971 * interpreting it, since we're just passing it through, anyway.
3973 memcpy(&clientCookie, &inCookiep[17], 4);
3975 memcpy(mask, dsp->mask, 12);
3977 /* assume we're doing a star match if it has continued for more
3983 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3984 nextCookie, dsp->cookie, attribute);
3986 userp = smb_GetUserFromVCP(vcp, inp);
3988 /* try to get the vnode for the path name next */
3989 lock_ObtainMutex(&dsp->mx);
3992 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3996 spacep = inp->spacep;
3997 smb_StripLastComponent(spacep->data, NULL, pathp);
3998 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4000 lock_ReleaseMutex(&dsp->mx);
4001 cm_ReleaseUser(userp);
4002 smb_DeleteDirSearch(dsp);
4003 smb_ReleaseDirSearch(dsp);
4004 return CM_ERROR_NOFILES;
4006 strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
4007 strcpy(dsp->relPath, spacep->data);
4009 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4010 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4013 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4014 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4015 cm_ReleaseSCache(scp);
4016 lock_ReleaseMutex(&dsp->mx);
4017 cm_ReleaseUser(userp);
4018 smb_DeleteDirSearch(dsp);
4019 smb_ReleaseDirSearch(dsp);
4020 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4021 return CM_ERROR_PATH_NOT_COVERED;
4023 return CM_ERROR_BADSHARENAME;
4025 #endif /* DFS_SUPPORT */
4028 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4029 /* we need one hold for the entry we just stored into,
4030 * and one for our own processing. When we're done with this
4031 * function, we'll drop the one for our own processing.
4032 * We held it once from the namei call, and so we do another hold
4036 lock_ObtainMutex(&scp->mx);
4037 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4038 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4039 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4040 dsp->flags |= SMB_DIRSEARCH_BULKST;
4041 dsp->scp->bulkStatProgress = hzero;
4043 lock_ReleaseMutex(&scp->mx);
4046 lock_ReleaseMutex(&dsp->mx);
4048 cm_ReleaseUser(userp);
4049 smb_DeleteDirSearch(dsp);
4050 smb_ReleaseDirSearch(dsp);
4054 /* reserves space for parameter; we'll adjust it again later to the
4055 * real count of the # of entries we returned once we've actually
4056 * assembled the directory listing.
4058 smb_SetSMBParm(outp, 0, 0);
4060 /* get the directory size */
4061 lock_ObtainMutex(&scp->mx);
4062 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4063 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4065 lock_ReleaseMutex(&scp->mx);
4066 cm_ReleaseSCache(scp);
4067 cm_ReleaseUser(userp);
4068 smb_DeleteDirSearch(dsp);
4069 smb_ReleaseDirSearch(dsp);
4073 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4075 dirLength = scp->length;
4077 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4078 curOffset.HighPart = 0;
4079 curOffset.LowPart = nextCookie;
4080 origOp = op = smb_GetSMBData(outp, NULL);
4081 /* and write out the basic header */
4082 *op++ = 5; /* variable block */
4083 op += 2; /* skip vbl block length; we'll fill it in later */
4087 /* make sure that curOffset.LowPart doesn't point to the first
4088 * 32 bytes in the 2nd through last dir page, and that it doesn't
4089 * point at the first 13 32-byte chunks in the first dir page,
4090 * since those are dir and page headers, and don't contain useful
4093 temp = curOffset.LowPart & (2048-1);
4094 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4095 /* we're in the first page */
4096 if (temp < 13*32) temp = 13*32;
4099 /* we're in a later dir page */
4100 if (temp < 32) temp = 32;
4103 /* make sure the low order 5 bits are zero */
4106 /* now put temp bits back ito curOffset.LowPart */
4107 curOffset.LowPart &= ~(2048-1);
4108 curOffset.LowPart |= temp;
4110 /* check if we've returned all the names that will fit in the
4113 if (returnedNames >= maxCount) {
4114 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4115 returnedNames, maxCount);
4119 /* check if we've passed the dir's EOF */
4120 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4122 /* see if we can use the bufferp we have now; compute in which page
4123 * the current offset would be, and check whether that's the offset
4124 * of the buffer we have. If not, get the buffer.
4126 thyper.HighPart = curOffset.HighPart;
4127 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4128 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4131 buf_Release(bufferp);
4134 lock_ReleaseMutex(&scp->mx);
4135 lock_ObtainRead(&scp->bufCreateLock);
4136 code = buf_Get(scp, &thyper, &bufferp);
4137 lock_ReleaseRead(&scp->bufCreateLock);
4138 lock_ObtainMutex(&dsp->mx);
4140 /* now, if we're doing a star match, do bulk fetching of all of
4141 * the status info for files in the dir.
4144 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4145 lock_ObtainMutex(&scp->mx);
4146 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4147 LargeIntegerGreaterThanOrEqualTo(thyper,
4148 scp->bulkStatProgress)) {
4149 /* Don't bulk stat if risking timeout */
4150 int now = GetTickCount();
4151 if (now - req.startTime > RDRtimeout * 1000) {
4152 scp->bulkStatProgress = thyper;
4153 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4154 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4155 dsp->scp->bulkStatProgress = hzero;
4157 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4160 lock_ObtainMutex(&scp->mx);
4162 lock_ReleaseMutex(&dsp->mx);
4164 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4168 bufferOffset = thyper;
4170 /* now get the data in the cache */
4172 code = cm_SyncOp(scp, bufferp, userp, &req,
4174 CM_SCACHESYNC_NEEDCALLBACK |
4175 CM_SCACHESYNC_READ);
4177 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4181 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4183 if (cm_HaveBuffer(scp, bufferp, 0)) {
4184 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4188 /* otherwise, load the buffer and try again */
4189 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4191 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4192 scp, bufferp, code);
4197 buf_Release(bufferp);
4201 } /* if (wrong buffer) ... */
4203 /* now we have the buffer containing the entry we're interested in; copy
4204 * it out if it represents a non-deleted entry.
4206 entryInDir = curOffset.LowPart & (2048-1);
4207 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4209 /* page header will help tell us which entries are free. Page header
4210 * can change more often than once per buffer, since AFS 3 dir page size
4211 * may be less than (but not more than a buffer package buffer.
4213 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4214 temp &= ~(2048 - 1); /* turn off intra-page bits */
4215 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4217 /* now determine which entry we're looking at in the page. If it is
4218 * free (there's a free bitmap at the start of the dir), we should
4219 * skip these 32 bytes.
4221 slotInPage = (entryInDir & 0x7e0) >> 5;
4222 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4223 /* this entry is free */
4224 numDirChunks = 1; /* only skip this guy */
4228 tp = bufferp->datap + entryInBuffer;
4229 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4231 /* while we're here, compute the next entry's location, too,
4232 * since we'll need it when writing out the cookie into the dir
4235 * XXXX Probably should do more sanity checking.
4237 numDirChunks = cm_NameEntries(dep->name, NULL);
4239 /* compute the offset of the cookie representing the next entry */
4240 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4242 /* Compute 8.3 name if necessary */
4243 actualName = dep->name;
4244 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4245 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4246 actualName = shortName;
4249 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4250 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4251 osi_LogSaveString(smb_logp, actualName));
4253 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4254 /* this is one of the entries to use: it is not deleted
4255 * and it matches the star pattern we're looking for.
4258 /* Eliminate entries that don't match requested
4261 /* no hidden files */
4262 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4263 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4267 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4269 /* We have already done the cm_TryBulkStat above */
4270 fid.cell = scp->fid.cell;
4271 fid.volume = scp->fid.volume;
4272 fid.vnode = ntohl(dep->fid.vnode);
4273 fid.unique = ntohl(dep->fid.unique);
4274 fileType = cm_FindFileType(&fid);
4275 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4276 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4278 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4279 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4280 fileType == CM_SCACHETYPE_DFSLINK ||
4281 fileType == CM_SCACHETYPE_INVALID)
4282 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4287 memcpy(op, mask, 11); op += 11;
4288 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4289 *op++ = (char)(nextEntryCookie & 0xff);
4290 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4291 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4292 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4293 memcpy(op, &clientCookie, 4); op += 4;
4295 /* now we emit the attribute. This is sort of tricky,
4296 * since we need to really stat the file to find out
4297 * what type of entry we've got. Right now, we're
4298 * copying out data from a buffer, while holding the
4299 * scp locked, so it isn't really convenient to stat
4300 * something now. We'll put in a place holder now,
4301 * and make a second pass before returning this to get
4302 * the real attributes. So, we just skip the data for
4303 * now, and adjust it later. We allocate a patch
4304 * record to make it easy to find this point later.
4305 * The replay will happen at a time when it is safe to
4306 * unlock the directory.
4308 curPatchp = malloc(sizeof(*curPatchp));
4309 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4310 curPatchp->dptr = op;
4311 curPatchp->fid.cell = scp->fid.cell;
4312 curPatchp->fid.volume = scp->fid.volume;
4313 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4314 curPatchp->fid.unique = ntohl(dep->fid.unique);
4316 /* do hidden attribute here since name won't be around when applying
4320 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4321 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4323 curPatchp->flags = 0;
4325 op += 9; /* skip attr, time, date and size */
4327 /* zero out name area. The spec says to pad with
4328 * spaces, but Samba doesn't, and neither do we.
4332 /* finally, we get to copy out the name; we know that
4333 * it fits in 8.3 or the pattern wouldn't match, but it
4334 * never hurts to be sure.
4336 strncpy(op, actualName, 13);
4337 if (smb_StoreAnsiFilenames)
4340 /* Uppercase if requested by client */
4341 if (!KNOWS_LONG_NAMES(inp))
4346 /* now, adjust the # of entries copied */
4348 } /* if we're including this name */
4351 /* and adjust curOffset to be where the new cookie is */
4352 thyper.HighPart = 0;
4353 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4354 curOffset = LargeIntegerAdd(thyper, curOffset);
4355 } /* while copying data for dir listing */
4357 /* release the mutex */
4358 lock_ReleaseMutex(&scp->mx);
4360 buf_Release(bufferp);
4364 /* apply and free last set of patches; if not doing a star match, this
4365 * will be empty, but better safe (and freeing everything) than sorry.
4367 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4369 /* special return code for unsuccessful search */
4370 if (code == 0 && dataLength < 21 && returnedNames == 0)
4371 code = CM_ERROR_NOFILES;
4373 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4374 returnedNames, code);
4377 smb_DeleteDirSearch(dsp);
4378 smb_ReleaseDirSearch(dsp);
4379 cm_ReleaseSCache(scp);
4380 cm_ReleaseUser(userp);
4384 /* finalize the output buffer */
4385 smb_SetSMBParm(outp, 0, returnedNames);
4386 temp = (long) (op - origOp);
4387 smb_SetSMBDataLength(outp, temp);
4389 /* the data area is a variable block, which has a 5 (already there)
4390 * followed by the length of the # of data bytes. We now know this to
4391 * be "temp," although that includes the 3 bytes of vbl block header.
4392 * Deduct for them and fill in the length field.
4394 temp -= 3; /* deduct vbl block info */
4395 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4396 origOp[1] = (char)(temp & 0xff);
4397 origOp[2] = (char)((temp>>8) & 0xff);
4398 if (returnedNames == 0)
4399 smb_DeleteDirSearch(dsp);
4400 smb_ReleaseDirSearch(dsp);
4401 cm_ReleaseSCache(scp);
4402 cm_ReleaseUser(userp);
4406 /* verify that this is a valid path to a directory. I don't know why they
4407 * don't use the get file attributes call.
4409 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4413 cm_scache_t *rootScp;
4414 cm_scache_t *newScp;
4423 pathp = smb_GetSMBData(inp, NULL);
4424 pathp = smb_ParseASCIIBlock(pathp, NULL);
4426 return CM_ERROR_BADFD;
4427 if (smb_StoreAnsiFilenames)
4428 OemToChar(pathp,pathp);
4429 osi_Log1(smb_logp, "SMB receive check path %s",
4430 osi_LogSaveString(smb_logp, pathp));
4432 rootScp = cm_data.rootSCachep;
4434 userp = smb_GetUserFromVCP(vcp, inp);
4436 caseFold = CM_FLAG_CASEFOLD;
4438 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4440 cm_ReleaseUser(userp);
4441 return CM_ERROR_NOSUCHPATH;
4443 code = cm_NameI(rootScp, pathp,
4444 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4445 userp, tidPathp, &req, &newScp);
4448 cm_ReleaseUser(userp);
4453 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4454 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4455 cm_ReleaseSCache(newScp);
4456 cm_ReleaseUser(userp);
4457 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4458 return CM_ERROR_PATH_NOT_COVERED;
4460 return CM_ERROR_BADSHARENAME;
4462 #endif /* DFS_SUPPORT */
4464 /* now lock the vnode with a callback; returns with newScp locked */
4465 lock_ObtainMutex(&newScp->mx);
4466 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4467 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4469 if (code != CM_ERROR_NOACCESS) {
4470 lock_ReleaseMutex(&newScp->mx);
4471 cm_ReleaseSCache(newScp);
4472 cm_ReleaseUser(userp);
4476 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4479 attrs = smb_Attributes(newScp);
4481 if (!(attrs & SMB_ATTR_DIRECTORY))
4482 code = CM_ERROR_NOTDIR;
4484 lock_ReleaseMutex(&newScp->mx);
4486 cm_ReleaseSCache(newScp);
4487 cm_ReleaseUser(userp);
4491 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4495 cm_scache_t *rootScp;
4496 unsigned short attribute;
4498 cm_scache_t *newScp;
4507 /* decode basic attributes we're passed */
4508 attribute = smb_GetSMBParm(inp, 0);
4509 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4511 pathp = smb_GetSMBData(inp, NULL);
4512 pathp = smb_ParseASCIIBlock(pathp, NULL);
4514 return CM_ERROR_BADSMB;
4515 if (smb_StoreAnsiFilenames)
4516 OemToChar(pathp,pathp);
4518 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4519 dosTime, attribute);
4521 rootScp = cm_data.rootSCachep;
4523 userp = smb_GetUserFromVCP(vcp, inp);
4525 caseFold = CM_FLAG_CASEFOLD;
4527 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4529 cm_ReleaseUser(userp);
4530 return CM_ERROR_NOSUCHFILE;
4532 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4533 tidPathp, &req, &newScp);
4536 cm_ReleaseUser(userp);
4541 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4542 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4543 cm_ReleaseSCache(newScp);
4544 cm_ReleaseUser(userp);
4545 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4546 return CM_ERROR_PATH_NOT_COVERED;
4548 return CM_ERROR_BADSHARENAME;
4550 #endif /* DFS_SUPPORT */
4552 /* now lock the vnode with a callback; returns with newScp locked; we
4553 * need the current status to determine what the new status is, in some
4556 lock_ObtainMutex(&newScp->mx);
4557 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4558 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4560 lock_ReleaseMutex(&newScp->mx);
4561 cm_ReleaseSCache(newScp);
4562 cm_ReleaseUser(userp);
4566 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4568 /* Check for RO volume */
4569 if (newScp->flags & CM_SCACHEFLAG_RO) {
4570 lock_ReleaseMutex(&newScp->mx);
4571 cm_ReleaseSCache(newScp);
4572 cm_ReleaseUser(userp);
4573 return CM_ERROR_READONLY;
4576 /* prepare for setattr call */
4579 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4580 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4582 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4583 /* we're told to make a writable file read-only */
4584 attr.unixModeBits = newScp->unixModeBits & ~0222;
4585 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4587 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4588 /* we're told to make a read-only file writable */
4589 attr.unixModeBits = newScp->unixModeBits | 0222;
4590 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4592 lock_ReleaseMutex(&newScp->mx);
4594 /* now call setattr */
4596 code = cm_SetAttr(newScp, &attr, userp, &req);
4600 cm_ReleaseSCache(newScp);
4601 cm_ReleaseUser(userp);
4606 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4610 cm_scache_t *rootScp;
4611 cm_scache_t *newScp, *dscp;
4623 pathp = smb_GetSMBData(inp, NULL);
4624 pathp = smb_ParseASCIIBlock(pathp, NULL);
4626 return CM_ERROR_BADSMB;
4628 if (*pathp == 0) /* null path */
4631 if (smb_StoreAnsiFilenames)
4632 OemToChar(pathp,pathp);
4634 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4635 osi_LogSaveString(smb_logp, pathp));
4637 rootScp = cm_data.rootSCachep;
4639 userp = smb_GetUserFromVCP(vcp, inp);
4641 /* we shouldn't need this for V3 requests, but we seem to */
4642 caseFold = CM_FLAG_CASEFOLD;
4644 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4646 cm_ReleaseUser(userp);
4647 return CM_ERROR_NOSUCHFILE;
4651 * XXX Strange hack XXX
4653 * As of Patch 5 (16 July 97), we are having the following problem:
4654 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4655 * requests to look up "desktop.ini" in all the subdirectories.
4656 * This can cause zillions of timeouts looking up non-existent cells
4657 * and volumes, especially in the top-level directory.
4659 * We have not found any way to avoid this or work around it except
4660 * to explicitly ignore the requests for mount points that haven't
4661 * yet been evaluated and for directories that haven't yet been
4664 * We should modify this hack to provide a fake desktop.ini file
4665 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4667 spacep = inp->spacep;
4668 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4669 #ifndef SPECIAL_FOLDERS
4670 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4671 code = cm_NameI(rootScp, spacep->data,
4672 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4673 userp, tidPathp, &req, &dscp);
4676 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4677 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
4678 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4679 return CM_ERROR_PATH_NOT_COVERED;
4681 return CM_ERROR_BADSHARENAME;
4683 #endif /* DFS_SUPPORT */
4684 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4685 code = CM_ERROR_NOSUCHFILE;
4686 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4687 cm_buf_t *bp = buf_Find(dscp, &hzero);
4692 code = CM_ERROR_NOSUCHFILE;
4694 cm_ReleaseSCache(dscp);
4696 cm_ReleaseUser(userp);
4701 #endif /* SPECIAL_FOLDERS */
4703 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4704 tidPathp, &req, &newScp);
4706 cm_ReleaseUser(userp);
4711 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4712 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4713 cm_ReleaseSCache(newScp);
4714 cm_ReleaseUser(userp);
4715 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4716 return CM_ERROR_PATH_NOT_COVERED;
4718 return CM_ERROR_BADSHARENAME;
4720 #endif /* DFS_SUPPORT */
4722 /* now lock the vnode with a callback; returns with newScp locked */
4723 lock_ObtainMutex(&newScp->mx);
4724 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4725 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4727 lock_ReleaseMutex(&newScp->mx);
4728 cm_ReleaseSCache(newScp);
4729 cm_ReleaseUser(userp);
4733 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4736 /* use smb_Attributes instead. Also the fact that a file is
4737 * in a readonly volume doesn't mean it shojuld be marked as RO
4739 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4740 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4741 newScp->fileType == CM_SCACHETYPE_INVALID)
4742 attrs = SMB_ATTR_DIRECTORY;
4745 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4746 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4748 attrs = smb_Attributes(newScp);
4751 smb_SetSMBParm(outp, 0, attrs);
4753 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4754 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4755 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4756 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4757 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4758 smb_SetSMBParm(outp, 5, 0);
4759 smb_SetSMBParm(outp, 6, 0);
4760 smb_SetSMBParm(outp, 7, 0);
4761 smb_SetSMBParm(outp, 8, 0);
4762 smb_SetSMBParm(outp, 9, 0);
4763 smb_SetSMBDataLength(outp, 0);
4764 lock_ReleaseMutex(&newScp->mx);
4766 cm_ReleaseSCache(newScp);
4767 cm_ReleaseUser(userp);
4772 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4776 osi_Log0(smb_logp, "SMB receive tree disconnect");
4778 /* find the tree and free it */
4779 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4781 lock_ObtainWrite(&smb_rctLock);
4783 lock_ReleaseWrite(&smb_rctLock);
4784 smb_ReleaseTID(tidp);
4790 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4808 pathp = smb_GetSMBData(inp, NULL);
4809 pathp = smb_ParseASCIIBlock(pathp, NULL);
4810 if (smb_StoreAnsiFilenames)
4811 OemToChar(pathp,pathp);
4813 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4815 #ifdef DEBUG_VERBOSE
4819 hexpath = osi_HexifyString( pathp );
4820 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4825 share = smb_GetSMBParm(inp, 0);
4826 attribute = smb_GetSMBParm(inp, 1);
4828 spacep = inp->spacep;
4829 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4830 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4831 /* special case magic file name for receiving IOCTL requests
4832 * (since IOCTL calls themselves aren't getting through).
4834 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4835 smb_SetupIoctlFid(fidp, spacep);
4836 smb_SetSMBParm(outp, 0, fidp->fid);
4837 smb_SetSMBParm(outp, 1, 0); /* attrs */
4838 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4839 smb_SetSMBParm(outp, 3, 0);
4840 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4841 smb_SetSMBParm(outp, 5, 0x7fff);
4842 /* pass the open mode back */
4843 smb_SetSMBParm(outp, 6, (share & 0xf));
4844 smb_SetSMBDataLength(outp, 0);
4845 smb_ReleaseFID(fidp);
4849 userp = smb_GetUserFromVCP(vcp, inp);
4851 caseFold = CM_FLAG_CASEFOLD;
4853 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4855 cm_ReleaseUser(userp);
4856 return CM_ERROR_NOSUCHPATH;
4858 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4859 tidPathp, &req, &scp);
4862 cm_ReleaseUser(userp);
4867 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4868 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
4869 cm_ReleaseSCache(scp);
4870 cm_ReleaseUser(userp);
4871 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4872 return CM_ERROR_PATH_NOT_COVERED;
4874 return CM_ERROR_BADSHARENAME;
4876 #endif /* DFS_SUPPORT */
4878 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4880 cm_ReleaseSCache(scp);
4881 cm_ReleaseUser(userp);
4885 /* don't need callback to check file type, since file types never
4886 * change, and namei and cm_Lookup all stat the object at least once on
4887 * a successful return.
4889 if (scp->fileType != CM_SCACHETYPE_FILE) {
4890 cm_ReleaseSCache(scp);
4891 cm_ReleaseUser(userp);
4892 return CM_ERROR_ISDIR;
4895 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4896 osi_assertx(fidp, "null smb_fid_t");
4898 /* save a pointer to the vnode */
4900 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4901 lock_ObtainMutex(&scp->mx);
4902 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4903 lock_ReleaseMutex(&scp->mx);
4907 fidp->userp = userp;
4909 lock_ObtainMutex(&fidp->mx);
4910 if ((share & 0xf) == 0)
4911 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4912 else if ((share & 0xf) == 1)
4913 fidp->flags |= SMB_FID_OPENWRITE;
4915 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4916 lock_ReleaseMutex(&fidp->mx);
4918 lock_ObtainMutex(&scp->mx);
4919 smb_SetSMBParm(outp, 0, fidp->fid);
4920 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4921 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4922 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4923 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4924 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4925 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4926 /* pass the open mode back; XXXX add access checks */
4927 smb_SetSMBParm(outp, 6, (share & 0xf));
4928 smb_SetSMBDataLength(outp, 0);
4929 lock_ReleaseMutex(&scp->mx);
4932 cm_Open(scp, 0, userp);
4934 /* send and free packet */
4935 smb_ReleaseFID(fidp);
4936 cm_ReleaseUser(userp);
4937 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4941 typedef struct smb_unlinkRock {
4946 char *maskp; /* pointer to the star pattern */
4949 cm_dirEntryList_t * matches;
4952 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4955 smb_unlinkRock_t *rockp;
4963 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4964 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4965 caseFold |= CM_FLAG_8DOT3;
4967 matchName = dep->name;
4968 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4970 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4971 !cm_Is8Dot3(dep->name)) {
4972 cm_Gen8Dot3Name(dep, shortName, NULL);
4973 matchName = shortName;
4974 /* 8.3 matches are always case insensitive */
4975 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4978 osi_Log1(smb_logp, "Found match %s",
4979 osi_LogSaveString(smb_logp, matchName));
4981 cm_DirEntryListAdd(dep->name, &rockp->matches);
4985 /* If we made a case sensitive exact match, we might as well quit now. */
4986 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4987 code = CM_ERROR_STOPNOW;
4996 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5005 smb_unlinkRock_t rock;
5014 attribute = smb_GetSMBParm(inp, 0);
5016 tp = smb_GetSMBData(inp, NULL);
5017 pathp = smb_ParseASCIIBlock(tp, &tp);
5018 if (smb_StoreAnsiFilenames)
5019 OemToChar(pathp,pathp);
5021 osi_Log1(smb_logp, "SMB receive unlink %s",
5022 osi_LogSaveString(smb_logp, pathp));
5024 spacep = inp->spacep;
5025 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5027 userp = smb_GetUserFromVCP(vcp, inp);
5029 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5031 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5033 cm_ReleaseUser(userp);
5034 return CM_ERROR_NOSUCHPATH;
5036 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5039 cm_ReleaseUser(userp);
5044 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5045 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,spacep->data);
5046 cm_ReleaseSCache(dscp);
5047 cm_ReleaseUser(userp);
5048 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5049 return CM_ERROR_PATH_NOT_COVERED;
5051 return CM_ERROR_BADSHARENAME;
5053 #endif /* DFS_SUPPORT */
5055 /* otherwise, scp points to the parent directory. */
5062 rock.maskp = smb_FindMask(pathp);
5063 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5066 thyper.HighPart = 0;
5071 rock.matches = NULL;
5073 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5074 * match. If that fails, we do a case insensitve match.
5076 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5077 !smb_IsStarMask(rock.maskp)) {
5078 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5081 thyper.HighPart = 0;
5082 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5087 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5089 if (code == CM_ERROR_STOPNOW)
5092 if (code == 0 && rock.matches) {
5093 cm_dirEntryList_t * entry;
5095 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5097 osi_Log1(smb_logp, "Unlinking %s",
5098 osi_LogSaveString(smb_logp, entry->name));
5099 code = cm_Unlink(dscp, entry->name, userp, &req);
5101 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5102 smb_NotifyChange(FILE_ACTION_REMOVED,
5103 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5104 dscp, entry->name, NULL, TRUE);
5108 cm_DirEntryListFree(&rock.matches);
5110 cm_ReleaseUser(userp);
5112 cm_ReleaseSCache(dscp);
5114 if (code == 0 && !rock.any)
5115 code = CM_ERROR_NOSUCHFILE;
5119 typedef struct smb_renameRock {
5120 cm_scache_t *odscp; /* old dir */
5121 cm_scache_t *ndscp; /* new dir */
5122 cm_user_t *userp; /* user */
5123 cm_req_t *reqp; /* request struct */
5124 smb_vc_t *vcp; /* virtual circuit */
5125 char *maskp; /* pointer to star pattern of old file name */
5126 int flags; /* tilde, casefold, etc */
5127 char *newNamep; /* ptr to the new file's name */
5128 char oldName[MAX_PATH];
5132 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5135 smb_renameRock_t *rockp;
5138 char shortName[13]="";
5140 rockp = (smb_renameRock_t *) vrockp;
5142 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5143 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5144 caseFold |= CM_FLAG_8DOT3;
5146 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5148 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5149 !cm_Is8Dot3(dep->name)) {
5150 cm_Gen8Dot3Name(dep, shortName, NULL);
5151 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5156 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5157 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5158 code = CM_ERROR_STOPNOW;
5168 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5171 cm_space_t *spacep = NULL;
5172 smb_renameRock_t rock;
5173 cm_scache_t *oldDscp = NULL;
5174 cm_scache_t *newDscp = NULL;
5175 cm_scache_t *tmpscp= NULL;
5176 cm_scache_t *tmpscp2 = NULL;
5186 userp = smb_GetUserFromVCP(vcp, inp);
5187 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5189 cm_ReleaseUser(userp);
5190 return CM_ERROR_NOSUCHPATH;
5194 spacep = inp->spacep;
5195 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5197 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5198 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5199 userp, tidPathp, &req, &oldDscp);
5201 cm_ReleaseUser(userp);
5206 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5207 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5208 cm_ReleaseSCache(oldDscp);
5209 cm_ReleaseUser(userp);
5210 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5211 return CM_ERROR_PATH_NOT_COVERED;
5213 return CM_ERROR_BADSHARENAME;
5215 #endif /* DFS_SUPPORT */
5217 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5218 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5219 userp, tidPathp, &req, &newDscp);
5222 cm_ReleaseSCache(oldDscp);
5223 cm_ReleaseUser(userp);
5228 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5229 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5230 cm_ReleaseSCache(oldDscp);
5231 cm_ReleaseSCache(newDscp);
5232 cm_ReleaseUser(userp);
5233 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5234 return CM_ERROR_PATH_NOT_COVERED;
5236 return CM_ERROR_BADSHARENAME;
5238 #endif /* DFS_SUPPORT */
5241 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5242 * next, get the component names, and lower case them.
5245 /* handle the old name first */
5247 oldLastNamep = oldPathp;
5251 /* and handle the new name, too */
5253 newLastNamep = newPathp;
5257 /* TODO: The old name could be a wildcard. The new name must not be */
5259 /* do the vnode call */
5260 rock.odscp = oldDscp;
5261 rock.ndscp = newDscp;
5265 rock.maskp = oldLastNamep;
5266 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5267 rock.newNamep = newLastNamep;
5268 rock.oldName[0] = '\0';
5271 /* Check if the file already exists; if so return error */
5272 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5273 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5274 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5276 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5277 osi_LogSaveString(smb_logp, newLastNamep));
5279 /* Check if the old and the new names differ only in case. If so return
5280 * success, else return CM_ERROR_EXISTS
5282 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5284 /* This would be a success only if the old file is *as same as* the new file */
5285 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5287 if (tmpscp == tmpscp2)
5290 code = CM_ERROR_EXISTS;
5291 cm_ReleaseSCache(tmpscp2);
5294 code = CM_ERROR_NOSUCHFILE;
5297 /* file exist, do not rename, also fixes move */
5298 osi_Log0(smb_logp, "Can't rename. Target already exists");
5299 code = CM_ERROR_EXISTS;
5303 cm_ReleaseSCache(tmpscp);
5304 cm_ReleaseSCache(newDscp);
5305 cm_ReleaseSCache(oldDscp);
5306 cm_ReleaseUser(userp);
5310 /* Now search the directory for the pattern, and do the appropriate rename when found */
5311 thyper.LowPart = 0; /* search dir from here */
5312 thyper.HighPart = 0;
5314 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5315 if (code == 0 && !rock.any) {
5317 thyper.HighPart = 0;
5318 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5319 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5321 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5323 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5324 code = cm_Rename(rock.odscp, rock.oldName,
5325 rock.ndscp, rock.newNamep, rock.userp,
5327 /* if the call worked, stop doing the search now, since we
5328 * really only want to rename one file.
5330 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5331 } else if (code == 0) {
5332 code = CM_ERROR_NOSUCHFILE;
5335 /* Handle Change Notification */
5337 * Being lazy, not distinguishing between files and dirs in this
5338 * filter, since we'd have to do a lookup.
5341 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5342 if (oldDscp == newDscp) {
5343 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5344 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5345 filter, oldDscp, oldLastNamep,
5346 newLastNamep, TRUE);
5348 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5349 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5350 filter, oldDscp, oldLastNamep,
5352 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5353 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5354 filter, newDscp, newLastNamep,
5360 cm_ReleaseSCache(tmpscp);
5361 cm_ReleaseUser(userp);
5362 cm_ReleaseSCache(oldDscp);
5363 cm_ReleaseSCache(newDscp);
5368 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5371 cm_space_t *spacep = NULL;
5372 cm_scache_t *oldDscp = NULL;
5373 cm_scache_t *newDscp = NULL;
5374 cm_scache_t *tmpscp= NULL;
5375 cm_scache_t *tmpscp2 = NULL;
5376 cm_scache_t *sscp = NULL;
5385 userp = smb_GetUserFromVCP(vcp, inp);
5387 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5389 cm_ReleaseUser(userp);
5390 return CM_ERROR_NOSUCHPATH;
5395 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5397 spacep = inp->spacep;
5398 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5400 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5401 userp, tidPathp, &req, &oldDscp);
5403 cm_ReleaseUser(userp);
5408 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5409 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5410 cm_ReleaseSCache(oldDscp);
5411 cm_ReleaseUser(userp);
5412 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5413 return CM_ERROR_PATH_NOT_COVERED;
5415 return CM_ERROR_BADSHARENAME;
5417 #endif /* DFS_SUPPORT */
5419 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5420 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5421 userp, tidPathp, &req, &newDscp);
5423 cm_ReleaseSCache(oldDscp);
5424 cm_ReleaseUser(userp);
5429 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5430 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5431 cm_ReleaseSCache(newDscp);
5432 cm_ReleaseSCache(oldDscp);
5433 cm_ReleaseUser(userp);
5434 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5435 return CM_ERROR_PATH_NOT_COVERED;
5437 return CM_ERROR_BADSHARENAME;
5439 #endif /* DFS_SUPPORT */
5441 /* Now, although we did two lookups for the two directories (because the same
5442 * directory can be referenced through different paths), we only allow hard links
5443 * within the same directory. */
5444 if (oldDscp != newDscp) {
5445 cm_ReleaseSCache(oldDscp);
5446 cm_ReleaseSCache(newDscp);
5447 cm_ReleaseUser(userp);
5448 return CM_ERROR_CROSSDEVLINK;
5451 /* handle the old name first */
5453 oldLastNamep = oldPathp;
5457 /* and handle the new name, too */
5459 newLastNamep = newPathp;
5463 /* now lookup the old name */
5464 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5465 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5467 cm_ReleaseSCache(oldDscp);
5468 cm_ReleaseSCache(newDscp);
5469 cm_ReleaseUser(userp);
5473 /* Check if the file already exists; if so return error */
5474 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5475 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5476 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5478 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5479 osi_LogSaveString(smb_logp, newLastNamep));
5481 /* if the existing link is to the same file, then we return success */
5483 if(sscp == tmpscp) {
5486 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5487 code = CM_ERROR_EXISTS;
5492 cm_ReleaseSCache(tmpscp);
5493 cm_ReleaseSCache(sscp);
5494 cm_ReleaseSCache(newDscp);
5495 cm_ReleaseSCache(oldDscp);
5496 cm_ReleaseUser(userp);
5500 /* now create the hardlink */
5501 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5502 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5503 osi_Log1(smb_logp," Link returns 0x%x", code);
5505 /* Handle Change Notification */
5507 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5508 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5509 smb_NotifyChange(FILE_ACTION_ADDED,
5510 filter, newDscp, newLastNamep,
5515 cm_ReleaseSCache(tmpscp);
5516 cm_ReleaseUser(userp);
5517 cm_ReleaseSCache(sscp);
5518 cm_ReleaseSCache(oldDscp);
5519 cm_ReleaseSCache(newDscp);
5524 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5531 tp = smb_GetSMBData(inp, NULL);
5532 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5533 if (smb_StoreAnsiFilenames)
5534 OemToChar(oldPathp,oldPathp);
5535 newPathp = smb_ParseASCIIBlock(tp, &tp);
5536 if (smb_StoreAnsiFilenames)
5537 OemToChar(newPathp,newPathp);
5539 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5540 osi_LogSaveString(smb_logp, oldPathp),
5541 osi_LogSaveString(smb_logp, newPathp));
5543 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5545 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5551 typedef struct smb_rmdirRock {
5555 char *maskp; /* pointer to the star pattern */
5558 cm_dirEntryList_t * matches;
5561 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5564 smb_rmdirRock_t *rockp;
5569 rockp = (smb_rmdirRock_t *) vrockp;
5571 matchName = dep->name;
5572 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5573 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5575 match = (strcmp(matchName, rockp->maskp) == 0);
5577 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5578 !cm_Is8Dot3(dep->name)) {
5579 cm_Gen8Dot3Name(dep, shortName, NULL);
5580 matchName = shortName;
5581 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5586 cm_DirEntryListAdd(dep->name, &rockp->matches);
5592 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5600 smb_rmdirRock_t rock;
5609 tp = smb_GetSMBData(inp, NULL);
5610 pathp = smb_ParseASCIIBlock(tp, &tp);
5611 if (smb_StoreAnsiFilenames)
5612 OemToChar(pathp,pathp);
5614 spacep = inp->spacep;
5615 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5617 userp = smb_GetUserFromVCP(vcp, inp);
5619 caseFold = CM_FLAG_CASEFOLD;
5621 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5623 cm_ReleaseUser(userp);
5624 return CM_ERROR_NOSUCHPATH;
5626 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5627 userp, tidPathp, &req, &dscp);
5630 cm_ReleaseUser(userp);
5635 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5636 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
5637 cm_ReleaseSCache(dscp);
5638 cm_ReleaseUser(userp);
5639 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5640 return CM_ERROR_PATH_NOT_COVERED;
5642 return CM_ERROR_BADSHARENAME;
5644 #endif /* DFS_SUPPORT */
5646 /* otherwise, scp points to the parent directory. */
5653 rock.maskp = lastNamep;
5654 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5657 thyper.HighPart = 0;
5661 rock.matches = NULL;
5663 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5664 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5665 if (code == 0 && !rock.any) {
5667 thyper.HighPart = 0;
5668 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5669 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5672 if (code == 0 && rock.matches) {
5673 cm_dirEntryList_t * entry;
5675 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5676 osi_Log1(smb_logp, "Removing directory %s",
5677 osi_LogSaveString(smb_logp, entry->name));
5679 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5681 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5682 smb_NotifyChange(FILE_ACTION_REMOVED,
5683 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5684 dscp, entry->name, NULL, TRUE);
5688 cm_DirEntryListFree(&rock.matches);
5690 cm_ReleaseUser(userp);
5692 cm_ReleaseSCache(dscp);
5694 if (code == 0 && !rock.any)
5695 code = CM_ERROR_NOSUCHFILE;
5699 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5709 fid = smb_GetSMBParm(inp, 0);
5711 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5713 fid = smb_ChainFID(fid, inp);
5714 fidp = smb_FindFID(vcp, fid, 0);
5716 return CM_ERROR_BADFD;
5718 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5719 smb_CloseFID(vcp, fidp, NULL, 0);
5720 smb_ReleaseFID(fidp);
5721 return CM_ERROR_NOSUCHFILE;
5724 lock_ObtainMutex(&fidp->mx);
5725 if (fidp->flags & SMB_FID_IOCTL) {
5726 lock_ReleaseMutex(&fidp->mx);
5727 smb_ReleaseFID(fidp);
5728 return CM_ERROR_BADFD;
5730 lock_ReleaseMutex(&fidp->mx);
5732 userp = smb_GetUserFromVCP(vcp, inp);
5734 lock_ObtainMutex(&fidp->mx);
5735 if (fidp->flags & SMB_FID_OPENWRITE) {
5736 cm_scache_t * scp = fidp->scp;
5738 lock_ReleaseMutex(&fidp->mx);
5739 code = cm_FSync(scp, userp, &req);
5740 cm_ReleaseSCache(scp);
5743 lock_ReleaseMutex(&fidp->mx);
5746 smb_ReleaseFID(fidp);
5748 cm_ReleaseUser(userp);
5753 struct smb_FullNameRock {
5759 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5763 struct smb_FullNameRock *vrockp;
5765 vrockp = (struct smb_FullNameRock *)rockp;
5767 if (!cm_Is8Dot3(dep->name)) {
5768 cm_Gen8Dot3Name(dep, shortName, NULL);
5770 if (cm_stricmp(shortName, vrockp->name) == 0) {
5771 vrockp->fullName = strdup(dep->name);
5772 return CM_ERROR_STOPNOW;
5775 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5776 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5777 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5778 vrockp->fullName = strdup(dep->name);
5779 return CM_ERROR_STOPNOW;
5784 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5785 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5787 struct smb_FullNameRock rock;
5793 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5794 if (code == CM_ERROR_STOPNOW)
5795 *newPathp = rock.fullName;
5797 *newPathp = strdup(pathp);
5800 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5801 afs_uint32 dosTime) {
5804 cm_scache_t *dscp = NULL;
5806 cm_scache_t * scp = NULL;
5807 cm_scache_t *delscp = NULL;
5809 int nullcreator = 0;
5811 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5812 fidp, fidp->fid, scp, vcp);
5815 lock_ObtainMutex(&fidp->mx);
5816 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5817 lock_ReleaseMutex(&fidp->mx);
5818 osi_Log0(smb_logp, " No user specified. Not closing fid");
5819 return CM_ERROR_BADFD;
5822 userp = fidp->userp; /* no hold required since fidp is held
5823 throughout the function */
5824 lock_ReleaseMutex(&fidp->mx);
5829 lock_ObtainWrite(&smb_rctLock);
5831 osi_Log0(smb_logp, " Fid already closed.");
5832 lock_ReleaseWrite(&smb_rctLock);
5833 return CM_ERROR_BADFD;
5836 lock_ReleaseWrite(&smb_rctLock);
5838 lock_ObtainMutex(&fidp->mx);
5839 if (fidp->NTopen_dscp) {
5840 dscp = fidp->NTopen_dscp;
5841 cm_HoldSCache(dscp);
5844 if (fidp->NTopen_pathp) {
5845 pathp = strdup(fidp->NTopen_pathp);
5853 /* Don't jump the gun on an async raw write */
5854 while (fidp->raw_writers) {
5855 lock_ReleaseMutex(&fidp->mx);
5856 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5857 lock_ObtainMutex(&fidp->mx);
5860 /* watch for ioctl closes, and read-only opens */
5862 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5863 == SMB_FID_OPENWRITE) {
5864 if (dosTime != 0 && dosTime != -1) {
5865 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5866 /* This fixes defect 10958 */
5867 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5868 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5870 lock_ReleaseMutex(&fidp->mx);
5871 code = cm_FSync(scp, userp, &req);
5872 lock_ObtainMutex(&fidp->mx);
5877 /* unlock any pending locks */
5878 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5879 scp->fileType == CM_SCACHETYPE_FILE) {
5883 lock_ReleaseMutex(&fidp->mx);
5885 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5887 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5888 lock_ObtainMutex(&scp->mx);
5890 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5891 CM_SCACHESYNC_NEEDCALLBACK
5892 | CM_SCACHESYNC_GETSTATUS
5893 | CM_SCACHESYNC_LOCK);
5897 "smb CoreClose SyncOp failure code 0x%x", tcode);
5898 goto post_syncopdone;
5901 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5903 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5907 lock_ReleaseMutex(&scp->mx);
5908 lock_ObtainMutex(&fidp->mx);
5911 if (fidp->flags & SMB_FID_DELONCLOSE) {
5914 lock_ReleaseMutex(&fidp->mx);
5916 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
5921 smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
5922 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5923 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5926 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5927 smb_NotifyChange(FILE_ACTION_REMOVED,
5928 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5929 dscp, fullPathp, NULL, TRUE);
5932 code = cm_Unlink(dscp, fullPathp, userp, &req);
5935 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5936 smb_NotifyChange(FILE_ACTION_REMOVED,
5937 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5938 dscp, fullPathp, NULL, TRUE);
5942 lock_ObtainMutex(&fidp->mx);
5943 fidp->flags &= ~SMB_FID_DELONCLOSE;
5946 /* if this was a newly created file, then clear the creator
5947 * in the stat cache entry. */
5948 if (fidp->flags & SMB_FID_CREATED) {
5950 fidp->flags &= ~SMB_FID_CREATED;
5953 if (fidp->flags & SMB_FID_NTOPEN) {
5954 cm_ReleaseSCache(fidp->NTopen_dscp);
5955 fidp->NTopen_dscp = NULL;
5956 free(fidp->NTopen_pathp);
5957 fidp->NTopen_pathp = NULL;
5958 fidp->flags &= ~SMB_FID_NTOPEN;
5960 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
5961 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
5964 if (fidp->NTopen_wholepathp) {
5965 free(fidp->NTopen_wholepathp);
5966 fidp->NTopen_wholepathp = NULL;
5970 cm_ReleaseSCache(fidp->scp);
5973 lock_ReleaseMutex(&fidp->mx);
5976 cm_ReleaseSCache(dscp);
5980 lock_ObtainMutex(&delscp->mx);
5982 delscp->flags |= CM_SCACHEFLAG_DELETED;
5983 lock_ReleaseMutex(&delscp->mx);
5985 cm_ReleaseSCache(delscp);
5989 lock_ObtainMutex(&scp->mx);
5990 if (nullcreator && scp->creator == userp)
5991 scp->creator = NULL;
5992 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5993 lock_ReleaseMutex(&scp->mx);
5994 cm_ReleaseSCache(scp);
6003 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6011 fid = smb_GetSMBParm(inp, 0);
6012 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6014 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6016 fid = smb_ChainFID(fid, inp);
6017 fidp = smb_FindFID(vcp, fid, 0);
6019 return CM_ERROR_BADFD;
6022 userp = smb_GetUserFromVCP(vcp, inp);
6024 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6026 smb_ReleaseFID(fidp);
6027 cm_ReleaseUser(userp);
6032 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6034 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6035 cm_user_t *userp, long *readp)
6041 osi_hyper_t fileLength;
6043 osi_hyper_t lastByte;
6044 osi_hyper_t bufferOffset;
6045 long bufIndex, nbytes;
6047 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6055 lock_ObtainMutex(&fidp->mx);
6058 lock_ObtainMutex(&scp->mx);
6060 if (offset.HighPart == 0) {
6061 chunk = offset.LowPart >> cm_logChunkSize;
6062 if (chunk != fidp->curr_chunk) {
6063 fidp->prev_chunk = fidp->curr_chunk;
6064 fidp->curr_chunk = chunk;
6066 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6069 lock_ReleaseMutex(&fidp->mx);
6071 /* start by looking up the file's end */
6072 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6073 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6077 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6079 /* now we have the entry locked, look up the length */
6080 fileLength = scp->length;
6082 /* adjust count down so that it won't go past EOF */
6083 thyper.LowPart = count;
6084 thyper.HighPart = 0;
6085 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6087 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6088 /* we'd read past EOF, so just stop at fileLength bytes.
6089 * Start by computing how many bytes remain in the file.
6091 thyper = LargeIntegerSubtract(fileLength, offset);
6093 /* if we are past EOF, read 0 bytes */
6094 if (LargeIntegerLessThanZero(thyper))
6097 count = thyper.LowPart;
6102 /* now, copy the data one buffer at a time,
6103 * until we've filled the request packet
6106 /* if we've copied all the data requested, we're done */
6107 if (count <= 0) break;
6109 /* otherwise, load up a buffer of data */
6110 thyper.HighPart = offset.HighPart;
6111 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6112 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6115 buf_Release(bufferp);
6118 lock_ReleaseMutex(&scp->mx);
6120 lock_ObtainRead(&scp->bufCreateLock);
6121 code = buf_Get(scp, &thyper, &bufferp);
6122 lock_ReleaseRead(&scp->bufCreateLock);
6124 lock_ObtainMutex(&scp->mx);
6125 if (code) goto done;
6126 bufferOffset = thyper;
6128 /* now get the data in the cache */
6130 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6131 CM_SCACHESYNC_NEEDCALLBACK |
6132 CM_SCACHESYNC_READ);
6136 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6138 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6140 /* otherwise, load the buffer and try again */
6141 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6145 buf_Release(bufferp);
6149 } /* if (wrong buffer) ... */
6151 /* now we have the right buffer loaded. Copy out the
6152 * data from here to the user's buffer.
6154 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6156 /* and figure out how many bytes we want from this buffer */
6157 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6158 if (nbytes > count) nbytes = count; /* don't go past EOF */
6160 /* now copy the data */
6161 memcpy(op, bufferp->datap + bufIndex, nbytes);
6163 /* adjust counters, pointers, etc. */
6166 thyper.LowPart = nbytes;
6167 thyper.HighPart = 0;
6168 offset = LargeIntegerAdd(thyper, offset);
6172 lock_ReleaseMutex(&scp->mx);
6174 buf_Release(bufferp);
6176 if (code == 0 && sequential)
6177 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6179 cm_ReleaseSCache(scp);
6185 * smb_WriteData -- common code for Write and Raw Write
6187 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6188 cm_user_t *userp, long *writtenp)
6194 osi_hyper_t fileLength; /* file's length at start of write */
6195 osi_hyper_t minLength; /* don't read past this */
6196 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6198 osi_hyper_t thyper; /* hyper tmp variable */
6199 osi_hyper_t bufferOffset;
6200 afs_uint32 bufIndex; /* index in buffer where our data is */
6202 osi_hyper_t writeBackOffset;/* offset of region to write back when
6207 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6208 fidp->fid, offsetp->LowPart, count);
6218 lock_ObtainMutex(&fidp->mx);
6219 /* make sure we have a writable FD */
6220 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6221 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6222 fidp->fid, fidp->flags);
6223 lock_ReleaseMutex(&fidp->mx);
6224 code = CM_ERROR_BADFDOP;
6230 lock_ReleaseMutex(&fidp->mx);
6232 lock_ObtainMutex(&scp->mx);
6233 /* start by looking up the file's end */
6234 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6235 CM_SCACHESYNC_NEEDCALLBACK
6236 | CM_SCACHESYNC_SETSTATUS
6237 | CM_SCACHESYNC_GETSTATUS);
6241 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6243 /* now we have the entry locked, look up the length */
6244 fileLength = scp->length;
6245 minLength = fileLength;
6246 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6247 minLength = scp->serverLength;
6249 /* adjust file length if we extend past EOF */
6250 thyper.LowPart = count;
6251 thyper.HighPart = 0;
6252 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6253 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6254 /* we'd write past EOF, so extend the file */
6255 scp->mask |= CM_SCACHEMASK_LENGTH;
6256 scp->length = thyper;
6257 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6259 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6261 /* now, if the new position (thyper) and the old (offset) are in
6262 * different storeback windows, remember to store back the previous
6263 * storeback window when we're done with the write.
6265 if ((thyper.LowPart & (-cm_chunkSize)) !=
6266 (offset.LowPart & (-cm_chunkSize))) {
6267 /* they're different */
6269 writeBackOffset.HighPart = offset.HighPart;
6270 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6275 /* now, copy the data one buffer at a time, until we've filled the
6278 /* if we've copied all the data requested, we're done */
6282 /* handle over quota or out of space */
6283 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6284 *writtenp = written;
6285 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6289 /* otherwise, load up a buffer of data */
6290 thyper.HighPart = offset.HighPart;
6291 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6292 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6295 lock_ReleaseMutex(&bufferp->mx);
6296 buf_Release(bufferp);
6299 lock_ReleaseMutex(&scp->mx);
6301 lock_ObtainRead(&scp->bufCreateLock);
6302 code = buf_Get(scp, &thyper, &bufferp);
6303 lock_ReleaseRead(&scp->bufCreateLock);
6305 lock_ObtainMutex(&bufferp->mx);
6306 lock_ObtainMutex(&scp->mx);
6307 if (code) goto done;
6309 bufferOffset = thyper;
6311 /* now get the data in the cache */
6313 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6314 CM_SCACHESYNC_NEEDCALLBACK
6315 | CM_SCACHESYNC_WRITE
6316 | CM_SCACHESYNC_BUFLOCKED);
6320 cm_SyncOpDone(scp, bufferp,
6321 CM_SCACHESYNC_NEEDCALLBACK
6322 | CM_SCACHESYNC_WRITE
6323 | CM_SCACHESYNC_BUFLOCKED);
6325 /* If we're overwriting the entire buffer, or
6326 * if we're writing at or past EOF, mark the
6327 * buffer as current so we don't call
6328 * cm_GetBuffer. This skips the fetch from the
6329 * server in those cases where we're going to
6330 * obliterate all the data in the buffer anyway,
6331 * or in those cases where there is no useful
6332 * data at the server to start with.
6334 * Use minLength instead of scp->length, since
6335 * the latter has already been updated by this
6338 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6339 || LargeIntegerEqualTo(offset, bufferp->offset)
6340 && (count >= cm_data.buf_blockSize
6341 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6342 ConvertLongToLargeInteger(count)),
6344 if (count < cm_data.buf_blockSize
6345 && bufferp->dataVersion == -1)
6346 memset(bufferp->datap, 0,
6347 cm_data.buf_blockSize);
6348 bufferp->dataVersion = scp->dataVersion;
6351 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6353 /* otherwise, load the buffer and try again */
6354 lock_ReleaseMutex(&bufferp->mx);
6355 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6357 lock_ReleaseMutex(&scp->mx);
6358 lock_ObtainMutex(&bufferp->mx);
6359 lock_ObtainMutex(&scp->mx);
6363 lock_ReleaseMutex(&bufferp->mx);
6364 buf_Release(bufferp);
6368 } /* if (wrong buffer) ... */
6370 /* now we have the right buffer loaded. Copy out the
6371 * data from here to the user's buffer.
6373 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6375 /* and figure out how many bytes we want from this buffer */
6376 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6378 nbytes = count; /* don't go past end of request */
6380 /* now copy the data */
6381 memcpy(bufferp->datap + bufIndex, op, nbytes);
6382 buf_SetDirty(bufferp, bufIndex, nbytes);
6384 /* and record the last writer */
6385 if (bufferp->userp != userp) {
6388 cm_ReleaseUser(bufferp->userp);
6389 bufferp->userp = userp;
6392 /* adjust counters, pointers, etc. */
6396 thyper.LowPart = nbytes;
6397 thyper.HighPart = 0;
6398 offset = LargeIntegerAdd(thyper, offset);
6402 lock_ReleaseMutex(&scp->mx);
6405 lock_ReleaseMutex(&bufferp->mx);
6406 buf_Release(bufferp);
6409 lock_ObtainMutex(&fidp->mx);
6410 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6411 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6412 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6413 fidp->NTopen_dscp, fidp->NTopen_pathp,
6416 lock_ReleaseMutex(&fidp->mx);
6418 if (code == 0 && doWriteBack) {
6420 lock_ObtainMutex(&scp->mx);
6421 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6423 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6424 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6426 lock_ReleaseMutex(&scp->mx);
6427 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6428 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6429 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6432 cm_ReleaseSCache(scp);
6434 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6435 fidp->fid, code, *writtenp);
6439 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6442 unsigned short count;
6444 unsigned short hint;
6445 long written = 0, total_written = 0;
6450 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6452 int inDataBlockCount;
6454 fd = smb_GetSMBParm(inp, 0);
6455 count = smb_GetSMBParm(inp, 1);
6456 offset.HighPart = 0; /* too bad */
6457 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6458 hint = smb_GetSMBParm(inp, 4);
6460 op = smb_GetSMBData(inp, NULL);
6461 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6463 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6464 fd, offset.LowPart, count);
6466 fd = smb_ChainFID(fd, inp);
6467 fidp = smb_FindFID(vcp, fd, 0);
6469 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6470 return CM_ERROR_BADFD;
6473 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6474 smb_CloseFID(vcp, fidp, NULL, 0);
6475 smb_ReleaseFID(fidp);
6476 return CM_ERROR_NOSUCHFILE;
6479 lock_ObtainMutex(&fidp->mx);
6480 if (fidp->flags & SMB_FID_IOCTL) {
6481 lock_ReleaseMutex(&fidp->mx);
6482 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6483 smb_ReleaseFID(fidp);
6484 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6487 lock_ReleaseMutex(&fidp->mx);
6488 userp = smb_GetUserFromVCP(vcp, inp);
6492 LARGE_INTEGER LOffset;
6493 LARGE_INTEGER LLength;
6495 pid = ((smb_t *) inp)->pid;
6496 key = cm_GenerateKey(vcp->vcID, pid, fd);
6498 LOffset.HighPart = offset.HighPart;
6499 LOffset.LowPart = offset.LowPart;
6500 LLength.HighPart = 0;
6501 LLength.LowPart = count;
6503 lock_ObtainMutex(&fidp->scp->mx);
6504 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6505 lock_ReleaseMutex(&fidp->scp->mx);
6508 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6513 /* special case: 0 bytes transferred means truncate to this position */
6517 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6521 truncAttr.mask = CM_ATTRMASK_LENGTH;
6522 truncAttr.length.LowPart = offset.LowPart;
6523 truncAttr.length.HighPart = 0;
6524 lock_ObtainMutex(&fidp->mx);
6525 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6526 fidp->flags |= SMB_FID_LENGTHSETDONE;
6527 lock_ReleaseMutex(&fidp->mx);
6528 smb_SetSMBParm(outp, 0, 0 /* count */);
6529 smb_SetSMBDataLength(outp, 0);
6534 * Work around bug in NT client
6536 * When copying a file, the NT client should first copy the data,
6537 * then copy the last write time. But sometimes the NT client does
6538 * these in the wrong order, so the data copies would inadvertently
6539 * cause the last write time to be overwritten. We try to detect this,
6540 * and don't set client mod time if we think that would go against the
6543 lock_ObtainMutex(&fidp->mx);
6544 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6545 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6546 fidp->scp->clientModTime = time(NULL);
6548 lock_ReleaseMutex(&fidp->mx);
6551 while ( code == 0 && count > 0 ) {
6552 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6553 if (code == 0 && written == 0)
6554 code = CM_ERROR_PARTIALWRITE;
6556 offset = LargeIntegerAdd(offset,
6557 ConvertLongToLargeInteger(written));
6558 count -= (unsigned short)written;
6559 total_written += written;
6563 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6564 total_written, code);
6566 /* set the packet data length to 3 bytes for the data block header,
6567 * plus the size of the data.
6569 smb_SetSMBParm(outp, 0, total_written);
6570 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6571 smb_SetSMBParm(outp, 3, hint);
6572 smb_SetSMBDataLength(outp, 0);
6575 smb_ReleaseFID(fidp);
6576 cm_ReleaseUser(userp);
6581 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6582 NCB *ncbp, raw_write_cont_t *rwcp)
6591 fd = smb_GetSMBParm(inp, 0);
6592 fidp = smb_FindFID(vcp, fd, 0);
6594 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6595 smb_CloseFID(vcp, fidp, NULL, 0);
6596 smb_ReleaseFID(fidp);
6600 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6601 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6603 userp = smb_GetUserFromVCP(vcp, inp);
6606 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6608 if (rwcp->writeMode & 0x1) { /* synchronous */
6611 smb_FormatResponsePacket(vcp, inp, outp);
6612 op = (smb_t *) outp;
6613 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6614 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6615 smb_SetSMBDataLength(outp, 0);
6616 smb_SendPacket(vcp, outp);
6617 smb_FreePacket(outp);
6619 else { /* asynchronous */
6620 lock_ObtainMutex(&fidp->mx);
6621 fidp->raw_writers--;
6622 if (fidp->raw_writers == 0)
6623 thrd_SetEvent(fidp->raw_write_event);
6624 lock_ReleaseMutex(&fidp->mx);
6627 /* Give back raw buffer */
6628 lock_ObtainMutex(&smb_RawBufLock);
6629 *((char **)rawBuf) = smb_RawBufs;
6630 smb_RawBufs = rawBuf;
6631 lock_ReleaseMutex(&smb_RawBufLock);
6633 smb_ReleaseFID(fidp);
6634 cm_ReleaseUser(userp);
6637 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6642 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6645 long count, written = 0, total_written = 0;
6652 unsigned short writeMode;
6654 fd = smb_GetSMBParm(inp, 0);
6655 totalCount = smb_GetSMBParm(inp, 1);
6656 count = smb_GetSMBParm(inp, 10);
6657 writeMode = smb_GetSMBParm(inp, 7);
6659 op = (char *) inp->data;
6660 op += smb_GetSMBParm(inp, 11);
6662 offset.HighPart = 0;
6663 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6665 if (*inp->wctp == 14) {
6666 /* we received a 64-bit file offset */
6667 #ifdef AFS_LARGEFILES
6668 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6670 if (LargeIntegerLessThanZero(offset)) {
6672 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6673 offset.HighPart, offset.LowPart);
6674 return CM_ERROR_BADSMB;
6677 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6679 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6680 return CM_ERROR_BADSMB;
6683 offset.HighPart = 0;
6686 offset.HighPart = 0; /* 32-bit file offset */
6690 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6691 fd, offset.HighPart, offset.LowPart, count);
6693 " WriteRaw WriteMode 0x%x",
6696 fd = smb_ChainFID(fd, inp);
6697 fidp = smb_FindFID(vcp, fd, 0);
6699 return CM_ERROR_BADFD;
6702 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6703 smb_CloseFID(vcp, fidp, NULL, 0);
6704 smb_ReleaseFID(fidp);
6705 return CM_ERROR_NOSUCHFILE;
6711 LARGE_INTEGER LOffset;
6712 LARGE_INTEGER LLength;
6714 pid = ((smb_t *) inp)->pid;
6715 key = cm_GenerateKey(vcp->vcID, pid, fd);
6717 LOffset.HighPart = offset.HighPart;
6718 LOffset.LowPart = offset.LowPart;
6719 LLength.HighPart = 0;
6720 LLength.LowPart = count;
6722 lock_ObtainMutex(&fidp->scp->mx);
6723 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6724 lock_ReleaseMutex(&fidp->scp->mx);
6727 smb_ReleaseFID(fidp);
6732 userp = smb_GetUserFromVCP(vcp, inp);
6735 * Work around bug in NT client
6737 * When copying a file, the NT client should first copy the data,
6738 * then copy the last write time. But sometimes the NT client does
6739 * these in the wrong order, so the data copies would inadvertently
6740 * cause the last write time to be overwritten. We try to detect this,
6741 * and don't set client mod time if we think that would go against the
6744 lock_ObtainMutex(&fidp->mx);
6745 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6746 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6747 fidp->scp->clientModTime = time(NULL);
6749 lock_ReleaseMutex(&fidp->mx);
6752 while ( code == 0 && count > 0 ) {
6753 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6754 if (code == 0 && written == 0)
6755 code = CM_ERROR_PARTIALWRITE;
6757 offset = LargeIntegerAdd(offset,
6758 ConvertLongToLargeInteger(written));
6761 total_written += written;
6765 /* Get a raw buffer */
6768 lock_ObtainMutex(&smb_RawBufLock);
6770 /* Get a raw buf, from head of list */
6771 rawBuf = smb_RawBufs;
6772 smb_RawBufs = *(char **)smb_RawBufs;
6775 code = CM_ERROR_USESTD;
6777 lock_ReleaseMutex(&smb_RawBufLock);
6780 /* Don't allow a premature Close */
6781 if (code == 0 && (writeMode & 1) == 0) {
6782 lock_ObtainMutex(&fidp->mx);
6783 fidp->raw_writers++;
6784 thrd_ResetEvent(fidp->raw_write_event);
6785 lock_ReleaseMutex(&fidp->mx);
6788 smb_ReleaseFID(fidp);
6789 cm_ReleaseUser(userp);
6792 smb_SetSMBParm(outp, 0, total_written);
6793 smb_SetSMBDataLength(outp, 0);
6794 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6799 offset = LargeIntegerAdd(offset,
6800 ConvertLongToLargeInteger(count));
6804 rwcp->offset.HighPart = offset.HighPart;
6805 rwcp->offset.LowPart = offset.LowPart;
6806 rwcp->count = totalCount - count;
6807 rwcp->writeMode = writeMode;
6808 rwcp->alreadyWritten = total_written;
6810 /* set the packet data length to 3 bytes for the data block header,
6811 * plus the size of the data.
6813 smb_SetSMBParm(outp, 0, 0xffff);
6814 smb_SetSMBDataLength(outp, 0);
6819 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6822 long count, finalCount;
6830 fd = smb_GetSMBParm(inp, 0);
6831 count = smb_GetSMBParm(inp, 1);
6832 offset.HighPart = 0; /* too bad */
6833 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6835 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6836 fd, offset.LowPart, count);
6838 fd = smb_ChainFID(fd, inp);
6839 fidp = smb_FindFID(vcp, fd, 0);
6841 return CM_ERROR_BADFD;
6843 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6844 smb_CloseFID(vcp, fidp, NULL, 0);
6845 smb_ReleaseFID(fidp);
6846 return CM_ERROR_NOSUCHFILE;
6849 lock_ObtainMutex(&fidp->mx);
6850 if (fidp->flags & SMB_FID_IOCTL) {
6851 lock_ReleaseMutex(&fidp->mx);
6852 code = smb_IoctlRead(fidp, vcp, inp, outp);
6853 smb_ReleaseFID(fidp);
6856 lock_ReleaseMutex(&fidp->mx);
6859 LARGE_INTEGER LOffset, LLength;
6862 pid = ((smb_t *) inp)->pid;
6863 key = cm_GenerateKey(vcp->vcID, pid, fd);
6865 LOffset.HighPart = 0;
6866 LOffset.LowPart = offset.LowPart;
6867 LLength.HighPart = 0;
6868 LLength.LowPart = count;
6870 lock_ObtainMutex(&fidp->scp->mx);
6871 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6872 lock_ReleaseMutex(&fidp->scp->mx);
6875 smb_ReleaseFID(fidp);
6879 userp = smb_GetUserFromVCP(vcp, inp);
6881 /* remember this for final results */
6882 smb_SetSMBParm(outp, 0, count);
6883 smb_SetSMBParm(outp, 1, 0);
6884 smb_SetSMBParm(outp, 2, 0);
6885 smb_SetSMBParm(outp, 3, 0);
6886 smb_SetSMBParm(outp, 4, 0);
6888 /* set the packet data length to 3 bytes for the data block header,
6889 * plus the size of the data.
6891 smb_SetSMBDataLength(outp, count+3);
6893 /* get op ptr after putting in the parms, since otherwise we don't
6894 * know where the data really is.
6896 op = smb_GetSMBData(outp, NULL);
6898 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6899 *op++ = 1; /* data block marker */
6900 *op++ = (unsigned char) (count & 0xff);
6901 *op++ = (unsigned char) ((count >> 8) & 0xff);
6903 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6905 /* fix some things up */
6906 smb_SetSMBParm(outp, 0, finalCount);
6907 smb_SetSMBDataLength(outp, finalCount+3);
6909 smb_ReleaseFID(fidp);
6911 cm_ReleaseUser(userp);
6915 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6922 cm_scache_t *dscp; /* dir we're dealing with */
6923 cm_scache_t *scp; /* file we're creating */
6925 int initialModeBits;
6935 /* compute initial mode bits based on read-only flag in attributes */
6936 initialModeBits = 0777;
6938 tp = smb_GetSMBData(inp, NULL);
6939 pathp = smb_ParseASCIIBlock(tp, &tp);
6940 if (smb_StoreAnsiFilenames)
6941 OemToChar(pathp,pathp);
6943 if (strcmp(pathp, "\\") == 0)
6944 return CM_ERROR_EXISTS;
6946 spacep = inp->spacep;
6947 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6949 userp = smb_GetUserFromVCP(vcp, inp);
6951 caseFold = CM_FLAG_CASEFOLD;
6953 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6955 cm_ReleaseUser(userp);
6956 return CM_ERROR_NOSUCHPATH;
6959 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6960 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6961 userp, tidPathp, &req, &dscp);
6964 cm_ReleaseUser(userp);
6969 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6970 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
6971 cm_ReleaseSCache(dscp);
6972 cm_ReleaseUser(userp);
6973 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6974 return CM_ERROR_PATH_NOT_COVERED;
6976 return CM_ERROR_BADSHARENAME;
6978 #endif /* DFS_SUPPORT */
6980 /* otherwise, scp points to the parent directory. Do a lookup, and
6981 * fail if we find it. Otherwise, we do the create.
6987 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6988 if (scp) cm_ReleaseSCache(scp);
6989 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6990 if (code == 0) code = CM_ERROR_EXISTS;
6991 cm_ReleaseSCache(dscp);
6992 cm_ReleaseUser(userp);
6996 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6997 setAttr.clientModTime = time(NULL);
6998 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6999 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7000 smb_NotifyChange(FILE_ACTION_ADDED,
7001 FILE_NOTIFY_CHANGE_DIR_NAME,
7002 dscp, lastNamep, NULL, TRUE);
7004 /* we don't need this any longer */
7005 cm_ReleaseSCache(dscp);
7008 /* something went wrong creating or truncating the file */
7009 cm_ReleaseUser(userp);
7013 /* otherwise we succeeded */
7014 smb_SetSMBDataLength(outp, 0);
7015 cm_ReleaseUser(userp);
7020 BOOL smb_IsLegalFilename(char *filename)
7023 * Find the longest substring of filename that does not contain
7024 * any of the chars in illegalChars. If that substring is less
7025 * than the length of the whole string, then one or more of the
7026 * illegal chars is in filename.
7028 if (strcspn(filename, illegalChars) < strlen(filename))
7034 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7042 cm_scache_t *dscp; /* dir we're dealing with */
7043 cm_scache_t *scp; /* file we're creating */
7045 int initialModeBits;
7053 int created = 0; /* the file was new */
7058 excl = (inp->inCom == 0x03)? 0 : 1;
7060 attributes = smb_GetSMBParm(inp, 0);
7061 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7063 /* compute initial mode bits based on read-only flag in attributes */
7064 initialModeBits = 0666;
7065 if (attributes & SMB_ATTR_READONLY)
7066 initialModeBits &= ~0222;
7068 tp = smb_GetSMBData(inp, NULL);
7069 pathp = smb_ParseASCIIBlock(tp, &tp);
7070 if (smb_StoreAnsiFilenames)
7071 OemToChar(pathp,pathp);
7073 spacep = inp->spacep;
7074 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7076 userp = smb_GetUserFromVCP(vcp, inp);
7078 caseFold = CM_FLAG_CASEFOLD;
7080 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7082 cm_ReleaseUser(userp);
7083 return CM_ERROR_NOSUCHPATH;
7085 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7086 userp, tidPathp, &req, &dscp);
7089 cm_ReleaseUser(userp);
7094 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7095 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7096 cm_ReleaseSCache(dscp);
7097 cm_ReleaseUser(userp);
7098 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7099 return CM_ERROR_PATH_NOT_COVERED;
7101 return CM_ERROR_BADSHARENAME;
7103 #endif /* DFS_SUPPORT */
7105 /* otherwise, scp points to the parent directory. Do a lookup, and
7106 * truncate the file if we find it, otherwise we create the file.
7113 if (!smb_IsLegalFilename(lastNamep))
7114 return CM_ERROR_BADNTFILENAME;
7116 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7117 #ifdef DEBUG_VERBOSE
7120 hexp = osi_HexifyString( lastNamep );
7121 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7126 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7127 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7128 cm_ReleaseSCache(dscp);
7129 cm_ReleaseUser(userp);
7133 /* if we get here, if code is 0, the file exists and is represented by
7134 * scp. Otherwise, we have to create it.
7138 /* oops, file shouldn't be there */
7139 cm_ReleaseSCache(dscp);
7140 cm_ReleaseSCache(scp);
7141 cm_ReleaseUser(userp);
7142 return CM_ERROR_EXISTS;
7145 setAttr.mask = CM_ATTRMASK_LENGTH;
7146 setAttr.length.LowPart = 0;
7147 setAttr.length.HighPart = 0;
7148 code = cm_SetAttr(scp, &setAttr, userp, &req);
7151 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7152 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7153 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7157 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7158 smb_NotifyChange(FILE_ACTION_ADDED,
7159 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7160 dscp, lastNamep, NULL, TRUE);
7161 } else if (!excl && code == CM_ERROR_EXISTS) {
7162 /* not an exclusive create, and someone else tried
7163 * creating it already, then we open it anyway. We
7164 * don't bother retrying after this, since if this next
7165 * fails, that means that the file was deleted after
7166 * we started this call.
7168 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7171 setAttr.mask = CM_ATTRMASK_LENGTH;
7172 setAttr.length.LowPart = 0;
7173 setAttr.length.HighPart = 0;
7174 code = cm_SetAttr(scp, &setAttr, userp, &req);
7179 /* we don't need this any longer */
7180 cm_ReleaseSCache(dscp);
7183 /* something went wrong creating or truncating the file */
7184 if (scp) cm_ReleaseSCache(scp);
7185 cm_ReleaseUser(userp);
7189 /* make sure we only open files */
7190 if (scp->fileType != CM_SCACHETYPE_FILE) {
7191 cm_ReleaseSCache(scp);
7192 cm_ReleaseUser(userp);
7193 return CM_ERROR_ISDIR;
7196 /* now all we have to do is open the file itself */
7197 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7198 osi_assertx(fidp, "null smb_fid_t");
7202 lock_ObtainMutex(&fidp->mx);
7203 /* always create it open for read/write */
7204 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7206 /* remember that the file was newly created */
7208 fidp->flags |= SMB_FID_CREATED;
7210 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7212 /* save a pointer to the vnode */
7214 lock_ObtainMutex(&scp->mx);
7215 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7216 lock_ReleaseMutex(&scp->mx);
7219 fidp->userp = userp;
7220 lock_ReleaseMutex(&fidp->mx);
7222 smb_SetSMBParm(outp, 0, fidp->fid);
7223 smb_SetSMBDataLength(outp, 0);
7225 cm_Open(scp, 0, userp);
7227 smb_ReleaseFID(fidp);
7228 cm_ReleaseUser(userp);
7229 /* leave scp held since we put it in fidp->scp */
7233 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7236 osi_hyper_t new_offset;
7247 fd = smb_GetSMBParm(inp, 0);
7248 whence = smb_GetSMBParm(inp, 1);
7249 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7251 /* try to find the file descriptor */
7252 fd = smb_ChainFID(fd, inp);
7253 fidp = smb_FindFID(vcp, fd, 0);
7255 return CM_ERROR_BADFD;
7257 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7258 smb_CloseFID(vcp, fidp, NULL, 0);
7259 smb_ReleaseFID(fidp);
7260 return CM_ERROR_NOSUCHFILE;
7263 lock_ObtainMutex(&fidp->mx);
7264 if (fidp->flags & SMB_FID_IOCTL) {
7265 lock_ReleaseMutex(&fidp->mx);
7266 smb_ReleaseFID(fidp);
7267 return CM_ERROR_BADFD;
7269 lock_ReleaseMutex(&fidp->mx);
7271 userp = smb_GetUserFromVCP(vcp, inp);
7273 lock_ObtainMutex(&fidp->mx);
7276 lock_ReleaseMutex(&fidp->mx);
7277 lock_ObtainMutex(&scp->mx);
7278 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7279 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7281 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7283 /* offset from current offset */
7284 new_offset = LargeIntegerAdd(fidp->offset,
7285 ConvertLongToLargeInteger(offset));
7287 else if (whence == 2) {
7288 /* offset from current EOF */
7289 new_offset = LargeIntegerAdd(scp->length,
7290 ConvertLongToLargeInteger(offset));
7292 new_offset = ConvertLongToLargeInteger(offset);
7295 fidp->offset = new_offset;
7296 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7297 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7298 smb_SetSMBDataLength(outp, 0);
7300 lock_ReleaseMutex(&scp->mx);
7301 smb_ReleaseFID(fidp);
7302 cm_ReleaseSCache(scp);
7303 cm_ReleaseUser(userp);
7307 /* dispatch all of the requests received in a packet. Due to chaining, this may
7308 * be more than one request.
7310 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7311 NCB *ncbp, raw_write_cont_t *rwcp)
7315 unsigned long code = 0;
7316 unsigned char *outWctp;
7317 int nparms; /* # of bytes of parameters */
7319 int nbytes; /* bytes of data, excluding count */
7322 unsigned short errCode;
7323 unsigned long NTStatus;
7325 unsigned char errClass;
7326 unsigned int oldGen;
7327 DWORD oldTime, newTime;
7329 /* get easy pointer to the data */
7330 smbp = (smb_t *) inp->data;
7332 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7333 /* setup the basic parms for the initial request in the packet */
7334 inp->inCom = smbp->com;
7335 inp->wctp = &smbp->wct;
7337 inp->ncb_length = ncbp->ncb_length;
7342 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7343 /* log it and discard it */
7344 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7345 __FILE__, __LINE__, ncbp->ncb_length);
7346 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7350 /* We are an ongoing op */
7351 thrd_Increment(&ongoingOps);
7353 /* set up response packet for receiving output */
7354 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7355 smb_FormatResponsePacket(vcp, inp, outp);
7356 outWctp = outp->wctp;
7358 /* Remember session generation number and time */
7359 oldGen = sessionGen;
7360 oldTime = GetTickCount();
7362 while (inp->inCom != 0xff) {
7363 dp = &smb_dispatchTable[inp->inCom];
7365 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7366 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7367 code = outp->resumeCode;
7371 /* process each request in the packet; inCom, wctp and inCount
7372 * are already set up.
7374 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7377 /* now do the dispatch */
7378 /* start by formatting the response record a little, as a default */
7379 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7381 outWctp[1] = 0xff; /* no operation */
7382 outWctp[2] = 0; /* padding */
7387 /* not a chained request, this is a more reasonable default */
7388 outWctp[0] = 0; /* wct of zero */
7389 outWctp[1] = 0; /* and bcc (word) of zero */
7393 /* once set, stays set. Doesn't matter, since we never chain
7394 * "no response" calls.
7396 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7400 /* we have a recognized operation */
7402 if (inp->inCom == 0x1d)
7404 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7406 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7407 code = (*(dp->procp)) (vcp, inp, outp);
7408 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7410 if ( code == CM_ERROR_BADSMB ||
7411 code == CM_ERROR_BADOP )
7413 #endif /* LOG_PACKET */
7416 if (oldGen != sessionGen) {
7417 newTime = GetTickCount();
7418 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7419 newTime - oldTime, ncbp->ncb_length);
7420 osi_Log2(smb_logp, "Pkt straddled session startup, "
7421 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7425 /* bad opcode, fail the request, after displaying it */
7426 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7429 #endif /* LOG_PACKET */
7432 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7433 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7434 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7435 if (code == IDCANCEL)
7438 code = CM_ERROR_BADOP;
7441 /* catastrophic failure: log as much as possible */
7442 if (code == CM_ERROR_BADSMB) {
7443 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7447 #endif /* LOG_PACKET */
7448 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7451 code = CM_ERROR_INVAL;
7454 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7455 thrd_Decrement(&ongoingOps);
7460 /* now, if we failed, turn the current response into an empty
7461 * one, and fill in the response packet's error code.
7464 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7465 smb_MapNTError(code, &NTStatus);
7466 outWctp = outp->wctp;
7467 smbp = (smb_t *) &outp->data;
7468 if (code != CM_ERROR_PARTIALWRITE
7469 && code != CM_ERROR_BUFFERTOOSMALL
7470 && code != CM_ERROR_GSSCONTINUE) {
7471 /* nuke wct and bcc. For a partial
7472 * write or an in-process authentication handshake,
7473 * assume they're OK.
7479 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7480 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7481 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7482 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7483 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7487 smb_MapCoreError(code, vcp, &errCode, &errClass);
7488 outWctp = outp->wctp;
7489 smbp = (smb_t *) &outp->data;
7490 if (code != CM_ERROR_PARTIALWRITE) {
7491 /* nuke wct and bcc. For a partial
7492 * write, assume they're OK.
7498 smbp->errLow = (unsigned char) (errCode & 0xff);
7499 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7500 smbp->rcls = errClass;
7503 } /* error occurred */
7505 /* if we're here, we've finished one request. Look to see if
7506 * this is a chained opcode. If it is, setup things to process
7507 * the chained request, and setup the output buffer to hold the
7508 * chained response. Start by finding the next input record.
7510 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7511 break; /* not a chained req */
7512 tp = inp->wctp; /* points to start of last request */
7513 /* in a chained request, the first two
7514 * parm fields are required, and are
7515 * AndXCommand/AndXReserved and
7517 if (tp[0] < 2) break;
7518 if (tp[1] == 0xff) break; /* no more chained opcodes */
7520 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7523 /* and now append the next output request to the end of this
7524 * last request. Begin by finding out where the last response
7525 * ends, since that's where we'll put our new response.
7527 outWctp = outp->wctp; /* ptr to out parameters */
7528 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7529 nparms = outWctp[0] << 1;
7530 tp = outWctp + nparms + 1; /* now points to bcc field */
7531 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7532 tp += 2 /* for the count itself */ + nbytes;
7533 /* tp now points to the new output record; go back and patch the
7534 * second parameter (off2) to point to the new record.
7536 temp = (unsigned int)(tp - outp->data);
7537 outWctp[3] = (unsigned char) (temp & 0xff);
7538 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7539 outWctp[2] = 0; /* padding */
7540 outWctp[1] = inp->inCom; /* next opcode */
7542 /* finally, setup for the next iteration */
7545 } /* while loop over all requests in the packet */
7547 /* now send the output packet, and return */
7549 smb_SendPacket(vcp, outp);
7550 thrd_Decrement(&ongoingOps);
7555 /* Wait for Netbios() calls to return, and make the results available to server
7556 * threads. Note that server threads can't wait on the NCBevents array
7557 * themselves, because NCB events are manual-reset, and the servers would race
7558 * each other to reset them.
7560 void smb_ClientWaiter(void *parmp)
7565 while (smbShutdownFlag == 0) {
7566 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7568 if (code == WAIT_OBJECT_0)
7571 /* error checking */
7572 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7574 int abandonIdx = code - WAIT_ABANDONED_0;
7575 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7578 if (code == WAIT_IO_COMPLETION)
7580 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7584 if (code == WAIT_TIMEOUT)
7586 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7589 if (code == WAIT_FAILED)
7591 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7594 idx = code - WAIT_OBJECT_0;
7596 /* check idx range! */
7597 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7599 /* this is fatal - log as much as possible */
7600 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7601 osi_assertx(0, "invalid index");
7604 thrd_ResetEvent(NCBevents[idx]);
7605 thrd_SetEvent(NCBreturns[0][idx]);
7610 * Try to have one NCBRECV request waiting for every live session. Not more
7611 * than one, because if there is more than one, it's hard to handle Write Raw.
7613 void smb_ServerWaiter(void *parmp)
7616 int idx_session, idx_NCB;
7619 while (smbShutdownFlag == 0) {
7621 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7623 if (code == WAIT_OBJECT_0)
7626 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7628 int abandonIdx = code - WAIT_ABANDONED_0;
7629 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7632 if (code == WAIT_IO_COMPLETION)
7634 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7638 if (code == WAIT_TIMEOUT)
7640 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7643 if (code == WAIT_FAILED)
7645 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7648 idx_session = code - WAIT_OBJECT_0;
7650 /* check idx range! */
7651 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7653 /* this is fatal - log as much as possible */
7654 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7655 osi_assertx(0, "invalid index");
7660 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7662 if (code == WAIT_OBJECT_0) {
7663 if (smbShutdownFlag == 1)
7669 /* error checking */
7670 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7672 int abandonIdx = code - WAIT_ABANDONED_0;
7673 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7676 if (code == WAIT_IO_COMPLETION)
7678 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7682 if (code == WAIT_TIMEOUT)
7684 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7687 if (code == WAIT_FAILED)
7689 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7692 idx_NCB = code - WAIT_OBJECT_0;
7694 /* check idx range! */
7695 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7697 /* this is fatal - log as much as possible */
7698 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7699 osi_assertx(0, "invalid index");
7702 /* Link them together */
7703 NCBsessions[idx_NCB] = idx_session;
7706 ncbp = NCBs[idx_NCB];
7707 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7708 ncbp->ncb_command = NCBRECV | ASYNCH;
7709 ncbp->ncb_lana_num = lanas[idx_session];
7710 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7711 ncbp->ncb_event = NCBevents[idx_NCB];
7712 ncbp->ncb_length = SMB_PACKETSIZE;
7718 * The top level loop for handling SMB request messages. Each server thread
7719 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7720 * NCB and buffer for the incoming request are loaned to us.
7722 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7723 * to immediately send a request for the rest of the data. This must come
7724 * before any other traffic for that session, so we delay setting the session
7725 * event until that data has come in.
7727 void smb_Server(VOID *parmp)
7729 INT_PTR myIdx = (INT_PTR) parmp;
7733 smb_packet_t *outbufp;
7735 int idx_NCB, idx_session;
7737 smb_vc_t *vcp = NULL;
7740 rx_StartClientThread();
7743 outbufp = GetPacket();
7744 outbufp->ncbp = outncbp;
7752 smb_ResetServerPriority();
7754 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7757 /* terminate silently if shutdown flag is set */
7758 if (code == WAIT_OBJECT_0) {
7759 if (smbShutdownFlag == 1) {
7760 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7766 /* error checking */
7767 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7769 int abandonIdx = code - WAIT_ABANDONED_0;
7770 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7773 if (code == WAIT_IO_COMPLETION)
7775 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7779 if (code == WAIT_TIMEOUT)
7781 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7784 if (code == WAIT_FAILED)
7786 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7789 idx_NCB = code - WAIT_OBJECT_0;
7791 /* check idx range! */
7792 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7794 /* this is fatal - log as much as possible */
7795 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7796 osi_assertx(0, "invalid index");
7799 ncbp = NCBs[idx_NCB];
7800 idx_session = NCBsessions[idx_NCB];
7801 rc = ncbp->ncb_retcode;
7803 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7804 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7808 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7812 /* Can this happen? Or is it just my UNIX paranoia? */
7813 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7818 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7821 /* Client closed session */
7822 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7824 lock_ObtainMutex(&vcp->mx);
7825 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7826 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7828 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7829 lock_ReleaseMutex(&vcp->mx);
7830 lock_ObtainWrite(&smb_globalLock);
7831 dead_sessions[vcp->session] = TRUE;
7832 lock_ReleaseWrite(&smb_globalLock);
7833 smb_CleanupDeadVC(vcp);
7837 lock_ReleaseMutex(&vcp->mx);
7843 /* Treat as transient error */
7844 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7847 "dispatch smb recv failed, message incomplete, ncb_length %d",
7850 "SMB message incomplete, "
7851 "length %d", ncbp->ncb_length);
7854 * We used to discard the packet.
7855 * Instead, try handling it normally.
7859 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7863 /* A weird error code. Log it, sleep, and continue. */
7864 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7866 lock_ObtainMutex(&vcp->mx);
7867 if (vcp && vcp->errorCount++ > 3) {
7868 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7869 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7870 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7872 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7873 lock_ReleaseMutex(&vcp->mx);
7874 lock_ObtainWrite(&smb_globalLock);
7875 dead_sessions[vcp->session] = TRUE;
7876 lock_ReleaseWrite(&smb_globalLock);
7877 smb_CleanupDeadVC(vcp);
7881 lock_ReleaseMutex(&vcp->mx);
7887 lock_ReleaseMutex(&vcp->mx);
7889 thrd_SetEvent(SessionEvents[idx_session]);
7894 /* Success, so now dispatch on all the data in the packet */
7896 smb_concurrentCalls++;
7897 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7898 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7901 * If at this point vcp is NULL (implies that packet was invalid)
7902 * then we are in big trouble. This means either :
7903 * a) we have the wrong NCB.
7904 * b) Netbios screwed up the call.
7905 * c) The VC was already marked dead before we were able to
7907 * Obviously this implies that
7908 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7909 * lanas[idx_session] != ncbp->ncb_lana_num )
7910 * Either way, we can't do anything with this packet.
7911 * Log, sleep and resume.
7914 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7918 ncbp->ncb_lana_num);
7920 /* Also log in the trace log. */
7921 osi_Log4(smb_logp, "Server: VCP does not exist!"
7922 "LSNs[idx_session]=[%d],"
7923 "lanas[idx_session]=[%d],"
7924 "ncbp->ncb_lsn=[%d],"
7925 "ncbp->ncb_lana_num=[%d]",
7929 ncbp->ncb_lana_num);
7931 /* thrd_Sleep(1000); Don't bother sleeping */
7932 thrd_SetEvent(SessionEvents[idx_session]);
7933 smb_concurrentCalls--;
7937 smb_SetRequestStartTime();
7939 vcp->errorCount = 0;
7940 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7941 smbp = (smb_t *)bufp->data;
7946 if (smbp->com == 0x1d) {
7947 /* Special handling for Write Raw */
7948 raw_write_cont_t rwc;
7949 EVENT_HANDLE rwevent;
7950 char eventName[MAX_PATH];
7952 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7953 if (rwc.code == 0) {
7954 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7955 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7956 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7957 ncbp->ncb_command = NCBRECV | ASYNCH;
7958 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7959 ncbp->ncb_lana_num = vcp->lana;
7960 ncbp->ncb_buffer = rwc.buf;
7961 ncbp->ncb_length = 65535;
7962 ncbp->ncb_event = rwevent;
7964 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7965 thrd_CloseHandle(rwevent);
7967 thrd_SetEvent(SessionEvents[idx_session]);
7969 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7971 else if (smbp->com == 0xa0) {
7973 * Serialize the handling for NT Transact
7976 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7977 thrd_SetEvent(SessionEvents[idx_session]);
7979 thrd_SetEvent(SessionEvents[idx_session]);
7980 /* TODO: what else needs to be serialized? */
7981 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7984 __except( smb_ServerExceptionFilter() ) {
7987 smb_concurrentCalls--;
7990 thrd_SetEvent(NCBavails[idx_NCB]);
7997 * Exception filter for the server threads. If an exception occurs in the
7998 * dispatch routines, which is where exceptions are most common, then do a
7999 * force trace and give control to upstream exception handlers. Useful for
8002 DWORD smb_ServerExceptionFilter(void) {
8003 /* While this is not the best time to do a trace, if it succeeds, then
8004 * we have a trace (assuming tracing was enabled). Otherwise, this should
8005 * throw a second exception.
8007 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8008 afsd_ForceTrace(TRUE);
8009 buf_ForceTrace(TRUE);
8010 return EXCEPTION_CONTINUE_SEARCH;
8014 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8015 * If the number of server threads is M, and the number of live sessions is
8016 * N, then the number of NCB's in use at any time either waiting for, or
8017 * holding, received messages is M + N, so that is how many NCB's get created.
8019 void InitNCBslot(int idx)
8021 struct smb_packet *bufp;
8022 EVENT_HANDLE retHandle;
8024 char eventName[MAX_PATH];
8026 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8028 NCBs[idx] = GetNCB();
8029 sprintf(eventName,"NCBavails[%d]", idx);
8030 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8031 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8032 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8033 sprintf(eventName,"NCBevents[%d]", idx);
8034 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8035 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8036 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8037 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8038 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8039 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8040 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8041 for (i=0; i<smb_NumServerThreads; i++)
8042 NCBreturns[i][idx] = retHandle;
8044 bufp->spacep = cm_GetSpace();
8048 /* listen for new connections */
8049 void smb_Listener(void *parmp)
8055 int session, thread;
8056 smb_vc_t *vcp = NULL;
8058 char rname[NCBNAMSZ+1];
8059 char cname[MAX_COMPUTERNAME_LENGTH+1];
8060 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8061 INT_PTR lana = (INT_PTR) parmp;
8062 char eventName[MAX_PATH];
8064 sprintf(eventName,"smb_Listener_lana_%d", (char)lana);
8065 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8066 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8067 thrd_ResetEvent(ListenerShutdown[lana]);
8071 /* retrieve computer name */
8072 GetComputerName(cname, &cnamelen);
8075 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8076 memset(ncbp, 0, sizeof(NCB));
8079 ncbp->ncb_command = NCBLISTEN;
8080 ncbp->ncb_rto = 0; /* No receive timeout */
8081 ncbp->ncb_sto = 0; /* No send timeout */
8083 /* pad out with spaces instead of null termination */
8084 len = (long)strlen(smb_localNamep);
8085 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8086 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8088 strcpy(ncbp->ncb_callname, "*");
8089 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8091 ncbp->ncb_lana_num = (UCHAR)lana;
8093 code = Netbios(ncbp);
8095 if (code == NRC_NAMERR) {
8096 /* An smb shutdown or Vista resume must have taken place */
8098 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8099 ncbp->ncb_lana_num, code);
8101 if (lock_TryMutex(&smb_StartedLock)) {
8102 lana_list.lana[i] = LANA_INVALID;
8103 lock_ReleaseMutex(&smb_StartedLock);
8106 } else if (code == NRC_BRIDGE || code != 0) {
8107 int lanaRemaining = 0;
8109 while (!lock_TryMutex(&smb_StartedLock)) {
8110 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8116 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8117 ncbp->ncb_lana_num, ncb_error_string(code));
8119 for (i = 0; i < lana_list.length; i++) {
8120 if (lana_list.lana[i] == lana) {
8121 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8122 lana_list.lana[i] = LANA_INVALID;
8124 if (lana_list.lana[i] != LANA_INVALID)
8128 if (lanaRemaining == 0) {
8129 cm_VolStatus_Network_Stopped(cm_NetbiosName
8134 smb_ListenerState = SMB_LISTENER_STOPPED;
8135 smb_LANadapter = LANA_INVALID;
8136 lana_list.length = 0;
8138 lock_ReleaseMutex(&smb_StartedLock);
8142 else if (code != 0) {
8143 char tbuffer[AFSPATHMAX];
8145 /* terminate silently if shutdown flag is set */
8146 while (!lock_TryMutex(&smb_StartedLock)) {
8147 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8153 "NCBLISTEN lana=%d failed with code %d [%s]",
8154 ncbp->ncb_lana_num, code, ncb_error_string(code));
8156 "Client exiting due to network failure. Please restart client.\n");
8159 "Client exiting due to network failure. Please restart client.\n"
8160 "NCBLISTEN lana=%d failed with code %d [%s]",
8161 ncbp->ncb_lana_num, code, ncb_error_string(code));
8163 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8164 MB_OK|MB_SERVICE_NOTIFICATION);
8165 osi_panic(tbuffer, __FILE__, __LINE__);
8167 lock_ReleaseMutex(&smb_StartedLock);
8172 /* check for remote conns */
8173 /* first get remote name and insert null terminator */
8174 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8175 for (i=NCBNAMSZ; i>0; i--) {
8176 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8182 /* compare with local name */
8184 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8185 flags |= SMB_VCFLAG_REMOTECONN;
8188 lock_ObtainMutex(&smb_ListenerLock);
8190 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8191 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8193 /* now ncbp->ncb_lsn is the connection ID */
8194 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8195 if (vcp->session == 0) {
8196 /* New generation */
8197 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8200 /* Log session startup */
8202 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8203 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8204 #endif /* NOTSERVICE */
8205 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8206 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8208 if (reportSessionStartups) {
8209 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8212 lock_ObtainMutex(&vcp->mx);
8213 strcpy(vcp->rname, rname);
8214 vcp->flags |= flags;
8215 lock_ReleaseMutex(&vcp->mx);
8217 /* Allocate slot in session arrays */
8218 /* Re-use dead session if possible, otherwise add one more */
8219 /* But don't look at session[0], it is reserved */
8220 lock_ObtainWrite(&smb_globalLock);
8221 for (session = 1; session < numSessions; session++) {
8222 if (dead_sessions[session]) {
8223 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8224 dead_sessions[session] = FALSE;
8228 lock_ReleaseWrite(&smb_globalLock);
8230 /* We are re-using an existing VC because the lsn and lana
8232 session = vcp->session;
8234 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8236 /* Log session startup */
8238 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8239 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8240 #endif /* NOTSERVICE */
8241 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8242 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8244 if (reportSessionStartups) {
8245 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8249 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8250 unsigned long code = CM_ERROR_ALLBUSY;
8251 smb_packet_t * outp = GetPacket();
8252 unsigned char *outWctp;
8255 smb_FormatResponsePacket(vcp, NULL, outp);
8258 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8259 unsigned long NTStatus;
8260 smb_MapNTError(code, &NTStatus);
8261 outWctp = outp->wctp;
8262 smbp = (smb_t *) &outp->data;
8266 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8267 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8268 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8269 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8270 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8272 unsigned short errCode;
8273 unsigned char errClass;
8274 smb_MapCoreError(code, vcp, &errCode, &errClass);
8275 outWctp = outp->wctp;
8276 smbp = (smb_t *) &outp->data;
8280 smbp->errLow = (unsigned char) (errCode & 0xff);
8281 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8282 smbp->rcls = errClass;
8284 smb_SendPacket(vcp, outp);
8285 smb_FreePacket(outp);
8287 lock_ObtainMutex(&vcp->mx);
8288 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8289 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8291 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8292 lock_ReleaseMutex(&vcp->mx);
8293 lock_ObtainWrite(&smb_globalLock);
8294 dead_sessions[vcp->session] = TRUE;
8295 lock_ReleaseWrite(&smb_globalLock);
8296 smb_CleanupDeadVC(vcp);
8298 lock_ReleaseMutex(&vcp->mx);
8301 /* assert that we do not exceed the maximum number of sessions or NCBs.
8302 * we should probably want to wait for a session to be freed in case
8305 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8306 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8308 lock_ObtainMutex(&vcp->mx);
8309 vcp->session = session;
8310 lock_ReleaseMutex(&vcp->mx);
8311 lock_ObtainWrite(&smb_globalLock);
8312 LSNs[session] = ncbp->ncb_lsn;
8313 lanas[session] = ncbp->ncb_lana_num;
8314 lock_ReleaseWrite(&smb_globalLock);
8316 if (session == numSessions) {
8317 /* Add new NCB for new session */
8318 char eventName[MAX_PATH];
8320 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8322 InitNCBslot(numNCBs);
8323 lock_ObtainWrite(&smb_globalLock);
8325 lock_ReleaseWrite(&smb_globalLock);
8326 thrd_SetEvent(NCBavails[0]);
8327 thrd_SetEvent(NCBevents[0]);
8328 for (thread = 0; thread < smb_NumServerThreads; thread++)
8329 thrd_SetEvent(NCBreturns[thread][0]);
8330 /* Also add new session event */
8331 sprintf(eventName, "SessionEvents[%d]", session);
8332 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8333 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8334 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8335 lock_ObtainWrite(&smb_globalLock);
8337 lock_ReleaseWrite(&smb_globalLock);
8338 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8339 thrd_SetEvent(SessionEvents[0]);
8341 thrd_SetEvent(SessionEvents[session]);
8347 lock_ReleaseMutex(&smb_ListenerLock);
8348 } /* dispatch while loop */
8352 thrd_SetEvent(ListenerShutdown[lana]);
8356 void smb_SetLanAdapterChangeDetected(void)
8358 lock_ObtainMutex(&smb_StartedLock);
8359 smb_LanAdapterChangeDetected = 1;
8360 lock_ReleaseMutex(&smb_StartedLock);
8363 void smb_LanAdapterChange(int locked) {
8364 lana_number_t lanaNum;
8366 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
8368 LANA_ENUM temp_list;
8373 afsi_log("smb_LanAdapterChange");
8376 lock_ObtainMutex(&smb_StartedLock);
8378 smb_LanAdapterChangeDetected = 0;
8380 if (!powerStateSuspended &&
8381 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
8382 LANA_NETBIOS_NAME_FULL)) &&
8383 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
8384 if ( isGateway != bGateway ||
8385 strcmp(cm_NetbiosName, NetbiosName) ) {
8388 NCB *ncbp = GetNCB();
8389 ncbp->ncb_command = NCBENUM;
8390 ncbp->ncb_buffer = (PUCHAR)&temp_list;
8391 ncbp->ncb_length = sizeof(temp_list);
8392 code = Netbios(ncbp);
8394 if (temp_list.length != lana_list.length)
8397 for (i=0; i<lana_list.length; i++) {
8398 if ( temp_list.lana[i] != lana_list.lana[i] ) {
8410 afsi_log("Lan Adapter Change detected");
8411 smb_StopListeners(1);
8412 smb_RestartListeners(1);
8415 lock_ReleaseMutex(&smb_StartedLock);
8418 /* initialize Netbios */
8419 int smb_NetbiosInit(int locked)
8422 int i, lana, code, l;
8424 int delname_tried=0;
8427 lana_number_t lanaNum;
8430 lock_ObtainMutex(&smb_StartedLock);
8432 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
8433 smb_ListenerState != SMB_LISTENER_STOPPED) {
8436 lock_ReleaseMutex(&smb_StartedLock);
8439 /* setup the NCB system */
8442 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8443 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8444 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8446 if (smb_LANadapter != LANA_INVALID)
8447 afsi_log("LAN adapter number %d", smb_LANadapter);
8449 afsi_log("LAN adapter number not determined");
8452 afsi_log("Set for gateway service");
8454 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8456 /* something went horribly wrong. We can't proceed without a netbios name */
8458 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8459 osi_panic(buf, __FILE__, __LINE__);
8462 /* remember the name */
8463 len = (int)strlen(cm_NetbiosName);
8465 free(smb_localNamep);
8466 smb_localNamep = malloc(len+1);
8467 strcpy(smb_localNamep, cm_NetbiosName);
8468 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8471 if (smb_LANadapter == LANA_INVALID) {
8472 ncbp->ncb_command = NCBENUM;
8473 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8474 ncbp->ncb_length = sizeof(lana_list);
8475 code = Netbios(ncbp);
8477 afsi_log("Netbios NCBENUM error code %d", code);
8478 osi_panic(s, __FILE__, __LINE__);
8482 lana_list.length = 1;
8483 lana_list.lana[0] = smb_LANadapter;
8486 for (i = 0; i < lana_list.length; i++) {
8487 /* reset the adaptor: in Win32, this is required for every process, and
8488 * acts as an init call, not as a real hardware reset.
8490 ncbp->ncb_command = NCBRESET;
8491 ncbp->ncb_callname[0] = 100;
8492 ncbp->ncb_callname[2] = 100;
8493 ncbp->ncb_lana_num = lana_list.lana[i];
8494 code = Netbios(ncbp);
8496 code = ncbp->ncb_retcode;
8498 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8499 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
8501 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8505 /* and declare our name so we can receive connections */
8506 memset(ncbp, 0, sizeof(*ncbp));
8507 len=lstrlen(smb_localNamep);
8508 memset(smb_sharename,' ',NCBNAMSZ);
8509 memcpy(smb_sharename,smb_localNamep,len);
8510 afsi_log("lana_list.length %d", lana_list.length);
8512 /* Keep the name so we can unregister it later */
8513 for (l = 0; l < lana_list.length; l++) {
8514 lana = lana_list.lana[l];
8516 ncbp->ncb_command = NCBADDNAME;
8517 ncbp->ncb_lana_num = lana;
8518 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8519 code = Netbios(ncbp);
8521 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8522 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8524 char name[NCBNAMSZ+1];
8526 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8527 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8531 code = ncbp->ncb_retcode;
8534 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8537 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8538 if (code == NRC_BRIDGE) { /* invalid LANA num */
8539 lana_list.lana[l] = LANA_INVALID;
8542 else if (code == NRC_DUPNAME) {
8543 afsi_log("Name already exists; try to delete it");
8544 memset(ncbp, 0, sizeof(*ncbp));
8545 ncbp->ncb_command = NCBDELNAME;
8546 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8547 ncbp->ncb_lana_num = lana;
8548 code = Netbios(ncbp);
8550 code = ncbp->ncb_retcode;
8552 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8554 if (code != 0 || delname_tried) {
8555 lana_list.lana[l] = LANA_INVALID;
8557 else if (code == 0) {
8558 if (!delname_tried) {
8566 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8567 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8571 smb_LANadapter = lana;
8572 lana_found = 1; /* at least one worked */
8576 osi_assertx(lana_list.length >= 0, "empty lana list");
8578 afsi_log("No valid LANA numbers found!");
8579 lana_list.length = 0;
8580 smb_LANadapter = LANA_INVALID;
8581 smb_ListenerState = SMB_LISTENER_STOPPED;
8582 cm_VolStatus_Network_Stopped(cm_NetbiosName
8589 /* we're done with the NCB now */
8592 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
8593 if (lana_list.length > 0)
8594 osi_assert(smb_LANadapter != LANA_INVALID);
8597 lock_ReleaseMutex(&smb_StartedLock);
8599 return (lana_list.length > 0 ? 1 : 0);
8602 void smb_StartListeners(int locked)
8609 lock_ObtainMutex(&smb_StartedLock);
8611 if (smb_ListenerState == SMB_LISTENER_STARTED) {
8613 lock_ReleaseMutex(&smb_StartedLock);
8617 afsi_log("smb_StartListeners");
8618 smb_ListenerState = SMB_LISTENER_STARTED;
8619 cm_VolStatus_Network_Started(cm_NetbiosName
8625 for (i = 0; i < lana_list.length; i++) {
8626 if (lana_list.lana[i] == LANA_INVALID)
8628 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8629 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8630 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
8631 thrd_CloseHandle(phandle);
8634 lock_ReleaseMutex(&smb_StartedLock);
8637 void smb_RestartListeners(int locked)
8640 lock_ObtainMutex(&smb_StartedLock);
8642 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
8643 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8644 if (smb_NetbiosInit(1))
8645 smb_StartListeners(1);
8646 } else if (smb_LanAdapterChangeDetected) {
8647 smb_LanAdapterChange(1);
8651 lock_ReleaseMutex(&smb_StartedLock);
8654 void smb_StopListener(NCB *ncbp, int lana, int wait)
8658 memset(ncbp, 0, sizeof(*ncbp));
8659 ncbp->ncb_command = NCBDELNAME;
8660 ncbp->ncb_lana_num = lana;
8661 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8662 code = Netbios(ncbp);
8664 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8665 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8667 /* and then reset the LANA; this will cause the listener threads to exit */
8668 ncbp->ncb_command = NCBRESET;
8669 ncbp->ncb_callname[0] = 100;
8670 ncbp->ncb_callname[2] = 100;
8671 ncbp->ncb_lana_num = lana;
8672 code = Netbios(ncbp);
8674 code = ncbp->ncb_retcode;
8676 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8678 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8682 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
8685 void smb_StopListeners(int locked)
8691 lock_ObtainMutex(&smb_StartedLock);
8693 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8695 lock_ReleaseMutex(&smb_StartedLock);
8699 afsi_log("smb_StopListeners");
8700 smb_ListenerState = SMB_LISTENER_STOPPED;
8701 cm_VolStatus_Network_Stopped(cm_NetbiosName
8709 /* Unregister the SMB name */
8710 for (l = 0; l < lana_list.length; l++) {
8711 lana = lana_list.lana[l];
8713 if (lana != LANA_INVALID) {
8714 smb_StopListener(ncbp, lana, TRUE);
8716 /* mark the adapter invalid */
8717 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8721 /* force a re-evaluation of the network adapters */
8722 lana_list.length = 0;
8723 smb_LANadapter = LANA_INVALID;
8726 lock_ReleaseMutex(&smb_StartedLock);
8729 void smb_Init(osi_log_t *logp, int useV3,
8739 EVENT_HANDLE retHandle;
8740 char eventName[MAX_PATH];
8741 int startListeners = 0;
8743 smb_TlsRequestSlot = TlsAlloc();
8745 smb_MBfunc = aMBfunc;
8749 /* Initialize smb_localZero */
8750 myTime.tm_isdst = -1; /* compute whether on DST or not */
8751 myTime.tm_year = 70;
8757 smb_localZero = mktime(&myTime);
8759 #ifndef USE_NUMERIC_TIME_CONV
8760 /* Initialize kludge-GMT */
8761 smb_CalculateNowTZ();
8762 #endif /* USE_NUMERIC_TIME_CONV */
8763 #ifdef AFS_FREELANCE_CLIENT
8764 /* Make sure the root.afs volume has the correct time */
8765 cm_noteLocalMountPointChange();
8768 /* initialize the remote debugging log */
8771 /* and the global lock */
8772 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8773 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8775 /* Raw I/O data structures */
8776 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8778 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8779 lock_InitializeMutex(&smb_StartedLock, "smb started lock");
8781 /* 4 Raw I/O buffers */
8782 smb_RawBufs = calloc(65536,1);
8783 *((char **)smb_RawBufs) = NULL;
8784 for (i=0; i<3; i++) {
8785 char *rawBuf = calloc(65536,1);
8786 *((char **)rawBuf) = smb_RawBufs;
8787 smb_RawBufs = rawBuf;
8790 /* global free lists */
8791 smb_ncbFreeListp = NULL;
8792 smb_packetFreeListp = NULL;
8794 lock_ObtainMutex(&smb_StartedLock);
8795 startListeners = smb_NetbiosInit(1);
8797 /* Initialize listener and server structures */
8799 memset(dead_sessions, 0, sizeof(dead_sessions));
8800 sprintf(eventName, "SessionEvents[0]");
8801 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8802 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8803 afsi_log("Event Object Already Exists: %s", eventName);
8805 smb_NumServerThreads = nThreads;
8806 sprintf(eventName, "NCBavails[0]");
8807 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8808 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8809 afsi_log("Event Object Already Exists: %s", eventName);
8810 sprintf(eventName, "NCBevents[0]");
8811 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8812 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8813 afsi_log("Event Object Already Exists: %s", eventName);
8814 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8815 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8816 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8817 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8818 afsi_log("Event Object Already Exists: %s", eventName);
8819 for (i = 0; i < smb_NumServerThreads; i++) {
8820 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8821 NCBreturns[i][0] = retHandle;
8824 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8825 for (i = 0; i < smb_NumServerThreads; i++) {
8826 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8827 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8828 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8829 afsi_log("Event Object Already Exists: %s", eventName);
8830 InitNCBslot((int)(i+1));
8832 numNCBs = smb_NumServerThreads + 1;
8834 /* Initialize dispatch table */
8835 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8836 /* Prepare the table for unknown operations */
8837 for(i=0; i<= SMB_NOPCODES; i++) {
8838 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8840 /* Fill in the ones we do know */
8841 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8842 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8843 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8844 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8845 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8846 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8847 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8848 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8849 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8850 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8851 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8852 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8853 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8854 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8855 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8856 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8857 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8858 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8859 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8860 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8861 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8862 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8863 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8864 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8865 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8866 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8867 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8868 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8869 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8870 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8871 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8872 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8873 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8874 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8875 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8876 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8877 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8878 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8879 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8880 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8881 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8882 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8883 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8884 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8885 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8886 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8887 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8888 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8889 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8890 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8891 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8892 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8893 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8894 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8895 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8896 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8897 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8898 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8899 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8900 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8901 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8902 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8903 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8904 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8905 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8906 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8907 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8908 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8909 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8910 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8911 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8912 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8913 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8914 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8916 /* setup tran 2 dispatch table */
8917 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8918 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8919 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8920 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8921 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8922 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8923 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8924 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8925 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8926 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8927 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8928 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8929 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8930 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8931 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8932 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8933 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8934 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8936 /* setup the rap dispatch table */
8937 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8938 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8939 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8940 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8941 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8945 /* if we are doing SMB authentication we have register outselves as a logon process */
8946 if (smb_authType != SMB_AUTH_NONE) {
8947 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8948 LSA_STRING afsProcessName;
8949 LSA_OPERATIONAL_MODE dummy; /*junk*/
8951 afsProcessName.Buffer = "OpenAFSClientDaemon";
8952 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8953 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8955 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8957 if (nts == STATUS_SUCCESS) {
8958 LSA_STRING packageName;
8959 /* we are registered. Find out the security package id */
8960 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8961 packageName.Length = (USHORT)strlen(packageName.Buffer);
8962 packageName.MaximumLength = packageName.Length + 1;
8963 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8964 if (nts == STATUS_SUCCESS) {
8966 * This code forces Windows to authenticate against the Logon Cache
8967 * first instead of attempting to authenticate against the Domain
8968 * Controller. When the Windows logon cache is enabled this improves
8969 * performance by removing the network access and works around a bug
8970 * seen at sites which are using a MIT Kerberos principal to login
8971 * to machines joined to a non-root domain in a multi-domain forest.
8972 * MsV1_0SetProcessOption was added in Windows XP.
8974 PVOID pResponse = NULL;
8975 ULONG cbResponse = 0;
8976 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8978 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8979 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8980 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8981 OptionsRequest.DisableOptions = FALSE;
8983 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8986 sizeof(OptionsRequest),
8992 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8993 char message[AFSPATHMAX];
8994 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8996 OutputDebugString(message);
8999 OutputDebugString("MsV1_0SetProcessOption success");
9000 afsi_log("MsV1_0SetProcessOption success");
9002 /* END - code from Larry */
9004 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9005 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9006 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9008 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9010 /* something went wrong. We report the error and revert back to no authentication
9011 because we can't perform any auth requests without a successful lsa handle
9012 or sec package id. */
9013 afsi_log("Reverting to NO SMB AUTH");
9014 smb_authType = SMB_AUTH_NONE;
9017 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9019 /* something went wrong. We report the error and revert back to no authentication
9020 because we can't perform any auth requests without a successful lsa handle
9021 or sec package id. */
9022 afsi_log("Reverting to NO SMB AUTH");
9023 smb_authType = SMB_AUTH_NONE;
9027 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9028 * time prevents the failure of authentication when logged into Windows with an
9029 * external Kerberos principal mapped to a local account.
9031 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9032 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9033 * then the only option is NTLMSSP anyway; so just fallback.
9038 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9039 if (secBlobLength == 0) {
9040 smb_authType = SMB_AUTH_NTLM;
9041 afsi_log("Reverting to SMB AUTH NTLM");
9050 /* Now get ourselves a domain name. */
9051 /* For now we are using the local computer name as the domain name.
9052 * It is actually the domain for local logins, and we are acting as
9053 * a local SMB server.
9055 bufsize = sizeof(smb_ServerDomainName) - 1;
9056 GetComputerName(smb_ServerDomainName, &bufsize);
9057 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9058 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
9061 /* Start listeners, waiters, servers, and daemons */
9063 smb_StartListeners(1);
9065 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9066 NULL, 0, &lpid, "smb_ClientWaiter");
9067 osi_assertx(phandle != NULL, , "smb_ClientWaiter thread creation failure");
9068 thrd_CloseHandle(phandle);
9070 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9071 NULL, 0, &lpid, "smb_ServerWaiter");
9072 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9073 thrd_CloseHandle(phandle);
9075 for (i=0; i<smb_NumServerThreads; i++) {
9076 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9077 (void *) i, 0, &lpid, "smb_Server");
9078 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9079 thrd_CloseHandle(phandle);
9082 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9083 NULL, 0, &lpid, "smb_Daemon");
9084 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9085 thrd_CloseHandle(phandle);
9087 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9088 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9089 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9090 thrd_CloseHandle(phandle);
9092 lock_ReleaseMutex(&smb_StartedLock);
9096 void smb_Shutdown(void)
9103 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9105 /* setup the NCB system */
9108 /* Block new sessions by setting shutdown flag */
9109 smbShutdownFlag = 1;
9111 /* Hang up all sessions */
9112 memset((char *)ncbp, 0, sizeof(NCB));
9113 for (i = 1; i < numSessions; i++)
9115 if (dead_sessions[i])
9118 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9119 ncbp->ncb_command = NCBHANGUP;
9120 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9121 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9122 code = Netbios(ncbp);
9123 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9124 if (code == 0) code = ncbp->ncb_retcode;
9126 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9127 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9131 /* Trigger the shutdown of all SMB threads */
9132 for (i = 0; i < smb_NumServerThreads; i++)
9133 thrd_SetEvent(NCBreturns[i][0]);
9135 thrd_SetEvent(NCBevents[0]);
9136 thrd_SetEvent(SessionEvents[0]);
9137 thrd_SetEvent(NCBavails[0]);
9139 for (i = 0;i < smb_NumServerThreads; i++) {
9140 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9141 if (code == WAIT_OBJECT_0) {
9144 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9145 thrd_SetEvent(NCBreturns[i--][0]);
9149 /* Delete Netbios name */
9150 memset((char *)ncbp, 0, sizeof(NCB));
9151 for (i = 0; i < lana_list.length; i++) {
9152 if (lana_list.lana[i] == LANA_INVALID) continue;
9153 ncbp->ncb_command = NCBDELNAME;
9154 ncbp->ncb_lana_num = lana_list.lana[i];
9155 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9156 code = Netbios(ncbp);
9158 code = ncbp->ncb_retcode;
9160 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9161 ncbp->ncb_lana_num, code);
9166 /* Release the reference counts held by the VCs */
9167 lock_ObtainWrite(&smb_rctLock);
9168 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9173 if (vcp->magic != SMB_VC_MAGIC)
9174 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9175 __FILE__, __LINE__);
9177 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9179 if (fidp->scp != NULL) {
9182 lock_ObtainMutex(&fidp->mx);
9183 if (fidp->scp != NULL) {
9186 lock_ObtainMutex(&scp->mx);
9187 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9188 lock_ReleaseMutex(&scp->mx);
9189 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9190 cm_ReleaseSCache(scp);
9192 lock_ReleaseMutex(&fidp->mx);
9196 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9198 smb_ReleaseVCNoLock(tidp->vcp);
9200 cm_user_t *userp = tidp->userp;
9202 lock_ReleaseWrite(&smb_rctLock);
9203 cm_ReleaseUser(userp);
9204 lock_ObtainWrite(&smb_rctLock);
9208 lock_ReleaseWrite(&smb_rctLock);
9210 TlsFree(smb_TlsRequestSlot);
9213 /* Get the UNC \\<servername>\<sharename> prefix. */
9214 char *smb_GetSharename()
9218 /* Make sure we have been properly initialized. */
9219 if (smb_localNamep == NULL)
9222 /* Allocate space for \\<servername>\<sharename>, plus the
9225 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9226 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9232 void smb_LogPacket(smb_packet_t *packet)
9235 unsigned length, paramlen, datalen, i, j;
9237 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9239 if (!packet) return;
9241 osi_Log0(smb_logp, "*** SMB packet dump ***");
9243 vp = (BYTE *) packet->data;
9245 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9246 length = paramlen + 2 + datalen;
9249 for (i=0;i < length; i+=16)
9251 memset( buf, ' ', 80 );
9256 buf[strlen(buf)] = ' ';
9258 cp = (BYTE*) buf + 7;
9260 for (j=0;j < 16 && (i+j)<length; j++)
9262 *(cp++) = hex[vp[i+j] >> 4];
9263 *(cp++) = hex[vp[i+j] & 0xf];
9273 for (j=0;j < 16 && (i+j)<length;j++)
9275 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9286 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9289 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9291 #endif /* LOG_PACKET */
9294 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9302 lock_ObtainRead(&smb_rctLock);
9304 sprintf(output, "begin dumping smb_vc_t\r\n");
9305 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9307 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9311 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9312 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9313 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9315 sprintf(output, "begin dumping smb_fid_t\r\n");
9316 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9318 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9320 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n",
9321 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9322 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9323 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9324 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9327 sprintf(output, "done dumping smb_fid_t\r\n");
9328 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9331 sprintf(output, "done dumping smb_vc_t\r\n");
9332 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9334 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9335 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9337 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9341 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9342 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9343 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9345 sprintf(output, "begin dumping smb_fid_t\r\n");
9346 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9348 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9350 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n",
9351 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9352 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9353 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9354 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9357 sprintf(output, "done dumping smb_fid_t\r\n");
9358 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9361 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9362 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9365 lock_ReleaseRead(&smb_rctLock);
9369 long smb_IsNetworkStarted(void)
9372 lock_ObtainWrite(&smb_globalLock);
9373 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
9374 lock_ReleaseWrite(&smb_globalLock);