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 smb_ReleaseTID(tidpIter, TRUE);
1039 tidpNext = vcp->tidsp;
1042 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1043 uidpNext = uidpIter->nextp;
1044 if (uidpIter->delete)
1046 uidpIter->delete = 1;
1048 /* do not add an additional reference count for the smb_user_t
1049 * as the smb_vc_t already is holding a reference */
1050 lock_ReleaseWrite(&smb_rctLock);
1052 smb_ReleaseUID(uidpIter);
1054 lock_ObtainWrite(&smb_rctLock);
1055 uidpNext = vcp->usersp;
1058 /* The vcp is now on the deadVCsp list. We intentionally drop the
1059 * reference so that the refcount can reach 0 and we can delete it */
1060 smb_ReleaseVCNoLock(vcp);
1062 lock_ReleaseWrite(&smb_rctLock);
1063 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1066 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1070 lock_ObtainWrite(&smb_rctLock);
1072 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1073 if (tidp->refCount == 0 && tidp->delete) {
1075 smb_ReleaseTID(tidp, TRUE);
1079 if (tid == tidp->tid) {
1084 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1085 tidp = malloc(sizeof(*tidp));
1086 memset(tidp, 0, sizeof(*tidp));
1087 tidp->nextp = vcp->tidsp;
1090 smb_HoldVCNoLock(vcp);
1092 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1095 lock_ReleaseWrite(&smb_rctLock);
1099 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1104 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1112 lock_ObtainWrite(&smb_rctLock);
1113 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1114 if (tidp->refCount == 0 && (tidp->delete)) {
1115 ltpp = &tidp->vcp->tidsp;
1116 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1120 osi_assertx(tp != NULL, "null smb_tid_t");
1122 lock_FinalizeMutex(&tidp->mx);
1123 userp = tidp->userp; /* remember to drop ref later */
1125 smb_ReleaseVCNoLock(tidp->vcp);
1129 lock_ReleaseWrite(&smb_rctLock);
1131 cm_ReleaseUser(userp);
1134 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1136 smb_user_t *uidp = NULL;
1138 lock_ObtainWrite(&smb_rctLock);
1139 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1140 if (uid == uidp->userID) {
1142 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1144 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1148 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1149 uidp = malloc(sizeof(*uidp));
1150 memset(uidp, 0, sizeof(*uidp));
1151 uidp->nextp = vcp->usersp;
1152 uidp->refCount = 2; /* one for the vcp and one for the caller */
1154 smb_HoldVCNoLock(vcp);
1156 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1158 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1160 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1162 lock_ReleaseWrite(&smb_rctLock);
1166 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1168 smb_username_t *unp= NULL;
1170 lock_ObtainWrite(&smb_rctLock);
1171 for(unp = usernamesp; unp; unp = unp->nextp) {
1172 if (stricmp(unp->name, usern) == 0 &&
1173 stricmp(unp->machine, machine) == 0) {
1178 if (!unp && (flags & SMB_FLAG_CREATE)) {
1179 unp = malloc(sizeof(*unp));
1180 memset(unp, 0, sizeof(*unp));
1182 unp->nextp = usernamesp;
1183 unp->name = strdup(usern);
1184 unp->machine = strdup(machine);
1186 lock_InitializeMutex(&unp->mx, "username_t mutex");
1187 if (flags & SMB_FLAG_AFSLOGON)
1188 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1191 lock_ReleaseWrite(&smb_rctLock);
1195 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1197 smb_user_t *uidp= NULL;
1199 lock_ObtainWrite(&smb_rctLock);
1200 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1203 if (stricmp(uidp->unp->name, usern) == 0) {
1205 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1206 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1211 lock_ReleaseWrite(&smb_rctLock);
1215 void smb_ReleaseUsername(smb_username_t *unp)
1218 smb_username_t **lupp;
1219 cm_user_t *userp = NULL;
1220 time_t now = osi_Time();
1222 lock_ObtainWrite(&smb_rctLock);
1223 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1224 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1225 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1227 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1231 osi_assertx(up != NULL, "null smb_username_t");
1233 up->nextp = NULL; /* do not remove this */
1234 lock_FinalizeMutex(&unp->mx);
1240 lock_ReleaseWrite(&smb_rctLock);
1242 cm_ReleaseUser(userp);
1245 void smb_HoldUIDNoLock(smb_user_t *uidp)
1250 void smb_ReleaseUID(smb_user_t *uidp)
1254 smb_username_t *unp = NULL;
1256 lock_ObtainWrite(&smb_rctLock);
1257 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1258 if (uidp->refCount == 0) {
1259 lupp = &uidp->vcp->usersp;
1260 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1264 osi_assertx(up != NULL, "null smb_user_t");
1266 lock_FinalizeMutex(&uidp->mx);
1268 smb_ReleaseVCNoLock(uidp->vcp);
1272 lock_ReleaseWrite(&smb_rctLock);
1276 cm_ReleaseUserVCRef(unp->userp);
1277 smb_ReleaseUsername(unp);
1281 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1283 cm_user_t *up = NULL;
1288 lock_ObtainMutex(&uidp->mx);
1290 up = uidp->unp->userp;
1293 lock_ReleaseMutex(&uidp->mx);
1299 /* retrieve a held reference to a user structure corresponding to an incoming
1301 * corresponding release function is cm_ReleaseUser.
1303 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1306 cm_user_t *up = NULL;
1309 smbp = (smb_t *) inp;
1310 uidp = smb_FindUID(vcp, smbp->uid, 0);
1314 up = smb_GetUserFromUID(uidp);
1316 smb_ReleaseUID(uidp);
1321 * Return a pointer to a pathname extracted from a TID structure. The
1322 * TID structure is not held; assume it won't go away.
1324 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1329 tidp = smb_FindTID(vcp, tid, 0);
1333 if (tidp->flags & SMB_TIDFLAG_IPC) {
1334 code = CM_ERROR_TIDIPC;
1335 /* tidp->pathname would be NULL, but that's fine */
1337 *treepath = tidp->pathname;
1338 smb_ReleaseTID(tidp, FALSE);
1343 /* check to see if we have a chained fid, that is, a fid that comes from an
1344 * OpenAndX message that ran earlier in this packet. In this case, the fid
1345 * field in a read, for example, request, isn't set, since the value is
1346 * supposed to be inherited from the openAndX call.
1348 int smb_ChainFID(int fid, smb_packet_t *inp)
1350 if (inp->fid == 0 || inp->inCount == 0)
1356 /* are we a priv'd user? What does this mean on NT? */
1357 int smb_SUser(cm_user_t *userp)
1362 /* find a file ID. If we pass in 0 we select an unused File ID.
1363 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1364 * smb_fid_t data structure if desired File ID cannot be found.
1366 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1371 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1374 lock_ObtainWrite(&smb_rctLock);
1375 /* figure out if we need to allocate a new file ID */
1378 fid = vcp->fidCounter;
1382 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1383 if (fidp->refCount == 0 && fidp->delete) {
1385 lock_ReleaseWrite(&smb_rctLock);
1386 smb_ReleaseFID(fidp);
1387 lock_ObtainWrite(&smb_rctLock);
1390 if (fid == fidp->fid) {
1393 if (fid == 0xFFFF) {
1395 "New FID number wraps on vcp 0x%x", vcp);
1405 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1406 char eventName[MAX_PATH];
1408 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1409 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1410 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1411 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1412 thrd_CloseHandle(event);
1414 if (fid == 0xFFFF) {
1415 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1421 fidp = malloc(sizeof(*fidp));
1422 memset(fidp, 0, sizeof(*fidp));
1423 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1426 smb_HoldVCNoLock(vcp);
1427 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1429 fidp->curr_chunk = fidp->prev_chunk = -2;
1430 fidp->raw_write_event = event;
1432 vcp->fidCounter = fid+1;
1433 if (vcp->fidCounter == 0xFFFF) {
1434 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1436 vcp->fidCounter = 1;
1441 lock_ReleaseWrite(&smb_rctLock);
1445 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1447 smb_fid_t *fidp = NULL;
1453 lock_ObtainWrite(&smb_rctLock);
1454 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1455 if (scp == fidp->scp) {
1460 lock_ReleaseWrite(&smb_rctLock);
1464 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1470 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1471 /* the sm_fid_t->mx and smb_rctLock must not be held */
1472 void smb_ReleaseFID(smb_fid_t *fidp)
1474 cm_scache_t *scp = NULL;
1475 cm_user_t *userp = NULL;
1476 smb_vc_t *vcp = NULL;
1477 smb_ioctl_t *ioctlp;
1479 lock_ObtainMutex(&fidp->mx);
1480 lock_ObtainWrite(&smb_rctLock);
1481 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1482 if (fidp->refCount == 0 && (fidp->delete)) {
1485 scp = fidp->scp; /* release after lock is released */
1487 lock_ObtainMutex(&scp->mx);
1488 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1489 lock_ReleaseMutex(&scp->mx);
1490 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1493 userp = fidp->userp;
1497 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1498 thrd_CloseHandle(fidp->raw_write_event);
1500 /* and see if there is ioctl stuff to free */
1501 ioctlp = fidp->ioctlp;
1504 cm_FreeSpace(ioctlp->prefix);
1505 if (ioctlp->inAllocp)
1506 free(ioctlp->inAllocp);
1507 if (ioctlp->outAllocp)
1508 free(ioctlp->outAllocp);
1511 lock_ReleaseMutex(&fidp->mx);
1512 lock_FinalizeMutex(&fidp->mx);
1516 smb_ReleaseVCNoLock(vcp);
1518 lock_ReleaseMutex(&fidp->mx);
1520 lock_ReleaseWrite(&smb_rctLock);
1522 /* now release the scache structure */
1524 cm_ReleaseSCache(scp);
1527 cm_ReleaseUser(userp);
1531 * Case-insensitive search for one string in another;
1532 * used to find variable names in submount pathnames.
1534 static char *smb_stristr(char *str1, char *str2)
1538 for (cursor = str1; *cursor; cursor++)
1539 if (stricmp(cursor, str2) == 0)
1546 * Substitute a variable value for its name in a submount pathname. Variable
1547 * name has been identified by smb_stristr() and is in substr. Variable name
1548 * length (plus one) is in substr_size. Variable value is in newstr.
1550 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1555 strcpy(temp, substr + substr_size - 1);
1556 strcpy(substr, newstr);
1560 char VNUserName[] = "%USERNAME%";
1561 char VNLCUserName[] = "%LCUSERNAME%";
1562 char VNComputerName[] = "%COMPUTERNAME%";
1563 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1566 typedef struct smb_findShare_rock {
1570 } smb_findShare_rock_t;
1572 #define SMB_FINDSHARE_EXACT_MATCH 1
1573 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1575 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1579 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1580 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1581 if(!stricmp(dep->name, vrock->shareName))
1582 matchType = SMB_FINDSHARE_EXACT_MATCH;
1584 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1585 if(vrock->match) free(vrock->match);
1586 vrock->match = strdup(dep->name);
1587 vrock->matchType = matchType;
1589 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1590 return CM_ERROR_STOPNOW;
1596 /* find a shareName in the table of submounts */
1597 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1601 char pathName[1024];
1608 DWORD allSubmount = 1;
1610 /* if allSubmounts == 0, only return the //mountRoot/all share
1611 * if in fact it has been been created in the subMounts table.
1612 * This is to allow sites that want to restrict access to the
1615 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1616 0, KEY_QUERY_VALUE, &parmKey);
1617 if (code == ERROR_SUCCESS) {
1618 len = sizeof(allSubmount);
1619 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1620 (BYTE *) &allSubmount, &len);
1621 if (code != ERROR_SUCCESS) {
1624 RegCloseKey (parmKey);
1627 if (allSubmount && _stricmp(shareName, "all") == 0) {
1632 /* In case, the all share is disabled we need to still be able
1633 * to handle ioctl requests
1635 if (_stricmp(shareName, "ioctl$") == 0) {
1636 *pathNamep = strdup("/.__ioctl__");
1640 if (_stricmp(shareName, "IPC$") == 0 ||
1641 _stricmp(shareName, "srvsvc") == 0 ||
1642 _stricmp(shareName, "wkssvc") == 0 ||
1643 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1644 _stricmp(shareName, "DESKTOP.INI") == 0
1650 /* Check for volume references
1652 * They look like <cell>{%,#}<volume>
1654 if (strchr(shareName, '%') != NULL ||
1655 strchr(shareName, '#') != NULL) {
1656 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1657 /* make room for '/@vol:' + mountchar + NULL terminator*/
1659 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1660 osi_LogSaveString(smb_logp, shareName));
1662 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1663 "/" CM_PREFIX_VOL "%s", shareName);
1664 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1665 len = strlen(pathstr) + 1;
1667 *pathNamep = malloc(len);
1669 strcpy(*pathNamep, pathstr);
1671 osi_Log1(smb_logp, " returning pathname [%s]",
1672 osi_LogSaveString(smb_logp, *pathNamep));
1680 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1681 0, KEY_QUERY_VALUE, &parmKey);
1682 if (code == ERROR_SUCCESS) {
1683 len = sizeof(pathName);
1684 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1685 (BYTE *) pathName, &len);
1686 if (code != ERROR_SUCCESS)
1688 RegCloseKey (parmKey);
1692 if (len != 0 && len != sizeof(pathName) - 1) {
1693 /* We can accept either unix or PC style AFS pathnames. Convert
1694 * Unix-style to PC style here for internal use.
1697 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1698 p += strlen(cm_mountRoot); /* skip mount path */
1701 if (*q == '/') *q = '\\'; /* change to \ */
1707 if (var = smb_stristr(p, VNUserName)) {
1708 if (uidp && uidp->unp)
1709 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1711 smb_subst(p, var, sizeof(VNUserName)," ");
1713 else if (var = smb_stristr(p, VNLCUserName))
1715 if (uidp && uidp->unp)
1716 strcpy(temp, uidp->unp->name);
1720 smb_subst(p, var, sizeof(VNLCUserName), temp);
1722 else if (var = smb_stristr(p, VNComputerName))
1724 sizeTemp = sizeof(temp);
1725 GetComputerName((LPTSTR)temp, &sizeTemp);
1726 smb_subst(p, var, sizeof(VNComputerName), temp);
1728 else if (var = smb_stristr(p, VNLCComputerName))
1730 sizeTemp = sizeof(temp);
1731 GetComputerName((LPTSTR)temp, &sizeTemp);
1733 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1738 *pathNamep = strdup(p);
1743 /* First lookup shareName in root.afs */
1745 smb_findShare_rock_t vrock;
1747 char * p = shareName;
1750 /* attempt to locate a partial match in root.afs. This is because
1751 when using the ANSI RAP calls, the share name is limited to 13 chars
1752 and hence is truncated. Of course we prefer exact matches. */
1754 thyper.HighPart = 0;
1757 vrock.shareName = shareName;
1759 vrock.matchType = 0;
1761 cm_HoldSCache(cm_data.rootSCachep);
1762 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1763 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1764 cm_ReleaseSCache(cm_data.rootSCachep);
1766 if (vrock.matchType) {
1767 sprintf(pathName,"/%s/",vrock.match);
1768 *pathNamep = strdup(strlwr(pathName));
1773 /* if we get here, there was no match for the share in root.afs */
1774 /* so try to create \\<netbiosName>\<cellname> */
1779 /* Get the full name for this cell */
1780 code = cm_SearchCellFile(p, temp, 0, 0);
1781 #ifdef AFS_AFSDB_ENV
1782 if (code && cm_dnsEnabled) {
1784 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1787 /* construct the path */
1789 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1790 *pathNamep = strdup(strlwr(pathName));
1799 /* Client-side offline caching policy types */
1800 #define CSC_POLICY_MANUAL 0
1801 #define CSC_POLICY_DOCUMENTS 1
1802 #define CSC_POLICY_PROGRAMS 2
1803 #define CSC_POLICY_DISABLE 3
1805 int smb_FindShareCSCPolicy(char *shareName)
1811 int retval = CSC_POLICY_MANUAL;
1813 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1814 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1817 REG_OPTION_NON_VOLATILE,
1823 len = sizeof(policy);
1824 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1826 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1828 else if (stricmp(policy, "documents") == 0)
1830 retval = CSC_POLICY_DOCUMENTS;
1832 else if (stricmp(policy, "programs") == 0)
1834 retval = CSC_POLICY_PROGRAMS;
1836 else if (stricmp(policy, "disable") == 0)
1838 retval = CSC_POLICY_DISABLE;
1841 RegCloseKey(hkCSCPolicy);
1845 /* find a dir search structure by cookie value, and return it held.
1846 * Must be called with smb_globalLock held.
1848 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1850 smb_dirSearch_t *dsp;
1852 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1853 if (dsp->cookie == cookie) {
1854 if (dsp != smb_firstDirSearchp) {
1855 /* move to head of LRU queue, too, if we're not already there */
1856 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1857 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1858 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1859 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1860 if (!smb_lastDirSearchp)
1861 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1863 lock_ObtainMutex(&dsp->mx);
1865 lock_ReleaseMutex(&dsp->mx);
1871 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1872 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1873 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1879 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1881 lock_ObtainWrite(&smb_globalLock);
1882 lock_ObtainMutex(&dsp->mx);
1883 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1884 dsp->cookie, dsp, dsp->scp);
1885 dsp->flags |= SMB_DIRSEARCH_DELETE;
1886 if (dsp->scp != NULL) {
1887 lock_ObtainMutex(&dsp->scp->mx);
1888 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1889 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1890 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1891 dsp->scp->bulkStatProgress = hzero;
1893 lock_ReleaseMutex(&dsp->scp->mx);
1895 lock_ReleaseMutex(&dsp->mx);
1896 lock_ReleaseWrite(&smb_globalLock);
1899 /* Must be called with the smb_globalLock held */
1900 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1902 cm_scache_t *scp = NULL;
1904 lock_ObtainMutex(&dsp->mx);
1905 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1906 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1907 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1908 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1909 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1910 lock_ReleaseMutex(&dsp->mx);
1911 lock_FinalizeMutex(&dsp->mx);
1913 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1914 dsp->cookie, dsp, scp);
1917 lock_ReleaseMutex(&dsp->mx);
1919 /* do this now to avoid spurious locking hierarchy creation */
1921 cm_ReleaseSCache(scp);
1924 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1926 lock_ObtainWrite(&smb_globalLock);
1927 smb_ReleaseDirSearchNoLock(dsp);
1928 lock_ReleaseWrite(&smb_globalLock);
1931 /* find a dir search structure by cookie value, and return it held */
1932 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1934 smb_dirSearch_t *dsp;
1936 lock_ObtainWrite(&smb_globalLock);
1937 dsp = smb_FindDirSearchNoLock(cookie);
1938 lock_ReleaseWrite(&smb_globalLock);
1942 /* GC some dir search entries, in the address space expected by the specific protocol.
1943 * Must be called with smb_globalLock held; release the lock temporarily.
1945 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1946 void smb_GCDirSearches(int isV3)
1948 smb_dirSearch_t *prevp;
1949 smb_dirSearch_t *tp;
1950 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1954 victimCount = 0; /* how many have we got so far */
1955 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1956 /* we'll move tp from queue, so
1959 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1960 /* if no one is using this guy, and we're either in the new protocol,
1961 * or we're in the old one and this is a small enough ID to be useful
1962 * to the old protocol, GC this guy.
1964 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1965 /* hold and delete */
1966 lock_ObtainMutex(&tp->mx);
1967 tp->flags |= SMB_DIRSEARCH_DELETE;
1968 lock_ReleaseMutex(&tp->mx);
1969 victimsp[victimCount++] = tp;
1973 /* don't do more than this */
1974 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1978 /* now release them */
1979 for (i = 0; i < victimCount; i++) {
1980 smb_ReleaseDirSearchNoLock(victimsp[i]);
1984 /* function for allocating a dir search entry. We need these to remember enough context
1985 * since we don't get passed the path from call to call during a directory search.
1987 * Returns a held dir search structure, and bumps the reference count on the vnode,
1988 * since it saves a pointer to the vnode.
1990 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1992 smb_dirSearch_t *dsp;
1998 lock_ObtainWrite(&smb_globalLock);
2001 /* what's the biggest ID allowed in this version of the protocol */
2002 /* TODO: do we really want a non v3 dir search request to wrap
2003 smb_dirSearchCounter? */
2004 maxAllowed = isV3 ? 65535 : 255;
2005 if (smb_dirSearchCounter > maxAllowed)
2006 smb_dirSearchCounter = 1;
2008 start = smb_dirSearchCounter;
2011 /* twice so we have enough tries to find guys we GC after one pass;
2012 * 10 extra is just in case I mis-counted.
2014 if (++counter > 2*maxAllowed+10)
2015 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2017 if (smb_dirSearchCounter > maxAllowed) {
2018 smb_dirSearchCounter = 1;
2020 if (smb_dirSearchCounter == start) {
2022 smb_GCDirSearches(isV3);
2025 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2027 /* don't need to watch for refcount zero and deleted, since
2028 * we haven't dropped the global lock.
2030 lock_ObtainMutex(&dsp->mx);
2032 lock_ReleaseMutex(&dsp->mx);
2033 ++smb_dirSearchCounter;
2037 dsp = malloc(sizeof(*dsp));
2038 memset(dsp, 0, sizeof(*dsp));
2039 dsp->cookie = smb_dirSearchCounter;
2040 ++smb_dirSearchCounter;
2042 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2043 dsp->lastTime = osi_Time();
2044 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2045 if (!smb_lastDirSearchp)
2046 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2048 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2052 lock_ReleaseWrite(&smb_globalLock);
2056 static smb_packet_t *GetPacket(void)
2060 lock_ObtainWrite(&smb_globalLock);
2061 tbp = smb_packetFreeListp;
2063 smb_packetFreeListp = tbp->nextp;
2064 lock_ReleaseWrite(&smb_globalLock);
2066 tbp = calloc(65540,1);
2067 tbp->magic = SMB_PACKETMAGIC;
2070 tbp->resumeCode = 0;
2076 tbp->ncb_length = 0;
2081 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2086 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2090 memcpy(tbp, pkt, sizeof(smb_packet_t));
2091 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2093 smb_HoldVC(tbp->vcp);
2097 static NCB *GetNCB(void)
2102 lock_ObtainWrite(&smb_globalLock);
2103 tbp = smb_ncbFreeListp;
2105 smb_ncbFreeListp = tbp->nextp;
2106 lock_ReleaseWrite(&smb_globalLock);
2108 tbp = calloc(sizeof(*tbp),1);
2109 tbp->magic = SMB_NCBMAGIC;
2112 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2114 memset(&tbp->ncb, 0, sizeof(NCB));
2119 void smb_FreePacket(smb_packet_t *tbp)
2121 smb_vc_t * vcp = NULL;
2122 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2124 lock_ObtainWrite(&smb_globalLock);
2125 tbp->nextp = smb_packetFreeListp;
2126 smb_packetFreeListp = tbp;
2127 tbp->magic = SMB_PACKETMAGIC;
2131 tbp->resumeCode = 0;
2137 tbp->ncb_length = 0;
2139 lock_ReleaseWrite(&smb_globalLock);
2145 static void FreeNCB(NCB *bufferp)
2149 tbp = (smb_ncb_t *) bufferp;
2150 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2152 lock_ObtainWrite(&smb_globalLock);
2153 tbp->nextp = smb_ncbFreeListp;
2154 smb_ncbFreeListp = tbp;
2155 lock_ReleaseWrite(&smb_globalLock);
2158 /* get a ptr to the data part of a packet, and its count */
2159 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2163 unsigned char *afterParmsp;
2165 parmBytes = *smbp->wctp << 1;
2166 afterParmsp = smbp->wctp + parmBytes + 1;
2168 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2169 if (nbytesp) *nbytesp = dataBytes;
2171 /* don't forget to skip the data byte count, since it follows
2172 * the parameters; that's where the "2" comes from below.
2174 return (unsigned char *) (afterParmsp + 2);
2177 /* must set all the returned parameters before playing around with the
2178 * data region, since the data region is located past the end of the
2179 * variable number of parameters.
2181 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2183 unsigned char *afterParmsp;
2185 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2187 *afterParmsp++ = dsize & 0xff;
2188 *afterParmsp = (dsize>>8) & 0xff;
2191 /* return the parm'th parameter in the smbp packet */
2192 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2195 unsigned char *parmDatap;
2197 parmCount = *smbp->wctp;
2199 if (parm >= parmCount) {
2202 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2203 parm, parmCount, smbp->ncb_length);
2204 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2205 parm, parmCount, smbp->ncb_length);
2206 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2207 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2208 osi_panic(s, __FILE__, __LINE__);
2210 parmDatap = smbp->wctp + (2*parm) + 1;
2212 return parmDatap[0] + (parmDatap[1] << 8);
2215 /* return the parm'th parameter in the smbp packet */
2216 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2219 unsigned char *parmDatap;
2221 parmCount = *smbp->wctp;
2223 if (parm >= parmCount) {
2226 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2227 parm, parmCount, smbp->ncb_length);
2228 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2229 parm, parmCount, smbp->ncb_length);
2230 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2231 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2232 osi_panic(s, __FILE__, __LINE__);
2234 parmDatap = smbp->wctp + (2*parm) + 1;
2236 return parmDatap[0];
2239 /* return the parm'th parameter in the smbp packet */
2240 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2243 unsigned char *parmDatap;
2245 parmCount = *smbp->wctp;
2247 if (parm + 1 >= parmCount) {
2250 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2251 parm, parmCount, smbp->ncb_length);
2252 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2253 parm, parmCount, smbp->ncb_length);
2254 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2255 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2256 osi_panic(s, __FILE__, __LINE__);
2258 parmDatap = smbp->wctp + (2*parm) + 1;
2260 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2263 /* return the parm'th parameter in the smbp packet */
2264 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2267 unsigned char *parmDatap;
2269 parmCount = *smbp->wctp;
2271 if (parm * 2 + offset >= parmCount * 2) {
2274 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2275 parm, offset, parmCount, smbp->ncb_length);
2276 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2277 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2278 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2279 parm, offset, parmCount, smbp->ncb_length);
2280 osi_panic(s, __FILE__, __LINE__);
2282 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2284 return parmDatap[0] + (parmDatap[1] << 8);
2287 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2291 /* make sure we have enough slots */
2292 if (*smbp->wctp <= slot)
2293 *smbp->wctp = slot+1;
2295 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2296 *parmDatap++ = parmValue & 0xff;
2297 *parmDatap = (parmValue>>8) & 0xff;
2300 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2304 /* make sure we have enough slots */
2305 if (*smbp->wctp <= slot)
2306 *smbp->wctp = slot+2;
2308 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2309 *parmDatap++ = parmValue & 0xff;
2310 *parmDatap++ = (parmValue>>8) & 0xff;
2311 *parmDatap++ = (parmValue>>16) & 0xff;
2312 *parmDatap = (parmValue>>24) & 0xff;
2315 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2320 /* make sure we have enough slots */
2321 if (*smbp->wctp <= slot)
2322 *smbp->wctp = slot+4;
2324 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2326 *parmDatap++ = *parmValuep++;
2329 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2333 /* make sure we have enough slots */
2334 if (*smbp->wctp <= slot) {
2335 if (smbp->oddByte) {
2337 *smbp->wctp = slot+1;
2342 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2343 *parmDatap++ = parmValue & 0xff;
2346 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2350 lastSlashp = strrchr(inPathp, '\\');
2352 *lastComponentp = lastSlashp;
2355 if (inPathp == lastSlashp)
2357 *outPathp++ = *inPathp++;
2366 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2371 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2376 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2382 tlen = inp[0] + (inp[1]<<8);
2383 inp += 2; /* skip length field */
2386 *chainpp = inp + tlen;
2395 /* format a packet as a response */
2396 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2401 outp = (smb_t *) op;
2403 /* zero the basic structure through the smb_wct field, and zero the data
2404 * size field, assuming that wct stays zero; otherwise, you have to
2405 * explicitly set the data size field, too.
2407 inSmbp = (smb_t *) inp;
2408 memset(outp, 0, sizeof(smb_t)+2);
2414 outp->com = inSmbp->com;
2415 outp->tid = inSmbp->tid;
2416 outp->pid = inSmbp->pid;
2417 outp->uid = inSmbp->uid;
2418 outp->mid = inSmbp->mid;
2419 outp->res[0] = inSmbp->res[0];
2420 outp->res[1] = inSmbp->res[1];
2421 op->inCom = inSmbp->com;
2423 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2424 #ifdef SEND_CANONICAL_PATHNAMES
2425 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2427 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2429 /* copy fields in generic packet area */
2430 op->wctp = &outp->wct;
2433 /* send a (probably response) packet; vcp tells us to whom to send it.
2434 * we compute the length by looking at wct and bcc fields.
2436 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2450 memset((char *)ncbp, 0, sizeof(NCB));
2452 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2453 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2454 extra += tp[0] + (tp[1]<<8);
2455 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2456 extra += 3; /* wct and length fields */
2458 ncbp->ncb_length = extra; /* bytes to send */
2459 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2460 ncbp->ncb_lana_num = vcp->lana;
2461 ncbp->ncb_command = NCBSEND; /* op means send data */
2462 ncbp->ncb_buffer = (char *) inp;/* packet */
2463 code = Netbios(ncbp);
2466 const char * s = ncb_error_string(code);
2467 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2468 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2470 lock_ObtainMutex(&vcp->mx);
2471 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2472 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2474 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2475 lock_ReleaseMutex(&vcp->mx);
2476 lock_ObtainWrite(&smb_globalLock);
2477 dead_sessions[vcp->session] = TRUE;
2478 lock_ReleaseWrite(&smb_globalLock);
2479 smb_CleanupDeadVC(vcp);
2481 lock_ReleaseMutex(&vcp->mx);
2489 void smb_MapNTError(long code, unsigned long *NTStatusp)
2491 unsigned long NTStatus;
2493 /* map CM_ERROR_* errors to NT 32-bit status codes */
2494 /* NT Status codes are listed in ntstatus.h not winerror.h */
2495 if (code == CM_ERROR_NOSUCHCELL) {
2496 NTStatus = 0xC000000FL; /* No such file */
2498 else if (code == CM_ERROR_NOSUCHVOLUME) {
2499 NTStatus = 0xC000000FL; /* No such file */
2501 else if (code == CM_ERROR_TIMEDOUT) {
2503 NTStatus = 0xC00000CFL; /* Sharing Paused */
2505 NTStatus = 0x00000102L; /* Timeout */
2508 else if (code == CM_ERROR_RETRY) {
2509 NTStatus = 0xC000022DL; /* Retry */
2511 else if (code == CM_ERROR_NOACCESS) {
2512 NTStatus = 0xC0000022L; /* Access denied */
2514 else if (code == CM_ERROR_READONLY) {
2515 NTStatus = 0xC00000A2L; /* Write protected */
2517 else if (code == CM_ERROR_NOSUCHFILE ||
2518 code == CM_ERROR_BPLUS_NOMATCH) {
2519 NTStatus = 0xC000000FL; /* No such file */
2521 else if (code == CM_ERROR_NOSUCHPATH) {
2522 NTStatus = 0xC000003AL; /* Object path not found */
2524 else if (code == CM_ERROR_TOOBIG) {
2525 NTStatus = 0xC000007BL; /* Invalid image format */
2527 else if (code == CM_ERROR_INVAL) {
2528 NTStatus = 0xC000000DL; /* Invalid parameter */
2530 else if (code == CM_ERROR_BADFD) {
2531 NTStatus = 0xC0000008L; /* Invalid handle */
2533 else if (code == CM_ERROR_BADFDOP) {
2534 NTStatus = 0xC0000022L; /* Access denied */
2536 else if (code == CM_ERROR_EXISTS) {
2537 NTStatus = 0xC0000035L; /* Object name collision */
2539 else if (code == CM_ERROR_NOTEMPTY) {
2540 NTStatus = 0xC0000101L; /* Directory not empty */
2542 else if (code == CM_ERROR_CROSSDEVLINK) {
2543 NTStatus = 0xC00000D4L; /* Not same device */
2545 else if (code == CM_ERROR_NOTDIR) {
2546 NTStatus = 0xC0000103L; /* Not a directory */
2548 else if (code == CM_ERROR_ISDIR) {
2549 NTStatus = 0xC00000BAL; /* File is a directory */
2551 else if (code == CM_ERROR_BADOP) {
2553 /* I have no idea where this comes from */
2554 NTStatus = 0xC09820FFL; /* SMB no support */
2556 NTStatus = 0xC00000BBL; /* Not supported */
2557 #endif /* COMMENT */
2559 else if (code == CM_ERROR_BADSHARENAME) {
2560 NTStatus = 0xC00000CCL; /* Bad network name */
2562 else if (code == CM_ERROR_NOIPC) {
2564 NTStatus = 0xC0000022L; /* Access Denied */
2566 NTStatus = 0xC000013DL; /* Remote Resources */
2569 else if (code == CM_ERROR_CLOCKSKEW) {
2570 NTStatus = 0xC0000133L; /* Time difference at DC */
2572 else if (code == CM_ERROR_BADTID) {
2573 NTStatus = 0xC0982005L; /* SMB bad TID */
2575 else if (code == CM_ERROR_USESTD) {
2576 NTStatus = 0xC09820FBL; /* SMB use standard */
2578 else if (code == CM_ERROR_QUOTA) {
2579 NTStatus = 0xC0000044L; /* Quota exceeded */
2581 else if (code == CM_ERROR_SPACE) {
2582 NTStatus = 0xC000007FL; /* Disk full */
2584 else if (code == CM_ERROR_ATSYS) {
2585 NTStatus = 0xC0000033L; /* Object name invalid */
2587 else if (code == CM_ERROR_BADNTFILENAME) {
2588 NTStatus = 0xC0000033L; /* Object name invalid */
2590 else if (code == CM_ERROR_WOULDBLOCK) {
2591 NTStatus = 0xC0000055L; /* Lock not granted */
2593 else if (code == CM_ERROR_SHARING_VIOLATION) {
2594 NTStatus = 0xC0000043L; /* Sharing violation */
2596 else if (code == CM_ERROR_LOCK_CONFLICT) {
2597 NTStatus = 0xC0000054L; /* Lock conflict */
2599 else if (code == CM_ERROR_PARTIALWRITE) {
2600 NTStatus = 0xC000007FL; /* Disk full */
2602 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2603 NTStatus = 0xC0000023L; /* Buffer too small */
2605 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2606 NTStatus = 0xC0000035L; /* Object name collision */
2608 else if (code == CM_ERROR_BADPASSWORD) {
2609 NTStatus = 0xC000006DL; /* unknown username or bad password */
2611 else if (code == CM_ERROR_BADLOGONTYPE) {
2612 NTStatus = 0xC000015BL; /* logon type not granted */
2614 else if (code == CM_ERROR_GSSCONTINUE) {
2615 NTStatus = 0xC0000016L; /* more processing required */
2617 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2619 NTStatus = 0xC0000280L; /* reparse point not resolved */
2621 NTStatus = 0xC0000022L; /* Access Denied */
2624 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2625 NTStatus = 0xC0000257L; /* Path Not Covered */
2627 else if (code == CM_ERROR_ALLBUSY) {
2628 NTStatus = 0xC000022DL; /* Retry */
2630 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2631 NTStatus = 0xC00000BEL; /* Bad Network Path */
2633 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
2634 NTStatus = 0xC0000322L; /* No Kerberos key */
2636 else if (code == CM_ERROR_BAD_LEVEL) {
2637 NTStatus = 0xC0000148L; /* Invalid Level */
2639 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
2640 NTStatus = 0xC000007EL; /* Range Not Locked */
2643 NTStatus = 0xC0982001L; /* SMB non-specific error */
2646 *NTStatusp = NTStatus;
2647 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2650 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2651 unsigned char *classp)
2653 unsigned char class;
2654 unsigned short error;
2656 /* map CM_ERROR_* errors to SMB errors */
2657 if (code == CM_ERROR_NOSUCHCELL) {
2659 error = 3; /* bad path */
2661 else if (code == CM_ERROR_NOSUCHVOLUME) {
2663 error = 3; /* bad path */
2665 else if (code == CM_ERROR_TIMEDOUT) {
2667 error = 81; /* server is paused */
2669 else if (code == CM_ERROR_RETRY) {
2670 class = 2; /* shouldn't happen */
2673 else if (code == CM_ERROR_NOACCESS) {
2675 error = 4; /* bad access */
2677 else if (code == CM_ERROR_READONLY) {
2679 error = 19; /* read only */
2681 else if (code == CM_ERROR_NOSUCHFILE ||
2682 code == CM_ERROR_BPLUS_NOMATCH) {
2684 error = 2; /* ENOENT! */
2686 else if (code == CM_ERROR_NOSUCHPATH) {
2688 error = 3; /* Bad path */
2690 else if (code == CM_ERROR_TOOBIG) {
2692 error = 11; /* bad format */
2694 else if (code == CM_ERROR_INVAL) {
2695 class = 2; /* server non-specific error code */
2698 else if (code == CM_ERROR_BADFD) {
2700 error = 6; /* invalid file handle */
2702 else if (code == CM_ERROR_BADFDOP) {
2703 class = 1; /* invalid op on FD */
2706 else if (code == CM_ERROR_EXISTS) {
2708 error = 80; /* file already exists */
2710 else if (code == CM_ERROR_NOTEMPTY) {
2712 error = 5; /* delete directory not empty */
2714 else if (code == CM_ERROR_CROSSDEVLINK) {
2716 error = 17; /* EXDEV */
2718 else if (code == CM_ERROR_NOTDIR) {
2719 class = 1; /* bad path */
2722 else if (code == CM_ERROR_ISDIR) {
2723 class = 1; /* access denied; DOS doesn't have a good match */
2726 else if (code == CM_ERROR_BADOP) {
2730 else if (code == CM_ERROR_BADSHARENAME) {
2734 else if (code == CM_ERROR_NOIPC) {
2736 error = 4; /* bad access */
2738 else if (code == CM_ERROR_CLOCKSKEW) {
2739 class = 1; /* invalid function */
2742 else if (code == CM_ERROR_BADTID) {
2746 else if (code == CM_ERROR_USESTD) {
2750 else if (code == CM_ERROR_REMOTECONN) {
2754 else if (code == CM_ERROR_QUOTA) {
2755 if (vcp->flags & SMB_VCFLAG_USEV3) {
2757 error = 39; /* disk full */
2761 error = 5; /* access denied */
2764 else if (code == CM_ERROR_SPACE) {
2765 if (vcp->flags & SMB_VCFLAG_USEV3) {
2767 error = 39; /* disk full */
2771 error = 5; /* access denied */
2774 else if (code == CM_ERROR_PARTIALWRITE) {
2776 error = 39; /* disk full */
2778 else if (code == CM_ERROR_ATSYS) {
2780 error = 2; /* ENOENT */
2782 else if (code == CM_ERROR_WOULDBLOCK) {
2784 error = 33; /* lock conflict */
2786 else if (code == CM_ERROR_LOCK_CONFLICT) {
2788 error = 33; /* lock conflict */
2790 else if (code == CM_ERROR_SHARING_VIOLATION) {
2792 error = 33; /* lock conflict */
2794 else if (code == CM_ERROR_NOFILES) {
2796 error = 18; /* no files in search */
2798 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2800 error = 183; /* Samba uses this */
2802 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2803 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2805 error = 2; /* bad password */
2807 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2809 error = 3; /* bad path */
2818 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2821 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2823 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2824 return CM_ERROR_BADOP;
2827 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2829 unsigned short EchoCount, i;
2830 char *data, *outdata;
2833 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2835 for (i=1; i<=EchoCount; i++) {
2836 data = smb_GetSMBData(inp, &dataSize);
2837 smb_SetSMBParm(outp, 0, i);
2838 smb_SetSMBDataLength(outp, dataSize);
2839 outdata = smb_GetSMBData(outp, NULL);
2840 memcpy(outdata, data, dataSize);
2841 smb_SendPacket(vcp, outp);
2847 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2850 long count, minCount, finalCount;
2855 cm_user_t *userp = NULL;
2858 char *rawBuf = NULL;
2863 fd = smb_GetSMBParm(inp, 0);
2864 count = smb_GetSMBParm(inp, 3);
2865 minCount = smb_GetSMBParm(inp, 4);
2866 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2868 if (*inp->wctp == 10) {
2869 /* we were sent a request with 64-bit file offsets */
2870 #ifdef AFS_LARGEFILES
2871 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2873 if (LargeIntegerLessThanZero(offset)) {
2874 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2878 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2879 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2882 offset.HighPart = 0;
2886 /* we were sent a request with 32-bit file offsets */
2887 offset.HighPart = 0;
2890 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2891 fd, offset.HighPart, offset.LowPart, count);
2893 fidp = smb_FindFID(vcp, fd, 0);
2897 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2898 smb_CloseFID(vcp, fidp, NULL, 0);
2899 code = CM_ERROR_NOSUCHFILE;
2904 pid = ((smb_t *) inp)->pid;
2906 LARGE_INTEGER LOffset, LLength;
2909 key = cm_GenerateKey(vcp->vcID, pid, fd);
2911 LOffset.HighPart = offset.HighPart;
2912 LOffset.LowPart = offset.LowPart;
2913 LLength.HighPart = 0;
2914 LLength.LowPart = count;
2916 lock_ObtainMutex(&fidp->scp->mx);
2917 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2918 lock_ReleaseMutex(&fidp->scp->mx);
2924 lock_ObtainMutex(&smb_RawBufLock);
2926 /* Get a raw buf, from head of list */
2927 rawBuf = smb_RawBufs;
2928 smb_RawBufs = *(char **)smb_RawBufs;
2930 lock_ReleaseMutex(&smb_RawBufLock);
2934 lock_ObtainMutex(&fidp->mx);
2935 if (fidp->flags & SMB_FID_IOCTL)
2937 lock_ReleaseMutex(&fidp->mx);
2938 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2940 /* Give back raw buffer */
2941 lock_ObtainMutex(&smb_RawBufLock);
2942 *((char **) rawBuf) = smb_RawBufs;
2944 smb_RawBufs = rawBuf;
2945 lock_ReleaseMutex(&smb_RawBufLock);
2948 lock_ReleaseMutex(&fidp->mx);
2949 smb_ReleaseFID(fidp);
2952 lock_ReleaseMutex(&fidp->mx);
2954 userp = smb_GetUserFromVCP(vcp, inp);
2956 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2962 cm_ReleaseUser(userp);
2965 smb_ReleaseFID(fidp);
2969 memset((char *)ncbp, 0, sizeof(NCB));
2971 ncbp->ncb_length = (unsigned short) finalCount;
2972 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2973 ncbp->ncb_lana_num = vcp->lana;
2974 ncbp->ncb_command = NCBSEND;
2975 ncbp->ncb_buffer = rawBuf;
2977 code = Netbios(ncbp);
2979 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2982 /* Give back raw buffer */
2983 lock_ObtainMutex(&smb_RawBufLock);
2984 *((char **) rawBuf) = smb_RawBufs;
2986 smb_RawBufs = rawBuf;
2987 lock_ReleaseMutex(&smb_RawBufLock);
2993 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2995 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3000 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3002 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3007 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3014 int VistaProtoIndex;
3015 int protoIndex; /* index we're using */
3020 char protocol_array[10][1024]; /* protocol signature of the client */
3021 int caps; /* capabilities */
3024 TIME_ZONE_INFORMATION tzi;
3026 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3029 namep = smb_GetSMBData(inp, &dbytes);
3032 coreProtoIndex = -1; /* not found */
3035 VistaProtoIndex = -1;
3036 while(namex < dbytes) {
3037 osi_Log1(smb_logp, "Protocol %s",
3038 osi_LogSaveString(smb_logp, namep+1));
3039 strcpy(protocol_array[tcounter], namep+1);
3041 /* namep points at the first protocol, or really, a 0x02
3042 * byte preceding the null-terminated ASCII name.
3044 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3045 coreProtoIndex = tcounter;
3047 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3048 v3ProtoIndex = tcounter;
3050 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3051 NTProtoIndex = tcounter;
3053 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3054 VistaProtoIndex = tcounter;
3057 /* compute size of protocol entry */
3058 entryLength = (int)strlen(namep+1);
3059 entryLength += 2; /* 0x02 bytes and null termination */
3061 /* advance over this protocol entry */
3062 namex += entryLength;
3063 namep += entryLength;
3064 tcounter++; /* which proto entry we're looking at */
3067 lock_ObtainMutex(&vcp->mx);
3069 if (VistaProtoIndex != -1) {
3070 protoIndex = VistaProtoIndex;
3071 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3074 if (NTProtoIndex != -1) {
3075 protoIndex = NTProtoIndex;
3076 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3078 else if (v3ProtoIndex != -1) {
3079 protoIndex = v3ProtoIndex;
3080 vcp->flags |= SMB_VCFLAG_USEV3;
3082 else if (coreProtoIndex != -1) {
3083 protoIndex = coreProtoIndex;
3084 vcp->flags |= SMB_VCFLAG_USECORE;
3086 else protoIndex = -1;
3087 lock_ReleaseMutex(&vcp->mx);
3089 if (protoIndex == -1)
3090 return CM_ERROR_INVAL;
3091 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3092 smb_SetSMBParm(outp, 0, protoIndex);
3093 if (smb_authType != SMB_AUTH_NONE) {
3094 smb_SetSMBParmByte(outp, 1,
3095 NEGOTIATE_SECURITY_USER_LEVEL |
3096 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3098 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3100 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3101 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3102 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3103 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3104 /* The session key is not a well documented field however most clients
3105 * will echo back the session key to the server. Currently we are using
3106 * the same value for all sessions. We should generate a random value
3107 * and store it into the vcp
3109 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3110 smb_SetSMBParm(outp, 8, 1);
3112 * Tried changing the capabilities to support for W2K - defect 117695
3113 * Maybe something else needs to be changed here?
3117 smb_SetSMBParmLong(outp, 9, 0x43fd);
3119 smb_SetSMBParmLong(outp, 9, 0x251);
3122 * 32-bit error codes *
3127 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3129 NTNEGOTIATE_CAPABILITY_DFS |
3131 #ifdef AFS_LARGEFILES
3132 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3134 NTNEGOTIATE_CAPABILITY_NTFIND |
3135 NTNEGOTIATE_CAPABILITY_RAWMODE |
3136 NTNEGOTIATE_CAPABILITY_NTSMB;
3138 if ( smb_authType == SMB_AUTH_EXTENDED )
3139 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3141 smb_SetSMBParmLong(outp, 9, caps);
3143 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3144 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3145 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3147 GetTimeZoneInformation(&tzi);
3148 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3150 if (smb_authType == SMB_AUTH_NTLM) {
3151 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3152 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3153 /* paste in encryption key */
3154 datap = smb_GetSMBData(outp, NULL);
3155 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3156 /* and the faux domain name */
3157 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3158 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3162 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3164 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3166 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3168 datap = smb_GetSMBData(outp, NULL);
3169 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3172 datap += sizeof(smb_ServerGUID);
3173 memcpy(datap, secBlob, secBlobLength);
3177 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3178 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3181 else if (v3ProtoIndex != -1) {
3182 smb_SetSMBParm(outp, 0, protoIndex);
3184 /* NOTE: Extended authentication cannot be negotiated with v3
3185 * therefore we fail over to NTLM
3187 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3188 smb_SetSMBParm(outp, 1,
3189 NEGOTIATE_SECURITY_USER_LEVEL |
3190 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3192 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3194 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3195 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3196 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3197 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3198 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3199 smb_SetSMBParm(outp, 7, 1);
3201 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3202 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3203 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3205 GetTimeZoneInformation(&tzi);
3206 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3208 /* NOTE: Extended authentication cannot be negotiated with v3
3209 * therefore we fail over to NTLM
3211 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3212 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3213 smb_SetSMBParm(outp, 12, 0); /* resvd */
3214 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3215 datap = smb_GetSMBData(outp, NULL);
3216 /* paste in a new encryption key */
3217 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3218 /* and the faux domain name */
3219 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3221 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3222 smb_SetSMBParm(outp, 12, 0); /* resvd */
3223 smb_SetSMBDataLength(outp, 0);
3226 else if (coreProtoIndex != -1) { /* not really supported anymore */
3227 smb_SetSMBParm(outp, 0, protoIndex);
3228 smb_SetSMBDataLength(outp, 0);
3233 void smb_CheckVCs(void)
3235 smb_vc_t * vcp, *nextp;
3236 smb_packet_t * outp = GetPacket();
3239 lock_ObtainWrite(&smb_rctLock);
3240 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3242 if (vcp->magic != SMB_VC_MAGIC)
3243 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3244 __FILE__, __LINE__);
3248 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3251 smb_HoldVCNoLock(vcp);
3253 smb_HoldVCNoLock(nextp);
3254 smb_FormatResponsePacket(vcp, NULL, outp);
3255 smbp = (smb_t *)outp;
3256 outp->inCom = smbp->com = 0x2b /* Echo */;
3264 smb_SetSMBParm(outp, 0, 0);
3265 smb_SetSMBDataLength(outp, 0);
3266 lock_ReleaseWrite(&smb_rctLock);
3268 smb_SendPacket(vcp, outp);
3270 lock_ObtainWrite(&smb_rctLock);
3271 smb_ReleaseVCNoLock(vcp);
3273 smb_ReleaseVCNoLock(nextp);
3275 lock_ReleaseWrite(&smb_rctLock);
3276 smb_FreePacket(outp);
3279 void smb_Daemon(void *parmp)
3281 afs_uint32 count = 0;
3282 smb_username_t **unpp;
3285 while(smbShutdownFlag == 0) {
3289 if (smbShutdownFlag == 1)
3292 if ((count % 72) == 0) { /* every five minutes */
3294 time_t old_localZero = smb_localZero;
3296 /* Initialize smb_localZero */
3297 myTime.tm_isdst = -1; /* compute whether on DST or not */
3298 myTime.tm_year = 70;
3304 smb_localZero = mktime(&myTime);
3306 #ifndef USE_NUMERIC_TIME_CONV
3307 smb_CalculateNowTZ();
3308 #endif /* USE_NUMERIC_TIME_CONV */
3309 #ifdef AFS_FREELANCE
3310 if ( smb_localZero != old_localZero )
3311 cm_noteLocalMountPointChange();
3317 /* GC smb_username_t objects that will no longer be used */
3319 lock_ObtainWrite(&smb_rctLock);
3320 for ( unpp=&usernamesp; *unpp; ) {
3322 smb_username_t *unp;
3324 lock_ObtainMutex(&(*unpp)->mx);
3325 if ( (*unpp)->refCount > 0 ||
3326 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3327 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3329 else if (!smb_LogoffTokenTransfer ||
3330 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3332 lock_ReleaseMutex(&(*unpp)->mx);
3340 lock_FinalizeMutex(&unp->mx);
3346 cm_ReleaseUser(userp);
3348 unpp = &(*unpp)->nextp;
3351 lock_ReleaseWrite(&smb_rctLock);
3353 /* XXX GC dir search entries */
3357 void smb_WaitingLocksDaemon()
3359 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3360 smb_waitingLock_t *wl, *wlNext;
3363 smb_packet_t *inp, *outp;
3367 while (smbShutdownFlag == 0) {
3368 lock_ObtainWrite(&smb_globalLock);
3369 nwlRequest = smb_allWaitingLocks;
3370 if (nwlRequest == NULL) {
3371 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3376 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3383 lock_ObtainWrite(&smb_globalLock);
3385 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3387 wlRequest = nwlRequest;
3388 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3389 lock_ReleaseWrite(&smb_globalLock);
3393 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3394 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3397 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3399 /* wl->state is either _DONE or _WAITING. _ERROR
3400 would no longer be on the queue. */
3401 code = cm_RetryLock( wl->lockp,
3402 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3405 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3406 } else if (code != CM_ERROR_WOULDBLOCK) {
3407 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3412 if (code == CM_ERROR_WOULDBLOCK) {
3415 if (wlRequest->timeRemaining != 0xffffffff
3416 && (wlRequest->timeRemaining -= 1000) < 0)
3428 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3431 scp = wlRequest->scp;
3432 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3436 lock_ObtainMutex(&scp->mx);
3438 for (wl = wlRequest->locks; wl; wl = wlNext) {
3439 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3441 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3442 wl->LLength, wl->key, NULL, &req);
3444 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3449 lock_ReleaseMutex(&scp->mx);
3453 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3456 for (wl = wlRequest->locks; wl; wl = wlNext) {
3457 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3458 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3463 vcp = wlRequest->vcp;
3464 inp = wlRequest->inp;
3465 outp = wlRequest->outp;
3467 ncbp->ncb_length = inp->ncb_length;
3468 inp->spacep = cm_GetSpace();
3470 /* Remove waitingLock from list */
3471 lock_ObtainWrite(&smb_globalLock);
3472 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3474 lock_ReleaseWrite(&smb_globalLock);
3476 /* Resume packet processing */
3478 smb_SetSMBDataLength(outp, 0);
3479 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3480 outp->resumeCode = code;
3482 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3485 cm_FreeSpace(inp->spacep);
3486 smb_FreePacket(inp);
3487 smb_FreePacket(outp);
3489 cm_ReleaseSCache(wlRequest->scp);
3492 } while (nwlRequest && smbShutdownFlag == 0);
3497 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3499 osi_Log0(smb_logp, "SMB receive get disk attributes");
3501 smb_SetSMBParm(outp, 0, 32000);
3502 smb_SetSMBParm(outp, 1, 64);
3503 smb_SetSMBParm(outp, 2, 1024);
3504 smb_SetSMBParm(outp, 3, 30000);
3505 smb_SetSMBParm(outp, 4, 0);
3506 smb_SetSMBDataLength(outp, 0);
3510 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3514 unsigned short newTid;
3515 char shareName[AFSPATHMAX];
3523 osi_Log0(smb_logp, "SMB receive tree connect");
3525 /* parse input parameters */
3526 tp = smb_GetSMBData(inp, NULL);
3527 pathp = smb_ParseASCIIBlock(tp, &tp);
3528 if (smb_StoreAnsiFilenames)
3529 OemToChar(pathp,pathp);
3530 passwordp = smb_ParseASCIIBlock(tp, &tp);
3531 tp = strrchr(pathp, '\\');
3533 return CM_ERROR_BADSMB;
3534 strcpy(shareName, tp+1);
3536 lock_ObtainMutex(&vcp->mx);
3537 newTid = vcp->tidCounter++;
3538 lock_ReleaseMutex(&vcp->mx);
3540 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3541 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3542 userp = smb_GetUserFromUID(uidp);
3543 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3545 smb_ReleaseUID(uidp);
3547 smb_ReleaseTID(tidp, FALSE);
3548 return CM_ERROR_BADSHARENAME;
3550 lock_ObtainMutex(&tidp->mx);
3551 tidp->userp = userp;
3552 tidp->pathname = sharePath;
3553 lock_ReleaseMutex(&tidp->mx);
3554 smb_ReleaseTID(tidp, FALSE);
3556 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3557 smb_SetSMBParm(rsp, 1, newTid);
3558 smb_SetSMBDataLength(rsp, 0);
3560 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3564 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3568 if (*inp++ != 0x1) return NULL;
3569 tlen = inp[0] + (inp[1]<<8);
3570 inp += 2; /* skip length field */
3573 *chainpp = inp + tlen;
3576 if (lengthp) *lengthp = tlen;
3581 /* set maskp to the mask part of the incoming path.
3582 * Mask is 11 bytes long (8.3 with the dot elided).
3583 * Returns true if succeeds with a valid name, otherwise it does
3584 * its best, but returns false.
3586 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3594 /* starts off valid */
3597 /* mask starts out all blanks */
3598 memset(maskp, ' ', 11);
3601 /* find last backslash, or use whole thing if there is none */
3602 tp = strrchr(pathp, '\\');
3606 tp++; /* skip slash */
3610 /* names starting with a dot are illegal */
3618 if (tc == '.' || tc == '"')
3626 /* if we get here, tp point after the dot */
3627 up = maskp+8; /* ext goes here */
3634 if (tc == '.' || tc == '"')
3637 /* copy extension if not too long */
3647 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3657 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3659 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3663 /* otherwise, we have a valid 8.3 name; see if we have a match,
3664 * treating '?' as a wildcard in maskp (but not in the file name).
3666 tp1 = umask; /* real name, in mask format */
3667 tp2 = maskp; /* mask, in mask format */
3668 for(i=0; i<11; i++) {
3669 tc1 = *tp1++; /* char from real name */
3670 tc2 = *tp2++; /* char from mask */
3671 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3672 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3675 if (tc2 == '?' && tc1 != ' ')
3682 /* we got a match */
3686 char *smb_FindMask(char *pathp)
3690 tp = strrchr(pathp, '\\'); /* find last slash */
3693 return tp+1; /* skip the slash */
3695 return pathp; /* no slash, return the entire path */
3698 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3700 unsigned char *pathp;
3702 unsigned char mask[12];
3703 unsigned char *statBlockp;
3704 unsigned char initStatBlock[21];
3707 osi_Log0(smb_logp, "SMB receive search volume");
3709 /* pull pathname and stat block out of request */
3710 tp = smb_GetSMBData(inp, NULL);
3711 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3712 osi_assertx(pathp != NULL, "null path");
3713 if (smb_StoreAnsiFilenames)
3714 OemToChar(pathp,pathp);
3715 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3716 osi_assertx(statBlockp != NULL, "null statBlock");
3718 statBlockp = initStatBlock;
3722 /* for returning to caller */
3723 smb_Get8Dot3MaskFromPath(mask, pathp);
3725 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3726 tp = smb_GetSMBData(outp, NULL);
3728 *tp++ = 43; /* bytes in a dir entry */
3729 *tp++ = 0; /* high byte in counter */
3731 /* now marshall the dir entry, starting with the search status */
3732 *tp++ = statBlockp[0]; /* Reserved */
3733 memcpy(tp, mask, 11); tp += 11; /* FileName */
3735 /* now pass back server use info, with 1st byte non-zero */
3737 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3739 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3741 *tp++ = 0x8; /* attribute: volume */
3751 /* 4 byte file size */
3757 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3758 memset(tp, ' ', 13);
3761 /* set the length of the data part of the packet to 43 + 3, for the dir
3762 * entry plus the 5 and the length fields.
3764 smb_SetSMBDataLength(outp, 46);
3769 smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3770 char * tidPathp, char * relPathp,
3771 cm_user_t *userp, cm_req_t *reqp)
3779 smb_dirListPatch_t *patchp;
3780 smb_dirListPatch_t *npatchp;
3781 char path[AFSPATHMAX];
3783 for (patchp = *dirPatchespp; patchp; patchp =
3784 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3786 dptr = patchp->dptr;
3788 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
3789 reqp->relPathp = path;
3790 reqp->tidPathp = tidPathp;
3792 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3793 reqp->relPathp = reqp->tidPathp = NULL;
3796 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3797 *dptr++ = SMB_ATTR_HIDDEN;
3800 lock_ObtainMutex(&scp->mx);
3801 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3802 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3804 lock_ReleaseMutex(&scp->mx);
3805 cm_ReleaseSCache(scp);
3806 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3807 *dptr++ = SMB_ATTR_HIDDEN;
3811 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3813 attr = smb_Attributes(scp);
3814 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3815 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3816 attr |= SMB_ATTR_HIDDEN;
3820 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3823 shortTemp = (unsigned short) (dosTime & 0xffff);
3824 *((u_short *)dptr) = shortTemp;
3827 /* and copy out date */
3828 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3829 *((u_short *)dptr) = shortTemp;
3832 /* copy out file length */
3833 *((u_long *)dptr) = scp->length.LowPart;
3835 lock_ReleaseMutex(&scp->mx);
3836 cm_ReleaseSCache(scp);
3839 /* now free the patches */
3840 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3841 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3845 /* and mark the list as empty */
3846 *dirPatchespp = NULL;
3851 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3858 cm_dirEntry_t *dep = 0;
3860 smb_dirListPatch_t *dirListPatchesp;
3861 smb_dirListPatch_t *curPatchp;
3865 osi_hyper_t dirLength;
3866 osi_hyper_t bufferOffset;
3867 osi_hyper_t curOffset;
3869 unsigned char *inCookiep;
3870 smb_dirSearch_t *dsp;
3874 unsigned long clientCookie;
3875 cm_pageHeader_t *pageHeaderp;
3876 cm_user_t *userp = NULL;
3883 long nextEntryCookie;
3884 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3885 char resByte; /* reserved byte from the cookie */
3886 char *op; /* output data ptr */
3887 char *origOp; /* original value of op */
3888 cm_space_t *spacep; /* for pathname buffer */
3899 maxCount = smb_GetSMBParm(inp, 0);
3901 dirListPatchesp = NULL;
3903 caseFold = CM_FLAG_CASEFOLD;
3905 tp = smb_GetSMBData(inp, NULL);
3906 pathp = smb_ParseASCIIBlock(tp, &tp);
3907 if (smb_StoreAnsiFilenames)
3908 OemToChar(pathp,pathp);
3909 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3911 /* bail out if request looks bad */
3912 if (!tp || !pathp) {
3913 return CM_ERROR_BADSMB;
3916 /* We can handle long names */
3917 if (vcp->flags & SMB_VCFLAG_USENT)
3918 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3920 /* make sure we got a whole search status */
3921 if (dataLength < 21) {
3922 nextCookie = 0; /* start at the beginning of the dir */
3925 attribute = smb_GetSMBParm(inp, 1);
3927 /* handle volume info in another function */
3928 if (attribute & 0x8)
3929 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3931 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3932 maxCount, osi_LogSaveString(smb_logp, pathp));
3934 if (*pathp == 0) { /* null pathp, treat as root dir */
3935 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3936 return CM_ERROR_NOFILES;
3940 dsp = smb_NewDirSearch(0);
3941 dsp->attribute = attribute;
3942 smb_Get8Dot3MaskFromPath(mask, pathp);
3943 memcpy(dsp->mask, mask, 12);
3945 /* track if this is likely to match a lot of entries */
3946 if (smb_IsStarMask(mask))
3951 /* pull the next cookie value out of the search status block */
3952 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3953 + (inCookiep[16]<<24);
3954 dsp = smb_FindDirSearch(inCookiep[12]);
3956 /* can't find dir search status; fatal error */
3957 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3958 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3959 return CM_ERROR_BADFD;
3961 attribute = dsp->attribute;
3962 resByte = inCookiep[0];
3964 /* copy out client cookie, in host byte order. Don't bother
3965 * interpreting it, since we're just passing it through, anyway.
3967 memcpy(&clientCookie, &inCookiep[17], 4);
3969 memcpy(mask, dsp->mask, 12);
3971 /* assume we're doing a star match if it has continued for more
3977 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3978 nextCookie, dsp->cookie, attribute);
3980 userp = smb_GetUserFromVCP(vcp, inp);
3982 /* try to get the vnode for the path name next */
3983 lock_ObtainMutex(&dsp->mx);
3986 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3990 spacep = inp->spacep;
3991 smb_StripLastComponent(spacep->data, NULL, pathp);
3992 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3994 lock_ReleaseMutex(&dsp->mx);
3995 cm_ReleaseUser(userp);
3996 smb_DeleteDirSearch(dsp);
3997 smb_ReleaseDirSearch(dsp);
3998 return CM_ERROR_NOFILES;
4000 strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
4001 strcpy(dsp->relPath, spacep->data);
4003 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4004 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4007 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4008 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4009 cm_ReleaseSCache(scp);
4010 lock_ReleaseMutex(&dsp->mx);
4011 cm_ReleaseUser(userp);
4012 smb_DeleteDirSearch(dsp);
4013 smb_ReleaseDirSearch(dsp);
4014 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4015 return CM_ERROR_PATH_NOT_COVERED;
4017 return CM_ERROR_BADSHARENAME;
4019 #endif /* DFS_SUPPORT */
4022 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4023 /* we need one hold for the entry we just stored into,
4024 * and one for our own processing. When we're done with this
4025 * function, we'll drop the one for our own processing.
4026 * We held it once from the namei call, and so we do another hold
4030 lock_ObtainMutex(&scp->mx);
4031 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4032 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4033 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4034 dsp->flags |= SMB_DIRSEARCH_BULKST;
4035 dsp->scp->bulkStatProgress = hzero;
4037 lock_ReleaseMutex(&scp->mx);
4040 lock_ReleaseMutex(&dsp->mx);
4042 cm_ReleaseUser(userp);
4043 smb_DeleteDirSearch(dsp);
4044 smb_ReleaseDirSearch(dsp);
4048 /* reserves space for parameter; we'll adjust it again later to the
4049 * real count of the # of entries we returned once we've actually
4050 * assembled the directory listing.
4052 smb_SetSMBParm(outp, 0, 0);
4054 /* get the directory size */
4055 lock_ObtainMutex(&scp->mx);
4056 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4057 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4059 lock_ReleaseMutex(&scp->mx);
4060 cm_ReleaseSCache(scp);
4061 cm_ReleaseUser(userp);
4062 smb_DeleteDirSearch(dsp);
4063 smb_ReleaseDirSearch(dsp);
4067 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4069 dirLength = scp->length;
4071 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4072 curOffset.HighPart = 0;
4073 curOffset.LowPart = nextCookie;
4074 origOp = op = smb_GetSMBData(outp, NULL);
4075 /* and write out the basic header */
4076 *op++ = 5; /* variable block */
4077 op += 2; /* skip vbl block length; we'll fill it in later */
4081 /* make sure that curOffset.LowPart doesn't point to the first
4082 * 32 bytes in the 2nd through last dir page, and that it doesn't
4083 * point at the first 13 32-byte chunks in the first dir page,
4084 * since those are dir and page headers, and don't contain useful
4087 temp = curOffset.LowPart & (2048-1);
4088 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4089 /* we're in the first page */
4090 if (temp < 13*32) temp = 13*32;
4093 /* we're in a later dir page */
4094 if (temp < 32) temp = 32;
4097 /* make sure the low order 5 bits are zero */
4100 /* now put temp bits back ito curOffset.LowPart */
4101 curOffset.LowPart &= ~(2048-1);
4102 curOffset.LowPart |= temp;
4104 /* check if we've returned all the names that will fit in the
4107 if (returnedNames >= maxCount) {
4108 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4109 returnedNames, maxCount);
4113 /* check if we've passed the dir's EOF */
4114 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4116 /* see if we can use the bufferp we have now; compute in which page
4117 * the current offset would be, and check whether that's the offset
4118 * of the buffer we have. If not, get the buffer.
4120 thyper.HighPart = curOffset.HighPart;
4121 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4122 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4125 buf_Release(bufferp);
4128 lock_ReleaseMutex(&scp->mx);
4129 code = buf_Get(scp, &thyper, &bufferp);
4130 lock_ObtainMutex(&dsp->mx);
4132 /* now, if we're doing a star match, do bulk fetching of all of
4133 * the status info for files in the dir.
4136 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4137 lock_ObtainMutex(&scp->mx);
4138 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4139 LargeIntegerGreaterThanOrEqualTo(thyper,
4140 scp->bulkStatProgress)) {
4141 /* Don't bulk stat if risking timeout */
4142 int now = GetTickCount();
4143 if (now - req.startTime > RDRtimeout * 1000) {
4144 scp->bulkStatProgress = thyper;
4145 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4146 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4147 dsp->scp->bulkStatProgress = hzero;
4149 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4152 lock_ObtainMutex(&scp->mx);
4154 lock_ReleaseMutex(&dsp->mx);
4156 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4160 bufferOffset = thyper;
4162 /* now get the data in the cache */
4164 code = cm_SyncOp(scp, bufferp, userp, &req,
4166 CM_SCACHESYNC_NEEDCALLBACK |
4167 CM_SCACHESYNC_READ);
4169 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4173 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4175 if (cm_HaveBuffer(scp, bufferp, 0)) {
4176 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4180 /* otherwise, load the buffer and try again */
4181 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4183 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4184 scp, bufferp, code);
4189 buf_Release(bufferp);
4193 } /* if (wrong buffer) ... */
4195 /* now we have the buffer containing the entry we're interested in; copy
4196 * it out if it represents a non-deleted entry.
4198 entryInDir = curOffset.LowPart & (2048-1);
4199 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4201 /* page header will help tell us which entries are free. Page header
4202 * can change more often than once per buffer, since AFS 3 dir page size
4203 * may be less than (but not more than a buffer package buffer.
4205 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4206 temp &= ~(2048 - 1); /* turn off intra-page bits */
4207 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4209 /* now determine which entry we're looking at in the page. If it is
4210 * free (there's a free bitmap at the start of the dir), we should
4211 * skip these 32 bytes.
4213 slotInPage = (entryInDir & 0x7e0) >> 5;
4214 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4215 /* this entry is free */
4216 numDirChunks = 1; /* only skip this guy */
4220 tp = bufferp->datap + entryInBuffer;
4221 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4223 /* while we're here, compute the next entry's location, too,
4224 * since we'll need it when writing out the cookie into the dir
4227 * XXXX Probably should do more sanity checking.
4229 numDirChunks = cm_NameEntries(dep->name, NULL);
4231 /* compute the offset of the cookie representing the next entry */
4232 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4234 /* Compute 8.3 name if necessary */
4235 actualName = dep->name;
4236 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4237 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4238 actualName = shortName;
4241 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4242 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4243 osi_LogSaveString(smb_logp, actualName));
4245 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4246 /* this is one of the entries to use: it is not deleted
4247 * and it matches the star pattern we're looking for.
4250 /* Eliminate entries that don't match requested
4253 /* no hidden files */
4254 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4255 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4259 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4261 /* We have already done the cm_TryBulkStat above */
4262 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4263 fileType = cm_FindFileType(&fid);
4264 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4265 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4267 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4268 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4269 fileType == CM_SCACHETYPE_DFSLINK ||
4270 fileType == CM_SCACHETYPE_INVALID)
4271 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4276 memcpy(op, mask, 11); op += 11;
4277 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4278 *op++ = (char)(nextEntryCookie & 0xff);
4279 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4280 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4281 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4282 memcpy(op, &clientCookie, 4); op += 4;
4284 /* now we emit the attribute. This is sort of tricky,
4285 * since we need to really stat the file to find out
4286 * what type of entry we've got. Right now, we're
4287 * copying out data from a buffer, while holding the
4288 * scp locked, so it isn't really convenient to stat
4289 * something now. We'll put in a place holder now,
4290 * and make a second pass before returning this to get
4291 * the real attributes. So, we just skip the data for
4292 * now, and adjust it later. We allocate a patch
4293 * record to make it easy to find this point later.
4294 * The replay will happen at a time when it is safe to
4295 * unlock the directory.
4297 curPatchp = malloc(sizeof(*curPatchp));
4298 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4299 curPatchp->dptr = op;
4300 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4302 /* do hidden attribute here since name won't be around when applying
4306 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4307 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4309 curPatchp->flags = 0;
4311 op += 9; /* skip attr, time, date and size */
4313 /* zero out name area. The spec says to pad with
4314 * spaces, but Samba doesn't, and neither do we.
4318 /* finally, we get to copy out the name; we know that
4319 * it fits in 8.3 or the pattern wouldn't match, but it
4320 * never hurts to be sure.
4322 strncpy(op, actualName, 13);
4323 if (smb_StoreAnsiFilenames)
4326 /* Uppercase if requested by client */
4327 if (!KNOWS_LONG_NAMES(inp))
4332 /* now, adjust the # of entries copied */
4334 } /* if we're including this name */
4337 /* and adjust curOffset to be where the new cookie is */
4338 thyper.HighPart = 0;
4339 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4340 curOffset = LargeIntegerAdd(thyper, curOffset);
4341 } /* while copying data for dir listing */
4343 /* release the mutex */
4344 lock_ReleaseMutex(&scp->mx);
4346 buf_Release(bufferp);
4350 /* apply and free last set of patches; if not doing a star match, this
4351 * will be empty, but better safe (and freeing everything) than sorry.
4353 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4355 /* special return code for unsuccessful search */
4356 if (code == 0 && dataLength < 21 && returnedNames == 0)
4357 code = CM_ERROR_NOFILES;
4359 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4360 returnedNames, code);
4363 smb_DeleteDirSearch(dsp);
4364 smb_ReleaseDirSearch(dsp);
4365 cm_ReleaseSCache(scp);
4366 cm_ReleaseUser(userp);
4370 /* finalize the output buffer */
4371 smb_SetSMBParm(outp, 0, returnedNames);
4372 temp = (long) (op - origOp);
4373 smb_SetSMBDataLength(outp, temp);
4375 /* the data area is a variable block, which has a 5 (already there)
4376 * followed by the length of the # of data bytes. We now know this to
4377 * be "temp," although that includes the 3 bytes of vbl block header.
4378 * Deduct for them and fill in the length field.
4380 temp -= 3; /* deduct vbl block info */
4381 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4382 origOp[1] = (char)(temp & 0xff);
4383 origOp[2] = (char)((temp>>8) & 0xff);
4384 if (returnedNames == 0)
4385 smb_DeleteDirSearch(dsp);
4386 smb_ReleaseDirSearch(dsp);
4387 cm_ReleaseSCache(scp);
4388 cm_ReleaseUser(userp);
4392 /* verify that this is a valid path to a directory. I don't know why they
4393 * don't use the get file attributes call.
4395 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4399 cm_scache_t *rootScp;
4400 cm_scache_t *newScp;
4409 pathp = smb_GetSMBData(inp, NULL);
4410 pathp = smb_ParseASCIIBlock(pathp, NULL);
4412 return CM_ERROR_BADFD;
4413 if (smb_StoreAnsiFilenames)
4414 OemToChar(pathp,pathp);
4415 osi_Log1(smb_logp, "SMB receive check path %s",
4416 osi_LogSaveString(smb_logp, pathp));
4418 rootScp = cm_data.rootSCachep;
4420 userp = smb_GetUserFromVCP(vcp, inp);
4422 caseFold = CM_FLAG_CASEFOLD;
4424 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4426 cm_ReleaseUser(userp);
4427 return CM_ERROR_NOSUCHPATH;
4429 code = cm_NameI(rootScp, pathp,
4430 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4431 userp, tidPathp, &req, &newScp);
4434 cm_ReleaseUser(userp);
4439 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4440 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4441 cm_ReleaseSCache(newScp);
4442 cm_ReleaseUser(userp);
4443 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4444 return CM_ERROR_PATH_NOT_COVERED;
4446 return CM_ERROR_BADSHARENAME;
4448 #endif /* DFS_SUPPORT */
4450 /* now lock the vnode with a callback; returns with newScp locked */
4451 lock_ObtainMutex(&newScp->mx);
4452 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4453 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4455 if (code != CM_ERROR_NOACCESS) {
4456 lock_ReleaseMutex(&newScp->mx);
4457 cm_ReleaseSCache(newScp);
4458 cm_ReleaseUser(userp);
4462 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4465 attrs = smb_Attributes(newScp);
4467 if (!(attrs & SMB_ATTR_DIRECTORY))
4468 code = CM_ERROR_NOTDIR;
4470 lock_ReleaseMutex(&newScp->mx);
4472 cm_ReleaseSCache(newScp);
4473 cm_ReleaseUser(userp);
4477 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4481 cm_scache_t *rootScp;
4482 unsigned short attribute;
4484 cm_scache_t *newScp;
4493 /* decode basic attributes we're passed */
4494 attribute = smb_GetSMBParm(inp, 0);
4495 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4497 pathp = smb_GetSMBData(inp, NULL);
4498 pathp = smb_ParseASCIIBlock(pathp, NULL);
4500 return CM_ERROR_BADSMB;
4501 if (smb_StoreAnsiFilenames)
4502 OemToChar(pathp,pathp);
4504 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4505 dosTime, attribute);
4507 rootScp = cm_data.rootSCachep;
4509 userp = smb_GetUserFromVCP(vcp, inp);
4511 caseFold = CM_FLAG_CASEFOLD;
4513 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4515 cm_ReleaseUser(userp);
4516 return CM_ERROR_NOSUCHFILE;
4518 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4519 tidPathp, &req, &newScp);
4522 cm_ReleaseUser(userp);
4527 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4528 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4529 cm_ReleaseSCache(newScp);
4530 cm_ReleaseUser(userp);
4531 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4532 return CM_ERROR_PATH_NOT_COVERED;
4534 return CM_ERROR_BADSHARENAME;
4536 #endif /* DFS_SUPPORT */
4538 /* now lock the vnode with a callback; returns with newScp locked; we
4539 * need the current status to determine what the new status is, in some
4542 lock_ObtainMutex(&newScp->mx);
4543 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4544 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4546 lock_ReleaseMutex(&newScp->mx);
4547 cm_ReleaseSCache(newScp);
4548 cm_ReleaseUser(userp);
4552 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4554 /* Check for RO volume */
4555 if (newScp->flags & CM_SCACHEFLAG_RO) {
4556 lock_ReleaseMutex(&newScp->mx);
4557 cm_ReleaseSCache(newScp);
4558 cm_ReleaseUser(userp);
4559 return CM_ERROR_READONLY;
4562 /* prepare for setattr call */
4565 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4566 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4568 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4569 /* we're told to make a writable file read-only */
4570 attr.unixModeBits = newScp->unixModeBits & ~0222;
4571 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4573 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4574 /* we're told to make a read-only file writable */
4575 attr.unixModeBits = newScp->unixModeBits | 0222;
4576 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4578 lock_ReleaseMutex(&newScp->mx);
4580 /* now call setattr */
4582 code = cm_SetAttr(newScp, &attr, userp, &req);
4586 cm_ReleaseSCache(newScp);
4587 cm_ReleaseUser(userp);
4592 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4596 cm_scache_t *rootScp;
4597 cm_scache_t *newScp, *dscp;
4609 pathp = smb_GetSMBData(inp, NULL);
4610 pathp = smb_ParseASCIIBlock(pathp, NULL);
4612 return CM_ERROR_BADSMB;
4614 if (*pathp == 0) /* null path */
4617 if (smb_StoreAnsiFilenames)
4618 OemToChar(pathp,pathp);
4620 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4621 osi_LogSaveString(smb_logp, pathp));
4623 rootScp = cm_data.rootSCachep;
4625 userp = smb_GetUserFromVCP(vcp, inp);
4627 /* we shouldn't need this for V3 requests, but we seem to */
4628 caseFold = CM_FLAG_CASEFOLD;
4630 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4632 cm_ReleaseUser(userp);
4633 return CM_ERROR_NOSUCHFILE;
4637 * XXX Strange hack XXX
4639 * As of Patch 5 (16 July 97), we are having the following problem:
4640 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4641 * requests to look up "desktop.ini" in all the subdirectories.
4642 * This can cause zillions of timeouts looking up non-existent cells
4643 * and volumes, especially in the top-level directory.
4645 * We have not found any way to avoid this or work around it except
4646 * to explicitly ignore the requests for mount points that haven't
4647 * yet been evaluated and for directories that haven't yet been
4650 * We should modify this hack to provide a fake desktop.ini file
4651 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4653 spacep = inp->spacep;
4654 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4655 #ifndef SPECIAL_FOLDERS
4656 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4657 code = cm_NameI(rootScp, spacep->data,
4658 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4659 userp, tidPathp, &req, &dscp);
4662 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4663 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
4664 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4665 return CM_ERROR_PATH_NOT_COVERED;
4667 return CM_ERROR_BADSHARENAME;
4669 #endif /* DFS_SUPPORT */
4670 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4671 code = CM_ERROR_NOSUCHFILE;
4672 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4673 cm_buf_t *bp = buf_Find(dscp, &hzero);
4678 code = CM_ERROR_NOSUCHFILE;
4680 cm_ReleaseSCache(dscp);
4682 cm_ReleaseUser(userp);
4687 #endif /* SPECIAL_FOLDERS */
4689 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4690 tidPathp, &req, &newScp);
4692 cm_ReleaseUser(userp);
4697 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4698 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4699 cm_ReleaseSCache(newScp);
4700 cm_ReleaseUser(userp);
4701 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4702 return CM_ERROR_PATH_NOT_COVERED;
4704 return CM_ERROR_BADSHARENAME;
4706 #endif /* DFS_SUPPORT */
4708 /* now lock the vnode with a callback; returns with newScp locked */
4709 lock_ObtainMutex(&newScp->mx);
4710 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4711 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4713 lock_ReleaseMutex(&newScp->mx);
4714 cm_ReleaseSCache(newScp);
4715 cm_ReleaseUser(userp);
4719 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4722 /* use smb_Attributes instead. Also the fact that a file is
4723 * in a readonly volume doesn't mean it shojuld be marked as RO
4725 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4726 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4727 newScp->fileType == CM_SCACHETYPE_INVALID)
4728 attrs = SMB_ATTR_DIRECTORY;
4731 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4732 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4734 attrs = smb_Attributes(newScp);
4737 smb_SetSMBParm(outp, 0, attrs);
4739 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4740 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4741 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4742 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4743 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4744 smb_SetSMBParm(outp, 5, 0);
4745 smb_SetSMBParm(outp, 6, 0);
4746 smb_SetSMBParm(outp, 7, 0);
4747 smb_SetSMBParm(outp, 8, 0);
4748 smb_SetSMBParm(outp, 9, 0);
4749 smb_SetSMBDataLength(outp, 0);
4750 lock_ReleaseMutex(&newScp->mx);
4752 cm_ReleaseSCache(newScp);
4753 cm_ReleaseUser(userp);
4758 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4762 osi_Log0(smb_logp, "SMB receive tree disconnect");
4764 /* find the tree and free it */
4765 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4767 lock_ObtainWrite(&smb_rctLock);
4769 smb_ReleaseTID(tidp, TRUE);
4770 lock_ReleaseWrite(&smb_rctLock);
4776 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4794 pathp = smb_GetSMBData(inp, NULL);
4795 pathp = smb_ParseASCIIBlock(pathp, NULL);
4796 if (smb_StoreAnsiFilenames)
4797 OemToChar(pathp,pathp);
4799 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4801 #ifdef DEBUG_VERBOSE
4805 hexpath = osi_HexifyString( pathp );
4806 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4811 share = smb_GetSMBParm(inp, 0);
4812 attribute = smb_GetSMBParm(inp, 1);
4814 spacep = inp->spacep;
4815 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4816 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4817 /* special case magic file name for receiving IOCTL requests
4818 * (since IOCTL calls themselves aren't getting through).
4820 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4821 smb_SetupIoctlFid(fidp, spacep);
4822 smb_SetSMBParm(outp, 0, fidp->fid);
4823 smb_SetSMBParm(outp, 1, 0); /* attrs */
4824 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4825 smb_SetSMBParm(outp, 3, 0);
4826 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4827 smb_SetSMBParm(outp, 5, 0x7fff);
4828 /* pass the open mode back */
4829 smb_SetSMBParm(outp, 6, (share & 0xf));
4830 smb_SetSMBDataLength(outp, 0);
4831 smb_ReleaseFID(fidp);
4835 userp = smb_GetUserFromVCP(vcp, inp);
4837 caseFold = CM_FLAG_CASEFOLD;
4839 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4841 cm_ReleaseUser(userp);
4842 return CM_ERROR_NOSUCHPATH;
4844 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4845 tidPathp, &req, &scp);
4848 cm_ReleaseUser(userp);
4853 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4854 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
4855 cm_ReleaseSCache(scp);
4856 cm_ReleaseUser(userp);
4857 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4858 return CM_ERROR_PATH_NOT_COVERED;
4860 return CM_ERROR_BADSHARENAME;
4862 #endif /* DFS_SUPPORT */
4864 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4866 cm_ReleaseSCache(scp);
4867 cm_ReleaseUser(userp);
4871 /* don't need callback to check file type, since file types never
4872 * change, and namei and cm_Lookup all stat the object at least once on
4873 * a successful return.
4875 if (scp->fileType != CM_SCACHETYPE_FILE) {
4876 cm_ReleaseSCache(scp);
4877 cm_ReleaseUser(userp);
4878 return CM_ERROR_ISDIR;
4881 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4882 osi_assertx(fidp, "null smb_fid_t");
4884 /* save a pointer to the vnode */
4886 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4887 lock_ObtainMutex(&scp->mx);
4888 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4889 lock_ReleaseMutex(&scp->mx);
4893 fidp->userp = userp;
4895 lock_ObtainMutex(&fidp->mx);
4896 if ((share & 0xf) == 0)
4897 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4898 else if ((share & 0xf) == 1)
4899 fidp->flags |= SMB_FID_OPENWRITE;
4901 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4902 lock_ReleaseMutex(&fidp->mx);
4904 lock_ObtainMutex(&scp->mx);
4905 smb_SetSMBParm(outp, 0, fidp->fid);
4906 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4907 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4908 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4909 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4910 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4911 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4912 /* pass the open mode back; XXXX add access checks */
4913 smb_SetSMBParm(outp, 6, (share & 0xf));
4914 smb_SetSMBDataLength(outp, 0);
4915 lock_ReleaseMutex(&scp->mx);
4918 cm_Open(scp, 0, userp);
4920 /* send and free packet */
4921 smb_ReleaseFID(fidp);
4922 cm_ReleaseUser(userp);
4923 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4927 typedef struct smb_unlinkRock {
4932 char *maskp; /* pointer to the star pattern */
4935 cm_dirEntryList_t * matches;
4938 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4941 smb_unlinkRock_t *rockp;
4949 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4950 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4951 caseFold |= CM_FLAG_8DOT3;
4953 matchName = dep->name;
4954 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4956 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4957 !cm_Is8Dot3(dep->name)) {
4958 cm_Gen8Dot3Name(dep, shortName, NULL);
4959 matchName = shortName;
4960 /* 8.3 matches are always case insensitive */
4961 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4964 osi_Log1(smb_logp, "Found match %s",
4965 osi_LogSaveString(smb_logp, matchName));
4967 cm_DirEntryListAdd(dep->name, &rockp->matches);
4971 /* If we made a case sensitive exact match, we might as well quit now. */
4972 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4973 code = CM_ERROR_STOPNOW;
4982 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4991 smb_unlinkRock_t rock;
5000 attribute = smb_GetSMBParm(inp, 0);
5002 tp = smb_GetSMBData(inp, NULL);
5003 pathp = smb_ParseASCIIBlock(tp, &tp);
5004 if (smb_StoreAnsiFilenames)
5005 OemToChar(pathp,pathp);
5007 osi_Log1(smb_logp, "SMB receive unlink %s",
5008 osi_LogSaveString(smb_logp, pathp));
5010 spacep = inp->spacep;
5011 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5013 userp = smb_GetUserFromVCP(vcp, inp);
5015 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5017 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5019 cm_ReleaseUser(userp);
5020 return CM_ERROR_NOSUCHPATH;
5022 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5025 cm_ReleaseUser(userp);
5030 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5031 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,spacep->data);
5032 cm_ReleaseSCache(dscp);
5033 cm_ReleaseUser(userp);
5034 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5035 return CM_ERROR_PATH_NOT_COVERED;
5037 return CM_ERROR_BADSHARENAME;
5039 #endif /* DFS_SUPPORT */
5041 /* otherwise, scp points to the parent directory. */
5048 rock.maskp = smb_FindMask(pathp);
5049 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5052 thyper.HighPart = 0;
5057 rock.matches = NULL;
5059 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5060 * match. If that fails, we do a case insensitve match.
5062 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5063 !smb_IsStarMask(rock.maskp)) {
5064 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5067 thyper.HighPart = 0;
5068 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5073 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5075 if (code == CM_ERROR_STOPNOW)
5078 if (code == 0 && rock.matches) {
5079 cm_dirEntryList_t * entry;
5081 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5083 osi_Log1(smb_logp, "Unlinking %s",
5084 osi_LogSaveString(smb_logp, entry->name));
5085 code = cm_Unlink(dscp, entry->name, userp, &req);
5087 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5088 smb_NotifyChange(FILE_ACTION_REMOVED,
5089 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5090 dscp, entry->name, NULL, TRUE);
5094 cm_DirEntryListFree(&rock.matches);
5096 cm_ReleaseUser(userp);
5098 cm_ReleaseSCache(dscp);
5100 if (code == 0 && !rock.any)
5101 code = CM_ERROR_NOSUCHFILE;
5105 typedef struct smb_renameRock {
5106 cm_scache_t *odscp; /* old dir */
5107 cm_scache_t *ndscp; /* new dir */
5108 cm_user_t *userp; /* user */
5109 cm_req_t *reqp; /* request struct */
5110 smb_vc_t *vcp; /* virtual circuit */
5111 char *maskp; /* pointer to star pattern of old file name */
5112 int flags; /* tilde, casefold, etc */
5113 char *newNamep; /* ptr to the new file's name */
5114 char oldName[MAX_PATH];
5118 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5121 smb_renameRock_t *rockp;
5124 char shortName[13]="";
5126 rockp = (smb_renameRock_t *) vrockp;
5128 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5129 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5130 caseFold |= CM_FLAG_8DOT3;
5132 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5134 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5135 !cm_Is8Dot3(dep->name)) {
5136 cm_Gen8Dot3Name(dep, shortName, NULL);
5137 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5142 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5143 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5144 code = CM_ERROR_STOPNOW;
5154 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5157 cm_space_t *spacep = NULL;
5158 smb_renameRock_t rock;
5159 cm_scache_t *oldDscp = NULL;
5160 cm_scache_t *newDscp = NULL;
5161 cm_scache_t *tmpscp= NULL;
5162 cm_scache_t *tmpscp2 = NULL;
5172 userp = smb_GetUserFromVCP(vcp, inp);
5173 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5175 cm_ReleaseUser(userp);
5176 return CM_ERROR_NOSUCHPATH;
5180 spacep = inp->spacep;
5181 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5183 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5184 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5185 userp, tidPathp, &req, &oldDscp);
5187 cm_ReleaseUser(userp);
5192 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5193 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5194 cm_ReleaseSCache(oldDscp);
5195 cm_ReleaseUser(userp);
5196 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5197 return CM_ERROR_PATH_NOT_COVERED;
5199 return CM_ERROR_BADSHARENAME;
5201 #endif /* DFS_SUPPORT */
5203 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5204 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5205 userp, tidPathp, &req, &newDscp);
5208 cm_ReleaseSCache(oldDscp);
5209 cm_ReleaseUser(userp);
5214 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5215 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5216 cm_ReleaseSCache(oldDscp);
5217 cm_ReleaseSCache(newDscp);
5218 cm_ReleaseUser(userp);
5219 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5220 return CM_ERROR_PATH_NOT_COVERED;
5222 return CM_ERROR_BADSHARENAME;
5224 #endif /* DFS_SUPPORT */
5227 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5228 * next, get the component names, and lower case them.
5231 /* handle the old name first */
5233 oldLastNamep = oldPathp;
5237 /* and handle the new name, too */
5239 newLastNamep = newPathp;
5243 /* TODO: The old name could be a wildcard. The new name must not be */
5245 /* do the vnode call */
5246 rock.odscp = oldDscp;
5247 rock.ndscp = newDscp;
5251 rock.maskp = oldLastNamep;
5252 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5253 rock.newNamep = newLastNamep;
5254 rock.oldName[0] = '\0';
5257 /* Check if the file already exists; if so return error */
5258 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5259 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5260 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5262 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5263 osi_LogSaveString(smb_logp, newLastNamep));
5265 /* Check if the old and the new names differ only in case. If so return
5266 * success, else return CM_ERROR_EXISTS
5268 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5270 /* This would be a success only if the old file is *as same as* the new file */
5271 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5273 if (tmpscp == tmpscp2)
5276 code = CM_ERROR_EXISTS;
5277 cm_ReleaseSCache(tmpscp2);
5280 code = CM_ERROR_NOSUCHFILE;
5283 /* file exist, do not rename, also fixes move */
5284 osi_Log0(smb_logp, "Can't rename. Target already exists");
5285 code = CM_ERROR_EXISTS;
5289 cm_ReleaseSCache(tmpscp);
5290 cm_ReleaseSCache(newDscp);
5291 cm_ReleaseSCache(oldDscp);
5292 cm_ReleaseUser(userp);
5296 /* Now search the directory for the pattern, and do the appropriate rename when found */
5297 thyper.LowPart = 0; /* search dir from here */
5298 thyper.HighPart = 0;
5300 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5301 if (code == 0 && !rock.any) {
5303 thyper.HighPart = 0;
5304 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5305 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5307 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5309 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5310 code = cm_Rename(rock.odscp, rock.oldName,
5311 rock.ndscp, rock.newNamep, rock.userp,
5313 /* if the call worked, stop doing the search now, since we
5314 * really only want to rename one file.
5316 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5317 } else if (code == 0) {
5318 code = CM_ERROR_NOSUCHFILE;
5321 /* Handle Change Notification */
5323 * Being lazy, not distinguishing between files and dirs in this
5324 * filter, since we'd have to do a lookup.
5327 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5328 if (oldDscp == newDscp) {
5329 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5330 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5331 filter, oldDscp, oldLastNamep,
5332 newLastNamep, TRUE);
5334 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5335 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5336 filter, oldDscp, oldLastNamep,
5338 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5339 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5340 filter, newDscp, newLastNamep,
5346 cm_ReleaseSCache(tmpscp);
5347 cm_ReleaseUser(userp);
5348 cm_ReleaseSCache(oldDscp);
5349 cm_ReleaseSCache(newDscp);
5354 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5357 cm_space_t *spacep = NULL;
5358 cm_scache_t *oldDscp = NULL;
5359 cm_scache_t *newDscp = NULL;
5360 cm_scache_t *tmpscp= NULL;
5361 cm_scache_t *tmpscp2 = NULL;
5362 cm_scache_t *sscp = NULL;
5371 userp = smb_GetUserFromVCP(vcp, inp);
5373 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5375 cm_ReleaseUser(userp);
5376 return CM_ERROR_NOSUCHPATH;
5381 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5383 spacep = inp->spacep;
5384 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5386 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5387 userp, tidPathp, &req, &oldDscp);
5389 cm_ReleaseUser(userp);
5394 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5395 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5396 cm_ReleaseSCache(oldDscp);
5397 cm_ReleaseUser(userp);
5398 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5399 return CM_ERROR_PATH_NOT_COVERED;
5401 return CM_ERROR_BADSHARENAME;
5403 #endif /* DFS_SUPPORT */
5405 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5406 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5407 userp, tidPathp, &req, &newDscp);
5409 cm_ReleaseSCache(oldDscp);
5410 cm_ReleaseUser(userp);
5415 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5416 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5417 cm_ReleaseSCache(newDscp);
5418 cm_ReleaseSCache(oldDscp);
5419 cm_ReleaseUser(userp);
5420 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5421 return CM_ERROR_PATH_NOT_COVERED;
5423 return CM_ERROR_BADSHARENAME;
5425 #endif /* DFS_SUPPORT */
5427 /* Now, although we did two lookups for the two directories (because the same
5428 * directory can be referenced through different paths), we only allow hard links
5429 * within the same directory. */
5430 if (oldDscp != newDscp) {
5431 cm_ReleaseSCache(oldDscp);
5432 cm_ReleaseSCache(newDscp);
5433 cm_ReleaseUser(userp);
5434 return CM_ERROR_CROSSDEVLINK;
5437 /* handle the old name first */
5439 oldLastNamep = oldPathp;
5443 /* and handle the new name, too */
5445 newLastNamep = newPathp;
5449 /* now lookup the old name */
5450 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5451 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5453 cm_ReleaseSCache(oldDscp);
5454 cm_ReleaseSCache(newDscp);
5455 cm_ReleaseUser(userp);
5459 /* Check if the file already exists; if so return error */
5460 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5461 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5462 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5464 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5465 osi_LogSaveString(smb_logp, newLastNamep));
5467 /* if the existing link is to the same file, then we return success */
5469 if(sscp == tmpscp) {
5472 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5473 code = CM_ERROR_EXISTS;
5478 cm_ReleaseSCache(tmpscp);
5479 cm_ReleaseSCache(sscp);
5480 cm_ReleaseSCache(newDscp);
5481 cm_ReleaseSCache(oldDscp);
5482 cm_ReleaseUser(userp);
5486 /* now create the hardlink */
5487 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5488 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5489 osi_Log1(smb_logp," Link returns 0x%x", code);
5491 /* Handle Change Notification */
5493 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5494 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5495 smb_NotifyChange(FILE_ACTION_ADDED,
5496 filter, newDscp, newLastNamep,
5501 cm_ReleaseSCache(tmpscp);
5502 cm_ReleaseUser(userp);
5503 cm_ReleaseSCache(sscp);
5504 cm_ReleaseSCache(oldDscp);
5505 cm_ReleaseSCache(newDscp);
5510 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5517 tp = smb_GetSMBData(inp, NULL);
5518 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5519 if (smb_StoreAnsiFilenames)
5520 OemToChar(oldPathp,oldPathp);
5521 newPathp = smb_ParseASCIIBlock(tp, &tp);
5522 if (smb_StoreAnsiFilenames)
5523 OemToChar(newPathp,newPathp);
5525 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5526 osi_LogSaveString(smb_logp, oldPathp),
5527 osi_LogSaveString(smb_logp, newPathp));
5529 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5531 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5537 typedef struct smb_rmdirRock {
5541 char *maskp; /* pointer to the star pattern */
5544 cm_dirEntryList_t * matches;
5547 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5550 smb_rmdirRock_t *rockp;
5555 rockp = (smb_rmdirRock_t *) vrockp;
5557 matchName = dep->name;
5558 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5559 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5561 match = (strcmp(matchName, rockp->maskp) == 0);
5563 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5564 !cm_Is8Dot3(dep->name)) {
5565 cm_Gen8Dot3Name(dep, shortName, NULL);
5566 matchName = shortName;
5567 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5572 cm_DirEntryListAdd(dep->name, &rockp->matches);
5578 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5586 smb_rmdirRock_t rock;
5595 tp = smb_GetSMBData(inp, NULL);
5596 pathp = smb_ParseASCIIBlock(tp, &tp);
5597 if (smb_StoreAnsiFilenames)
5598 OemToChar(pathp,pathp);
5600 spacep = inp->spacep;
5601 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5603 userp = smb_GetUserFromVCP(vcp, inp);
5605 caseFold = CM_FLAG_CASEFOLD;
5607 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5609 cm_ReleaseUser(userp);
5610 return CM_ERROR_NOSUCHPATH;
5612 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5613 userp, tidPathp, &req, &dscp);
5616 cm_ReleaseUser(userp);
5621 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5622 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
5623 cm_ReleaseSCache(dscp);
5624 cm_ReleaseUser(userp);
5625 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5626 return CM_ERROR_PATH_NOT_COVERED;
5628 return CM_ERROR_BADSHARENAME;
5630 #endif /* DFS_SUPPORT */
5632 /* otherwise, scp points to the parent directory. */
5639 rock.maskp = lastNamep;
5640 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5643 thyper.HighPart = 0;
5647 rock.matches = NULL;
5649 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5650 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5651 if (code == 0 && !rock.any) {
5653 thyper.HighPart = 0;
5654 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5655 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5658 if (code == 0 && rock.matches) {
5659 cm_dirEntryList_t * entry;
5661 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5662 osi_Log1(smb_logp, "Removing directory %s",
5663 osi_LogSaveString(smb_logp, entry->name));
5665 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5667 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5668 smb_NotifyChange(FILE_ACTION_REMOVED,
5669 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5670 dscp, entry->name, NULL, TRUE);
5674 cm_DirEntryListFree(&rock.matches);
5676 cm_ReleaseUser(userp);
5678 cm_ReleaseSCache(dscp);
5680 if (code == 0 && !rock.any)
5681 code = CM_ERROR_NOSUCHFILE;
5685 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5695 fid = smb_GetSMBParm(inp, 0);
5697 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5699 fid = smb_ChainFID(fid, inp);
5700 fidp = smb_FindFID(vcp, fid, 0);
5702 return CM_ERROR_BADFD;
5704 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5705 smb_CloseFID(vcp, fidp, NULL, 0);
5706 smb_ReleaseFID(fidp);
5707 return CM_ERROR_NOSUCHFILE;
5710 lock_ObtainMutex(&fidp->mx);
5711 if (fidp->flags & SMB_FID_IOCTL) {
5712 lock_ReleaseMutex(&fidp->mx);
5713 smb_ReleaseFID(fidp);
5714 return CM_ERROR_BADFD;
5716 lock_ReleaseMutex(&fidp->mx);
5718 userp = smb_GetUserFromVCP(vcp, inp);
5720 lock_ObtainMutex(&fidp->mx);
5721 if (fidp->flags & SMB_FID_OPENWRITE) {
5722 cm_scache_t * scp = fidp->scp;
5724 lock_ReleaseMutex(&fidp->mx);
5725 code = cm_FSync(scp, userp, &req);
5726 cm_ReleaseSCache(scp);
5729 lock_ReleaseMutex(&fidp->mx);
5732 smb_ReleaseFID(fidp);
5734 cm_ReleaseUser(userp);
5739 struct smb_FullNameRock {
5745 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5749 struct smb_FullNameRock *vrockp;
5751 vrockp = (struct smb_FullNameRock *)rockp;
5753 if (!cm_Is8Dot3(dep->name)) {
5754 cm_Gen8Dot3Name(dep, shortName, NULL);
5756 if (cm_stricmp(shortName, vrockp->name) == 0) {
5757 vrockp->fullName = strdup(dep->name);
5758 return CM_ERROR_STOPNOW;
5761 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5762 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5763 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5764 vrockp->fullName = strdup(dep->name);
5765 return CM_ERROR_STOPNOW;
5770 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5771 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5773 struct smb_FullNameRock rock;
5779 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5780 if (code == CM_ERROR_STOPNOW)
5781 *newPathp = rock.fullName;
5783 *newPathp = strdup(pathp);
5786 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5787 afs_uint32 dosTime) {
5790 cm_scache_t *dscp = NULL;
5792 cm_scache_t * scp = NULL;
5793 cm_scache_t *delscp = NULL;
5795 int nullcreator = 0;
5797 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5798 fidp, fidp->fid, scp, vcp);
5801 lock_ObtainMutex(&fidp->mx);
5802 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5803 lock_ReleaseMutex(&fidp->mx);
5804 osi_Log0(smb_logp, " No user specified. Not closing fid");
5805 return CM_ERROR_BADFD;
5808 userp = fidp->userp; /* no hold required since fidp is held
5809 throughout the function */
5810 lock_ReleaseMutex(&fidp->mx);
5815 lock_ObtainWrite(&smb_rctLock);
5817 osi_Log0(smb_logp, " Fid already closed.");
5818 lock_ReleaseWrite(&smb_rctLock);
5819 return CM_ERROR_BADFD;
5822 lock_ReleaseWrite(&smb_rctLock);
5824 lock_ObtainMutex(&fidp->mx);
5825 if (fidp->NTopen_dscp) {
5826 dscp = fidp->NTopen_dscp;
5827 cm_HoldSCache(dscp);
5830 if (fidp->NTopen_pathp) {
5831 pathp = strdup(fidp->NTopen_pathp);
5839 /* Don't jump the gun on an async raw write */
5840 while (fidp->raw_writers) {
5841 lock_ReleaseMutex(&fidp->mx);
5842 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5843 lock_ObtainMutex(&fidp->mx);
5846 /* watch for ioctl closes, and read-only opens */
5848 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5849 == SMB_FID_OPENWRITE) {
5850 if (dosTime != 0 && dosTime != -1) {
5851 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5852 /* This fixes defect 10958 */
5853 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5854 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5856 lock_ReleaseMutex(&fidp->mx);
5857 code = cm_FSync(scp, userp, &req);
5858 lock_ObtainMutex(&fidp->mx);
5863 /* unlock any pending locks */
5864 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5865 scp->fileType == CM_SCACHETYPE_FILE) {
5869 lock_ReleaseMutex(&fidp->mx);
5871 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5873 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5874 lock_ObtainMutex(&scp->mx);
5876 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5877 CM_SCACHESYNC_NEEDCALLBACK
5878 | CM_SCACHESYNC_GETSTATUS
5879 | CM_SCACHESYNC_LOCK);
5883 "smb CoreClose SyncOp failure code 0x%x", tcode);
5884 goto post_syncopdone;
5887 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5889 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5893 lock_ReleaseMutex(&scp->mx);
5894 lock_ObtainMutex(&fidp->mx);
5897 if (fidp->flags & SMB_FID_DELONCLOSE) {
5900 lock_ReleaseMutex(&fidp->mx);
5902 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
5907 smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
5908 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5909 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5912 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5913 smb_NotifyChange(FILE_ACTION_REMOVED,
5914 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5915 dscp, fullPathp, NULL, TRUE);
5918 code = cm_Unlink(dscp, fullPathp, userp, &req);
5921 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5922 smb_NotifyChange(FILE_ACTION_REMOVED,
5923 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5924 dscp, fullPathp, NULL, TRUE);
5928 lock_ObtainMutex(&fidp->mx);
5929 fidp->flags &= ~SMB_FID_DELONCLOSE;
5932 /* if this was a newly created file, then clear the creator
5933 * in the stat cache entry. */
5934 if (fidp->flags & SMB_FID_CREATED) {
5936 fidp->flags &= ~SMB_FID_CREATED;
5939 if (fidp->flags & SMB_FID_NTOPEN) {
5940 cm_ReleaseSCache(fidp->NTopen_dscp);
5941 fidp->NTopen_dscp = NULL;
5942 free(fidp->NTopen_pathp);
5943 fidp->NTopen_pathp = NULL;
5944 fidp->flags &= ~SMB_FID_NTOPEN;
5946 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
5947 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
5950 if (fidp->NTopen_wholepathp) {
5951 free(fidp->NTopen_wholepathp);
5952 fidp->NTopen_wholepathp = NULL;
5956 cm_ReleaseSCache(fidp->scp);
5959 lock_ReleaseMutex(&fidp->mx);
5962 cm_ReleaseSCache(dscp);
5966 lock_ObtainMutex(&delscp->mx);
5968 delscp->flags |= CM_SCACHEFLAG_DELETED;
5969 lock_ReleaseMutex(&delscp->mx);
5971 cm_ReleaseSCache(delscp);
5975 lock_ObtainMutex(&scp->mx);
5976 if (nullcreator && scp->creator == userp)
5977 scp->creator = NULL;
5978 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5979 lock_ReleaseMutex(&scp->mx);
5980 cm_ReleaseSCache(scp);
5989 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5997 fid = smb_GetSMBParm(inp, 0);
5998 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6000 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6002 fid = smb_ChainFID(fid, inp);
6003 fidp = smb_FindFID(vcp, fid, 0);
6005 return CM_ERROR_BADFD;
6008 userp = smb_GetUserFromVCP(vcp, inp);
6010 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6012 smb_ReleaseFID(fidp);
6013 cm_ReleaseUser(userp);
6018 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6020 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6021 cm_user_t *userp, long *readp)
6027 osi_hyper_t fileLength;
6029 osi_hyper_t lastByte;
6030 osi_hyper_t bufferOffset;
6031 long bufIndex, nbytes;
6033 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6041 lock_ObtainMutex(&fidp->mx);
6044 lock_ObtainMutex(&scp->mx);
6046 if (offset.HighPart == 0) {
6047 chunk = offset.LowPart >> cm_logChunkSize;
6048 if (chunk != fidp->curr_chunk) {
6049 fidp->prev_chunk = fidp->curr_chunk;
6050 fidp->curr_chunk = chunk;
6052 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6055 lock_ReleaseMutex(&fidp->mx);
6057 /* start by looking up the file's end */
6058 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6059 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6063 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6065 /* now we have the entry locked, look up the length */
6066 fileLength = scp->length;
6068 /* adjust count down so that it won't go past EOF */
6069 thyper.LowPart = count;
6070 thyper.HighPart = 0;
6071 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6073 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6074 /* we'd read past EOF, so just stop at fileLength bytes.
6075 * Start by computing how many bytes remain in the file.
6077 thyper = LargeIntegerSubtract(fileLength, offset);
6079 /* if we are past EOF, read 0 bytes */
6080 if (LargeIntegerLessThanZero(thyper))
6083 count = thyper.LowPart;
6088 /* now, copy the data one buffer at a time,
6089 * until we've filled the request packet
6092 /* if we've copied all the data requested, we're done */
6093 if (count <= 0) break;
6095 /* otherwise, load up a buffer of data */
6096 thyper.HighPart = offset.HighPart;
6097 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6098 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6101 buf_Release(bufferp);
6104 lock_ReleaseMutex(&scp->mx);
6106 code = buf_Get(scp, &thyper, &bufferp);
6108 lock_ObtainMutex(&scp->mx);
6109 if (code) goto done;
6110 bufferOffset = thyper;
6112 /* now get the data in the cache */
6114 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6115 CM_SCACHESYNC_NEEDCALLBACK |
6116 CM_SCACHESYNC_READ);
6120 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6122 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6124 /* otherwise, load the buffer and try again */
6125 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6129 buf_Release(bufferp);
6133 } /* if (wrong buffer) ... */
6135 /* now we have the right buffer loaded. Copy out the
6136 * data from here to the user's buffer.
6138 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6140 /* and figure out how many bytes we want from this buffer */
6141 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6142 if (nbytes > count) nbytes = count; /* don't go past EOF */
6144 /* now copy the data */
6145 memcpy(op, bufferp->datap + bufIndex, nbytes);
6147 /* adjust counters, pointers, etc. */
6150 thyper.LowPart = nbytes;
6151 thyper.HighPart = 0;
6152 offset = LargeIntegerAdd(thyper, offset);
6156 lock_ReleaseMutex(&scp->mx);
6158 buf_Release(bufferp);
6160 if (code == 0 && sequential)
6161 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6163 cm_ReleaseSCache(scp);
6169 * smb_WriteData -- common code for Write and Raw Write
6171 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6172 cm_user_t *userp, long *writtenp)
6174 osi_hyper_t offset = *offsetp;
6178 osi_hyper_t fileLength; /* file's length at start of write */
6179 osi_hyper_t minLength; /* don't read past this */
6180 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6181 cm_buf_t *bufferp = NULL;
6182 osi_hyper_t thyper; /* hyper tmp variable */
6183 osi_hyper_t bufferOffset;
6184 afs_uint32 bufIndex; /* index in buffer where our data is */
6185 int doWriteBack = 0;
6186 osi_hyper_t writeBackOffset;/* offset of region to write back when
6191 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6192 fidp->fid, offsetp->LowPart, count);
6198 lock_ObtainMutex(&fidp->mx);
6199 /* make sure we have a writable FD */
6200 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6201 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6202 fidp->fid, fidp->flags);
6203 lock_ReleaseMutex(&fidp->mx);
6204 code = CM_ERROR_BADFDOP;
6210 lock_ReleaseMutex(&fidp->mx);
6212 lock_ObtainMutex(&scp->mx);
6213 /* start by looking up the file's end */
6214 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6215 CM_SCACHESYNC_NEEDCALLBACK
6216 | CM_SCACHESYNC_SETSTATUS
6217 | CM_SCACHESYNC_GETSTATUS);
6221 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6223 /* now we have the entry locked, look up the length */
6224 fileLength = scp->length;
6225 minLength = fileLength;
6226 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6227 minLength = scp->serverLength;
6229 /* adjust file length if we extend past EOF */
6230 thyper.LowPart = count;
6231 thyper.HighPart = 0;
6232 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6233 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6234 /* we'd write past EOF, so extend the file */
6235 scp->mask |= CM_SCACHEMASK_LENGTH;
6236 scp->length = thyper;
6237 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6239 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6241 /* now, if the new position (thyper) and the old (offset) are in
6242 * different storeback windows, remember to store back the previous
6243 * storeback window when we're done with the write.
6245 * the purpose of this logic is to slow down the CIFS client
6246 * in order to avoid the client disconnecting during the CLOSE
6247 * operation if there are too many dirty buffers left to write
6248 * than can be accomplished during 45 seconds. This used to be
6249 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6250 * so that we can read larger amounts of data at a time.
6252 if ((thyper.LowPart & ~(cm_data.buf_blockSize-1)) !=
6253 (offset.LowPart & ~(cm_data.buf_blockSize-1))) {
6254 /* they're different */
6256 writeBackOffset.HighPart = offset.HighPart;
6257 writeBackOffset.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6262 /* now, copy the data one buffer at a time, until we've filled the
6265 /* if we've copied all the data requested, we're done */
6269 /* handle over quota or out of space */
6270 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6271 *writtenp = written;
6272 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6276 /* otherwise, load up a buffer of data */
6277 thyper.HighPart = offset.HighPart;
6278 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6279 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6282 lock_ReleaseMutex(&bufferp->mx);
6283 buf_Release(bufferp);
6286 lock_ReleaseMutex(&scp->mx);
6288 code = buf_Get(scp, &thyper, &bufferp);
6290 lock_ObtainMutex(&bufferp->mx);
6291 lock_ObtainMutex(&scp->mx);
6292 if (code) goto done;
6294 bufferOffset = thyper;
6296 /* now get the data in the cache */
6298 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6299 CM_SCACHESYNC_NEEDCALLBACK
6300 | CM_SCACHESYNC_WRITE
6301 | CM_SCACHESYNC_BUFLOCKED);
6305 cm_SyncOpDone(scp, bufferp,
6306 CM_SCACHESYNC_NEEDCALLBACK
6307 | CM_SCACHESYNC_WRITE
6308 | CM_SCACHESYNC_BUFLOCKED);
6310 /* If we're overwriting the entire buffer, or
6311 * if we're writing at or past EOF, mark the
6312 * buffer as current so we don't call
6313 * cm_GetBuffer. This skips the fetch from the
6314 * server in those cases where we're going to
6315 * obliterate all the data in the buffer anyway,
6316 * or in those cases where there is no useful
6317 * data at the server to start with.
6319 * Use minLength instead of scp->length, since
6320 * the latter has already been updated by this
6323 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6324 || LargeIntegerEqualTo(offset, bufferp->offset)
6325 && (count >= cm_data.buf_blockSize
6326 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6327 ConvertLongToLargeInteger(count)),
6329 if (count < cm_data.buf_blockSize
6330 && bufferp->dataVersion == -1)
6331 memset(bufferp->datap, 0,
6332 cm_data.buf_blockSize);
6333 bufferp->dataVersion = scp->dataVersion;
6336 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6338 /* otherwise, load the buffer and try again */
6339 lock_ReleaseMutex(&bufferp->mx);
6340 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6342 lock_ReleaseMutex(&scp->mx);
6343 lock_ObtainMutex(&bufferp->mx);
6344 lock_ObtainMutex(&scp->mx);
6348 lock_ReleaseMutex(&bufferp->mx);
6349 buf_Release(bufferp);
6353 } /* if (wrong buffer) ... */
6355 /* now we have the right buffer loaded. Copy out the
6356 * data from here to the user's buffer.
6358 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6360 /* and figure out how many bytes we want from this buffer */
6361 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6363 nbytes = count; /* don't go past end of request */
6365 /* now copy the data */
6366 memcpy(bufferp->datap + bufIndex, op, nbytes);
6367 buf_SetDirty(bufferp, bufIndex, nbytes);
6369 /* and record the last writer */
6370 if (bufferp->userp != userp) {
6373 cm_ReleaseUser(bufferp->userp);
6374 bufferp->userp = userp;
6377 /* adjust counters, pointers, etc. */
6381 thyper.LowPart = nbytes;
6382 thyper.HighPart = 0;
6383 offset = LargeIntegerAdd(thyper, offset);
6387 lock_ReleaseMutex(&scp->mx);
6390 lock_ReleaseMutex(&bufferp->mx);
6391 buf_Release(bufferp);
6394 lock_ObtainMutex(&fidp->mx);
6395 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6396 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6397 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6398 fidp->NTopen_dscp, fidp->NTopen_pathp,
6401 lock_ReleaseMutex(&fidp->mx);
6403 if (code == 0 && doWriteBack) {
6406 lock_ObtainMutex(&scp->mx);
6407 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6409 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6410 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6412 lock_ReleaseMutex(&scp->mx);
6413 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6414 writeBackOffset.HighPart,
6415 *writtenp & ~(cm_data.blockSize-1), 0, userp);
6416 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6419 cm_ReleaseSCache(scp);
6421 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6422 fidp->fid, code, *writtenp);
6426 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6429 unsigned short count;
6431 unsigned short hint;
6432 long written = 0, total_written = 0;
6437 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6439 int inDataBlockCount;
6441 fd = smb_GetSMBParm(inp, 0);
6442 count = smb_GetSMBParm(inp, 1);
6443 offset.HighPart = 0; /* too bad */
6444 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6445 hint = smb_GetSMBParm(inp, 4);
6447 op = smb_GetSMBData(inp, NULL);
6448 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6450 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6451 fd, offset.LowPart, count);
6453 fd = smb_ChainFID(fd, inp);
6454 fidp = smb_FindFID(vcp, fd, 0);
6456 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6457 return CM_ERROR_BADFD;
6460 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6461 smb_CloseFID(vcp, fidp, NULL, 0);
6462 smb_ReleaseFID(fidp);
6463 return CM_ERROR_NOSUCHFILE;
6466 lock_ObtainMutex(&fidp->mx);
6467 if (fidp->flags & SMB_FID_IOCTL) {
6468 lock_ReleaseMutex(&fidp->mx);
6469 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6470 smb_ReleaseFID(fidp);
6471 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6474 lock_ReleaseMutex(&fidp->mx);
6475 userp = smb_GetUserFromVCP(vcp, inp);
6479 LARGE_INTEGER LOffset;
6480 LARGE_INTEGER LLength;
6482 pid = ((smb_t *) inp)->pid;
6483 key = cm_GenerateKey(vcp->vcID, pid, fd);
6485 LOffset.HighPart = offset.HighPart;
6486 LOffset.LowPart = offset.LowPart;
6487 LLength.HighPart = 0;
6488 LLength.LowPart = count;
6490 lock_ObtainMutex(&fidp->scp->mx);
6491 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6492 lock_ReleaseMutex(&fidp->scp->mx);
6495 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6500 /* special case: 0 bytes transferred means truncate to this position */
6504 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6508 truncAttr.mask = CM_ATTRMASK_LENGTH;
6509 truncAttr.length.LowPart = offset.LowPart;
6510 truncAttr.length.HighPart = 0;
6511 lock_ObtainMutex(&fidp->mx);
6512 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6513 fidp->flags |= SMB_FID_LENGTHSETDONE;
6514 lock_ReleaseMutex(&fidp->mx);
6515 smb_SetSMBParm(outp, 0, 0 /* count */);
6516 smb_SetSMBDataLength(outp, 0);
6521 * Work around bug in NT client
6523 * When copying a file, the NT client should first copy the data,
6524 * then copy the last write time. But sometimes the NT client does
6525 * these in the wrong order, so the data copies would inadvertently
6526 * cause the last write time to be overwritten. We try to detect this,
6527 * and don't set client mod time if we think that would go against the
6530 lock_ObtainMutex(&fidp->mx);
6531 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6532 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6533 fidp->scp->clientModTime = time(NULL);
6535 lock_ReleaseMutex(&fidp->mx);
6538 while ( code == 0 && count > 0 ) {
6539 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6540 if (code == 0 && written == 0)
6541 code = CM_ERROR_PARTIALWRITE;
6543 offset = LargeIntegerAdd(offset,
6544 ConvertLongToLargeInteger(written));
6545 count -= (unsigned short)written;
6546 total_written += written;
6550 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6551 total_written, code);
6553 /* set the packet data length to 3 bytes for the data block header,
6554 * plus the size of the data.
6556 smb_SetSMBParm(outp, 0, total_written);
6557 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6558 smb_SetSMBParm(outp, 3, hint);
6559 smb_SetSMBDataLength(outp, 0);
6562 smb_ReleaseFID(fidp);
6563 cm_ReleaseUser(userp);
6568 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6569 NCB *ncbp, raw_write_cont_t *rwcp)
6578 fd = smb_GetSMBParm(inp, 0);
6579 fidp = smb_FindFID(vcp, fd, 0);
6581 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6582 smb_CloseFID(vcp, fidp, NULL, 0);
6583 smb_ReleaseFID(fidp);
6587 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6588 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6590 userp = smb_GetUserFromVCP(vcp, inp);
6593 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6595 if (rwcp->writeMode & 0x1) { /* synchronous */
6598 smb_FormatResponsePacket(vcp, inp, outp);
6599 op = (smb_t *) outp;
6600 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6601 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6602 smb_SetSMBDataLength(outp, 0);
6603 smb_SendPacket(vcp, outp);
6604 smb_FreePacket(outp);
6606 else { /* asynchronous */
6607 lock_ObtainMutex(&fidp->mx);
6608 fidp->raw_writers--;
6609 if (fidp->raw_writers == 0)
6610 thrd_SetEvent(fidp->raw_write_event);
6611 lock_ReleaseMutex(&fidp->mx);
6614 /* Give back raw buffer */
6615 lock_ObtainMutex(&smb_RawBufLock);
6616 *((char **)rawBuf) = smb_RawBufs;
6617 smb_RawBufs = rawBuf;
6618 lock_ReleaseMutex(&smb_RawBufLock);
6620 smb_ReleaseFID(fidp);
6621 cm_ReleaseUser(userp);
6624 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6629 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6632 long count, written = 0, total_written = 0;
6639 unsigned short writeMode;
6641 fd = smb_GetSMBParm(inp, 0);
6642 totalCount = smb_GetSMBParm(inp, 1);
6643 count = smb_GetSMBParm(inp, 10);
6644 writeMode = smb_GetSMBParm(inp, 7);
6646 op = (char *) inp->data;
6647 op += smb_GetSMBParm(inp, 11);
6649 offset.HighPart = 0;
6650 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6652 if (*inp->wctp == 14) {
6653 /* we received a 64-bit file offset */
6654 #ifdef AFS_LARGEFILES
6655 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6657 if (LargeIntegerLessThanZero(offset)) {
6659 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6660 offset.HighPart, offset.LowPart);
6661 return CM_ERROR_BADSMB;
6664 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6666 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6667 return CM_ERROR_BADSMB;
6670 offset.HighPart = 0;
6673 offset.HighPart = 0; /* 32-bit file offset */
6677 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6678 fd, offset.HighPart, offset.LowPart, count);
6680 " WriteRaw WriteMode 0x%x",
6683 fd = smb_ChainFID(fd, inp);
6684 fidp = smb_FindFID(vcp, fd, 0);
6686 return CM_ERROR_BADFD;
6689 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6690 smb_CloseFID(vcp, fidp, NULL, 0);
6691 smb_ReleaseFID(fidp);
6692 return CM_ERROR_NOSUCHFILE;
6698 LARGE_INTEGER LOffset;
6699 LARGE_INTEGER LLength;
6701 pid = ((smb_t *) inp)->pid;
6702 key = cm_GenerateKey(vcp->vcID, pid, fd);
6704 LOffset.HighPart = offset.HighPart;
6705 LOffset.LowPart = offset.LowPart;
6706 LLength.HighPart = 0;
6707 LLength.LowPart = count;
6709 lock_ObtainMutex(&fidp->scp->mx);
6710 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6711 lock_ReleaseMutex(&fidp->scp->mx);
6714 smb_ReleaseFID(fidp);
6719 userp = smb_GetUserFromVCP(vcp, inp);
6722 * Work around bug in NT client
6724 * When copying a file, the NT client should first copy the data,
6725 * then copy the last write time. But sometimes the NT client does
6726 * these in the wrong order, so the data copies would inadvertently
6727 * cause the last write time to be overwritten. We try to detect this,
6728 * and don't set client mod time if we think that would go against the
6731 lock_ObtainMutex(&fidp->mx);
6732 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6733 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6734 fidp->scp->clientModTime = time(NULL);
6736 lock_ReleaseMutex(&fidp->mx);
6739 while ( code == 0 && count > 0 ) {
6740 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6741 if (code == 0 && written == 0)
6742 code = CM_ERROR_PARTIALWRITE;
6744 offset = LargeIntegerAdd(offset,
6745 ConvertLongToLargeInteger(written));
6748 total_written += written;
6752 /* Get a raw buffer */
6755 lock_ObtainMutex(&smb_RawBufLock);
6757 /* Get a raw buf, from head of list */
6758 rawBuf = smb_RawBufs;
6759 smb_RawBufs = *(char **)smb_RawBufs;
6762 code = CM_ERROR_USESTD;
6764 lock_ReleaseMutex(&smb_RawBufLock);
6767 /* Don't allow a premature Close */
6768 if (code == 0 && (writeMode & 1) == 0) {
6769 lock_ObtainMutex(&fidp->mx);
6770 fidp->raw_writers++;
6771 thrd_ResetEvent(fidp->raw_write_event);
6772 lock_ReleaseMutex(&fidp->mx);
6775 smb_ReleaseFID(fidp);
6776 cm_ReleaseUser(userp);
6779 smb_SetSMBParm(outp, 0, total_written);
6780 smb_SetSMBDataLength(outp, 0);
6781 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6786 offset = LargeIntegerAdd(offset,
6787 ConvertLongToLargeInteger(count));
6791 rwcp->offset.HighPart = offset.HighPart;
6792 rwcp->offset.LowPart = offset.LowPart;
6793 rwcp->count = totalCount - count;
6794 rwcp->writeMode = writeMode;
6795 rwcp->alreadyWritten = total_written;
6797 /* set the packet data length to 3 bytes for the data block header,
6798 * plus the size of the data.
6800 smb_SetSMBParm(outp, 0, 0xffff);
6801 smb_SetSMBDataLength(outp, 0);
6806 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6809 long count, finalCount;
6817 fd = smb_GetSMBParm(inp, 0);
6818 count = smb_GetSMBParm(inp, 1);
6819 offset.HighPart = 0; /* too bad */
6820 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6822 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6823 fd, offset.LowPart, count);
6825 fd = smb_ChainFID(fd, inp);
6826 fidp = smb_FindFID(vcp, fd, 0);
6828 return CM_ERROR_BADFD;
6830 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6831 smb_CloseFID(vcp, fidp, NULL, 0);
6832 smb_ReleaseFID(fidp);
6833 return CM_ERROR_NOSUCHFILE;
6836 lock_ObtainMutex(&fidp->mx);
6837 if (fidp->flags & SMB_FID_IOCTL) {
6838 lock_ReleaseMutex(&fidp->mx);
6839 code = smb_IoctlRead(fidp, vcp, inp, outp);
6840 smb_ReleaseFID(fidp);
6843 lock_ReleaseMutex(&fidp->mx);
6846 LARGE_INTEGER LOffset, LLength;
6849 pid = ((smb_t *) inp)->pid;
6850 key = cm_GenerateKey(vcp->vcID, pid, fd);
6852 LOffset.HighPart = 0;
6853 LOffset.LowPart = offset.LowPart;
6854 LLength.HighPart = 0;
6855 LLength.LowPart = count;
6857 lock_ObtainMutex(&fidp->scp->mx);
6858 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6859 lock_ReleaseMutex(&fidp->scp->mx);
6862 smb_ReleaseFID(fidp);
6866 userp = smb_GetUserFromVCP(vcp, inp);
6868 /* remember this for final results */
6869 smb_SetSMBParm(outp, 0, count);
6870 smb_SetSMBParm(outp, 1, 0);
6871 smb_SetSMBParm(outp, 2, 0);
6872 smb_SetSMBParm(outp, 3, 0);
6873 smb_SetSMBParm(outp, 4, 0);
6875 /* set the packet data length to 3 bytes for the data block header,
6876 * plus the size of the data.
6878 smb_SetSMBDataLength(outp, count+3);
6880 /* get op ptr after putting in the parms, since otherwise we don't
6881 * know where the data really is.
6883 op = smb_GetSMBData(outp, NULL);
6885 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6886 *op++ = 1; /* data block marker */
6887 *op++ = (unsigned char) (count & 0xff);
6888 *op++ = (unsigned char) ((count >> 8) & 0xff);
6890 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6892 /* fix some things up */
6893 smb_SetSMBParm(outp, 0, finalCount);
6894 smb_SetSMBDataLength(outp, finalCount+3);
6896 smb_ReleaseFID(fidp);
6898 cm_ReleaseUser(userp);
6902 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6909 cm_scache_t *dscp; /* dir we're dealing with */
6910 cm_scache_t *scp; /* file we're creating */
6912 int initialModeBits;
6922 /* compute initial mode bits based on read-only flag in attributes */
6923 initialModeBits = 0777;
6925 tp = smb_GetSMBData(inp, NULL);
6926 pathp = smb_ParseASCIIBlock(tp, &tp);
6927 if (smb_StoreAnsiFilenames)
6928 OemToChar(pathp,pathp);
6930 if (strcmp(pathp, "\\") == 0)
6931 return CM_ERROR_EXISTS;
6933 spacep = inp->spacep;
6934 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6936 userp = smb_GetUserFromVCP(vcp, inp);
6938 caseFold = CM_FLAG_CASEFOLD;
6940 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6942 cm_ReleaseUser(userp);
6943 return CM_ERROR_NOSUCHPATH;
6946 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6947 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6948 userp, tidPathp, &req, &dscp);
6951 cm_ReleaseUser(userp);
6956 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6957 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
6958 cm_ReleaseSCache(dscp);
6959 cm_ReleaseUser(userp);
6960 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6961 return CM_ERROR_PATH_NOT_COVERED;
6963 return CM_ERROR_BADSHARENAME;
6965 #endif /* DFS_SUPPORT */
6967 /* otherwise, scp points to the parent directory. Do a lookup, and
6968 * fail if we find it. Otherwise, we do the create.
6974 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6975 if (scp) cm_ReleaseSCache(scp);
6976 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6977 if (code == 0) code = CM_ERROR_EXISTS;
6978 cm_ReleaseSCache(dscp);
6979 cm_ReleaseUser(userp);
6983 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6984 setAttr.clientModTime = time(NULL);
6985 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6986 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6987 smb_NotifyChange(FILE_ACTION_ADDED,
6988 FILE_NOTIFY_CHANGE_DIR_NAME,
6989 dscp, lastNamep, NULL, TRUE);
6991 /* we don't need this any longer */
6992 cm_ReleaseSCache(dscp);
6995 /* something went wrong creating or truncating the file */
6996 cm_ReleaseUser(userp);
7000 /* otherwise we succeeded */
7001 smb_SetSMBDataLength(outp, 0);
7002 cm_ReleaseUser(userp);
7007 BOOL smb_IsLegalFilename(char *filename)
7010 * Find the longest substring of filename that does not contain
7011 * any of the chars in illegalChars. If that substring is less
7012 * than the length of the whole string, then one or more of the
7013 * illegal chars is in filename.
7015 if (strcspn(filename, illegalChars) < strlen(filename))
7021 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7029 cm_scache_t *dscp; /* dir we're dealing with */
7030 cm_scache_t *scp; /* file we're creating */
7032 int initialModeBits;
7040 int created = 0; /* the file was new */
7045 excl = (inp->inCom == 0x03)? 0 : 1;
7047 attributes = smb_GetSMBParm(inp, 0);
7048 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7050 /* compute initial mode bits based on read-only flag in attributes */
7051 initialModeBits = 0666;
7052 if (attributes & SMB_ATTR_READONLY)
7053 initialModeBits &= ~0222;
7055 tp = smb_GetSMBData(inp, NULL);
7056 pathp = smb_ParseASCIIBlock(tp, &tp);
7057 if (smb_StoreAnsiFilenames)
7058 OemToChar(pathp,pathp);
7060 spacep = inp->spacep;
7061 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7063 userp = smb_GetUserFromVCP(vcp, inp);
7065 caseFold = CM_FLAG_CASEFOLD;
7067 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7069 cm_ReleaseUser(userp);
7070 return CM_ERROR_NOSUCHPATH;
7072 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7073 userp, tidPathp, &req, &dscp);
7076 cm_ReleaseUser(userp);
7081 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7082 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7083 cm_ReleaseSCache(dscp);
7084 cm_ReleaseUser(userp);
7085 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7086 return CM_ERROR_PATH_NOT_COVERED;
7088 return CM_ERROR_BADSHARENAME;
7090 #endif /* DFS_SUPPORT */
7092 /* otherwise, scp points to the parent directory. Do a lookup, and
7093 * truncate the file if we find it, otherwise we create the file.
7100 if (!smb_IsLegalFilename(lastNamep))
7101 return CM_ERROR_BADNTFILENAME;
7103 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7104 #ifdef DEBUG_VERBOSE
7107 hexp = osi_HexifyString( lastNamep );
7108 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7113 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7114 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7115 cm_ReleaseSCache(dscp);
7116 cm_ReleaseUser(userp);
7120 /* if we get here, if code is 0, the file exists and is represented by
7121 * scp. Otherwise, we have to create it.
7125 /* oops, file shouldn't be there */
7126 cm_ReleaseSCache(dscp);
7127 cm_ReleaseSCache(scp);
7128 cm_ReleaseUser(userp);
7129 return CM_ERROR_EXISTS;
7132 setAttr.mask = CM_ATTRMASK_LENGTH;
7133 setAttr.length.LowPart = 0;
7134 setAttr.length.HighPart = 0;
7135 code = cm_SetAttr(scp, &setAttr, userp, &req);
7138 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7139 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7140 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7144 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7145 smb_NotifyChange(FILE_ACTION_ADDED,
7146 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7147 dscp, lastNamep, NULL, TRUE);
7148 } else if (!excl && code == CM_ERROR_EXISTS) {
7149 /* not an exclusive create, and someone else tried
7150 * creating it already, then we open it anyway. We
7151 * don't bother retrying after this, since if this next
7152 * fails, that means that the file was deleted after
7153 * we started this call.
7155 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7158 setAttr.mask = CM_ATTRMASK_LENGTH;
7159 setAttr.length.LowPart = 0;
7160 setAttr.length.HighPart = 0;
7161 code = cm_SetAttr(scp, &setAttr, userp, &req);
7166 /* we don't need this any longer */
7167 cm_ReleaseSCache(dscp);
7170 /* something went wrong creating or truncating the file */
7171 if (scp) cm_ReleaseSCache(scp);
7172 cm_ReleaseUser(userp);
7176 /* make sure we only open files */
7177 if (scp->fileType != CM_SCACHETYPE_FILE) {
7178 cm_ReleaseSCache(scp);
7179 cm_ReleaseUser(userp);
7180 return CM_ERROR_ISDIR;
7183 /* now all we have to do is open the file itself */
7184 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7185 osi_assertx(fidp, "null smb_fid_t");
7189 lock_ObtainMutex(&fidp->mx);
7190 /* always create it open for read/write */
7191 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7193 /* remember that the file was newly created */
7195 fidp->flags |= SMB_FID_CREATED;
7197 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7199 /* save a pointer to the vnode */
7201 lock_ObtainMutex(&scp->mx);
7202 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7203 lock_ReleaseMutex(&scp->mx);
7206 fidp->userp = userp;
7207 lock_ReleaseMutex(&fidp->mx);
7209 smb_SetSMBParm(outp, 0, fidp->fid);
7210 smb_SetSMBDataLength(outp, 0);
7212 cm_Open(scp, 0, userp);
7214 smb_ReleaseFID(fidp);
7215 cm_ReleaseUser(userp);
7216 /* leave scp held since we put it in fidp->scp */
7220 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7223 osi_hyper_t new_offset;
7234 fd = smb_GetSMBParm(inp, 0);
7235 whence = smb_GetSMBParm(inp, 1);
7236 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7238 /* try to find the file descriptor */
7239 fd = smb_ChainFID(fd, inp);
7240 fidp = smb_FindFID(vcp, fd, 0);
7242 return CM_ERROR_BADFD;
7244 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7245 smb_CloseFID(vcp, fidp, NULL, 0);
7246 smb_ReleaseFID(fidp);
7247 return CM_ERROR_NOSUCHFILE;
7250 lock_ObtainMutex(&fidp->mx);
7251 if (fidp->flags & SMB_FID_IOCTL) {
7252 lock_ReleaseMutex(&fidp->mx);
7253 smb_ReleaseFID(fidp);
7254 return CM_ERROR_BADFD;
7256 lock_ReleaseMutex(&fidp->mx);
7258 userp = smb_GetUserFromVCP(vcp, inp);
7260 lock_ObtainMutex(&fidp->mx);
7263 lock_ReleaseMutex(&fidp->mx);
7264 lock_ObtainMutex(&scp->mx);
7265 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7266 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7268 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7270 /* offset from current offset */
7271 new_offset = LargeIntegerAdd(fidp->offset,
7272 ConvertLongToLargeInteger(offset));
7274 else if (whence == 2) {
7275 /* offset from current EOF */
7276 new_offset = LargeIntegerAdd(scp->length,
7277 ConvertLongToLargeInteger(offset));
7279 new_offset = ConvertLongToLargeInteger(offset);
7282 fidp->offset = new_offset;
7283 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7284 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7285 smb_SetSMBDataLength(outp, 0);
7287 lock_ReleaseMutex(&scp->mx);
7288 smb_ReleaseFID(fidp);
7289 cm_ReleaseSCache(scp);
7290 cm_ReleaseUser(userp);
7294 /* dispatch all of the requests received in a packet. Due to chaining, this may
7295 * be more than one request.
7297 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7298 NCB *ncbp, raw_write_cont_t *rwcp)
7302 unsigned long code = 0;
7303 unsigned char *outWctp;
7304 int nparms; /* # of bytes of parameters */
7306 int nbytes; /* bytes of data, excluding count */
7309 unsigned short errCode;
7310 unsigned long NTStatus;
7312 unsigned char errClass;
7313 unsigned int oldGen;
7314 DWORD oldTime, newTime;
7316 /* get easy pointer to the data */
7317 smbp = (smb_t *) inp->data;
7319 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7320 /* setup the basic parms for the initial request in the packet */
7321 inp->inCom = smbp->com;
7322 inp->wctp = &smbp->wct;
7324 inp->ncb_length = ncbp->ncb_length;
7329 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7330 /* log it and discard it */
7331 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7332 __FILE__, __LINE__, ncbp->ncb_length);
7333 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7337 /* We are an ongoing op */
7338 thrd_Increment(&ongoingOps);
7340 /* set up response packet for receiving output */
7341 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7342 smb_FormatResponsePacket(vcp, inp, outp);
7343 outWctp = outp->wctp;
7345 /* Remember session generation number and time */
7346 oldGen = sessionGen;
7347 oldTime = GetTickCount();
7349 while (inp->inCom != 0xff) {
7350 dp = &smb_dispatchTable[inp->inCom];
7352 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7353 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7354 code = outp->resumeCode;
7358 /* process each request in the packet; inCom, wctp and inCount
7359 * are already set up.
7361 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7364 /* now do the dispatch */
7365 /* start by formatting the response record a little, as a default */
7366 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7368 outWctp[1] = 0xff; /* no operation */
7369 outWctp[2] = 0; /* padding */
7374 /* not a chained request, this is a more reasonable default */
7375 outWctp[0] = 0; /* wct of zero */
7376 outWctp[1] = 0; /* and bcc (word) of zero */
7380 /* once set, stays set. Doesn't matter, since we never chain
7381 * "no response" calls.
7383 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7387 /* we have a recognized operation */
7388 char * opName = myCrt_Dispatch(inp->inCom);
7390 if (inp->inCom == 0x1d)
7392 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7394 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",opName,vcp,vcp->lana,vcp->lsn);
7395 code = (*(dp->procp)) (vcp, inp, outp);
7396 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7398 if ( code == CM_ERROR_BADSMB ||
7399 code == CM_ERROR_BADOP )
7401 #endif /* LOG_PACKET */
7404 newTime = GetTickCount();
7405 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
7407 if (oldGen != sessionGen) {
7408 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7409 newTime - oldTime, ncbp->ncb_length);
7410 osi_Log3(smb_logp, "Request %s straddled session startup, "
7411 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
7415 /* bad opcode, fail the request, after displaying it */
7416 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7419 #endif /* LOG_PACKET */
7422 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7423 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7424 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7425 if (code == IDCANCEL)
7428 code = CM_ERROR_BADOP;
7431 /* catastrophic failure: log as much as possible */
7432 if (code == CM_ERROR_BADSMB) {
7433 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7437 #endif /* LOG_PACKET */
7438 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7441 code = CM_ERROR_INVAL;
7444 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7445 thrd_Decrement(&ongoingOps);
7450 /* now, if we failed, turn the current response into an empty
7451 * one, and fill in the response packet's error code.
7454 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7455 smb_MapNTError(code, &NTStatus);
7456 outWctp = outp->wctp;
7457 smbp = (smb_t *) &outp->data;
7458 if (code != CM_ERROR_PARTIALWRITE
7459 && code != CM_ERROR_BUFFERTOOSMALL
7460 && code != CM_ERROR_GSSCONTINUE) {
7461 /* nuke wct and bcc. For a partial
7462 * write or an in-process authentication handshake,
7463 * assume they're OK.
7469 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7470 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7471 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7472 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7473 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7477 smb_MapCoreError(code, vcp, &errCode, &errClass);
7478 outWctp = outp->wctp;
7479 smbp = (smb_t *) &outp->data;
7480 if (code != CM_ERROR_PARTIALWRITE) {
7481 /* nuke wct and bcc. For a partial
7482 * write, assume they're OK.
7488 smbp->errLow = (unsigned char) (errCode & 0xff);
7489 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7490 smbp->rcls = errClass;
7493 } /* error occurred */
7495 /* if we're here, we've finished one request. Look to see if
7496 * this is a chained opcode. If it is, setup things to process
7497 * the chained request, and setup the output buffer to hold the
7498 * chained response. Start by finding the next input record.
7500 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7501 break; /* not a chained req */
7502 tp = inp->wctp; /* points to start of last request */
7503 /* in a chained request, the first two
7504 * parm fields are required, and are
7505 * AndXCommand/AndXReserved and
7507 if (tp[0] < 2) break;
7508 if (tp[1] == 0xff) break; /* no more chained opcodes */
7510 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7513 /* and now append the next output request to the end of this
7514 * last request. Begin by finding out where the last response
7515 * ends, since that's where we'll put our new response.
7517 outWctp = outp->wctp; /* ptr to out parameters */
7518 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7519 nparms = outWctp[0] << 1;
7520 tp = outWctp + nparms + 1; /* now points to bcc field */
7521 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7522 tp += 2 /* for the count itself */ + nbytes;
7523 /* tp now points to the new output record; go back and patch the
7524 * second parameter (off2) to point to the new record.
7526 temp = (unsigned int)(tp - outp->data);
7527 outWctp[3] = (unsigned char) (temp & 0xff);
7528 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7529 outWctp[2] = 0; /* padding */
7530 outWctp[1] = inp->inCom; /* next opcode */
7532 /* finally, setup for the next iteration */
7535 } /* while loop over all requests in the packet */
7537 /* now send the output packet, and return */
7539 smb_SendPacket(vcp, outp);
7540 thrd_Decrement(&ongoingOps);
7545 /* Wait for Netbios() calls to return, and make the results available to server
7546 * threads. Note that server threads can't wait on the NCBevents array
7547 * themselves, because NCB events are manual-reset, and the servers would race
7548 * each other to reset them.
7550 void smb_ClientWaiter(void *parmp)
7555 while (smbShutdownFlag == 0) {
7556 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7558 if (code == WAIT_OBJECT_0)
7561 /* error checking */
7562 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7564 int abandonIdx = code - WAIT_ABANDONED_0;
7565 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7568 if (code == WAIT_IO_COMPLETION)
7570 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7574 if (code == WAIT_TIMEOUT)
7576 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7579 if (code == WAIT_FAILED)
7581 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7584 idx = code - WAIT_OBJECT_0;
7586 /* check idx range! */
7587 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7589 /* this is fatal - log as much as possible */
7590 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7591 osi_assertx(0, "invalid index");
7594 thrd_ResetEvent(NCBevents[idx]);
7595 thrd_SetEvent(NCBreturns[0][idx]);
7600 * Try to have one NCBRECV request waiting for every live session. Not more
7601 * than one, because if there is more than one, it's hard to handle Write Raw.
7603 void smb_ServerWaiter(void *parmp)
7606 int idx_session, idx_NCB;
7609 while (smbShutdownFlag == 0) {
7611 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7613 if (code == WAIT_OBJECT_0)
7616 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7618 int abandonIdx = code - WAIT_ABANDONED_0;
7619 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7622 if (code == WAIT_IO_COMPLETION)
7624 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7628 if (code == WAIT_TIMEOUT)
7630 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7633 if (code == WAIT_FAILED)
7635 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7638 idx_session = code - WAIT_OBJECT_0;
7640 /* check idx range! */
7641 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7643 /* this is fatal - log as much as possible */
7644 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7645 osi_assertx(0, "invalid index");
7650 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7652 if (code == WAIT_OBJECT_0) {
7653 if (smbShutdownFlag == 1)
7659 /* error checking */
7660 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7662 int abandonIdx = code - WAIT_ABANDONED_0;
7663 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7666 if (code == WAIT_IO_COMPLETION)
7668 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7672 if (code == WAIT_TIMEOUT)
7674 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7677 if (code == WAIT_FAILED)
7679 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7682 idx_NCB = code - WAIT_OBJECT_0;
7684 /* check idx range! */
7685 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7687 /* this is fatal - log as much as possible */
7688 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7689 osi_assertx(0, "invalid index");
7692 /* Link them together */
7693 NCBsessions[idx_NCB] = idx_session;
7696 ncbp = NCBs[idx_NCB];
7697 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7698 ncbp->ncb_command = NCBRECV | ASYNCH;
7699 ncbp->ncb_lana_num = lanas[idx_session];
7700 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7701 ncbp->ncb_event = NCBevents[idx_NCB];
7702 ncbp->ncb_length = SMB_PACKETSIZE;
7708 * The top level loop for handling SMB request messages. Each server thread
7709 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7710 * NCB and buffer for the incoming request are loaned to us.
7712 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7713 * to immediately send a request for the rest of the data. This must come
7714 * before any other traffic for that session, so we delay setting the session
7715 * event until that data has come in.
7717 void smb_Server(VOID *parmp)
7719 INT_PTR myIdx = (INT_PTR) parmp;
7723 smb_packet_t *outbufp;
7725 int idx_NCB, idx_session;
7727 smb_vc_t *vcp = NULL;
7730 rx_StartClientThread();
7733 outbufp = GetPacket();
7734 outbufp->ncbp = outncbp;
7742 smb_ResetServerPriority();
7744 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7747 /* terminate silently if shutdown flag is set */
7748 if (code == WAIT_OBJECT_0) {
7749 if (smbShutdownFlag == 1) {
7750 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7756 /* error checking */
7757 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7759 int abandonIdx = code - WAIT_ABANDONED_0;
7760 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7763 if (code == WAIT_IO_COMPLETION)
7765 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7769 if (code == WAIT_TIMEOUT)
7771 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7774 if (code == WAIT_FAILED)
7776 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7779 idx_NCB = code - WAIT_OBJECT_0;
7781 /* check idx range! */
7782 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7784 /* this is fatal - log as much as possible */
7785 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7786 osi_assertx(0, "invalid index");
7789 ncbp = NCBs[idx_NCB];
7790 idx_session = NCBsessions[idx_NCB];
7791 rc = ncbp->ncb_retcode;
7793 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7794 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7798 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7802 /* Can this happen? Or is it just my UNIX paranoia? */
7803 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7808 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7811 /* Client closed session */
7812 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7814 lock_ObtainMutex(&vcp->mx);
7815 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7816 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7818 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7819 lock_ReleaseMutex(&vcp->mx);
7820 lock_ObtainWrite(&smb_globalLock);
7821 dead_sessions[vcp->session] = TRUE;
7822 lock_ReleaseWrite(&smb_globalLock);
7823 smb_CleanupDeadVC(vcp);
7827 lock_ReleaseMutex(&vcp->mx);
7833 /* Treat as transient error */
7834 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7837 "dispatch smb recv failed, message incomplete, ncb_length %d",
7840 "SMB message incomplete, "
7841 "length %d", ncbp->ncb_length);
7844 * We used to discard the packet.
7845 * Instead, try handling it normally.
7849 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7853 /* A weird error code. Log it, sleep, and continue. */
7854 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7856 lock_ObtainMutex(&vcp->mx);
7857 if (vcp && vcp->errorCount++ > 3) {
7858 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7859 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7860 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7862 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7863 lock_ReleaseMutex(&vcp->mx);
7864 lock_ObtainWrite(&smb_globalLock);
7865 dead_sessions[vcp->session] = TRUE;
7866 lock_ReleaseWrite(&smb_globalLock);
7867 smb_CleanupDeadVC(vcp);
7871 lock_ReleaseMutex(&vcp->mx);
7877 lock_ReleaseMutex(&vcp->mx);
7879 thrd_SetEvent(SessionEvents[idx_session]);
7884 /* Success, so now dispatch on all the data in the packet */
7886 smb_concurrentCalls++;
7887 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7888 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7891 * If at this point vcp is NULL (implies that packet was invalid)
7892 * then we are in big trouble. This means either :
7893 * a) we have the wrong NCB.
7894 * b) Netbios screwed up the call.
7895 * c) The VC was already marked dead before we were able to
7897 * Obviously this implies that
7898 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7899 * lanas[idx_session] != ncbp->ncb_lana_num )
7900 * Either way, we can't do anything with this packet.
7901 * Log, sleep and resume.
7904 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7908 ncbp->ncb_lana_num);
7910 /* Also log in the trace log. */
7911 osi_Log4(smb_logp, "Server: VCP does not exist!"
7912 "LSNs[idx_session]=[%d],"
7913 "lanas[idx_session]=[%d],"
7914 "ncbp->ncb_lsn=[%d],"
7915 "ncbp->ncb_lana_num=[%d]",
7919 ncbp->ncb_lana_num);
7921 /* thrd_Sleep(1000); Don't bother sleeping */
7922 thrd_SetEvent(SessionEvents[idx_session]);
7923 smb_concurrentCalls--;
7927 smb_SetRequestStartTime();
7929 vcp->errorCount = 0;
7930 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7931 smbp = (smb_t *)bufp->data;
7936 if (smbp->com == 0x1d) {
7937 /* Special handling for Write Raw */
7938 raw_write_cont_t rwc;
7939 EVENT_HANDLE rwevent;
7940 char eventName[MAX_PATH];
7942 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7943 if (rwc.code == 0) {
7944 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7945 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7946 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7947 ncbp->ncb_command = NCBRECV | ASYNCH;
7948 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7949 ncbp->ncb_lana_num = vcp->lana;
7950 ncbp->ncb_buffer = rwc.buf;
7951 ncbp->ncb_length = 65535;
7952 ncbp->ncb_event = rwevent;
7954 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7955 thrd_CloseHandle(rwevent);
7957 thrd_SetEvent(SessionEvents[idx_session]);
7959 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7961 else if (smbp->com == 0xa0) {
7963 * Serialize the handling for NT Transact
7966 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7967 thrd_SetEvent(SessionEvents[idx_session]);
7969 thrd_SetEvent(SessionEvents[idx_session]);
7970 /* TODO: what else needs to be serialized? */
7971 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7974 __except( smb_ServerExceptionFilter() ) {
7977 smb_concurrentCalls--;
7980 thrd_SetEvent(NCBavails[idx_NCB]);
7987 * Exception filter for the server threads. If an exception occurs in the
7988 * dispatch routines, which is where exceptions are most common, then do a
7989 * force trace and give control to upstream exception handlers. Useful for
7992 DWORD smb_ServerExceptionFilter(void) {
7993 /* While this is not the best time to do a trace, if it succeeds, then
7994 * we have a trace (assuming tracing was enabled). Otherwise, this should
7995 * throw a second exception.
7997 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7998 afsd_ForceTrace(TRUE);
7999 buf_ForceTrace(TRUE);
8000 return EXCEPTION_CONTINUE_SEARCH;
8004 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8005 * If the number of server threads is M, and the number of live sessions is
8006 * N, then the number of NCB's in use at any time either waiting for, or
8007 * holding, received messages is M + N, so that is how many NCB's get created.
8009 void InitNCBslot(int idx)
8011 struct smb_packet *bufp;
8012 EVENT_HANDLE retHandle;
8014 char eventName[MAX_PATH];
8016 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8018 NCBs[idx] = GetNCB();
8019 sprintf(eventName,"NCBavails[%d]", idx);
8020 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8021 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8022 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8023 sprintf(eventName,"NCBevents[%d]", idx);
8024 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8025 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8026 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8027 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8028 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8029 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8030 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8031 for (i=0; i<smb_NumServerThreads; i++)
8032 NCBreturns[i][idx] = retHandle;
8034 bufp->spacep = cm_GetSpace();
8038 /* listen for new connections */
8039 void smb_Listener(void *parmp)
8045 int session, thread;
8046 smb_vc_t *vcp = NULL;
8048 char rname[NCBNAMSZ+1];
8049 char cname[MAX_COMPUTERNAME_LENGTH+1];
8050 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8051 INT_PTR lana = (INT_PTR) parmp;
8052 char eventName[MAX_PATH];
8054 sprintf(eventName,"smb_Listener_lana_%d", (char)lana);
8055 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8056 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8057 thrd_ResetEvent(ListenerShutdown[lana]);
8061 /* retrieve computer name */
8062 GetComputerName(cname, &cnamelen);
8065 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8066 memset(ncbp, 0, sizeof(NCB));
8069 ncbp->ncb_command = NCBLISTEN;
8070 ncbp->ncb_rto = 0; /* No receive timeout */
8071 ncbp->ncb_sto = 0; /* No send timeout */
8073 /* pad out with spaces instead of null termination */
8074 len = (long)strlen(smb_localNamep);
8075 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8076 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8078 strcpy(ncbp->ncb_callname, "*");
8079 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8081 ncbp->ncb_lana_num = (UCHAR)lana;
8083 code = Netbios(ncbp);
8085 if (code == NRC_NAMERR) {
8086 /* An smb shutdown or Vista resume must have taken place */
8088 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8089 ncbp->ncb_lana_num, code);
8091 if (lock_TryMutex(&smb_StartedLock)) {
8092 lana_list.lana[i] = LANA_INVALID;
8093 lock_ReleaseMutex(&smb_StartedLock);
8096 } else if (code == NRC_BRIDGE || code != 0) {
8097 int lanaRemaining = 0;
8099 while (!lock_TryMutex(&smb_StartedLock)) {
8100 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8106 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8107 ncbp->ncb_lana_num, ncb_error_string(code));
8109 for (i = 0; i < lana_list.length; i++) {
8110 if (lana_list.lana[i] == lana) {
8111 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8112 lana_list.lana[i] = LANA_INVALID;
8114 if (lana_list.lana[i] != LANA_INVALID)
8118 if (lanaRemaining == 0) {
8119 cm_VolStatus_Network_Stopped(cm_NetbiosName
8124 smb_ListenerState = SMB_LISTENER_STOPPED;
8125 smb_LANadapter = LANA_INVALID;
8126 lana_list.length = 0;
8128 lock_ReleaseMutex(&smb_StartedLock);
8132 else if (code != 0) {
8133 char tbuffer[AFSPATHMAX];
8135 /* terminate silently if shutdown flag is set */
8136 while (!lock_TryMutex(&smb_StartedLock)) {
8137 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8143 "NCBLISTEN lana=%d failed with code %d [%s]",
8144 ncbp->ncb_lana_num, code, ncb_error_string(code));
8146 "Client exiting due to network failure. Please restart client.\n");
8149 "Client exiting due to network failure. Please restart client.\n"
8150 "NCBLISTEN lana=%d failed with code %d [%s]",
8151 ncbp->ncb_lana_num, code, ncb_error_string(code));
8153 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8154 MB_OK|MB_SERVICE_NOTIFICATION);
8155 osi_panic(tbuffer, __FILE__, __LINE__);
8157 lock_ReleaseMutex(&smb_StartedLock);
8162 /* check for remote conns */
8163 /* first get remote name and insert null terminator */
8164 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8165 for (i=NCBNAMSZ; i>0; i--) {
8166 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8172 /* compare with local name */
8174 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8175 flags |= SMB_VCFLAG_REMOTECONN;
8178 lock_ObtainMutex(&smb_ListenerLock);
8180 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8181 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8183 /* now ncbp->ncb_lsn is the connection ID */
8184 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8185 if (vcp->session == 0) {
8186 /* New generation */
8187 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8190 /* Log session startup */
8192 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8193 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8194 #endif /* NOTSERVICE */
8195 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8196 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8198 if (reportSessionStartups) {
8199 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8202 lock_ObtainMutex(&vcp->mx);
8203 strcpy(vcp->rname, rname);
8204 vcp->flags |= flags;
8205 lock_ReleaseMutex(&vcp->mx);
8207 /* Allocate slot in session arrays */
8208 /* Re-use dead session if possible, otherwise add one more */
8209 /* But don't look at session[0], it is reserved */
8210 lock_ObtainWrite(&smb_globalLock);
8211 for (session = 1; session < numSessions; session++) {
8212 if (dead_sessions[session]) {
8213 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8214 dead_sessions[session] = FALSE;
8218 lock_ReleaseWrite(&smb_globalLock);
8220 /* We are re-using an existing VC because the lsn and lana
8222 session = vcp->session;
8224 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8226 /* Log session startup */
8228 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8229 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8230 #endif /* NOTSERVICE */
8231 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8232 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8234 if (reportSessionStartups) {
8235 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8239 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8240 unsigned long code = CM_ERROR_ALLBUSY;
8241 smb_packet_t * outp = GetPacket();
8242 unsigned char *outWctp;
8245 smb_FormatResponsePacket(vcp, NULL, outp);
8248 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8249 unsigned long NTStatus;
8250 smb_MapNTError(code, &NTStatus);
8251 outWctp = outp->wctp;
8252 smbp = (smb_t *) &outp->data;
8256 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8257 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8258 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8259 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8260 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8262 unsigned short errCode;
8263 unsigned char errClass;
8264 smb_MapCoreError(code, vcp, &errCode, &errClass);
8265 outWctp = outp->wctp;
8266 smbp = (smb_t *) &outp->data;
8270 smbp->errLow = (unsigned char) (errCode & 0xff);
8271 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8272 smbp->rcls = errClass;
8274 smb_SendPacket(vcp, outp);
8275 smb_FreePacket(outp);
8277 lock_ObtainMutex(&vcp->mx);
8278 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8279 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8281 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8282 lock_ReleaseMutex(&vcp->mx);
8283 lock_ObtainWrite(&smb_globalLock);
8284 dead_sessions[vcp->session] = TRUE;
8285 lock_ReleaseWrite(&smb_globalLock);
8286 smb_CleanupDeadVC(vcp);
8288 lock_ReleaseMutex(&vcp->mx);
8291 /* assert that we do not exceed the maximum number of sessions or NCBs.
8292 * we should probably want to wait for a session to be freed in case
8295 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8296 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8298 lock_ObtainMutex(&vcp->mx);
8299 vcp->session = session;
8300 lock_ReleaseMutex(&vcp->mx);
8301 lock_ObtainWrite(&smb_globalLock);
8302 LSNs[session] = ncbp->ncb_lsn;
8303 lanas[session] = ncbp->ncb_lana_num;
8304 lock_ReleaseWrite(&smb_globalLock);
8306 if (session == numSessions) {
8307 /* Add new NCB for new session */
8308 char eventName[MAX_PATH];
8310 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8312 InitNCBslot(numNCBs);
8313 lock_ObtainWrite(&smb_globalLock);
8315 lock_ReleaseWrite(&smb_globalLock);
8316 thrd_SetEvent(NCBavails[0]);
8317 thrd_SetEvent(NCBevents[0]);
8318 for (thread = 0; thread < smb_NumServerThreads; thread++)
8319 thrd_SetEvent(NCBreturns[thread][0]);
8320 /* Also add new session event */
8321 sprintf(eventName, "SessionEvents[%d]", session);
8322 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8323 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8324 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8325 lock_ObtainWrite(&smb_globalLock);
8327 lock_ReleaseWrite(&smb_globalLock);
8328 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8329 thrd_SetEvent(SessionEvents[0]);
8331 thrd_SetEvent(SessionEvents[session]);
8337 lock_ReleaseMutex(&smb_ListenerLock);
8338 } /* dispatch while loop */
8342 thrd_SetEvent(ListenerShutdown[lana]);
8347 smb_LanAdapterChangeThread(void *param)
8350 * Give the IPAddrDaemon thread a chance
8351 * to block before we trigger.
8354 smb_LanAdapterChange(0);
8357 void smb_SetLanAdapterChangeDetected(void)
8362 lock_ObtainMutex(&smb_StartedLock);
8364 if (!powerStateSuspended) {
8365 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
8366 NULL, 0, &lpid, "smb_LanAdapterChange");
8367 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
8368 thrd_CloseHandle(phandle);
8371 smb_LanAdapterChangeDetected = 1;
8372 lock_ReleaseMutex(&smb_StartedLock);
8375 void smb_LanAdapterChange(int locked) {
8376 lana_number_t lanaNum;
8378 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
8380 LANA_ENUM temp_list;
8385 afsi_log("smb_LanAdapterChange");
8388 lock_ObtainMutex(&smb_StartedLock);
8390 smb_LanAdapterChangeDetected = 0;
8392 if (!powerStateSuspended &&
8393 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
8394 LANA_NETBIOS_NAME_FULL)) &&
8395 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
8396 if ( isGateway != bGateway ||
8397 strcmp(cm_NetbiosName, NetbiosName) ) {
8400 NCB *ncbp = GetNCB();
8401 ncbp->ncb_command = NCBENUM;
8402 ncbp->ncb_buffer = (PUCHAR)&temp_list;
8403 ncbp->ncb_length = sizeof(temp_list);
8404 code = Netbios(ncbp);
8406 if (temp_list.length != lana_list.length)
8409 for (i=0; i<lana_list.length; i++) {
8410 if ( temp_list.lana[i] != lana_list.lana[i] ) {
8422 afsi_log("Lan Adapter Change detected");
8423 smb_StopListeners(1);
8424 smb_RestartListeners(1);
8427 lock_ReleaseMutex(&smb_StartedLock);
8430 /* initialize Netbios */
8431 int smb_NetbiosInit(int locked)
8434 int i, lana, code, l;
8436 int delname_tried=0;
8439 lana_number_t lanaNum;
8442 lock_ObtainMutex(&smb_StartedLock);
8444 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
8445 smb_ListenerState != SMB_LISTENER_STOPPED) {
8448 lock_ReleaseMutex(&smb_StartedLock);
8451 /* setup the NCB system */
8454 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8455 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8456 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8458 if (smb_LANadapter != LANA_INVALID)
8459 afsi_log("LAN adapter number %d", smb_LANadapter);
8461 afsi_log("LAN adapter number not determined");
8464 afsi_log("Set for gateway service");
8466 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8468 /* something went horribly wrong. We can't proceed without a netbios name */
8470 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8471 osi_panic(buf, __FILE__, __LINE__);
8474 /* remember the name */
8475 len = (int)strlen(cm_NetbiosName);
8477 free(smb_localNamep);
8478 smb_localNamep = malloc(len+1);
8479 strcpy(smb_localNamep, cm_NetbiosName);
8480 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8483 if (smb_LANadapter == LANA_INVALID) {
8484 ncbp->ncb_command = NCBENUM;
8485 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8486 ncbp->ncb_length = sizeof(lana_list);
8487 code = Netbios(ncbp);
8489 afsi_log("Netbios NCBENUM error code %d", code);
8490 osi_panic(s, __FILE__, __LINE__);
8494 lana_list.length = 1;
8495 lana_list.lana[0] = smb_LANadapter;
8498 for (i = 0; i < lana_list.length; i++) {
8499 /* reset the adaptor: in Win32, this is required for every process, and
8500 * acts as an init call, not as a real hardware reset.
8502 ncbp->ncb_command = NCBRESET;
8503 ncbp->ncb_callname[0] = 100;
8504 ncbp->ncb_callname[2] = 100;
8505 ncbp->ncb_lana_num = lana_list.lana[i];
8506 code = Netbios(ncbp);
8508 code = ncbp->ncb_retcode;
8510 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8511 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
8513 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8517 /* and declare our name so we can receive connections */
8518 memset(ncbp, 0, sizeof(*ncbp));
8519 len=lstrlen(smb_localNamep);
8520 memset(smb_sharename,' ',NCBNAMSZ);
8521 memcpy(smb_sharename,smb_localNamep,len);
8522 afsi_log("lana_list.length %d", lana_list.length);
8524 /* Keep the name so we can unregister it later */
8525 for (l = 0; l < lana_list.length; l++) {
8526 lana = lana_list.lana[l];
8528 ncbp->ncb_command = NCBADDNAME;
8529 ncbp->ncb_lana_num = lana;
8530 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8531 code = Netbios(ncbp);
8533 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8534 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8536 char name[NCBNAMSZ+1];
8538 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8539 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8543 code = ncbp->ncb_retcode;
8546 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8549 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8550 if (code == NRC_BRIDGE) { /* invalid LANA num */
8551 lana_list.lana[l] = LANA_INVALID;
8554 else if (code == NRC_DUPNAME) {
8555 afsi_log("Name already exists; try to delete it");
8556 memset(ncbp, 0, sizeof(*ncbp));
8557 ncbp->ncb_command = NCBDELNAME;
8558 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8559 ncbp->ncb_lana_num = lana;
8560 code = Netbios(ncbp);
8562 code = ncbp->ncb_retcode;
8564 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8566 if (code != 0 || delname_tried) {
8567 lana_list.lana[l] = LANA_INVALID;
8569 else if (code == 0) {
8570 if (!delname_tried) {
8578 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8579 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8583 smb_LANadapter = lana;
8584 lana_found = 1; /* at least one worked */
8588 osi_assertx(lana_list.length >= 0, "empty lana list");
8590 afsi_log("No valid LANA numbers found!");
8591 lana_list.length = 0;
8592 smb_LANadapter = LANA_INVALID;
8593 smb_ListenerState = SMB_LISTENER_STOPPED;
8594 cm_VolStatus_Network_Stopped(cm_NetbiosName
8601 /* we're done with the NCB now */
8604 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
8605 if (lana_list.length > 0)
8606 osi_assert(smb_LANadapter != LANA_INVALID);
8609 lock_ReleaseMutex(&smb_StartedLock);
8611 return (lana_list.length > 0 ? 1 : 0);
8614 void smb_StartListeners(int locked)
8621 lock_ObtainMutex(&smb_StartedLock);
8623 if (smb_ListenerState == SMB_LISTENER_STARTED) {
8625 lock_ReleaseMutex(&smb_StartedLock);
8629 afsi_log("smb_StartListeners");
8630 smb_ListenerState = SMB_LISTENER_STARTED;
8631 cm_VolStatus_Network_Started(cm_NetbiosName
8637 for (i = 0; i < lana_list.length; i++) {
8638 if (lana_list.lana[i] == LANA_INVALID)
8640 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8641 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8642 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
8643 thrd_CloseHandle(phandle);
8646 lock_ReleaseMutex(&smb_StartedLock);
8649 void smb_RestartListeners(int locked)
8652 lock_ObtainMutex(&smb_StartedLock);
8654 if (powerStateSuspended)
8655 afsi_log("smb_RestartListeners called while suspended");
8657 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
8658 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8659 if (smb_NetbiosInit(1))
8660 smb_StartListeners(1);
8661 } else if (smb_LanAdapterChangeDetected) {
8662 smb_LanAdapterChange(1);
8666 lock_ReleaseMutex(&smb_StartedLock);
8669 void smb_StopListener(NCB *ncbp, int lana, int wait)
8673 memset(ncbp, 0, sizeof(*ncbp));
8674 ncbp->ncb_command = NCBDELNAME;
8675 ncbp->ncb_lana_num = lana;
8676 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8677 code = Netbios(ncbp);
8679 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8680 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8682 /* and then reset the LANA; this will cause the listener threads to exit */
8683 ncbp->ncb_command = NCBRESET;
8684 ncbp->ncb_callname[0] = 100;
8685 ncbp->ncb_callname[2] = 100;
8686 ncbp->ncb_lana_num = lana;
8687 code = Netbios(ncbp);
8689 code = ncbp->ncb_retcode;
8691 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8693 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8697 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
8700 void smb_StopListeners(int locked)
8706 lock_ObtainMutex(&smb_StartedLock);
8708 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8710 lock_ReleaseMutex(&smb_StartedLock);
8714 afsi_log("smb_StopListeners");
8715 smb_ListenerState = SMB_LISTENER_STOPPED;
8716 cm_VolStatus_Network_Stopped(cm_NetbiosName
8724 /* Unregister the SMB name */
8725 for (l = 0; l < lana_list.length; l++) {
8726 lana = lana_list.lana[l];
8728 if (lana != LANA_INVALID) {
8729 smb_StopListener(ncbp, lana, TRUE);
8731 /* mark the adapter invalid */
8732 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8736 /* force a re-evaluation of the network adapters */
8737 lana_list.length = 0;
8738 smb_LANadapter = LANA_INVALID;
8741 lock_ReleaseMutex(&smb_StartedLock);
8744 void smb_Init(osi_log_t *logp, int useV3,
8754 EVENT_HANDLE retHandle;
8755 char eventName[MAX_PATH];
8756 int startListeners = 0;
8758 smb_TlsRequestSlot = TlsAlloc();
8760 smb_MBfunc = aMBfunc;
8764 /* Initialize smb_localZero */
8765 myTime.tm_isdst = -1; /* compute whether on DST or not */
8766 myTime.tm_year = 70;
8772 smb_localZero = mktime(&myTime);
8774 #ifndef USE_NUMERIC_TIME_CONV
8775 /* Initialize kludge-GMT */
8776 smb_CalculateNowTZ();
8777 #endif /* USE_NUMERIC_TIME_CONV */
8778 #ifdef AFS_FREELANCE_CLIENT
8779 /* Make sure the root.afs volume has the correct time */
8780 cm_noteLocalMountPointChange();
8783 /* initialize the remote debugging log */
8786 /* and the global lock */
8787 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8788 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8790 /* Raw I/O data structures */
8791 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8793 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8794 lock_InitializeMutex(&smb_StartedLock, "smb started lock");
8796 /* 4 Raw I/O buffers */
8797 smb_RawBufs = calloc(65536,1);
8798 *((char **)smb_RawBufs) = NULL;
8799 for (i=0; i<3; i++) {
8800 char *rawBuf = calloc(65536,1);
8801 *((char **)rawBuf) = smb_RawBufs;
8802 smb_RawBufs = rawBuf;
8805 /* global free lists */
8806 smb_ncbFreeListp = NULL;
8807 smb_packetFreeListp = NULL;
8809 lock_ObtainMutex(&smb_StartedLock);
8810 startListeners = smb_NetbiosInit(1);
8812 /* Initialize listener and server structures */
8814 memset(dead_sessions, 0, sizeof(dead_sessions));
8815 sprintf(eventName, "SessionEvents[0]");
8816 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8817 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8818 afsi_log("Event Object Already Exists: %s", eventName);
8820 smb_NumServerThreads = nThreads;
8821 sprintf(eventName, "NCBavails[0]");
8822 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8823 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8824 afsi_log("Event Object Already Exists: %s", eventName);
8825 sprintf(eventName, "NCBevents[0]");
8826 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8827 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8828 afsi_log("Event Object Already Exists: %s", eventName);
8829 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8830 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8831 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8832 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8833 afsi_log("Event Object Already Exists: %s", eventName);
8834 for (i = 0; i < smb_NumServerThreads; i++) {
8835 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8836 NCBreturns[i][0] = retHandle;
8839 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8840 for (i = 0; i < smb_NumServerThreads; i++) {
8841 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8842 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8843 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8844 afsi_log("Event Object Already Exists: %s", eventName);
8845 InitNCBslot((int)(i+1));
8847 numNCBs = smb_NumServerThreads + 1;
8849 /* Initialize dispatch table */
8850 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8851 /* Prepare the table for unknown operations */
8852 for(i=0; i<= SMB_NOPCODES; i++) {
8853 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8855 /* Fill in the ones we do know */
8856 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8857 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8858 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8859 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8860 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8861 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8862 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8863 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8864 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8865 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8866 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8867 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8868 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8869 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8870 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8871 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8872 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8873 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8874 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8875 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8876 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8877 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8878 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8879 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8880 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8881 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8882 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8883 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8884 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8885 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8886 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8887 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8888 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8889 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8890 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8891 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8892 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8893 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8894 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8895 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8896 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8897 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8898 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8899 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8900 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8901 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8902 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8903 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8904 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8905 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8906 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8907 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8908 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8909 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8910 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8911 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8912 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8913 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8914 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8915 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8916 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8917 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8918 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8919 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8920 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8921 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8922 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8923 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8924 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8925 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8926 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8927 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8928 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8929 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8931 /* setup tran 2 dispatch table */
8932 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8933 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8934 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8935 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8936 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8937 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8938 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8939 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8940 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8941 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8942 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8943 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8944 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8945 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8946 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8947 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8948 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8949 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8951 /* setup the rap dispatch table */
8952 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8953 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8954 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8955 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8956 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8960 /* if we are doing SMB authentication we have register outselves as a logon process */
8961 if (smb_authType != SMB_AUTH_NONE) {
8962 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8963 LSA_STRING afsProcessName;
8964 LSA_OPERATIONAL_MODE dummy; /*junk*/
8966 afsProcessName.Buffer = "OpenAFSClientDaemon";
8967 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8968 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8970 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8972 if (nts == STATUS_SUCCESS) {
8973 LSA_STRING packageName;
8974 /* we are registered. Find out the security package id */
8975 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8976 packageName.Length = (USHORT)strlen(packageName.Buffer);
8977 packageName.MaximumLength = packageName.Length + 1;
8978 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8979 if (nts == STATUS_SUCCESS) {
8981 * This code forces Windows to authenticate against the Logon Cache
8982 * first instead of attempting to authenticate against the Domain
8983 * Controller. When the Windows logon cache is enabled this improves
8984 * performance by removing the network access and works around a bug
8985 * seen at sites which are using a MIT Kerberos principal to login
8986 * to machines joined to a non-root domain in a multi-domain forest.
8987 * MsV1_0SetProcessOption was added in Windows XP.
8989 PVOID pResponse = NULL;
8990 ULONG cbResponse = 0;
8991 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8993 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8994 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8995 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8996 OptionsRequest.DisableOptions = FALSE;
8998 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9001 sizeof(OptionsRequest),
9007 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9008 char message[AFSPATHMAX];
9009 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9011 OutputDebugString(message);
9014 OutputDebugString("MsV1_0SetProcessOption success");
9015 afsi_log("MsV1_0SetProcessOption success");
9017 /* END - code from Larry */
9019 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9020 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9021 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9023 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9025 /* something went wrong. We report the error and revert back to no authentication
9026 because we can't perform any auth requests without a successful lsa handle
9027 or sec package id. */
9028 afsi_log("Reverting to NO SMB AUTH");
9029 smb_authType = SMB_AUTH_NONE;
9032 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9034 /* something went wrong. We report the error and revert back to no authentication
9035 because we can't perform any auth requests without a successful lsa handle
9036 or sec package id. */
9037 afsi_log("Reverting to NO SMB AUTH");
9038 smb_authType = SMB_AUTH_NONE;
9042 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9043 * time prevents the failure of authentication when logged into Windows with an
9044 * external Kerberos principal mapped to a local account.
9046 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9047 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9048 * then the only option is NTLMSSP anyway; so just fallback.
9053 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9054 if (secBlobLength == 0) {
9055 smb_authType = SMB_AUTH_NTLM;
9056 afsi_log("Reverting to SMB AUTH NTLM");
9065 /* Now get ourselves a domain name. */
9066 /* For now we are using the local computer name as the domain name.
9067 * It is actually the domain for local logins, and we are acting as
9068 * a local SMB server.
9070 bufsize = sizeof(smb_ServerDomainName) - 1;
9071 GetComputerName(smb_ServerDomainName, &bufsize);
9072 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9073 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
9076 /* Start listeners, waiters, servers, and daemons */
9078 smb_StartListeners(1);
9080 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9081 NULL, 0, &lpid, "smb_ClientWaiter");
9082 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9083 thrd_CloseHandle(phandle);
9085 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9086 NULL, 0, &lpid, "smb_ServerWaiter");
9087 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9088 thrd_CloseHandle(phandle);
9090 for (i=0; i<smb_NumServerThreads; i++) {
9091 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9092 (void *) i, 0, &lpid, "smb_Server");
9093 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9094 thrd_CloseHandle(phandle);
9097 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9098 NULL, 0, &lpid, "smb_Daemon");
9099 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9100 thrd_CloseHandle(phandle);
9102 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9103 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9104 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9105 thrd_CloseHandle(phandle);
9107 lock_ReleaseMutex(&smb_StartedLock);
9111 void smb_Shutdown(void)
9118 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9120 /* setup the NCB system */
9123 /* Block new sessions by setting shutdown flag */
9124 smbShutdownFlag = 1;
9126 /* Hang up all sessions */
9127 memset((char *)ncbp, 0, sizeof(NCB));
9128 for (i = 1; i < numSessions; i++)
9130 if (dead_sessions[i])
9133 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9134 ncbp->ncb_command = NCBHANGUP;
9135 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9136 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9137 code = Netbios(ncbp);
9138 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9139 if (code == 0) code = ncbp->ncb_retcode;
9141 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9142 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9146 /* Trigger the shutdown of all SMB threads */
9147 for (i = 0; i < smb_NumServerThreads; i++)
9148 thrd_SetEvent(NCBreturns[i][0]);
9150 thrd_SetEvent(NCBevents[0]);
9151 thrd_SetEvent(SessionEvents[0]);
9152 thrd_SetEvent(NCBavails[0]);
9154 for (i = 0;i < smb_NumServerThreads; i++) {
9155 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9156 if (code == WAIT_OBJECT_0) {
9159 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9160 thrd_SetEvent(NCBreturns[i--][0]);
9164 /* Delete Netbios name */
9165 memset((char *)ncbp, 0, sizeof(NCB));
9166 for (i = 0; i < lana_list.length; i++) {
9167 if (lana_list.lana[i] == LANA_INVALID) continue;
9168 ncbp->ncb_command = NCBDELNAME;
9169 ncbp->ncb_lana_num = lana_list.lana[i];
9170 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9171 code = Netbios(ncbp);
9173 code = ncbp->ncb_retcode;
9175 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9176 ncbp->ncb_lana_num, code);
9181 /* Release the reference counts held by the VCs */
9182 lock_ObtainWrite(&smb_rctLock);
9183 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9188 if (vcp->magic != SMB_VC_MAGIC)
9189 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9190 __FILE__, __LINE__);
9192 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9194 if (fidp->scp != NULL) {
9197 lock_ObtainMutex(&fidp->mx);
9198 if (fidp->scp != NULL) {
9201 lock_ObtainMutex(&scp->mx);
9202 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9203 lock_ReleaseMutex(&scp->mx);
9204 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9205 cm_ReleaseSCache(scp);
9207 lock_ReleaseMutex(&fidp->mx);
9211 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9213 smb_ReleaseVCNoLock(tidp->vcp);
9215 cm_user_t *userp = tidp->userp;
9217 cm_ReleaseUser(userp);
9221 lock_ReleaseWrite(&smb_rctLock);
9223 TlsFree(smb_TlsRequestSlot);
9226 /* Get the UNC \\<servername>\<sharename> prefix. */
9227 char *smb_GetSharename()
9231 /* Make sure we have been properly initialized. */
9232 if (smb_localNamep == NULL)
9235 /* Allocate space for \\<servername>\<sharename>, plus the
9238 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9239 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9245 void smb_LogPacket(smb_packet_t *packet)
9248 unsigned length, paramlen, datalen, i, j;
9250 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9252 if (!packet) return;
9254 osi_Log0(smb_logp, "*** SMB packet dump ***");
9256 vp = (BYTE *) packet->data;
9258 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9259 length = paramlen + 2 + datalen;
9262 for (i=0;i < length; i+=16)
9264 memset( buf, ' ', 80 );
9269 buf[strlen(buf)] = ' ';
9271 cp = (BYTE*) buf + 7;
9273 for (j=0;j < 16 && (i+j)<length; j++)
9275 *(cp++) = hex[vp[i+j] >> 4];
9276 *(cp++) = hex[vp[i+j] & 0xf];
9286 for (j=0;j < 16 && (i+j)<length;j++)
9288 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9299 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9302 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9304 #endif /* LOG_PACKET */
9307 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9315 lock_ObtainRead(&smb_rctLock);
9317 sprintf(output, "begin dumping smb_vc_t\r\n");
9318 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9320 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9324 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9325 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9326 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9328 sprintf(output, "begin dumping smb_fid_t\r\n");
9329 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9331 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9333 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",
9334 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9335 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9336 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9337 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9340 sprintf(output, "done dumping smb_fid_t\r\n");
9341 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9344 sprintf(output, "done dumping smb_vc_t\r\n");
9345 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9347 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9348 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9350 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9354 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9355 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9356 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9358 sprintf(output, "begin dumping smb_fid_t\r\n");
9359 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9361 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9363 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",
9364 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9365 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9366 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9367 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9370 sprintf(output, "done dumping smb_fid_t\r\n");
9371 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9374 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9375 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9378 lock_ReleaseRead(&smb_rctLock);
9382 long smb_IsNetworkStarted(void)
9385 lock_ObtainWrite(&smb_globalLock);
9386 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
9387 lock_ReleaseWrite(&smb_globalLock);