2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 /* These characters are illegal in Windows filenames */
35 static char *illegalChars = "\\/:*?\"<>|";
37 static int smbShutdownFlag = 0;
38 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
40 int smb_LogoffTokenTransfer;
41 time_t smb_LogoffTransferTimeout;
43 int smb_StoreAnsiFilenames = 0;
45 DWORD last_msg_time = 0;
49 unsigned int sessionGen = 0;
51 extern void afsi_log(char *pattern, ...);
52 extern HANDLE afsi_file;
53 extern int powerStateSuspended;
55 osi_hyper_t hzero = {0, 0};
56 osi_hyper_t hones = {0xFFFFFFFF, -1};
59 osi_rwlock_t smb_globalLock;
60 osi_rwlock_t smb_rctLock;
61 osi_mutex_t smb_ListenerLock;
62 osi_mutex_t smb_StartedLock;
64 unsigned char smb_LANadapter = LANA_INVALID;
65 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
66 int smb_LanAdapterChangeDetected = 0;
68 BOOL isGateway = FALSE;
71 long smb_maxObsConcurrentCalls=0;
72 long smb_concurrentCalls=0;
74 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
76 smb_packet_t *smb_packetFreeListp;
77 smb_ncb_t *smb_ncbFreeListp;
79 int smb_NumServerThreads;
81 int numNCBs, numSessions, numVCs;
83 int smb_maxVCPerServer;
84 int smb_maxMpxRequests;
86 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
88 ULONG smb_lsaSecPackage;
89 LSA_STRING smb_lsaLogonOrigin;
91 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
92 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
93 EVENT_HANDLE **NCBreturns;
94 EVENT_HANDLE **NCBShutdown;
95 EVENT_HANDLE *smb_ServerShutdown;
96 EVENT_HANDLE ListenerShutdown[256];
97 DWORD NCBsessions[NCB_MAX];
99 struct smb_packet *bufs[NCB_MAX];
101 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
102 EVENT_HANDLE SessionEvents[SESSION_MAX];
103 unsigned short LSNs[SESSION_MAX];
104 int lanas[SESSION_MAX];
105 BOOL dead_sessions[SESSION_MAX];
108 osi_mutex_t smb_RawBufLock;
111 #define SMB_MASKFLAG_TILDE 1
112 #define SMB_MASKFLAG_CASEFOLD 2
114 #define RAWTIMEOUT INFINITE
117 typedef struct raw_write_cont {
126 /* dir search stuff */
127 long smb_dirSearchCounter = 1;
128 smb_dirSearch_t *smb_firstDirSearchp;
129 smb_dirSearch_t *smb_lastDirSearchp;
131 /* hide dot files? */
132 int smb_hideDotFiles;
134 /* global state about V3 protocols */
135 int smb_useV3; /* try to negotiate V3 */
137 static showErrors = 0;
138 /* MessageBox or something like it */
139 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
142 * Time in Unix format of midnight, 1/1/1970 local time.
143 * When added to dosUTime, gives Unix (AFS) time.
145 time_t smb_localZero = 0;
147 #define USE_NUMERIC_TIME_CONV 1
149 #ifndef USE_NUMERIC_TIME_CONV
150 /* Time difference for converting to kludge-GMT */
151 afs_uint32 smb_NowTZ;
152 #endif /* USE_NUMERIC_TIME_CONV */
154 char *smb_localNamep = NULL;
156 smb_vc_t *smb_allVCsp;
157 smb_vc_t *smb_deadVCsp;
159 smb_username_t *usernamesp = NULL;
161 smb_waitingLockRequest_t *smb_allWaitingLocks;
163 DWORD smb_TlsRequestSlot = -1;
166 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
167 NCB *ncbp, raw_write_cont_t *rwcp);
168 int smb_NetbiosInit(int);
171 void smb_LogPacket(smb_packet_t *packet);
172 #endif /* LOG_PACKET */
174 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
175 int smb_ServerDomainNameLength = 0;
176 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
177 int smb_ServerOSLength = sizeof(smb_ServerOS);
178 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
179 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
181 /* Faux server GUID. This is never checked. */
182 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
184 void smb_ResetServerPriority()
186 void * p = TlsGetValue(smb_TlsRequestSlot);
189 TlsSetValue(smb_TlsRequestSlot, NULL);
190 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
194 void smb_SetRequestStartTime()
196 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
198 tp = malloc(sizeof(time_t));
202 if (!TlsSetValue(smb_TlsRequestSlot, tp))
207 void smb_UpdateServerPriority()
209 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
212 time_t now = osi_Time();
214 /* Give one priority boost for each 15 seconds */
215 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
220 const char * ncb_error_string(int code)
224 case 0x01: s = "llegal buffer length"; break;
225 case 0x03: s = "illegal command"; break;
226 case 0x05: s = "command timed out"; break;
227 case 0x06: s = "message incomplete, issue another command"; break;
228 case 0x07: s = "illegal buffer address"; break;
229 case 0x08: s = "session number out of range"; break;
230 case 0x09: s = "no resource available"; break;
231 case 0x0a: s = "session closed"; break;
232 case 0x0b: s = "command cancelled"; break;
233 case 0x0d: s = "duplicate name"; break;
234 case 0x0e: s = "name table full"; break;
235 case 0x0f: s = "no deletions, name has active sessions"; break;
236 case 0x11: s = "local session table full"; break;
237 case 0x12: s = "remote session table full"; break;
238 case 0x13: s = "illegal name number"; break;
239 case 0x14: s = "no callname"; break;
240 case 0x15: s = "cannot put * in NCB_NAME"; break;
241 case 0x16: s = "name in use on remote adapter"; break;
242 case 0x17: s = "name deleted"; break;
243 case 0x18: s = "session ended abnormally"; break;
244 case 0x19: s = "name conflict detected"; break;
245 case 0x21: s = "interface busy, IRET before retrying"; break;
246 case 0x22: s = "too many commands outstanding, retry later";break;
247 case 0x23: s = "ncb_lana_num field invalid"; break;
248 case 0x24: s = "command completed while cancel occurring "; break;
249 case 0x26: s = "command not valid to cancel"; break;
250 case 0x30: s = "name defined by anther local process"; break;
251 case 0x34: s = "environment undefined. RESET required"; break;
252 case 0x35: s = "required OS resources exhausted"; break;
253 case 0x36: s = "max number of applications exceeded"; break;
254 case 0x37: s = "no saps available for netbios"; break;
255 case 0x38: s = "requested resources are not available"; break;
256 case 0x39: s = "invalid ncb address or length > segment"; break;
257 case 0x3B: s = "invalid NCB DDID"; break;
258 case 0x3C: s = "lock of user area failed"; break;
259 case 0x3f: s = "NETBIOS not loaded"; break;
260 case 0x40: s = "system error"; break;
261 default: s = "unknown error";
267 char * myCrt_Dispatch(int i)
272 return "(00)ReceiveCoreMakeDir";
274 return "(01)ReceiveCoreRemoveDir";
276 return "(02)ReceiveCoreOpen";
278 return "(03)ReceiveCoreCreate";
280 return "(04)ReceiveCoreClose";
282 return "(05)ReceiveCoreFlush";
284 return "(06)ReceiveCoreUnlink";
286 return "(07)ReceiveCoreRename";
288 return "(08)ReceiveCoreGetFileAttributes";
290 return "(09)ReceiveCoreSetFileAttributes";
292 return "(0a)ReceiveCoreRead";
294 return "(0b)ReceiveCoreWrite";
296 return "(0c)ReceiveCoreLockRecord";
298 return "(0d)ReceiveCoreUnlockRecord";
300 return "(0e)SendCoreBadOp";
302 return "(0f)ReceiveCoreCreate";
304 return "(10)ReceiveCoreCheckPath";
306 return "(11)SendCoreBadOp";
308 return "(12)ReceiveCoreSeek";
310 return "(1a)ReceiveCoreReadRaw";
312 return "(1d)ReceiveCoreWriteRawDummy";
314 return "(22)ReceiveV3SetAttributes";
316 return "(23)ReceiveV3GetAttributes";
318 return "(24)ReceiveV3LockingX";
320 return "(25)ReceiveV3Trans";
322 return "(26)ReceiveV3Trans[aux]";
324 return "(29)SendCoreBadOp";
326 return "(2b)ReceiveCoreEcho";
328 return "(2d)ReceiveV3OpenX";
330 return "(2e)ReceiveV3ReadX";
332 return "(2f)ReceiveV3WriteX";
334 return "(32)ReceiveV3Tran2A";
336 return "(33)ReceiveV3Tran2A[aux]";
338 return "(34)ReceiveV3FindClose";
340 return "(35)ReceiveV3FindNotifyClose";
342 return "(70)ReceiveCoreTreeConnect";
344 return "(71)ReceiveCoreTreeDisconnect";
346 return "(72)ReceiveNegotiate";
348 return "(73)ReceiveV3SessionSetupX";
350 return "(74)ReceiveV3UserLogoffX";
352 return "(75)ReceiveV3TreeConnectX";
354 return "(80)ReceiveCoreGetDiskAttributes";
356 return "(81)ReceiveCoreSearchDir";
360 return "(83)FindUnique";
362 return "(84)FindClose";
364 return "(A0)ReceiveNTTransact";
366 return "(A2)ReceiveNTCreateX";
368 return "(A4)ReceiveNTCancel";
370 return "(A5)ReceiveNTRename";
372 return "(C0)OpenPrintFile";
374 return "(C1)WritePrintFile";
376 return "(C2)ClosePrintFile";
378 return "(C3)GetPrintQueue";
380 return "(D8)ReadBulk";
382 return "(D9)WriteBulk";
384 return "(DA)WriteBulkData";
386 return "unknown SMB op";
390 char * myCrt_2Dispatch(int i)
395 return "unknown SMB op-2";
397 return "S(00)CreateFile_ReceiveTran2Open";
399 return "S(01)FindFirst_ReceiveTran2SearchDir";
401 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
403 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
405 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
407 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
409 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
411 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
413 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
415 return "S(09)_ReceiveTran2FSCTL";
417 return "S(0a)_ReceiveTran2IOCTL";
419 return "S(0b)_ReceiveTran2FindNotifyFirst";
421 return "S(0c)_ReceiveTran2FindNotifyNext";
423 return "S(0d)_ReceiveTran2CreateDirectory";
425 return "S(0e)_ReceiveTran2SessionSetup";
427 return "S(0f)_QueryFileSystemInformationFid";
429 return "S(10)_ReceiveTran2GetDfsReferral";
431 return "S(11)_ReceiveTran2ReportDfsInconsistency";
435 char * myCrt_RapDispatch(int i)
440 return "unknown RAP OP";
442 return "RAP(0)NetShareEnum";
444 return "RAP(1)NetShareGetInfo";
446 return "RAP(13)NetServerGetInfo";
448 return "RAP(63)NetWkStaGetInfo";
452 /* scache must be locked */
453 unsigned int smb_Attributes(cm_scache_t *scp)
457 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
458 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
459 scp->fileType == CM_SCACHETYPE_INVALID)
461 attrs = SMB_ATTR_DIRECTORY;
462 #ifdef SPECIAL_FOLDERS
463 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
464 #endif /* SPECIAL_FOLDERS */
465 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
466 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
471 * We used to mark a file RO if it was in an RO volume, but that
472 * turns out to be impolitic in NT. See defect 10007.
475 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
476 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
478 if ((scp->unixModeBits & 0222) == 0)
479 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
485 /* Check if the named file/dir is a dotfile/dotdir */
486 /* String pointed to by lastComp can have leading slashes, but otherwise should have
487 no other patch components */
488 unsigned int smb_IsDotFile(char *lastComp) {
491 /* skip over slashes */
492 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
497 /* nulls, curdir and parent dir doesn't count */
503 if(*(s+1) == '.' && !*(s + 2))
510 static int ExtractBits(WORD bits, short start, short len)
517 num = bits << (16 - end);
518 num = num >> ((16 - end) + start);
523 void ShowUnixTime(char *FuncName, time_t unixTime)
528 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
530 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
531 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
533 int day, month, year, sec, min, hour;
536 day = ExtractBits(wDate, 0, 5);
537 month = ExtractBits(wDate, 5, 4);
538 year = ExtractBits(wDate, 9, 7) + 1980;
540 sec = ExtractBits(wTime, 0, 5);
541 min = ExtractBits(wTime, 5, 6);
542 hour = ExtractBits(wTime, 11, 5);
544 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
545 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
549 /* Determine if we are observing daylight savings time */
550 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
552 TIME_ZONE_INFORMATION timeZoneInformation;
553 SYSTEMTIME utc, local, localDST;
555 /* Get the time zone info. NT uses this to calc if we are in DST. */
556 GetTimeZoneInformation(&timeZoneInformation);
558 /* Return the daylight bias */
559 *pDstBias = timeZoneInformation.DaylightBias;
561 /* Return the bias */
562 *pBias = timeZoneInformation.Bias;
564 /* Now determine if DST is being observed */
566 /* Get the UTC (GMT) time */
569 /* Convert UTC time to local time using the time zone info. If we are
570 observing DST, the calculated local time will include this.
572 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
574 /* Set the daylight bias to 0. The daylight bias is the amount of change
575 * in time that we use for daylight savings time. By setting this to 0
576 * we cause there to be no change in time during daylight savings time.
578 timeZoneInformation.DaylightBias = 0;
580 /* Convert the utc time to local time again, but this time without any
581 adjustment for daylight savings time.
583 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
585 /* If the two times are different, then it means that the localDST that
586 we calculated includes the daylight bias, and therefore we are
587 observing daylight savings time.
589 *pDST = localDST.wHour != local.wHour;
593 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
595 BOOL dst; /* Will be TRUE if observing DST */
596 LONG dstBias; /* Offset from local time if observing DST */
597 LONG bias; /* Offset from GMT for local time */
600 * This function will adjust the last write time to compensate
601 * for two bugs in the smb client:
603 * 1) During Daylight Savings Time, the LastWriteTime is ahead
604 * in time by the DaylightBias (ignoring the sign - the
605 * DaylightBias is always stored as a negative number). If
606 * the DaylightBias is -60, then the LastWriteTime will be
607 * ahead by 60 minutes.
609 * 2) If the local time zone is a positive offset from GMT, then
610 * the LastWriteTime will be the correct local time plus the
611 * Bias (ignoring the sign - a positive offset from GMT is
612 * always stored as a negative Bias). If the Bias is -120,
613 * then the LastWriteTime will be ahead by 120 minutes.
615 * These bugs can occur at the same time.
618 GetTimeZoneInfo(&dst, &dstBias, &bias);
620 /* First adjust for DST */
622 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
624 /* Now adjust for a positive offset from GMT (a negative bias). */
626 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
629 #ifndef USE_NUMERIC_TIME_CONV
631 * Calculate the difference (in seconds) between local time and GMT.
632 * This enables us to convert file times to kludge-GMT.
638 struct tm gmt_tm, local_tm;
639 int days, hours, minutes, seconds;
642 gmt_tm = *(gmtime(&t));
643 local_tm = *(localtime(&t));
645 days = local_tm.tm_yday - gmt_tm.tm_yday;
646 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
647 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
648 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
652 #endif /* USE_NUMERIC_TIME_CONV */
654 #ifdef USE_NUMERIC_TIME_CONV
655 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
657 // Note that LONGLONG is a 64-bit value
660 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
661 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
662 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
665 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
670 time_t ersatz_unixTime;
673 * Must use kludge-GMT instead of real GMT.
674 * kludge-GMT is computed by adding time zone difference to localtime.
677 * ltp = gmtime(&unixTime);
679 ersatz_unixTime = unixTime - smb_NowTZ;
680 ltp = localtime(&ersatz_unixTime);
682 /* if we fail, make up something */
685 localJunk.tm_year = 89 - 20;
686 localJunk.tm_mon = 4;
687 localJunk.tm_mday = 12;
688 localJunk.tm_hour = 0;
689 localJunk.tm_min = 0;
690 localJunk.tm_sec = 0;
693 stm.wYear = ltp->tm_year + 1900;
694 stm.wMonth = ltp->tm_mon + 1;
695 stm.wDayOfWeek = ltp->tm_wday;
696 stm.wDay = ltp->tm_mday;
697 stm.wHour = ltp->tm_hour;
698 stm.wMinute = ltp->tm_min;
699 stm.wSecond = ltp->tm_sec;
700 stm.wMilliseconds = 0;
702 SystemTimeToFileTime(&stm, largeTimep);
704 #endif /* USE_NUMERIC_TIME_CONV */
706 #ifdef USE_NUMERIC_TIME_CONV
707 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
709 // Note that LONGLONG is a 64-bit value
712 ll = largeTimep->dwHighDateTime;
714 ll += largeTimep->dwLowDateTime;
716 ll -= 116444736000000000;
719 *unixTimep = (DWORD)ll;
721 #else /* USE_NUMERIC_TIME_CONV */
722 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
728 FileTimeToSystemTime(largeTimep, &stm);
730 lt.tm_year = stm.wYear - 1900;
731 lt.tm_mon = stm.wMonth - 1;
732 lt.tm_wday = stm.wDayOfWeek;
733 lt.tm_mday = stm.wDay;
734 lt.tm_hour = stm.wHour;
735 lt.tm_min = stm.wMinute;
736 lt.tm_sec = stm.wSecond;
739 save_timezone = _timezone;
740 _timezone += smb_NowTZ;
741 *unixTimep = mktime(<);
742 _timezone = save_timezone;
744 #endif /* USE_NUMERIC_TIME_CONV */
746 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
756 /* if we fail, make up something */
759 localJunk.tm_year = 89 - 20;
760 localJunk.tm_mon = 4;
761 localJunk.tm_mday = 12;
762 localJunk.tm_hour = 0;
763 localJunk.tm_min = 0;
764 localJunk.tm_sec = 0;
767 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
768 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
769 *searchTimep = (dosDate<<16) | dosTime;
772 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
774 unsigned short dosDate;
775 unsigned short dosTime;
778 dosDate = (unsigned short) (searchTime & 0xffff);
779 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
781 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
782 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
783 localTm.tm_mday = (dosDate) & 0x1f;
784 localTm.tm_hour = (dosTime>>11) & 0x1f;
785 localTm.tm_min = (dosTime >> 5) & 0x3f;
786 localTm.tm_sec = (dosTime & 0x1f) * 2;
787 localTm.tm_isdst = -1; /* compute whether DST in effect */
789 *unixTimep = mktime(&localTm);
792 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
794 time_t diff_t = unixTime - smb_localZero;
795 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
796 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
798 *dosUTimep = (afs_uint32)diff_t;
801 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
803 *unixTimep = dosTime + smb_localZero;
806 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
810 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
811 lock_ObtainWrite(&smb_rctLock);
812 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
813 if (vcp->magic != SMB_VC_MAGIC)
814 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
817 if (lsn == vcp->lsn && lana == vcp->lana &&
818 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
819 smb_HoldVCNoLock(vcp);
823 if (!vcp && (flags & SMB_FLAG_CREATE)) {
824 vcp = malloc(sizeof(*vcp));
825 memset(vcp, 0, sizeof(*vcp));
826 vcp->vcID = ++numVCs;
827 vcp->magic = SMB_VC_MAGIC;
828 vcp->refCount = 2; /* smb_allVCsp and caller */
831 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
832 vcp->nextp = smb_allVCsp;
834 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
839 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
840 /* We must obtain a challenge for extended auth
841 * in case the client negotiates smb v3
843 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
844 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
845 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
846 ULONG lsaRespSize = 0;
848 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
850 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
857 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
858 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
859 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
860 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
861 nts, ntsEx, lsaRespSize);
863 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
865 if (ntsEx == STATUS_SUCCESS) {
866 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
867 LsaFreeReturnBuffer(lsaResp);
870 * This will cause the subsequent authentication to fail but
871 * that is better than us dereferencing a NULL pointer and
874 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
878 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
880 if (numVCs >= CM_SESSION_RESERVED) {
882 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
885 lock_ReleaseWrite(&smb_rctLock);
886 lock_ReleaseWrite(&smb_globalLock);
890 int smb_IsStarMask(char *maskp)
895 for(i=0; i<11; i++) {
897 if (tc == '?' || tc == '*' || tc == '>')
903 void smb_ReleaseVCInternal(smb_vc_t *vcp)
910 if (vcp->refCount == 0) {
911 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
912 /* remove VCP from smb_deadVCsp */
913 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
919 lock_FinalizeMutex(&vcp->mx);
920 memset(vcp,0,sizeof(smb_vc_t));
923 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
927 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
928 avcp?"not ":"",vcp, vcp->refCount);
930 GenerateMiniDump(NULL);
932 /* This is a wrong. However, I suspect that there is an undercount
933 * and I don't want to release 1.4.1 in a state that will allow
934 * smb_vc_t objects to be deallocated while still in the
935 * smb_allVCsp list. The list is supposed to keep a reference
936 * to the smb_vc_t. Put it back.
943 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
945 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
946 smb_ReleaseVCInternal(vcp);
949 void smb_ReleaseVC(smb_vc_t *vcp)
951 lock_ObtainWrite(&smb_rctLock);
952 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
953 smb_ReleaseVCInternal(vcp);
954 lock_ReleaseWrite(&smb_rctLock);
957 void smb_HoldVCNoLock(smb_vc_t *vcp)
960 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
963 void smb_HoldVC(smb_vc_t *vcp)
965 lock_ObtainWrite(&smb_rctLock);
967 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
968 lock_ReleaseWrite(&smb_rctLock);
971 void smb_CleanupDeadVC(smb_vc_t *vcp)
979 smb_user_t *uidpIter;
980 smb_user_t *uidpNext;
984 lock_ObtainMutex(&vcp->mx);
985 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
986 lock_ReleaseMutex(&vcp->mx);
987 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
990 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
991 lock_ReleaseMutex(&vcp->mx);
992 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
994 lock_ObtainWrite(&smb_rctLock);
995 /* remove VCP from smb_allVCsp */
996 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
997 if ((*vcpp)->magic != SMB_VC_MAGIC)
998 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1002 vcp->nextp = smb_deadVCsp;
1004 /* Hold onto the reference until we are done with this function */
1009 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1010 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1012 if (fidpIter->delete)
1015 fid = fidpIter->fid;
1016 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1018 smb_HoldFIDNoLock(fidpIter);
1019 lock_ReleaseWrite(&smb_rctLock);
1021 smb_CloseFID(vcp, fidpIter, NULL, 0);
1022 smb_ReleaseFID(fidpIter);
1024 lock_ObtainWrite(&smb_rctLock);
1025 fidpNext = vcp->fidsp;
1028 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1029 tidpNext = tidpIter->nextp;
1030 if (tidpIter->delete)
1032 tidpIter->delete = 1;
1034 tid = tidpIter->tid;
1035 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1037 smb_HoldTIDNoLock(tidpIter);
1038 lock_ReleaseWrite(&smb_rctLock);
1040 smb_ReleaseTID(tidpIter);
1042 lock_ObtainWrite(&smb_rctLock);
1043 tidpNext = vcp->tidsp;
1046 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1047 uidpNext = uidpIter->nextp;
1048 if (uidpIter->delete)
1050 uidpIter->delete = 1;
1052 /* do not add an additional reference count for the smb_user_t
1053 * as the smb_vc_t already is holding a reference */
1054 lock_ReleaseWrite(&smb_rctLock);
1056 smb_ReleaseUID(uidpIter);
1058 lock_ObtainWrite(&smb_rctLock);
1059 uidpNext = vcp->usersp;
1062 /* The vcp is now on the deadVCsp list. We intentionally drop the
1063 * reference so that the refcount can reach 0 and we can delete it */
1064 smb_ReleaseVCNoLock(vcp);
1066 lock_ReleaseWrite(&smb_rctLock);
1067 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1070 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1074 lock_ObtainWrite(&smb_rctLock);
1076 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1077 if (tidp->refCount == 0 && tidp->delete) {
1079 lock_ReleaseWrite(&smb_rctLock);
1080 smb_ReleaseTID(tidp);
1081 lock_ObtainWrite(&smb_rctLock);
1085 if (tid == tidp->tid) {
1090 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1091 tidp = malloc(sizeof(*tidp));
1092 memset(tidp, 0, sizeof(*tidp));
1093 tidp->nextp = vcp->tidsp;
1096 smb_HoldVCNoLock(vcp);
1098 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1101 lock_ReleaseWrite(&smb_rctLock);
1105 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1110 void smb_ReleaseTID(smb_tid_t *tidp)
1117 lock_ObtainWrite(&smb_rctLock);
1118 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1119 if (tidp->refCount == 0 && (tidp->delete)) {
1120 ltpp = &tidp->vcp->tidsp;
1121 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1125 osi_assertx(tp != NULL, "null smb_tid_t");
1127 lock_FinalizeMutex(&tidp->mx);
1128 userp = tidp->userp; /* remember to drop ref later */
1130 smb_ReleaseVCNoLock(tidp->vcp);
1133 lock_ReleaseWrite(&smb_rctLock);
1135 cm_ReleaseUser(userp);
1138 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1140 smb_user_t *uidp = NULL;
1142 lock_ObtainWrite(&smb_rctLock);
1143 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1144 if (uid == uidp->userID) {
1146 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1148 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1152 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1153 uidp = malloc(sizeof(*uidp));
1154 memset(uidp, 0, sizeof(*uidp));
1155 uidp->nextp = vcp->usersp;
1156 uidp->refCount = 2; /* one for the vcp and one for the caller */
1158 smb_HoldVCNoLock(vcp);
1160 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1162 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1164 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1166 lock_ReleaseWrite(&smb_rctLock);
1170 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1172 smb_username_t *unp= NULL;
1174 lock_ObtainWrite(&smb_rctLock);
1175 for(unp = usernamesp; unp; unp = unp->nextp) {
1176 if (stricmp(unp->name, usern) == 0 &&
1177 stricmp(unp->machine, machine) == 0) {
1182 if (!unp && (flags & SMB_FLAG_CREATE)) {
1183 unp = malloc(sizeof(*unp));
1184 memset(unp, 0, sizeof(*unp));
1186 unp->nextp = usernamesp;
1187 unp->name = strdup(usern);
1188 unp->machine = strdup(machine);
1190 lock_InitializeMutex(&unp->mx, "username_t mutex");
1191 if (flags & SMB_FLAG_AFSLOGON)
1192 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1195 lock_ReleaseWrite(&smb_rctLock);
1199 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1201 smb_user_t *uidp= NULL;
1203 lock_ObtainWrite(&smb_rctLock);
1204 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1207 if (stricmp(uidp->unp->name, usern) == 0) {
1209 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1210 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1215 lock_ReleaseWrite(&smb_rctLock);
1219 void smb_ReleaseUsername(smb_username_t *unp)
1222 smb_username_t **lupp;
1223 cm_user_t *userp = NULL;
1224 time_t now = osi_Time();
1226 lock_ObtainWrite(&smb_rctLock);
1227 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1228 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1229 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1231 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1235 osi_assertx(up != NULL, "null smb_username_t");
1237 up->nextp = NULL; /* do not remove this */
1238 lock_FinalizeMutex(&unp->mx);
1244 lock_ReleaseWrite(&smb_rctLock);
1247 cm_ReleaseUser(userp);
1251 void smb_HoldUIDNoLock(smb_user_t *uidp)
1256 void smb_ReleaseUID(smb_user_t *uidp)
1260 smb_username_t *unp = NULL;
1262 lock_ObtainWrite(&smb_rctLock);
1263 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1264 if (uidp->refCount == 0) {
1265 lupp = &uidp->vcp->usersp;
1266 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1270 osi_assertx(up != NULL, "null smb_user_t");
1272 lock_FinalizeMutex(&uidp->mx);
1274 smb_ReleaseVCNoLock(uidp->vcp);
1278 lock_ReleaseWrite(&smb_rctLock);
1282 cm_ReleaseUserVCRef(unp->userp);
1283 smb_ReleaseUsername(unp);
1287 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1289 cm_user_t *up = NULL;
1294 lock_ObtainMutex(&uidp->mx);
1296 up = uidp->unp->userp;
1299 lock_ReleaseMutex(&uidp->mx);
1305 /* retrieve a held reference to a user structure corresponding to an incoming
1307 * corresponding release function is cm_ReleaseUser.
1309 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1312 cm_user_t *up = NULL;
1315 smbp = (smb_t *) inp;
1316 uidp = smb_FindUID(vcp, smbp->uid, 0);
1320 up = smb_GetUserFromUID(uidp);
1322 smb_ReleaseUID(uidp);
1327 * Return a pointer to a pathname extracted from a TID structure. The
1328 * TID structure is not held; assume it won't go away.
1330 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1335 tidp = smb_FindTID(vcp, tid, 0);
1339 if (tidp->flags & SMB_TIDFLAG_IPC) {
1340 code = CM_ERROR_TIDIPC;
1341 /* tidp->pathname would be NULL, but that's fine */
1343 *treepath = tidp->pathname;
1344 smb_ReleaseTID(tidp);
1349 /* check to see if we have a chained fid, that is, a fid that comes from an
1350 * OpenAndX message that ran earlier in this packet. In this case, the fid
1351 * field in a read, for example, request, isn't set, since the value is
1352 * supposed to be inherited from the openAndX call.
1354 int smb_ChainFID(int fid, smb_packet_t *inp)
1356 if (inp->fid == 0 || inp->inCount == 0)
1362 /* are we a priv'd user? What does this mean on NT? */
1363 int smb_SUser(cm_user_t *userp)
1368 /* find a file ID. If we pass in 0 we select an unused File ID.
1369 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1370 * smb_fid_t data structure if desired File ID cannot be found.
1372 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1377 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1380 lock_ObtainWrite(&smb_rctLock);
1381 /* figure out if we need to allocate a new file ID */
1384 fid = vcp->fidCounter;
1388 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1389 if (fidp->refCount == 0 && fidp->delete) {
1391 lock_ReleaseWrite(&smb_rctLock);
1392 smb_ReleaseFID(fidp);
1393 lock_ObtainWrite(&smb_rctLock);
1396 if (fid == fidp->fid) {
1399 if (fid == 0xFFFF) {
1401 "New FID number wraps on vcp 0x%x", vcp);
1411 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1412 char eventName[MAX_PATH];
1414 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1415 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1416 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1417 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1418 thrd_CloseHandle(event);
1420 if (fid == 0xFFFF) {
1421 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1427 fidp = malloc(sizeof(*fidp));
1428 memset(fidp, 0, sizeof(*fidp));
1429 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1432 smb_HoldVCNoLock(vcp);
1433 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1435 fidp->curr_chunk = fidp->prev_chunk = -2;
1436 fidp->raw_write_event = event;
1438 vcp->fidCounter = fid+1;
1439 if (vcp->fidCounter == 0xFFFF) {
1440 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1442 vcp->fidCounter = 1;
1447 lock_ReleaseWrite(&smb_rctLock);
1451 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1453 smb_fid_t *fidp = NULL;
1459 lock_ObtainWrite(&smb_rctLock);
1460 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1461 if (scp == fidp->scp) {
1466 lock_ReleaseWrite(&smb_rctLock);
1470 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1476 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1477 /* the sm_fid_t->mx and smb_rctLock must not be held */
1478 void smb_ReleaseFID(smb_fid_t *fidp)
1480 cm_scache_t *scp = NULL;
1481 cm_user_t *userp = NULL;
1482 smb_vc_t *vcp = NULL;
1483 smb_ioctl_t *ioctlp;
1485 lock_ObtainMutex(&fidp->mx);
1486 lock_ObtainWrite(&smb_rctLock);
1487 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1488 if (fidp->refCount == 0 && (fidp->delete)) {
1491 scp = fidp->scp; /* release after lock is released */
1493 lock_ObtainMutex(&scp->mx);
1494 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1495 lock_ReleaseMutex(&scp->mx);
1496 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1499 userp = fidp->userp;
1503 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1504 thrd_CloseHandle(fidp->raw_write_event);
1506 /* and see if there is ioctl stuff to free */
1507 ioctlp = fidp->ioctlp;
1510 cm_FreeSpace(ioctlp->prefix);
1511 if (ioctlp->inAllocp)
1512 free(ioctlp->inAllocp);
1513 if (ioctlp->outAllocp)
1514 free(ioctlp->outAllocp);
1517 lock_ReleaseMutex(&fidp->mx);
1518 lock_FinalizeMutex(&fidp->mx);
1522 smb_ReleaseVCNoLock(vcp);
1524 lock_ReleaseMutex(&fidp->mx);
1526 lock_ReleaseWrite(&smb_rctLock);
1528 /* now release the scache structure */
1530 cm_ReleaseSCache(scp);
1533 cm_ReleaseUser(userp);
1537 * Case-insensitive search for one string in another;
1538 * used to find variable names in submount pathnames.
1540 static char *smb_stristr(char *str1, char *str2)
1544 for (cursor = str1; *cursor; cursor++)
1545 if (stricmp(cursor, str2) == 0)
1552 * Substitute a variable value for its name in a submount pathname. Variable
1553 * name has been identified by smb_stristr() and is in substr. Variable name
1554 * length (plus one) is in substr_size. Variable value is in newstr.
1556 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1561 strcpy(temp, substr + substr_size - 1);
1562 strcpy(substr, newstr);
1566 char VNUserName[] = "%USERNAME%";
1567 char VNLCUserName[] = "%LCUSERNAME%";
1568 char VNComputerName[] = "%COMPUTERNAME%";
1569 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1572 typedef struct smb_findShare_rock {
1576 } smb_findShare_rock_t;
1578 #define SMB_FINDSHARE_EXACT_MATCH 1
1579 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1581 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1585 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1586 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1587 if(!stricmp(dep->name, vrock->shareName))
1588 matchType = SMB_FINDSHARE_EXACT_MATCH;
1590 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1591 if(vrock->match) free(vrock->match);
1592 vrock->match = strdup(dep->name);
1593 vrock->matchType = matchType;
1595 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1596 return CM_ERROR_STOPNOW;
1602 /* find a shareName in the table of submounts */
1603 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1607 char pathName[1024];
1614 DWORD allSubmount = 1;
1616 /* if allSubmounts == 0, only return the //mountRoot/all share
1617 * if in fact it has been been created in the subMounts table.
1618 * This is to allow sites that want to restrict access to the
1621 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1622 0, KEY_QUERY_VALUE, &parmKey);
1623 if (code == ERROR_SUCCESS) {
1624 len = sizeof(allSubmount);
1625 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1626 (BYTE *) &allSubmount, &len);
1627 if (code != ERROR_SUCCESS) {
1630 RegCloseKey (parmKey);
1633 if (allSubmount && _stricmp(shareName, "all") == 0) {
1638 /* In case, the all share is disabled we need to still be able
1639 * to handle ioctl requests
1641 if (_stricmp(shareName, "ioctl$") == 0) {
1642 *pathNamep = strdup("/.__ioctl__");
1646 if (_stricmp(shareName, "IPC$") == 0 ||
1647 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1648 _stricmp(shareName, "DESKTOP.INI") == 0
1654 /* Check for volume references
1656 * They look like <cell>{%,#}<volume>
1658 if (strchr(shareName, '%') != NULL ||
1659 strchr(shareName, '#') != NULL) {
1660 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1661 /* make room for '/@vol:' + mountchar + NULL terminator*/
1663 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1664 osi_LogSaveString(smb_logp, shareName));
1666 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1667 "/" CM_PREFIX_VOL "%s", shareName);
1668 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1669 len = strlen(pathstr) + 1;
1671 *pathNamep = malloc(len);
1673 strcpy(*pathNamep, pathstr);
1675 osi_Log1(smb_logp, " returning pathname [%s]",
1676 osi_LogSaveString(smb_logp, *pathNamep));
1684 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1685 0, KEY_QUERY_VALUE, &parmKey);
1686 if (code == ERROR_SUCCESS) {
1687 len = sizeof(pathName);
1688 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1689 (BYTE *) pathName, &len);
1690 if (code != ERROR_SUCCESS)
1692 RegCloseKey (parmKey);
1696 if (len != 0 && len != sizeof(pathName) - 1) {
1697 /* We can accept either unix or PC style AFS pathnames. Convert
1698 * Unix-style to PC style here for internal use.
1701 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1702 p += strlen(cm_mountRoot); /* skip mount path */
1705 if (*q == '/') *q = '\\'; /* change to \ */
1711 if (var = smb_stristr(p, VNUserName)) {
1712 if (uidp && uidp->unp)
1713 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1715 smb_subst(p, var, sizeof(VNUserName)," ");
1717 else if (var = smb_stristr(p, VNLCUserName))
1719 if (uidp && uidp->unp)
1720 strcpy(temp, uidp->unp->name);
1724 smb_subst(p, var, sizeof(VNLCUserName), temp);
1726 else if (var = smb_stristr(p, VNComputerName))
1728 sizeTemp = sizeof(temp);
1729 GetComputerName((LPTSTR)temp, &sizeTemp);
1730 smb_subst(p, var, sizeof(VNComputerName), temp);
1732 else if (var = smb_stristr(p, VNLCComputerName))
1734 sizeTemp = sizeof(temp);
1735 GetComputerName((LPTSTR)temp, &sizeTemp);
1737 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1742 *pathNamep = strdup(p);
1747 /* First lookup shareName in root.afs */
1749 smb_findShare_rock_t vrock;
1751 char * p = shareName;
1754 /* attempt to locate a partial match in root.afs. This is because
1755 when using the ANSI RAP calls, the share name is limited to 13 chars
1756 and hence is truncated. Of course we prefer exact matches. */
1758 thyper.HighPart = 0;
1761 vrock.shareName = shareName;
1763 vrock.matchType = 0;
1765 cm_HoldSCache(cm_data.rootSCachep);
1766 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1767 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1768 cm_ReleaseSCache(cm_data.rootSCachep);
1770 if (vrock.matchType) {
1771 sprintf(pathName,"/%s/",vrock.match);
1772 *pathNamep = strdup(strlwr(pathName));
1777 /* if we get here, there was no match for the share in root.afs */
1778 /* so try to create \\<netbiosName>\<cellname> */
1783 /* Get the full name for this cell */
1784 code = cm_SearchCellFile(p, temp, 0, 0);
1785 #ifdef AFS_AFSDB_ENV
1786 if (code && cm_dnsEnabled) {
1788 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1791 /* construct the path */
1793 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1794 *pathNamep = strdup(strlwr(pathName));
1803 /* Client-side offline caching policy types */
1804 #define CSC_POLICY_MANUAL 0
1805 #define CSC_POLICY_DOCUMENTS 1
1806 #define CSC_POLICY_PROGRAMS 2
1807 #define CSC_POLICY_DISABLE 3
1809 int smb_FindShareCSCPolicy(char *shareName)
1815 int retval = CSC_POLICY_MANUAL;
1817 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1818 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1821 REG_OPTION_NON_VOLATILE,
1827 len = sizeof(policy);
1828 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1830 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1832 else if (stricmp(policy, "documents") == 0)
1834 retval = CSC_POLICY_DOCUMENTS;
1836 else if (stricmp(policy, "programs") == 0)
1838 retval = CSC_POLICY_PROGRAMS;
1840 else if (stricmp(policy, "disable") == 0)
1842 retval = CSC_POLICY_DISABLE;
1845 RegCloseKey(hkCSCPolicy);
1849 /* find a dir search structure by cookie value, and return it held.
1850 * Must be called with smb_globalLock held.
1852 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1854 smb_dirSearch_t *dsp;
1856 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1857 if (dsp->cookie == cookie) {
1858 if (dsp != smb_firstDirSearchp) {
1859 /* move to head of LRU queue, too, if we're not already there */
1860 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1861 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1862 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1863 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1864 if (!smb_lastDirSearchp)
1865 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1867 lock_ObtainMutex(&dsp->mx);
1869 lock_ReleaseMutex(&dsp->mx);
1875 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1876 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1877 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1883 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1885 lock_ObtainWrite(&smb_globalLock);
1886 lock_ObtainMutex(&dsp->mx);
1887 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1888 dsp->cookie, dsp, dsp->scp);
1889 dsp->flags |= SMB_DIRSEARCH_DELETE;
1890 if (dsp->scp != NULL) {
1891 lock_ObtainMutex(&dsp->scp->mx);
1892 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1893 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1894 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1895 dsp->scp->bulkStatProgress = hzero;
1897 lock_ReleaseMutex(&dsp->scp->mx);
1899 lock_ReleaseMutex(&dsp->mx);
1900 lock_ReleaseWrite(&smb_globalLock);
1903 /* Must be called with the smb_globalLock held */
1904 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1906 cm_scache_t *scp = NULL;
1908 lock_ObtainMutex(&dsp->mx);
1909 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1910 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1911 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1912 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1913 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1914 lock_ReleaseMutex(&dsp->mx);
1915 lock_FinalizeMutex(&dsp->mx);
1917 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1918 dsp->cookie, dsp, scp);
1921 lock_ReleaseMutex(&dsp->mx);
1923 /* do this now to avoid spurious locking hierarchy creation */
1925 cm_ReleaseSCache(scp);
1928 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1930 lock_ObtainWrite(&smb_globalLock);
1931 smb_ReleaseDirSearchNoLock(dsp);
1932 lock_ReleaseWrite(&smb_globalLock);
1935 /* find a dir search structure by cookie value, and return it held */
1936 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1938 smb_dirSearch_t *dsp;
1940 lock_ObtainWrite(&smb_globalLock);
1941 dsp = smb_FindDirSearchNoLock(cookie);
1942 lock_ReleaseWrite(&smb_globalLock);
1946 /* GC some dir search entries, in the address space expected by the specific protocol.
1947 * Must be called with smb_globalLock held; release the lock temporarily.
1949 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1950 void smb_GCDirSearches(int isV3)
1952 smb_dirSearch_t *prevp;
1953 smb_dirSearch_t *tp;
1954 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1958 victimCount = 0; /* how many have we got so far */
1959 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1960 /* we'll move tp from queue, so
1963 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1964 /* if no one is using this guy, and we're either in the new protocol,
1965 * or we're in the old one and this is a small enough ID to be useful
1966 * to the old protocol, GC this guy.
1968 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1969 /* hold and delete */
1970 lock_ObtainMutex(&tp->mx);
1971 tp->flags |= SMB_DIRSEARCH_DELETE;
1972 lock_ReleaseMutex(&tp->mx);
1973 victimsp[victimCount++] = tp;
1977 /* don't do more than this */
1978 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1982 /* now release them */
1983 for (i = 0; i < victimCount; i++) {
1984 smb_ReleaseDirSearchNoLock(victimsp[i]);
1988 /* function for allocating a dir search entry. We need these to remember enough context
1989 * since we don't get passed the path from call to call during a directory search.
1991 * Returns a held dir search structure, and bumps the reference count on the vnode,
1992 * since it saves a pointer to the vnode.
1994 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1996 smb_dirSearch_t *dsp;
2002 lock_ObtainWrite(&smb_globalLock);
2005 /* what's the biggest ID allowed in this version of the protocol */
2006 /* TODO: do we really want a non v3 dir search request to wrap
2007 smb_dirSearchCounter? */
2008 maxAllowed = isV3 ? 65535 : 255;
2009 if (smb_dirSearchCounter > maxAllowed)
2010 smb_dirSearchCounter = 1;
2012 start = smb_dirSearchCounter;
2015 /* twice so we have enough tries to find guys we GC after one pass;
2016 * 10 extra is just in case I mis-counted.
2018 if (++counter > 2*maxAllowed+10)
2019 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2021 if (smb_dirSearchCounter > maxAllowed) {
2022 smb_dirSearchCounter = 1;
2024 if (smb_dirSearchCounter == start) {
2026 smb_GCDirSearches(isV3);
2029 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2031 /* don't need to watch for refcount zero and deleted, since
2032 * we haven't dropped the global lock.
2034 lock_ObtainMutex(&dsp->mx);
2036 lock_ReleaseMutex(&dsp->mx);
2037 ++smb_dirSearchCounter;
2041 dsp = malloc(sizeof(*dsp));
2042 memset(dsp, 0, sizeof(*dsp));
2043 dsp->cookie = smb_dirSearchCounter;
2044 ++smb_dirSearchCounter;
2046 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2047 dsp->lastTime = osi_Time();
2048 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2049 if (!smb_lastDirSearchp)
2050 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2052 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2056 lock_ReleaseWrite(&smb_globalLock);
2060 static smb_packet_t *GetPacket(void)
2064 lock_ObtainWrite(&smb_globalLock);
2065 tbp = smb_packetFreeListp;
2067 smb_packetFreeListp = tbp->nextp;
2068 lock_ReleaseWrite(&smb_globalLock);
2070 tbp = calloc(65540,1);
2071 tbp->magic = SMB_PACKETMAGIC;
2074 tbp->resumeCode = 0;
2080 tbp->ncb_length = 0;
2085 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2090 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2094 memcpy(tbp, pkt, sizeof(smb_packet_t));
2095 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2097 smb_HoldVC(tbp->vcp);
2101 static NCB *GetNCB(void)
2106 lock_ObtainWrite(&smb_globalLock);
2107 tbp = smb_ncbFreeListp;
2109 smb_ncbFreeListp = tbp->nextp;
2110 lock_ReleaseWrite(&smb_globalLock);
2112 tbp = calloc(sizeof(*tbp),1);
2113 tbp->magic = SMB_NCBMAGIC;
2116 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2118 memset(&tbp->ncb, 0, sizeof(NCB));
2123 void smb_FreePacket(smb_packet_t *tbp)
2125 smb_vc_t * vcp = NULL;
2126 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2128 lock_ObtainWrite(&smb_globalLock);
2129 tbp->nextp = smb_packetFreeListp;
2130 smb_packetFreeListp = tbp;
2131 tbp->magic = SMB_PACKETMAGIC;
2135 tbp->resumeCode = 0;
2141 tbp->ncb_length = 0;
2143 lock_ReleaseWrite(&smb_globalLock);
2149 static void FreeNCB(NCB *bufferp)
2153 tbp = (smb_ncb_t *) bufferp;
2154 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2156 lock_ObtainWrite(&smb_globalLock);
2157 tbp->nextp = smb_ncbFreeListp;
2158 smb_ncbFreeListp = tbp;
2159 lock_ReleaseWrite(&smb_globalLock);
2162 /* get a ptr to the data part of a packet, and its count */
2163 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2167 unsigned char *afterParmsp;
2169 parmBytes = *smbp->wctp << 1;
2170 afterParmsp = smbp->wctp + parmBytes + 1;
2172 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2173 if (nbytesp) *nbytesp = dataBytes;
2175 /* don't forget to skip the data byte count, since it follows
2176 * the parameters; that's where the "2" comes from below.
2178 return (unsigned char *) (afterParmsp + 2);
2181 /* must set all the returned parameters before playing around with the
2182 * data region, since the data region is located past the end of the
2183 * variable number of parameters.
2185 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2187 unsigned char *afterParmsp;
2189 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2191 *afterParmsp++ = dsize & 0xff;
2192 *afterParmsp = (dsize>>8) & 0xff;
2195 /* return the parm'th parameter in the smbp packet */
2196 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2199 unsigned char *parmDatap;
2201 parmCount = *smbp->wctp;
2203 if (parm >= parmCount) {
2206 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2207 parm, parmCount, smbp->ncb_length);
2208 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2209 parm, parmCount, smbp->ncb_length);
2210 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2211 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2212 osi_panic(s, __FILE__, __LINE__);
2214 parmDatap = smbp->wctp + (2*parm) + 1;
2216 return parmDatap[0] + (parmDatap[1] << 8);
2219 /* return the parm'th parameter in the smbp packet */
2220 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2223 unsigned char *parmDatap;
2225 parmCount = *smbp->wctp;
2227 if (parm >= parmCount) {
2230 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2231 parm, parmCount, smbp->ncb_length);
2232 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2233 parm, parmCount, smbp->ncb_length);
2234 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2235 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2236 osi_panic(s, __FILE__, __LINE__);
2238 parmDatap = smbp->wctp + (2*parm) + 1;
2240 return parmDatap[0];
2243 /* return the parm'th parameter in the smbp packet */
2244 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2247 unsigned char *parmDatap;
2249 parmCount = *smbp->wctp;
2251 if (parm + 1 >= parmCount) {
2254 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2255 parm, parmCount, smbp->ncb_length);
2256 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2257 parm, parmCount, smbp->ncb_length);
2258 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2259 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2260 osi_panic(s, __FILE__, __LINE__);
2262 parmDatap = smbp->wctp + (2*parm) + 1;
2264 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2267 /* return the parm'th parameter in the smbp packet */
2268 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2271 unsigned char *parmDatap;
2273 parmCount = *smbp->wctp;
2275 if (parm * 2 + offset >= parmCount * 2) {
2278 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2279 parm, offset, parmCount, smbp->ncb_length);
2280 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2281 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2282 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2283 parm, offset, parmCount, smbp->ncb_length);
2284 osi_panic(s, __FILE__, __LINE__);
2286 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2288 return parmDatap[0] + (parmDatap[1] << 8);
2291 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2295 /* make sure we have enough slots */
2296 if (*smbp->wctp <= slot)
2297 *smbp->wctp = slot+1;
2299 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2300 *parmDatap++ = parmValue & 0xff;
2301 *parmDatap = (parmValue>>8) & 0xff;
2304 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2308 /* make sure we have enough slots */
2309 if (*smbp->wctp <= slot)
2310 *smbp->wctp = slot+2;
2312 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2313 *parmDatap++ = parmValue & 0xff;
2314 *parmDatap++ = (parmValue>>8) & 0xff;
2315 *parmDatap++ = (parmValue>>16) & 0xff;
2316 *parmDatap = (parmValue>>24) & 0xff;
2319 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2324 /* make sure we have enough slots */
2325 if (*smbp->wctp <= slot)
2326 *smbp->wctp = slot+4;
2328 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2330 *parmDatap++ = *parmValuep++;
2333 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2337 /* make sure we have enough slots */
2338 if (*smbp->wctp <= slot) {
2339 if (smbp->oddByte) {
2341 *smbp->wctp = slot+1;
2346 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2347 *parmDatap++ = parmValue & 0xff;
2350 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2354 lastSlashp = strrchr(inPathp, '\\');
2356 *lastComponentp = lastSlashp;
2359 if (inPathp == lastSlashp)
2361 *outPathp++ = *inPathp++;
2370 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2375 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2380 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2386 tlen = inp[0] + (inp[1]<<8);
2387 inp += 2; /* skip length field */
2390 *chainpp = inp + tlen;
2399 /* format a packet as a response */
2400 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2405 outp = (smb_t *) op;
2407 /* zero the basic structure through the smb_wct field, and zero the data
2408 * size field, assuming that wct stays zero; otherwise, you have to
2409 * explicitly set the data size field, too.
2411 inSmbp = (smb_t *) inp;
2412 memset(outp, 0, sizeof(smb_t)+2);
2418 outp->com = inSmbp->com;
2419 outp->tid = inSmbp->tid;
2420 outp->pid = inSmbp->pid;
2421 outp->uid = inSmbp->uid;
2422 outp->mid = inSmbp->mid;
2423 outp->res[0] = inSmbp->res[0];
2424 outp->res[1] = inSmbp->res[1];
2425 op->inCom = inSmbp->com;
2427 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2428 #ifdef SEND_CANONICAL_PATHNAMES
2429 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2431 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2433 /* copy fields in generic packet area */
2434 op->wctp = &outp->wct;
2437 /* send a (probably response) packet; vcp tells us to whom to send it.
2438 * we compute the length by looking at wct and bcc fields.
2440 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2454 memset((char *)ncbp, 0, sizeof(NCB));
2456 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2457 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2458 extra += tp[0] + (tp[1]<<8);
2459 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2460 extra += 3; /* wct and length fields */
2462 ncbp->ncb_length = extra; /* bytes to send */
2463 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2464 ncbp->ncb_lana_num = vcp->lana;
2465 ncbp->ncb_command = NCBSEND; /* op means send data */
2466 ncbp->ncb_buffer = (char *) inp;/* packet */
2467 code = Netbios(ncbp);
2470 const char * s = ncb_error_string(code);
2471 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2472 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2474 lock_ObtainMutex(&vcp->mx);
2475 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2476 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2478 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2479 lock_ReleaseMutex(&vcp->mx);
2480 lock_ObtainWrite(&smb_globalLock);
2481 dead_sessions[vcp->session] = TRUE;
2482 lock_ReleaseWrite(&smb_globalLock);
2483 smb_CleanupDeadVC(vcp);
2485 lock_ReleaseMutex(&vcp->mx);
2493 void smb_MapNTError(long code, unsigned long *NTStatusp)
2495 unsigned long NTStatus;
2497 /* map CM_ERROR_* errors to NT 32-bit status codes */
2498 /* NT Status codes are listed in ntstatus.h not winerror.h */
2499 if (code == CM_ERROR_NOSUCHCELL) {
2500 NTStatus = 0xC000000FL; /* No such file */
2502 else if (code == CM_ERROR_NOSUCHVOLUME) {
2503 NTStatus = 0xC000000FL; /* No such file */
2505 else if (code == CM_ERROR_TIMEDOUT) {
2507 NTStatus = 0xC00000CFL; /* Sharing Paused */
2509 NTStatus = 0x00000102L; /* Timeout */
2512 else if (code == CM_ERROR_RETRY) {
2513 NTStatus = 0xC000022DL; /* Retry */
2515 else if (code == CM_ERROR_NOACCESS) {
2516 NTStatus = 0xC0000022L; /* Access denied */
2518 else if (code == CM_ERROR_READONLY) {
2519 NTStatus = 0xC00000A2L; /* Write protected */
2521 else if (code == CM_ERROR_NOSUCHFILE ||
2522 code == CM_ERROR_BPLUS_NOMATCH) {
2523 NTStatus = 0xC000000FL; /* No such file */
2525 else if (code == CM_ERROR_NOSUCHPATH) {
2526 NTStatus = 0xC000003AL; /* Object path not found */
2528 else if (code == CM_ERROR_TOOBIG) {
2529 NTStatus = 0xC000007BL; /* Invalid image format */
2531 else if (code == CM_ERROR_INVAL) {
2532 NTStatus = 0xC000000DL; /* Invalid parameter */
2534 else if (code == CM_ERROR_BADFD) {
2535 NTStatus = 0xC0000008L; /* Invalid handle */
2537 else if (code == CM_ERROR_BADFDOP) {
2538 NTStatus = 0xC0000022L; /* Access denied */
2540 else if (code == CM_ERROR_EXISTS) {
2541 NTStatus = 0xC0000035L; /* Object name collision */
2543 else if (code == CM_ERROR_NOTEMPTY) {
2544 NTStatus = 0xC0000101L; /* Directory not empty */
2546 else if (code == CM_ERROR_CROSSDEVLINK) {
2547 NTStatus = 0xC00000D4L; /* Not same device */
2549 else if (code == CM_ERROR_NOTDIR) {
2550 NTStatus = 0xC0000103L; /* Not a directory */
2552 else if (code == CM_ERROR_ISDIR) {
2553 NTStatus = 0xC00000BAL; /* File is a directory */
2555 else if (code == CM_ERROR_BADOP) {
2557 /* I have no idea where this comes from */
2558 NTStatus = 0xC09820FFL; /* SMB no support */
2560 NTStatus = 0xC00000BBL; /* Not supported */
2561 #endif /* COMMENT */
2563 else if (code == CM_ERROR_BADSHARENAME) {
2564 NTStatus = 0xC00000CCL; /* Bad network name */
2566 else if (code == CM_ERROR_NOIPC) {
2568 NTStatus = 0xC0000022L; /* Access Denied */
2570 NTStatus = 0xC000013DL; /* Remote Resources */
2573 else if (code == CM_ERROR_CLOCKSKEW) {
2574 NTStatus = 0xC0000133L; /* Time difference at DC */
2576 else if (code == CM_ERROR_BADTID) {
2577 NTStatus = 0xC0982005L; /* SMB bad TID */
2579 else if (code == CM_ERROR_USESTD) {
2580 NTStatus = 0xC09820FBL; /* SMB use standard */
2582 else if (code == CM_ERROR_QUOTA) {
2583 NTStatus = 0xC0000044L; /* Quota exceeded */
2585 else if (code == CM_ERROR_SPACE) {
2586 NTStatus = 0xC000007FL; /* Disk full */
2588 else if (code == CM_ERROR_ATSYS) {
2589 NTStatus = 0xC0000033L; /* Object name invalid */
2591 else if (code == CM_ERROR_BADNTFILENAME) {
2592 NTStatus = 0xC0000033L; /* Object name invalid */
2594 else if (code == CM_ERROR_WOULDBLOCK) {
2595 NTStatus = 0xC0000055L; /* Lock not granted */
2597 else if (code == CM_ERROR_SHARING_VIOLATION) {
2598 NTStatus = 0xC0000043L; /* Sharing violation */
2600 else if (code == CM_ERROR_LOCK_CONFLICT) {
2601 NTStatus = 0xC0000054L; /* Lock conflict */
2603 else if (code == CM_ERROR_PARTIALWRITE) {
2604 NTStatus = 0xC000007FL; /* Disk full */
2606 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2607 NTStatus = 0xC0000023L; /* Buffer too small */
2609 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2610 NTStatus = 0xC0000035L; /* Object name collision */
2612 else if (code == CM_ERROR_BADPASSWORD) {
2613 NTStatus = 0xC000006DL; /* unknown username or bad password */
2615 else if (code == CM_ERROR_BADLOGONTYPE) {
2616 NTStatus = 0xC000015BL; /* logon type not granted */
2618 else if (code == CM_ERROR_GSSCONTINUE) {
2619 NTStatus = 0xC0000016L; /* more processing required */
2621 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2623 NTStatus = 0xC0000280L; /* reparse point not resolved */
2625 NTStatus = 0xC0000022L; /* Access Denied */
2628 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2629 NTStatus = 0xC0000257L; /* Path Not Covered */
2631 else if (code == CM_ERROR_ALLBUSY) {
2632 NTStatus = 0xC000022DL; /* Retry */
2634 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2635 NTStatus = 0xC00000BEL; /* Bad Network Path */
2637 else if (code == RXKADUNKNOWNKEY) {
2638 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2640 else if (code == CM_ERROR_BAD_LEVEL) {
2641 NTStatus = 0xC0000148L; /* Invalid Level */
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 smb_ReleaseFID(fidp);
2951 lock_ReleaseMutex(&fidp->mx);
2953 userp = smb_GetUserFromVCP(vcp, inp);
2955 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2961 cm_ReleaseUser(userp);
2964 smb_ReleaseFID(fidp);
2968 memset((char *)ncbp, 0, sizeof(NCB));
2970 ncbp->ncb_length = (unsigned short) finalCount;
2971 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2972 ncbp->ncb_lana_num = vcp->lana;
2973 ncbp->ncb_command = NCBSEND;
2974 ncbp->ncb_buffer = rawBuf;
2976 code = Netbios(ncbp);
2978 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2981 /* Give back raw buffer */
2982 lock_ObtainMutex(&smb_RawBufLock);
2983 *((char **) rawBuf) = smb_RawBufs;
2985 smb_RawBufs = rawBuf;
2986 lock_ReleaseMutex(&smb_RawBufLock);
2992 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2994 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2999 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3001 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3006 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3013 int VistaProtoIndex;
3014 int protoIndex; /* index we're using */
3019 char protocol_array[10][1024]; /* protocol signature of the client */
3020 int caps; /* capabilities */
3023 TIME_ZONE_INFORMATION tzi;
3025 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3028 namep = smb_GetSMBData(inp, &dbytes);
3031 coreProtoIndex = -1; /* not found */
3034 VistaProtoIndex = -1;
3035 while(namex < dbytes) {
3036 osi_Log1(smb_logp, "Protocol %s",
3037 osi_LogSaveString(smb_logp, namep+1));
3038 strcpy(protocol_array[tcounter], namep+1);
3040 /* namep points at the first protocol, or really, a 0x02
3041 * byte preceding the null-terminated ASCII name.
3043 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3044 coreProtoIndex = tcounter;
3046 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3047 v3ProtoIndex = tcounter;
3049 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3050 NTProtoIndex = tcounter;
3052 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3053 VistaProtoIndex = tcounter;
3056 /* compute size of protocol entry */
3057 entryLength = (int)strlen(namep+1);
3058 entryLength += 2; /* 0x02 bytes and null termination */
3060 /* advance over this protocol entry */
3061 namex += entryLength;
3062 namep += entryLength;
3063 tcounter++; /* which proto entry we're looking at */
3066 lock_ObtainMutex(&vcp->mx);
3068 if (VistaProtoIndex != -1) {
3069 protoIndex = VistaProtoIndex;
3070 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3073 if (NTProtoIndex != -1) {
3074 protoIndex = NTProtoIndex;
3075 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3077 else if (v3ProtoIndex != -1) {
3078 protoIndex = v3ProtoIndex;
3079 vcp->flags |= SMB_VCFLAG_USEV3;
3081 else if (coreProtoIndex != -1) {
3082 protoIndex = coreProtoIndex;
3083 vcp->flags |= SMB_VCFLAG_USECORE;
3085 else protoIndex = -1;
3086 lock_ReleaseMutex(&vcp->mx);
3088 if (protoIndex == -1)
3089 return CM_ERROR_INVAL;
3090 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3091 smb_SetSMBParm(outp, 0, protoIndex);
3092 if (smb_authType != SMB_AUTH_NONE) {
3093 smb_SetSMBParmByte(outp, 1,
3094 NEGOTIATE_SECURITY_USER_LEVEL |
3095 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3097 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3099 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3100 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3101 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3102 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3103 /* The session key is not a well documented field however most clients
3104 * will echo back the session key to the server. Currently we are using
3105 * the same value for all sessions. We should generate a random value
3106 * and store it into the vcp
3108 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3109 smb_SetSMBParm(outp, 8, 1);
3111 * Tried changing the capabilities to support for W2K - defect 117695
3112 * Maybe something else needs to be changed here?
3116 smb_SetSMBParmLong(outp, 9, 0x43fd);
3118 smb_SetSMBParmLong(outp, 9, 0x251);
3121 * 32-bit error codes *
3126 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3128 NTNEGOTIATE_CAPABILITY_DFS |
3130 #ifdef AFS_LARGEFILES
3131 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3133 NTNEGOTIATE_CAPABILITY_NTFIND |
3134 NTNEGOTIATE_CAPABILITY_RAWMODE |
3135 NTNEGOTIATE_CAPABILITY_NTSMB;
3137 if ( smb_authType == SMB_AUTH_EXTENDED )
3138 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3140 smb_SetSMBParmLong(outp, 9, caps);
3142 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3143 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3144 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3146 GetTimeZoneInformation(&tzi);
3147 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3149 if (smb_authType == SMB_AUTH_NTLM) {
3150 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3151 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3152 /* paste in encryption key */
3153 datap = smb_GetSMBData(outp, NULL);
3154 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3155 /* and the faux domain name */
3156 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3157 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3161 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3163 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3165 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3167 datap = smb_GetSMBData(outp, NULL);
3168 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3171 datap += sizeof(smb_ServerGUID);
3172 memcpy(datap, secBlob, secBlobLength);
3176 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3177 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3180 else if (v3ProtoIndex != -1) {
3181 smb_SetSMBParm(outp, 0, protoIndex);
3183 /* NOTE: Extended authentication cannot be negotiated with v3
3184 * therefore we fail over to NTLM
3186 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3187 smb_SetSMBParm(outp, 1,
3188 NEGOTIATE_SECURITY_USER_LEVEL |
3189 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3191 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3193 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3194 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3195 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3196 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3197 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3198 smb_SetSMBParm(outp, 7, 1);
3200 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3201 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3202 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3204 GetTimeZoneInformation(&tzi);
3205 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3207 /* NOTE: Extended authentication cannot be negotiated with v3
3208 * therefore we fail over to NTLM
3210 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3211 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3212 smb_SetSMBParm(outp, 12, 0); /* resvd */
3213 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3214 datap = smb_GetSMBData(outp, NULL);
3215 /* paste in a new encryption key */
3216 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3217 /* and the faux domain name */
3218 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3220 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3221 smb_SetSMBParm(outp, 12, 0); /* resvd */
3222 smb_SetSMBDataLength(outp, 0);
3225 else if (coreProtoIndex != -1) { /* not really supported anymore */
3226 smb_SetSMBParm(outp, 0, protoIndex);
3227 smb_SetSMBDataLength(outp, 0);
3232 void smb_CheckVCs(void)
3234 smb_vc_t * vcp, *nextp;
3235 smb_packet_t * outp = GetPacket();
3238 lock_ObtainWrite(&smb_rctLock);
3239 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3241 if (vcp->magic != SMB_VC_MAGIC)
3242 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3243 __FILE__, __LINE__);
3247 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3250 smb_HoldVCNoLock(vcp);
3252 smb_HoldVCNoLock(nextp);
3253 smb_FormatResponsePacket(vcp, NULL, outp);
3254 smbp = (smb_t *)outp;
3255 outp->inCom = smbp->com = 0x2b /* Echo */;
3263 smb_SetSMBParm(outp, 0, 0);
3264 smb_SetSMBDataLength(outp, 0);
3265 lock_ReleaseWrite(&smb_rctLock);
3267 smb_SendPacket(vcp, outp);
3269 lock_ObtainWrite(&smb_rctLock);
3270 smb_ReleaseVCNoLock(vcp);
3272 smb_ReleaseVCNoLock(nextp);
3274 lock_ReleaseWrite(&smb_rctLock);
3275 smb_FreePacket(outp);
3278 void smb_Daemon(void *parmp)
3280 afs_uint32 count = 0;
3281 smb_username_t **unpp;
3284 while(smbShutdownFlag == 0) {
3288 if (smbShutdownFlag == 1)
3291 if ((count % 72) == 0) { /* every five minutes */
3293 time_t old_localZero = smb_localZero;
3295 /* Initialize smb_localZero */
3296 myTime.tm_isdst = -1; /* compute whether on DST or not */
3297 myTime.tm_year = 70;
3303 smb_localZero = mktime(&myTime);
3305 #ifndef USE_NUMERIC_TIME_CONV
3306 smb_CalculateNowTZ();
3307 #endif /* USE_NUMERIC_TIME_CONV */
3308 #ifdef AFS_FREELANCE
3309 if ( smb_localZero != old_localZero )
3310 cm_noteLocalMountPointChange();
3316 /* GC smb_username_t objects that will no longer be used */
3318 lock_ObtainWrite(&smb_rctLock);
3319 for ( unpp=&usernamesp; *unpp; ) {
3321 smb_username_t *unp;
3323 lock_ObtainMutex(&(*unpp)->mx);
3324 if ( (*unpp)->refCount > 0 ||
3325 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3326 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3328 else if (!smb_LogoffTokenTransfer ||
3329 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3331 lock_ReleaseMutex(&(*unpp)->mx);
3339 lock_FinalizeMutex(&unp->mx);
3345 lock_ReleaseWrite(&smb_rctLock);
3346 cm_ReleaseUser(userp);
3347 lock_ObtainWrite(&smb_rctLock);
3350 unpp = &(*unpp)->nextp;
3353 lock_ReleaseWrite(&smb_rctLock);
3355 /* XXX GC dir search entries */
3359 void smb_WaitingLocksDaemon()
3361 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3362 smb_waitingLock_t *wl, *wlNext;
3365 smb_packet_t *inp, *outp;
3369 while (smbShutdownFlag == 0) {
3370 lock_ObtainWrite(&smb_globalLock);
3371 nwlRequest = smb_allWaitingLocks;
3372 if (nwlRequest == NULL) {
3373 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3378 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3385 lock_ObtainWrite(&smb_globalLock);
3387 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3389 wlRequest = nwlRequest;
3390 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3391 lock_ReleaseWrite(&smb_globalLock);
3395 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3396 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3399 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3401 /* wl->state is either _DONE or _WAITING. _ERROR
3402 would no longer be on the queue. */
3403 code = cm_RetryLock( wl->lockp,
3404 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3407 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3408 } else if (code != CM_ERROR_WOULDBLOCK) {
3409 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3414 if (code == CM_ERROR_WOULDBLOCK) {
3417 if (wlRequest->timeRemaining != 0xffffffff
3418 && (wlRequest->timeRemaining -= 1000) < 0)
3430 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3433 scp = wlRequest->scp;
3434 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3438 lock_ObtainMutex(&scp->mx);
3440 for (wl = wlRequest->locks; wl; wl = wlNext) {
3441 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3443 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3444 wl->LLength, wl->key, NULL, &req);
3446 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3451 lock_ReleaseMutex(&scp->mx);
3455 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3458 for (wl = wlRequest->locks; wl; wl = wlNext) {
3459 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3460 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3465 vcp = wlRequest->vcp;
3466 inp = wlRequest->inp;
3467 outp = wlRequest->outp;
3469 ncbp->ncb_length = inp->ncb_length;
3470 inp->spacep = cm_GetSpace();
3472 /* Remove waitingLock from list */
3473 lock_ObtainWrite(&smb_globalLock);
3474 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3476 lock_ReleaseWrite(&smb_globalLock);
3478 /* Resume packet processing */
3480 smb_SetSMBDataLength(outp, 0);
3481 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3482 outp->resumeCode = code;
3484 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3487 cm_FreeSpace(inp->spacep);
3488 smb_FreePacket(inp);
3489 smb_FreePacket(outp);
3491 cm_ReleaseSCache(wlRequest->scp);
3494 } while (nwlRequest && smbShutdownFlag == 0);
3499 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3501 osi_Log0(smb_logp, "SMB receive get disk attributes");
3503 smb_SetSMBParm(outp, 0, 32000);
3504 smb_SetSMBParm(outp, 1, 64);
3505 smb_SetSMBParm(outp, 2, 1024);
3506 smb_SetSMBParm(outp, 3, 30000);
3507 smb_SetSMBParm(outp, 4, 0);
3508 smb_SetSMBDataLength(outp, 0);
3512 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3516 unsigned short newTid;
3517 char shareName[AFSPATHMAX];
3525 osi_Log0(smb_logp, "SMB receive tree connect");
3527 /* parse input parameters */
3528 tp = smb_GetSMBData(inp, NULL);
3529 pathp = smb_ParseASCIIBlock(tp, &tp);
3530 if (smb_StoreAnsiFilenames)
3531 OemToChar(pathp,pathp);
3532 passwordp = smb_ParseASCIIBlock(tp, &tp);
3533 tp = strrchr(pathp, '\\');
3535 return CM_ERROR_BADSMB;
3536 strcpy(shareName, tp+1);
3538 lock_ObtainMutex(&vcp->mx);
3539 newTid = vcp->tidCounter++;
3540 lock_ReleaseMutex(&vcp->mx);
3542 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3543 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3544 userp = smb_GetUserFromUID(uidp);
3545 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3547 smb_ReleaseUID(uidp);
3549 smb_ReleaseTID(tidp);
3550 return CM_ERROR_BADSHARENAME;
3552 lock_ObtainMutex(&tidp->mx);
3553 tidp->userp = userp;
3554 tidp->pathname = sharePath;
3555 lock_ReleaseMutex(&tidp->mx);
3556 smb_ReleaseTID(tidp);
3558 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3559 smb_SetSMBParm(rsp, 1, newTid);
3560 smb_SetSMBDataLength(rsp, 0);
3562 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3566 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3570 if (*inp++ != 0x1) return NULL;
3571 tlen = inp[0] + (inp[1]<<8);
3572 inp += 2; /* skip length field */
3575 *chainpp = inp + tlen;
3578 if (lengthp) *lengthp = tlen;
3583 /* set maskp to the mask part of the incoming path.
3584 * Mask is 11 bytes long (8.3 with the dot elided).
3585 * Returns true if succeeds with a valid name, otherwise it does
3586 * its best, but returns false.
3588 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3596 /* starts off valid */
3599 /* mask starts out all blanks */
3600 memset(maskp, ' ', 11);
3603 /* find last backslash, or use whole thing if there is none */
3604 tp = strrchr(pathp, '\\');
3608 tp++; /* skip slash */
3612 /* names starting with a dot are illegal */
3620 if (tc == '.' || tc == '"')
3628 /* if we get here, tp point after the dot */
3629 up = maskp+8; /* ext goes here */
3636 if (tc == '.' || tc == '"')
3639 /* copy extension if not too long */
3649 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3659 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3661 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3665 /* otherwise, we have a valid 8.3 name; see if we have a match,
3666 * treating '?' as a wildcard in maskp (but not in the file name).
3668 tp1 = umask; /* real name, in mask format */
3669 tp2 = maskp; /* mask, in mask format */
3670 for(i=0; i<11; i++) {
3671 tc1 = *tp1++; /* char from real name */
3672 tc2 = *tp2++; /* char from mask */
3673 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3674 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3677 if (tc2 == '?' && tc1 != ' ')
3684 /* we got a match */
3688 char *smb_FindMask(char *pathp)
3692 tp = strrchr(pathp, '\\'); /* find last slash */
3695 return tp+1; /* skip the slash */
3697 return pathp; /* no slash, return the entire path */
3700 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3702 unsigned char *pathp;
3704 unsigned char mask[12];
3705 unsigned char *statBlockp;
3706 unsigned char initStatBlock[21];
3709 osi_Log0(smb_logp, "SMB receive search volume");
3711 /* pull pathname and stat block out of request */
3712 tp = smb_GetSMBData(inp, NULL);
3713 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3714 osi_assertx(pathp != NULL, "null path");
3715 if (smb_StoreAnsiFilenames)
3716 OemToChar(pathp,pathp);
3717 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3718 osi_assertx(statBlockp != NULL, "null statBlock");
3720 statBlockp = initStatBlock;
3724 /* for returning to caller */
3725 smb_Get8Dot3MaskFromPath(mask, pathp);
3727 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3728 tp = smb_GetSMBData(outp, NULL);
3730 *tp++ = 43; /* bytes in a dir entry */
3731 *tp++ = 0; /* high byte in counter */
3733 /* now marshall the dir entry, starting with the search status */
3734 *tp++ = statBlockp[0]; /* Reserved */
3735 memcpy(tp, mask, 11); tp += 11; /* FileName */
3737 /* now pass back server use info, with 1st byte non-zero */
3739 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3741 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3743 *tp++ = 0x8; /* attribute: volume */
3753 /* 4 byte file size */
3759 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3760 memset(tp, ' ', 13);
3763 /* set the length of the data part of the packet to 43 + 3, for the dir
3764 * entry plus the 5 and the length fields.
3766 smb_SetSMBDataLength(outp, 46);
3771 smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3772 char * tidPathp, char * relPathp,
3773 cm_user_t *userp, cm_req_t *reqp)
3781 smb_dirListPatch_t *patchp;
3782 smb_dirListPatch_t *npatchp;
3783 char path[AFSPATHMAX];
3785 for (patchp = *dirPatchespp; patchp; patchp =
3786 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3788 dptr = patchp->dptr;
3790 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
3791 reqp->relPathp = path;
3792 reqp->tidPathp = tidPathp;
3794 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3795 reqp->relPathp = reqp->tidPathp = NULL;
3798 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3799 *dptr++ = SMB_ATTR_HIDDEN;
3802 lock_ObtainMutex(&scp->mx);
3803 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3804 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3806 lock_ReleaseMutex(&scp->mx);
3807 cm_ReleaseSCache(scp);
3808 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3809 *dptr++ = SMB_ATTR_HIDDEN;
3813 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3815 attr = smb_Attributes(scp);
3816 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3817 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3818 attr |= SMB_ATTR_HIDDEN;
3822 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3825 shortTemp = (unsigned short) (dosTime & 0xffff);
3826 *((u_short *)dptr) = shortTemp;
3829 /* and copy out date */
3830 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3831 *((u_short *)dptr) = shortTemp;
3834 /* copy out file length */
3835 *((u_long *)dptr) = scp->length.LowPart;
3837 lock_ReleaseMutex(&scp->mx);
3838 cm_ReleaseSCache(scp);
3841 /* now free the patches */
3842 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3843 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3847 /* and mark the list as empty */
3848 *dirPatchespp = NULL;
3853 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3860 cm_dirEntry_t *dep = 0;
3862 smb_dirListPatch_t *dirListPatchesp;
3863 smb_dirListPatch_t *curPatchp;
3867 osi_hyper_t dirLength;
3868 osi_hyper_t bufferOffset;
3869 osi_hyper_t curOffset;
3871 unsigned char *inCookiep;
3872 smb_dirSearch_t *dsp;
3876 unsigned long clientCookie;
3877 cm_pageHeader_t *pageHeaderp;
3878 cm_user_t *userp = NULL;
3885 long nextEntryCookie;
3886 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3887 char resByte; /* reserved byte from the cookie */
3888 char *op; /* output data ptr */
3889 char *origOp; /* original value of op */
3890 cm_space_t *spacep; /* for pathname buffer */
3901 maxCount = smb_GetSMBParm(inp, 0);
3903 dirListPatchesp = NULL;
3905 caseFold = CM_FLAG_CASEFOLD;
3907 tp = smb_GetSMBData(inp, NULL);
3908 pathp = smb_ParseASCIIBlock(tp, &tp);
3909 if (smb_StoreAnsiFilenames)
3910 OemToChar(pathp,pathp);
3911 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3913 /* bail out if request looks bad */
3914 if (!tp || !pathp) {
3915 return CM_ERROR_BADSMB;
3918 /* We can handle long names */
3919 if (vcp->flags & SMB_VCFLAG_USENT)
3920 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3922 /* make sure we got a whole search status */
3923 if (dataLength < 21) {
3924 nextCookie = 0; /* start at the beginning of the dir */
3927 attribute = smb_GetSMBParm(inp, 1);
3929 /* handle volume info in another function */
3930 if (attribute & 0x8)
3931 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3933 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3934 maxCount, osi_LogSaveString(smb_logp, pathp));
3936 if (*pathp == 0) { /* null pathp, treat as root dir */
3937 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3938 return CM_ERROR_NOFILES;
3942 dsp = smb_NewDirSearch(0);
3943 dsp->attribute = attribute;
3944 smb_Get8Dot3MaskFromPath(mask, pathp);
3945 memcpy(dsp->mask, mask, 12);
3947 /* track if this is likely to match a lot of entries */
3948 if (smb_IsStarMask(mask))
3953 /* pull the next cookie value out of the search status block */
3954 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3955 + (inCookiep[16]<<24);
3956 dsp = smb_FindDirSearch(inCookiep[12]);
3958 /* can't find dir search status; fatal error */
3959 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3960 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3961 return CM_ERROR_BADFD;
3963 attribute = dsp->attribute;
3964 resByte = inCookiep[0];
3966 /* copy out client cookie, in host byte order. Don't bother
3967 * interpreting it, since we're just passing it through, anyway.
3969 memcpy(&clientCookie, &inCookiep[17], 4);
3971 memcpy(mask, dsp->mask, 12);
3973 /* assume we're doing a star match if it has continued for more
3979 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3980 nextCookie, dsp->cookie, attribute);
3982 userp = smb_GetUserFromVCP(vcp, inp);
3984 /* try to get the vnode for the path name next */
3985 lock_ObtainMutex(&dsp->mx);
3988 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3992 spacep = inp->spacep;
3993 smb_StripLastComponent(spacep->data, NULL, pathp);
3994 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3996 lock_ReleaseMutex(&dsp->mx);
3997 cm_ReleaseUser(userp);
3998 smb_DeleteDirSearch(dsp);
3999 smb_ReleaseDirSearch(dsp);
4000 return CM_ERROR_NOFILES;
4002 strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
4003 strcpy(dsp->relPath, spacep->data);
4005 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4006 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4009 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4010 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4011 cm_ReleaseSCache(scp);
4012 lock_ReleaseMutex(&dsp->mx);
4013 cm_ReleaseUser(userp);
4014 smb_DeleteDirSearch(dsp);
4015 smb_ReleaseDirSearch(dsp);
4016 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4017 return CM_ERROR_PATH_NOT_COVERED;
4019 return CM_ERROR_BADSHARENAME;
4021 #endif /* DFS_SUPPORT */
4024 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4025 /* we need one hold for the entry we just stored into,
4026 * and one for our own processing. When we're done with this
4027 * function, we'll drop the one for our own processing.
4028 * We held it once from the namei call, and so we do another hold
4032 lock_ObtainMutex(&scp->mx);
4033 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4034 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4035 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4036 dsp->flags |= SMB_DIRSEARCH_BULKST;
4037 dsp->scp->bulkStatProgress = hzero;
4039 lock_ReleaseMutex(&scp->mx);
4042 lock_ReleaseMutex(&dsp->mx);
4044 cm_ReleaseUser(userp);
4045 smb_DeleteDirSearch(dsp);
4046 smb_ReleaseDirSearch(dsp);
4050 /* reserves space for parameter; we'll adjust it again later to the
4051 * real count of the # of entries we returned once we've actually
4052 * assembled the directory listing.
4054 smb_SetSMBParm(outp, 0, 0);
4056 /* get the directory size */
4057 lock_ObtainMutex(&scp->mx);
4058 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4059 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4061 lock_ReleaseMutex(&scp->mx);
4062 cm_ReleaseSCache(scp);
4063 cm_ReleaseUser(userp);
4064 smb_DeleteDirSearch(dsp);
4065 smb_ReleaseDirSearch(dsp);
4069 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4071 dirLength = scp->length;
4073 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4074 curOffset.HighPart = 0;
4075 curOffset.LowPart = nextCookie;
4076 origOp = op = smb_GetSMBData(outp, NULL);
4077 /* and write out the basic header */
4078 *op++ = 5; /* variable block */
4079 op += 2; /* skip vbl block length; we'll fill it in later */
4083 /* make sure that curOffset.LowPart doesn't point to the first
4084 * 32 bytes in the 2nd through last dir page, and that it doesn't
4085 * point at the first 13 32-byte chunks in the first dir page,
4086 * since those are dir and page headers, and don't contain useful
4089 temp = curOffset.LowPart & (2048-1);
4090 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4091 /* we're in the first page */
4092 if (temp < 13*32) temp = 13*32;
4095 /* we're in a later dir page */
4096 if (temp < 32) temp = 32;
4099 /* make sure the low order 5 bits are zero */
4102 /* now put temp bits back ito curOffset.LowPart */
4103 curOffset.LowPart &= ~(2048-1);
4104 curOffset.LowPart |= temp;
4106 /* check if we've returned all the names that will fit in the
4109 if (returnedNames >= maxCount) {
4110 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4111 returnedNames, maxCount);
4115 /* check if we've passed the dir's EOF */
4116 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4118 /* see if we can use the bufferp we have now; compute in which page
4119 * the current offset would be, and check whether that's the offset
4120 * of the buffer we have. If not, get the buffer.
4122 thyper.HighPart = curOffset.HighPart;
4123 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4124 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4127 buf_Release(bufferp);
4130 lock_ReleaseMutex(&scp->mx);
4131 lock_ObtainRead(&scp->bufCreateLock);
4132 code = buf_Get(scp, &thyper, &bufferp);
4133 lock_ReleaseRead(&scp->bufCreateLock);
4134 lock_ObtainMutex(&dsp->mx);
4136 /* now, if we're doing a star match, do bulk fetching of all of
4137 * the status info for files in the dir.
4140 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4141 lock_ObtainMutex(&scp->mx);
4142 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4143 LargeIntegerGreaterThanOrEqualTo(thyper,
4144 scp->bulkStatProgress)) {
4145 /* Don't bulk stat if risking timeout */
4146 int now = GetTickCount();
4147 if (now - req.startTime > RDRtimeout * 1000) {
4148 scp->bulkStatProgress = thyper;
4149 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4150 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4151 dsp->scp->bulkStatProgress = hzero;
4153 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4156 lock_ObtainMutex(&scp->mx);
4158 lock_ReleaseMutex(&dsp->mx);
4160 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4164 bufferOffset = thyper;
4166 /* now get the data in the cache */
4168 code = cm_SyncOp(scp, bufferp, userp, &req,
4170 CM_SCACHESYNC_NEEDCALLBACK |
4171 CM_SCACHESYNC_READ);
4173 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4177 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4179 if (cm_HaveBuffer(scp, bufferp, 0)) {
4180 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4184 /* otherwise, load the buffer and try again */
4185 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4187 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4188 scp, bufferp, code);
4193 buf_Release(bufferp);
4197 } /* if (wrong buffer) ... */
4199 /* now we have the buffer containing the entry we're interested in; copy
4200 * it out if it represents a non-deleted entry.
4202 entryInDir = curOffset.LowPart & (2048-1);
4203 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4205 /* page header will help tell us which entries are free. Page header
4206 * can change more often than once per buffer, since AFS 3 dir page size
4207 * may be less than (but not more than a buffer package buffer.
4209 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4210 temp &= ~(2048 - 1); /* turn off intra-page bits */
4211 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4213 /* now determine which entry we're looking at in the page. If it is
4214 * free (there's a free bitmap at the start of the dir), we should
4215 * skip these 32 bytes.
4217 slotInPage = (entryInDir & 0x7e0) >> 5;
4218 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4219 /* this entry is free */
4220 numDirChunks = 1; /* only skip this guy */
4224 tp = bufferp->datap + entryInBuffer;
4225 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4227 /* while we're here, compute the next entry's location, too,
4228 * since we'll need it when writing out the cookie into the dir
4231 * XXXX Probably should do more sanity checking.
4233 numDirChunks = cm_NameEntries(dep->name, NULL);
4235 /* compute the offset of the cookie representing the next entry */
4236 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4238 /* Compute 8.3 name if necessary */
4239 actualName = dep->name;
4240 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4241 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4242 actualName = shortName;
4245 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4246 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4247 osi_LogSaveString(smb_logp, actualName));
4249 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4250 /* this is one of the entries to use: it is not deleted
4251 * and it matches the star pattern we're looking for.
4254 /* Eliminate entries that don't match requested
4257 /* no hidden files */
4258 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4259 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4263 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4265 /* We have already done the cm_TryBulkStat above */
4266 fid.cell = scp->fid.cell;
4267 fid.volume = scp->fid.volume;
4268 fid.vnode = ntohl(dep->fid.vnode);
4269 fid.unique = ntohl(dep->fid.unique);
4270 fileType = cm_FindFileType(&fid);
4271 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4272 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4274 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4275 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4276 fileType == CM_SCACHETYPE_DFSLINK ||
4277 fileType == CM_SCACHETYPE_INVALID)
4278 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4283 memcpy(op, mask, 11); op += 11;
4284 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4285 *op++ = (char)(nextEntryCookie & 0xff);
4286 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4287 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4288 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4289 memcpy(op, &clientCookie, 4); op += 4;
4291 /* now we emit the attribute. This is sort of tricky,
4292 * since we need to really stat the file to find out
4293 * what type of entry we've got. Right now, we're
4294 * copying out data from a buffer, while holding the
4295 * scp locked, so it isn't really convenient to stat
4296 * something now. We'll put in a place holder now,
4297 * and make a second pass before returning this to get
4298 * the real attributes. So, we just skip the data for
4299 * now, and adjust it later. We allocate a patch
4300 * record to make it easy to find this point later.
4301 * The replay will happen at a time when it is safe to
4302 * unlock the directory.
4304 curPatchp = malloc(sizeof(*curPatchp));
4305 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4306 curPatchp->dptr = op;
4307 curPatchp->fid.cell = scp->fid.cell;
4308 curPatchp->fid.volume = scp->fid.volume;
4309 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4310 curPatchp->fid.unique = ntohl(dep->fid.unique);
4312 /* do hidden attribute here since name won't be around when applying
4316 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4317 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4319 curPatchp->flags = 0;
4321 op += 9; /* skip attr, time, date and size */
4323 /* zero out name area. The spec says to pad with
4324 * spaces, but Samba doesn't, and neither do we.
4328 /* finally, we get to copy out the name; we know that
4329 * it fits in 8.3 or the pattern wouldn't match, but it
4330 * never hurts to be sure.
4332 strncpy(op, actualName, 13);
4333 if (smb_StoreAnsiFilenames)
4336 /* Uppercase if requested by client */
4337 if (!KNOWS_LONG_NAMES(inp))
4342 /* now, adjust the # of entries copied */
4344 } /* if we're including this name */
4347 /* and adjust curOffset to be where the new cookie is */
4348 thyper.HighPart = 0;
4349 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4350 curOffset = LargeIntegerAdd(thyper, curOffset);
4351 } /* while copying data for dir listing */
4353 /* release the mutex */
4354 lock_ReleaseMutex(&scp->mx);
4356 buf_Release(bufferp);
4360 /* apply and free last set of patches; if not doing a star match, this
4361 * will be empty, but better safe (and freeing everything) than sorry.
4363 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4365 /* special return code for unsuccessful search */
4366 if (code == 0 && dataLength < 21 && returnedNames == 0)
4367 code = CM_ERROR_NOFILES;
4369 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4370 returnedNames, code);
4373 smb_DeleteDirSearch(dsp);
4374 smb_ReleaseDirSearch(dsp);
4375 cm_ReleaseSCache(scp);
4376 cm_ReleaseUser(userp);
4380 /* finalize the output buffer */
4381 smb_SetSMBParm(outp, 0, returnedNames);
4382 temp = (long) (op - origOp);
4383 smb_SetSMBDataLength(outp, temp);
4385 /* the data area is a variable block, which has a 5 (already there)
4386 * followed by the length of the # of data bytes. We now know this to
4387 * be "temp," although that includes the 3 bytes of vbl block header.
4388 * Deduct for them and fill in the length field.
4390 temp -= 3; /* deduct vbl block info */
4391 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4392 origOp[1] = (char)(temp & 0xff);
4393 origOp[2] = (char)((temp>>8) & 0xff);
4394 if (returnedNames == 0)
4395 smb_DeleteDirSearch(dsp);
4396 smb_ReleaseDirSearch(dsp);
4397 cm_ReleaseSCache(scp);
4398 cm_ReleaseUser(userp);
4402 /* verify that this is a valid path to a directory. I don't know why they
4403 * don't use the get file attributes call.
4405 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4409 cm_scache_t *rootScp;
4410 cm_scache_t *newScp;
4419 pathp = smb_GetSMBData(inp, NULL);
4420 pathp = smb_ParseASCIIBlock(pathp, NULL);
4422 return CM_ERROR_BADFD;
4423 if (smb_StoreAnsiFilenames)
4424 OemToChar(pathp,pathp);
4425 osi_Log1(smb_logp, "SMB receive check path %s",
4426 osi_LogSaveString(smb_logp, pathp));
4428 rootScp = cm_data.rootSCachep;
4430 userp = smb_GetUserFromVCP(vcp, inp);
4432 caseFold = CM_FLAG_CASEFOLD;
4434 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4436 cm_ReleaseUser(userp);
4437 return CM_ERROR_NOSUCHPATH;
4439 code = cm_NameI(rootScp, pathp,
4440 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4441 userp, tidPathp, &req, &newScp);
4444 cm_ReleaseUser(userp);
4449 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4450 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4451 cm_ReleaseSCache(newScp);
4452 cm_ReleaseUser(userp);
4453 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4454 return CM_ERROR_PATH_NOT_COVERED;
4456 return CM_ERROR_BADSHARENAME;
4458 #endif /* DFS_SUPPORT */
4460 /* now lock the vnode with a callback; returns with newScp locked */
4461 lock_ObtainMutex(&newScp->mx);
4462 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4463 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4465 if (code != CM_ERROR_NOACCESS) {
4466 lock_ReleaseMutex(&newScp->mx);
4467 cm_ReleaseSCache(newScp);
4468 cm_ReleaseUser(userp);
4472 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4475 attrs = smb_Attributes(newScp);
4477 if (!(attrs & SMB_ATTR_DIRECTORY))
4478 code = CM_ERROR_NOTDIR;
4480 lock_ReleaseMutex(&newScp->mx);
4482 cm_ReleaseSCache(newScp);
4483 cm_ReleaseUser(userp);
4487 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4491 cm_scache_t *rootScp;
4492 unsigned short attribute;
4494 cm_scache_t *newScp;
4503 /* decode basic attributes we're passed */
4504 attribute = smb_GetSMBParm(inp, 0);
4505 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4507 pathp = smb_GetSMBData(inp, NULL);
4508 pathp = smb_ParseASCIIBlock(pathp, NULL);
4510 return CM_ERROR_BADSMB;
4511 if (smb_StoreAnsiFilenames)
4512 OemToChar(pathp,pathp);
4514 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4515 dosTime, attribute);
4517 rootScp = cm_data.rootSCachep;
4519 userp = smb_GetUserFromVCP(vcp, inp);
4521 caseFold = CM_FLAG_CASEFOLD;
4523 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4525 cm_ReleaseUser(userp);
4526 return CM_ERROR_NOSUCHFILE;
4528 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4529 tidPathp, &req, &newScp);
4532 cm_ReleaseUser(userp);
4537 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4538 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4539 cm_ReleaseSCache(newScp);
4540 cm_ReleaseUser(userp);
4541 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4542 return CM_ERROR_PATH_NOT_COVERED;
4544 return CM_ERROR_BADSHARENAME;
4546 #endif /* DFS_SUPPORT */
4548 /* now lock the vnode with a callback; returns with newScp locked; we
4549 * need the current status to determine what the new status is, in some
4552 lock_ObtainMutex(&newScp->mx);
4553 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4554 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4556 lock_ReleaseMutex(&newScp->mx);
4557 cm_ReleaseSCache(newScp);
4558 cm_ReleaseUser(userp);
4562 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4564 /* Check for RO volume */
4565 if (newScp->flags & CM_SCACHEFLAG_RO) {
4566 lock_ReleaseMutex(&newScp->mx);
4567 cm_ReleaseSCache(newScp);
4568 cm_ReleaseUser(userp);
4569 return CM_ERROR_READONLY;
4572 /* prepare for setattr call */
4575 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4576 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4578 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4579 /* we're told to make a writable file read-only */
4580 attr.unixModeBits = newScp->unixModeBits & ~0222;
4581 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4583 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4584 /* we're told to make a read-only file writable */
4585 attr.unixModeBits = newScp->unixModeBits | 0222;
4586 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4588 lock_ReleaseMutex(&newScp->mx);
4590 /* now call setattr */
4592 code = cm_SetAttr(newScp, &attr, userp, &req);
4596 cm_ReleaseSCache(newScp);
4597 cm_ReleaseUser(userp);
4602 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4606 cm_scache_t *rootScp;
4607 cm_scache_t *newScp, *dscp;
4619 pathp = smb_GetSMBData(inp, NULL);
4620 pathp = smb_ParseASCIIBlock(pathp, NULL);
4622 return CM_ERROR_BADSMB;
4624 if (*pathp == 0) /* null path */
4627 if (smb_StoreAnsiFilenames)
4628 OemToChar(pathp,pathp);
4630 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4631 osi_LogSaveString(smb_logp, pathp));
4633 rootScp = cm_data.rootSCachep;
4635 userp = smb_GetUserFromVCP(vcp, inp);
4637 /* we shouldn't need this for V3 requests, but we seem to */
4638 caseFold = CM_FLAG_CASEFOLD;
4640 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4642 cm_ReleaseUser(userp);
4643 return CM_ERROR_NOSUCHFILE;
4647 * XXX Strange hack XXX
4649 * As of Patch 5 (16 July 97), we are having the following problem:
4650 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4651 * requests to look up "desktop.ini" in all the subdirectories.
4652 * This can cause zillions of timeouts looking up non-existent cells
4653 * and volumes, especially in the top-level directory.
4655 * We have not found any way to avoid this or work around it except
4656 * to explicitly ignore the requests for mount points that haven't
4657 * yet been evaluated and for directories that haven't yet been
4660 * We should modify this hack to provide a fake desktop.ini file
4661 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4663 spacep = inp->spacep;
4664 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4665 #ifndef SPECIAL_FOLDERS
4666 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4667 code = cm_NameI(rootScp, spacep->data,
4668 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4669 userp, tidPathp, &req, &dscp);
4672 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4673 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
4674 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4675 return CM_ERROR_PATH_NOT_COVERED;
4677 return CM_ERROR_BADSHARENAME;
4679 #endif /* DFS_SUPPORT */
4680 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4681 code = CM_ERROR_NOSUCHFILE;
4682 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4683 cm_buf_t *bp = buf_Find(dscp, &hzero);
4688 code = CM_ERROR_NOSUCHFILE;
4690 cm_ReleaseSCache(dscp);
4692 cm_ReleaseUser(userp);
4697 #endif /* SPECIAL_FOLDERS */
4699 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4700 tidPathp, &req, &newScp);
4702 cm_ReleaseUser(userp);
4707 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4708 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4709 cm_ReleaseSCache(newScp);
4710 cm_ReleaseUser(userp);
4711 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4712 return CM_ERROR_PATH_NOT_COVERED;
4714 return CM_ERROR_BADSHARENAME;
4716 #endif /* DFS_SUPPORT */
4718 /* now lock the vnode with a callback; returns with newScp locked */
4719 lock_ObtainMutex(&newScp->mx);
4720 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4721 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4723 lock_ReleaseMutex(&newScp->mx);
4724 cm_ReleaseSCache(newScp);
4725 cm_ReleaseUser(userp);
4729 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4732 /* use smb_Attributes instead. Also the fact that a file is
4733 * in a readonly volume doesn't mean it shojuld be marked as RO
4735 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4736 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4737 newScp->fileType == CM_SCACHETYPE_INVALID)
4738 attrs = SMB_ATTR_DIRECTORY;
4741 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4742 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4744 attrs = smb_Attributes(newScp);
4747 smb_SetSMBParm(outp, 0, attrs);
4749 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4750 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4751 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4752 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4753 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4754 smb_SetSMBParm(outp, 5, 0);
4755 smb_SetSMBParm(outp, 6, 0);
4756 smb_SetSMBParm(outp, 7, 0);
4757 smb_SetSMBParm(outp, 8, 0);
4758 smb_SetSMBParm(outp, 9, 0);
4759 smb_SetSMBDataLength(outp, 0);
4760 lock_ReleaseMutex(&newScp->mx);
4762 cm_ReleaseSCache(newScp);
4763 cm_ReleaseUser(userp);
4768 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4772 osi_Log0(smb_logp, "SMB receive tree disconnect");
4774 /* find the tree and free it */
4775 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4777 lock_ObtainWrite(&smb_rctLock);
4779 lock_ReleaseWrite(&smb_rctLock);
4780 smb_ReleaseTID(tidp);
4786 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4804 pathp = smb_GetSMBData(inp, NULL);
4805 pathp = smb_ParseASCIIBlock(pathp, NULL);
4806 if (smb_StoreAnsiFilenames)
4807 OemToChar(pathp,pathp);
4809 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4811 #ifdef DEBUG_VERBOSE
4815 hexpath = osi_HexifyString( pathp );
4816 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4821 share = smb_GetSMBParm(inp, 0);
4822 attribute = smb_GetSMBParm(inp, 1);
4824 spacep = inp->spacep;
4825 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4826 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4827 /* special case magic file name for receiving IOCTL requests
4828 * (since IOCTL calls themselves aren't getting through).
4830 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4831 smb_SetupIoctlFid(fidp, spacep);
4832 smb_SetSMBParm(outp, 0, fidp->fid);
4833 smb_SetSMBParm(outp, 1, 0); /* attrs */
4834 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4835 smb_SetSMBParm(outp, 3, 0);
4836 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4837 smb_SetSMBParm(outp, 5, 0x7fff);
4838 /* pass the open mode back */
4839 smb_SetSMBParm(outp, 6, (share & 0xf));
4840 smb_SetSMBDataLength(outp, 0);
4841 smb_ReleaseFID(fidp);
4845 userp = smb_GetUserFromVCP(vcp, inp);
4847 caseFold = CM_FLAG_CASEFOLD;
4849 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4851 cm_ReleaseUser(userp);
4852 return CM_ERROR_NOSUCHPATH;
4854 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4855 tidPathp, &req, &scp);
4858 cm_ReleaseUser(userp);
4863 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4864 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
4865 cm_ReleaseSCache(scp);
4866 cm_ReleaseUser(userp);
4867 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4868 return CM_ERROR_PATH_NOT_COVERED;
4870 return CM_ERROR_BADSHARENAME;
4872 #endif /* DFS_SUPPORT */
4874 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4876 cm_ReleaseSCache(scp);
4877 cm_ReleaseUser(userp);
4881 /* don't need callback to check file type, since file types never
4882 * change, and namei and cm_Lookup all stat the object at least once on
4883 * a successful return.
4885 if (scp->fileType != CM_SCACHETYPE_FILE) {
4886 cm_ReleaseSCache(scp);
4887 cm_ReleaseUser(userp);
4888 return CM_ERROR_ISDIR;
4891 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4892 osi_assertx(fidp, "null smb_fid_t");
4894 /* save a pointer to the vnode */
4896 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4897 lock_ObtainMutex(&scp->mx);
4898 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4899 lock_ReleaseMutex(&scp->mx);
4903 fidp->userp = userp;
4905 lock_ObtainMutex(&fidp->mx);
4906 if ((share & 0xf) == 0)
4907 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4908 else if ((share & 0xf) == 1)
4909 fidp->flags |= SMB_FID_OPENWRITE;
4911 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4912 lock_ReleaseMutex(&fidp->mx);
4914 lock_ObtainMutex(&scp->mx);
4915 smb_SetSMBParm(outp, 0, fidp->fid);
4916 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4917 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4918 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4919 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4920 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4921 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4922 /* pass the open mode back; XXXX add access checks */
4923 smb_SetSMBParm(outp, 6, (share & 0xf));
4924 smb_SetSMBDataLength(outp, 0);
4925 lock_ReleaseMutex(&scp->mx);
4928 cm_Open(scp, 0, userp);
4930 /* send and free packet */
4931 smb_ReleaseFID(fidp);
4932 cm_ReleaseUser(userp);
4933 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4937 typedef struct smb_unlinkRock {
4942 char *maskp; /* pointer to the star pattern */
4945 cm_dirEntryList_t * matches;
4948 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4951 smb_unlinkRock_t *rockp;
4959 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4960 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4961 caseFold |= CM_FLAG_8DOT3;
4963 matchName = dep->name;
4964 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4966 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4967 !cm_Is8Dot3(dep->name)) {
4968 cm_Gen8Dot3Name(dep, shortName, NULL);
4969 matchName = shortName;
4970 /* 8.3 matches are always case insensitive */
4971 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4974 osi_Log1(smb_logp, "Found match %s",
4975 osi_LogSaveString(smb_logp, matchName));
4977 cm_DirEntryListAdd(dep->name, &rockp->matches);
4981 /* If we made a case sensitive exact match, we might as well quit now. */
4982 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4983 code = CM_ERROR_STOPNOW;
4992 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5001 smb_unlinkRock_t rock;
5010 attribute = smb_GetSMBParm(inp, 0);
5012 tp = smb_GetSMBData(inp, NULL);
5013 pathp = smb_ParseASCIIBlock(tp, &tp);
5014 if (smb_StoreAnsiFilenames)
5015 OemToChar(pathp,pathp);
5017 osi_Log1(smb_logp, "SMB receive unlink %s",
5018 osi_LogSaveString(smb_logp, pathp));
5020 spacep = inp->spacep;
5021 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5023 userp = smb_GetUserFromVCP(vcp, inp);
5025 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5027 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5029 cm_ReleaseUser(userp);
5030 return CM_ERROR_NOSUCHPATH;
5032 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5035 cm_ReleaseUser(userp);
5040 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5041 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,spacep->data);
5042 cm_ReleaseSCache(dscp);
5043 cm_ReleaseUser(userp);
5044 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5045 return CM_ERROR_PATH_NOT_COVERED;
5047 return CM_ERROR_BADSHARENAME;
5049 #endif /* DFS_SUPPORT */
5051 /* otherwise, scp points to the parent directory. */
5058 rock.maskp = smb_FindMask(pathp);
5059 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5062 thyper.HighPart = 0;
5067 rock.matches = NULL;
5069 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5070 * match. If that fails, we do a case insensitve match.
5072 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5073 !smb_IsStarMask(rock.maskp)) {
5074 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5077 thyper.HighPart = 0;
5078 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5083 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5085 if (code == CM_ERROR_STOPNOW)
5088 if (code == 0 && rock.matches) {
5089 cm_dirEntryList_t * entry;
5091 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5093 osi_Log1(smb_logp, "Unlinking %s",
5094 osi_LogSaveString(smb_logp, entry->name));
5095 code = cm_Unlink(dscp, entry->name, userp, &req);
5097 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5098 smb_NotifyChange(FILE_ACTION_REMOVED,
5099 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5100 dscp, entry->name, NULL, TRUE);
5104 cm_DirEntryListFree(&rock.matches);
5106 cm_ReleaseUser(userp);
5108 cm_ReleaseSCache(dscp);
5110 if (code == 0 && !rock.any)
5111 code = CM_ERROR_NOSUCHFILE;
5115 typedef struct smb_renameRock {
5116 cm_scache_t *odscp; /* old dir */
5117 cm_scache_t *ndscp; /* new dir */
5118 cm_user_t *userp; /* user */
5119 cm_req_t *reqp; /* request struct */
5120 smb_vc_t *vcp; /* virtual circuit */
5121 char *maskp; /* pointer to star pattern of old file name */
5122 int flags; /* tilde, casefold, etc */
5123 char *newNamep; /* ptr to the new file's name */
5124 char oldName[MAX_PATH];
5128 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5131 smb_renameRock_t *rockp;
5134 char shortName[13]="";
5136 rockp = (smb_renameRock_t *) vrockp;
5138 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5139 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5140 caseFold |= CM_FLAG_8DOT3;
5142 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5144 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5145 !cm_Is8Dot3(dep->name)) {
5146 cm_Gen8Dot3Name(dep, shortName, NULL);
5147 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5152 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5153 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5154 code = CM_ERROR_STOPNOW;
5164 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5167 cm_space_t *spacep = NULL;
5168 smb_renameRock_t rock;
5169 cm_scache_t *oldDscp = NULL;
5170 cm_scache_t *newDscp = NULL;
5171 cm_scache_t *tmpscp= NULL;
5172 cm_scache_t *tmpscp2 = NULL;
5182 userp = smb_GetUserFromVCP(vcp, inp);
5183 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5185 cm_ReleaseUser(userp);
5186 return CM_ERROR_NOSUCHPATH;
5190 spacep = inp->spacep;
5191 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5193 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5194 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5195 userp, tidPathp, &req, &oldDscp);
5197 cm_ReleaseUser(userp);
5202 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5203 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5204 cm_ReleaseSCache(oldDscp);
5205 cm_ReleaseUser(userp);
5206 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5207 return CM_ERROR_PATH_NOT_COVERED;
5209 return CM_ERROR_BADSHARENAME;
5211 #endif /* DFS_SUPPORT */
5213 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5214 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5215 userp, tidPathp, &req, &newDscp);
5218 cm_ReleaseSCache(oldDscp);
5219 cm_ReleaseUser(userp);
5224 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5225 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5226 cm_ReleaseSCache(oldDscp);
5227 cm_ReleaseSCache(newDscp);
5228 cm_ReleaseUser(userp);
5229 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5230 return CM_ERROR_PATH_NOT_COVERED;
5232 return CM_ERROR_BADSHARENAME;
5234 #endif /* DFS_SUPPORT */
5237 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5238 * next, get the component names, and lower case them.
5241 /* handle the old name first */
5243 oldLastNamep = oldPathp;
5247 /* and handle the new name, too */
5249 newLastNamep = newPathp;
5253 /* TODO: The old name could be a wildcard. The new name must not be */
5255 /* do the vnode call */
5256 rock.odscp = oldDscp;
5257 rock.ndscp = newDscp;
5261 rock.maskp = oldLastNamep;
5262 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5263 rock.newNamep = newLastNamep;
5264 rock.oldName[0] = '\0';
5267 /* Check if the file already exists; if so return error */
5268 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5269 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5270 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5272 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5273 osi_LogSaveString(smb_logp, newLastNamep));
5275 /* Check if the old and the new names differ only in case. If so return
5276 * success, else return CM_ERROR_EXISTS
5278 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5280 /* This would be a success only if the old file is *as same as* the new file */
5281 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5283 if (tmpscp == tmpscp2)
5286 code = CM_ERROR_EXISTS;
5287 cm_ReleaseSCache(tmpscp2);
5290 code = CM_ERROR_NOSUCHFILE;
5293 /* file exist, do not rename, also fixes move */
5294 osi_Log0(smb_logp, "Can't rename. Target already exists");
5295 code = CM_ERROR_EXISTS;
5299 cm_ReleaseSCache(tmpscp);
5300 cm_ReleaseSCache(newDscp);
5301 cm_ReleaseSCache(oldDscp);
5302 cm_ReleaseUser(userp);
5306 /* Now search the directory for the pattern, and do the appropriate rename when found */
5307 thyper.LowPart = 0; /* search dir from here */
5308 thyper.HighPart = 0;
5310 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5311 if (code == 0 && !rock.any) {
5313 thyper.HighPart = 0;
5314 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5315 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5317 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5319 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5320 code = cm_Rename(rock.odscp, rock.oldName,
5321 rock.ndscp, rock.newNamep, rock.userp,
5323 /* if the call worked, stop doing the search now, since we
5324 * really only want to rename one file.
5326 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5327 } else if (code == 0) {
5328 code = CM_ERROR_NOSUCHFILE;
5331 /* Handle Change Notification */
5333 * Being lazy, not distinguishing between files and dirs in this
5334 * filter, since we'd have to do a lookup.
5337 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5338 if (oldDscp == newDscp) {
5339 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5340 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5341 filter, oldDscp, oldLastNamep,
5342 newLastNamep, TRUE);
5344 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5345 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5346 filter, oldDscp, oldLastNamep,
5348 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5349 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5350 filter, newDscp, newLastNamep,
5356 cm_ReleaseSCache(tmpscp);
5357 cm_ReleaseUser(userp);
5358 cm_ReleaseSCache(oldDscp);
5359 cm_ReleaseSCache(newDscp);
5364 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5367 cm_space_t *spacep = NULL;
5368 cm_scache_t *oldDscp = NULL;
5369 cm_scache_t *newDscp = NULL;
5370 cm_scache_t *tmpscp= NULL;
5371 cm_scache_t *tmpscp2 = NULL;
5372 cm_scache_t *sscp = NULL;
5381 userp = smb_GetUserFromVCP(vcp, inp);
5383 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5385 cm_ReleaseUser(userp);
5386 return CM_ERROR_NOSUCHPATH;
5391 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5393 spacep = inp->spacep;
5394 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5396 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5397 userp, tidPathp, &req, &oldDscp);
5399 cm_ReleaseUser(userp);
5404 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5405 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5406 cm_ReleaseSCache(oldDscp);
5407 cm_ReleaseUser(userp);
5408 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5409 return CM_ERROR_PATH_NOT_COVERED;
5411 return CM_ERROR_BADSHARENAME;
5413 #endif /* DFS_SUPPORT */
5415 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5416 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5417 userp, tidPathp, &req, &newDscp);
5419 cm_ReleaseSCache(oldDscp);
5420 cm_ReleaseUser(userp);
5425 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5426 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5427 cm_ReleaseSCache(newDscp);
5428 cm_ReleaseSCache(oldDscp);
5429 cm_ReleaseUser(userp);
5430 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5431 return CM_ERROR_PATH_NOT_COVERED;
5433 return CM_ERROR_BADSHARENAME;
5435 #endif /* DFS_SUPPORT */
5437 /* Now, although we did two lookups for the two directories (because the same
5438 * directory can be referenced through different paths), we only allow hard links
5439 * within the same directory. */
5440 if (oldDscp != newDscp) {
5441 cm_ReleaseSCache(oldDscp);
5442 cm_ReleaseSCache(newDscp);
5443 cm_ReleaseUser(userp);
5444 return CM_ERROR_CROSSDEVLINK;
5447 /* handle the old name first */
5449 oldLastNamep = oldPathp;
5453 /* and handle the new name, too */
5455 newLastNamep = newPathp;
5459 /* now lookup the old name */
5460 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5461 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5463 cm_ReleaseSCache(oldDscp);
5464 cm_ReleaseSCache(newDscp);
5465 cm_ReleaseUser(userp);
5469 /* Check if the file already exists; if so return error */
5470 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5471 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5472 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5474 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5475 osi_LogSaveString(smb_logp, newLastNamep));
5477 /* if the existing link is to the same file, then we return success */
5479 if(sscp == tmpscp) {
5482 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5483 code = CM_ERROR_EXISTS;
5488 cm_ReleaseSCache(tmpscp);
5489 cm_ReleaseSCache(sscp);
5490 cm_ReleaseSCache(newDscp);
5491 cm_ReleaseSCache(oldDscp);
5492 cm_ReleaseUser(userp);
5496 /* now create the hardlink */
5497 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5498 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5499 osi_Log1(smb_logp," Link returns 0x%x", code);
5501 /* Handle Change Notification */
5503 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5504 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5505 smb_NotifyChange(FILE_ACTION_ADDED,
5506 filter, newDscp, newLastNamep,
5511 cm_ReleaseSCache(tmpscp);
5512 cm_ReleaseUser(userp);
5513 cm_ReleaseSCache(sscp);
5514 cm_ReleaseSCache(oldDscp);
5515 cm_ReleaseSCache(newDscp);
5520 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5527 tp = smb_GetSMBData(inp, NULL);
5528 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5529 if (smb_StoreAnsiFilenames)
5530 OemToChar(oldPathp,oldPathp);
5531 newPathp = smb_ParseASCIIBlock(tp, &tp);
5532 if (smb_StoreAnsiFilenames)
5533 OemToChar(newPathp,newPathp);
5535 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5536 osi_LogSaveString(smb_logp, oldPathp),
5537 osi_LogSaveString(smb_logp, newPathp));
5539 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5541 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5547 typedef struct smb_rmdirRock {
5551 char *maskp; /* pointer to the star pattern */
5554 cm_dirEntryList_t * matches;
5557 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5560 smb_rmdirRock_t *rockp;
5565 rockp = (smb_rmdirRock_t *) vrockp;
5567 matchName = dep->name;
5568 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5569 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5571 match = (strcmp(matchName, rockp->maskp) == 0);
5573 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5574 !cm_Is8Dot3(dep->name)) {
5575 cm_Gen8Dot3Name(dep, shortName, NULL);
5576 matchName = shortName;
5577 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5582 cm_DirEntryListAdd(dep->name, &rockp->matches);
5588 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5596 smb_rmdirRock_t rock;
5605 tp = smb_GetSMBData(inp, NULL);
5606 pathp = smb_ParseASCIIBlock(tp, &tp);
5607 if (smb_StoreAnsiFilenames)
5608 OemToChar(pathp,pathp);
5610 spacep = inp->spacep;
5611 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5613 userp = smb_GetUserFromVCP(vcp, inp);
5615 caseFold = CM_FLAG_CASEFOLD;
5617 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5619 cm_ReleaseUser(userp);
5620 return CM_ERROR_NOSUCHPATH;
5622 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5623 userp, tidPathp, &req, &dscp);
5626 cm_ReleaseUser(userp);
5631 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5632 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
5633 cm_ReleaseSCache(dscp);
5634 cm_ReleaseUser(userp);
5635 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5636 return CM_ERROR_PATH_NOT_COVERED;
5638 return CM_ERROR_BADSHARENAME;
5640 #endif /* DFS_SUPPORT */
5642 /* otherwise, scp points to the parent directory. */
5649 rock.maskp = lastNamep;
5650 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5653 thyper.HighPart = 0;
5657 rock.matches = NULL;
5659 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5660 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5661 if (code == 0 && !rock.any) {
5663 thyper.HighPart = 0;
5664 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5665 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5668 if (code == 0 && rock.matches) {
5669 cm_dirEntryList_t * entry;
5671 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5672 osi_Log1(smb_logp, "Removing directory %s",
5673 osi_LogSaveString(smb_logp, entry->name));
5675 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5677 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5678 smb_NotifyChange(FILE_ACTION_REMOVED,
5679 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5680 dscp, entry->name, NULL, TRUE);
5684 cm_DirEntryListFree(&rock.matches);
5686 cm_ReleaseUser(userp);
5688 cm_ReleaseSCache(dscp);
5690 if (code == 0 && !rock.any)
5691 code = CM_ERROR_NOSUCHFILE;
5695 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5705 fid = smb_GetSMBParm(inp, 0);
5707 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5709 fid = smb_ChainFID(fid, inp);
5710 fidp = smb_FindFID(vcp, fid, 0);
5712 return CM_ERROR_BADFD;
5714 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5715 smb_CloseFID(vcp, fidp, NULL, 0);
5716 smb_ReleaseFID(fidp);
5717 return CM_ERROR_NOSUCHFILE;
5720 lock_ObtainMutex(&fidp->mx);
5721 if (fidp->flags & SMB_FID_IOCTL) {
5722 lock_ReleaseMutex(&fidp->mx);
5723 smb_ReleaseFID(fidp);
5724 return CM_ERROR_BADFD;
5726 lock_ReleaseMutex(&fidp->mx);
5728 userp = smb_GetUserFromVCP(vcp, inp);
5730 lock_ObtainMutex(&fidp->mx);
5731 if (fidp->flags & SMB_FID_OPENWRITE) {
5732 cm_scache_t * scp = fidp->scp;
5734 lock_ReleaseMutex(&fidp->mx);
5735 code = cm_FSync(scp, userp, &req);
5736 cm_ReleaseSCache(scp);
5739 lock_ReleaseMutex(&fidp->mx);
5742 smb_ReleaseFID(fidp);
5744 cm_ReleaseUser(userp);
5749 struct smb_FullNameRock {
5755 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5759 struct smb_FullNameRock *vrockp;
5761 vrockp = (struct smb_FullNameRock *)rockp;
5763 if (!cm_Is8Dot3(dep->name)) {
5764 cm_Gen8Dot3Name(dep, shortName, NULL);
5766 if (cm_stricmp(shortName, vrockp->name) == 0) {
5767 vrockp->fullName = strdup(dep->name);
5768 return CM_ERROR_STOPNOW;
5771 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5772 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5773 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5774 vrockp->fullName = strdup(dep->name);
5775 return CM_ERROR_STOPNOW;
5780 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5781 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5783 struct smb_FullNameRock rock;
5789 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5790 if (code == CM_ERROR_STOPNOW)
5791 *newPathp = rock.fullName;
5793 *newPathp = strdup(pathp);
5796 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5797 afs_uint32 dosTime) {
5800 cm_scache_t *dscp = NULL;
5802 cm_scache_t * scp = NULL;
5803 cm_scache_t *delscp = NULL;
5805 int nullcreator = 0;
5807 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5808 fidp, fidp->fid, scp, vcp);
5811 lock_ObtainMutex(&fidp->mx);
5812 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5813 lock_ReleaseMutex(&fidp->mx);
5814 osi_Log0(smb_logp, " No user specified. Not closing fid");
5815 return CM_ERROR_BADFD;
5818 userp = fidp->userp; /* no hold required since fidp is held
5819 throughout the function */
5820 lock_ReleaseMutex(&fidp->mx);
5825 lock_ObtainWrite(&smb_rctLock);
5827 osi_Log0(smb_logp, " Fid already closed.");
5828 lock_ReleaseWrite(&smb_rctLock);
5829 return CM_ERROR_BADFD;
5832 lock_ReleaseWrite(&smb_rctLock);
5834 lock_ObtainMutex(&fidp->mx);
5835 if (fidp->NTopen_dscp) {
5836 dscp = fidp->NTopen_dscp;
5837 cm_HoldSCache(dscp);
5840 if (fidp->NTopen_pathp) {
5841 pathp = strdup(fidp->NTopen_pathp);
5849 /* Don't jump the gun on an async raw write */
5850 while (fidp->raw_writers) {
5851 lock_ReleaseMutex(&fidp->mx);
5852 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5853 lock_ObtainMutex(&fidp->mx);
5856 /* watch for ioctl closes, and read-only opens */
5858 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5859 == SMB_FID_OPENWRITE) {
5860 if (dosTime != 0 && dosTime != -1) {
5861 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5862 /* This fixes defect 10958 */
5863 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5864 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5866 lock_ReleaseMutex(&fidp->mx);
5867 code = cm_FSync(scp, userp, &req);
5868 lock_ObtainMutex(&fidp->mx);
5873 /* unlock any pending locks */
5874 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5875 scp->fileType == CM_SCACHETYPE_FILE) {
5879 lock_ReleaseMutex(&fidp->mx);
5881 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5883 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5884 lock_ObtainMutex(&scp->mx);
5886 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5887 CM_SCACHESYNC_NEEDCALLBACK
5888 | CM_SCACHESYNC_GETSTATUS
5889 | CM_SCACHESYNC_LOCK);
5893 "smb CoreClose SyncOp failure code 0x%x", tcode);
5894 goto post_syncopdone;
5897 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5899 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5903 lock_ReleaseMutex(&scp->mx);
5904 lock_ObtainMutex(&fidp->mx);
5907 if (fidp->flags & SMB_FID_DELONCLOSE) {
5910 lock_ReleaseMutex(&fidp->mx);
5912 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
5917 smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
5918 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5919 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5922 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5923 smb_NotifyChange(FILE_ACTION_REMOVED,
5924 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5925 dscp, fullPathp, NULL, TRUE);
5928 code = cm_Unlink(dscp, fullPathp, userp, &req);
5931 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5932 smb_NotifyChange(FILE_ACTION_REMOVED,
5933 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5934 dscp, fullPathp, NULL, TRUE);
5938 lock_ObtainMutex(&fidp->mx);
5939 fidp->flags &= ~SMB_FID_DELONCLOSE;
5942 /* if this was a newly created file, then clear the creator
5943 * in the stat cache entry. */
5944 if (fidp->flags & SMB_FID_CREATED) {
5946 fidp->flags &= ~SMB_FID_CREATED;
5949 if (fidp->flags & SMB_FID_NTOPEN) {
5950 cm_ReleaseSCache(fidp->NTopen_dscp);
5951 fidp->NTopen_dscp = NULL;
5952 free(fidp->NTopen_pathp);
5953 fidp->NTopen_pathp = NULL;
5954 fidp->flags &= ~SMB_FID_NTOPEN;
5956 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
5957 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
5960 if (fidp->NTopen_wholepathp) {
5961 free(fidp->NTopen_wholepathp);
5962 fidp->NTopen_wholepathp = NULL;
5966 cm_ReleaseSCache(fidp->scp);
5969 lock_ReleaseMutex(&fidp->mx);
5972 cm_ReleaseSCache(dscp);
5976 lock_ObtainMutex(&delscp->mx);
5978 delscp->flags |= CM_SCACHEFLAG_DELETED;
5979 lock_ReleaseMutex(&delscp->mx);
5981 cm_ReleaseSCache(delscp);
5985 lock_ObtainMutex(&scp->mx);
5986 if (nullcreator && scp->creator == userp)
5987 scp->creator = NULL;
5988 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5989 lock_ReleaseMutex(&scp->mx);
5990 cm_ReleaseSCache(scp);
5999 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6007 fid = smb_GetSMBParm(inp, 0);
6008 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6010 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6012 fid = smb_ChainFID(fid, inp);
6013 fidp = smb_FindFID(vcp, fid, 0);
6015 return CM_ERROR_BADFD;
6018 userp = smb_GetUserFromVCP(vcp, inp);
6020 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6022 smb_ReleaseFID(fidp);
6023 cm_ReleaseUser(userp);
6028 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6030 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6031 cm_user_t *userp, long *readp)
6037 osi_hyper_t fileLength;
6039 osi_hyper_t lastByte;
6040 osi_hyper_t bufferOffset;
6041 long bufIndex, nbytes;
6043 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6051 lock_ObtainMutex(&fidp->mx);
6054 lock_ObtainMutex(&scp->mx);
6056 if (offset.HighPart == 0) {
6057 chunk = offset.LowPart >> cm_logChunkSize;
6058 if (chunk != fidp->curr_chunk) {
6059 fidp->prev_chunk = fidp->curr_chunk;
6060 fidp->curr_chunk = chunk;
6062 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6065 lock_ReleaseMutex(&fidp->mx);
6067 /* start by looking up the file's end */
6068 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6069 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6073 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6075 /* now we have the entry locked, look up the length */
6076 fileLength = scp->length;
6078 /* adjust count down so that it won't go past EOF */
6079 thyper.LowPart = count;
6080 thyper.HighPart = 0;
6081 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6083 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6084 /* we'd read past EOF, so just stop at fileLength bytes.
6085 * Start by computing how many bytes remain in the file.
6087 thyper = LargeIntegerSubtract(fileLength, offset);
6089 /* if we are past EOF, read 0 bytes */
6090 if (LargeIntegerLessThanZero(thyper))
6093 count = thyper.LowPart;
6098 /* now, copy the data one buffer at a time,
6099 * until we've filled the request packet
6102 /* if we've copied all the data requested, we're done */
6103 if (count <= 0) break;
6105 /* otherwise, load up a buffer of data */
6106 thyper.HighPart = offset.HighPart;
6107 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6108 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6111 buf_Release(bufferp);
6114 lock_ReleaseMutex(&scp->mx);
6116 lock_ObtainRead(&scp->bufCreateLock);
6117 code = buf_Get(scp, &thyper, &bufferp);
6118 lock_ReleaseRead(&scp->bufCreateLock);
6120 lock_ObtainMutex(&scp->mx);
6121 if (code) goto done;
6122 bufferOffset = thyper;
6124 /* now get the data in the cache */
6126 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6127 CM_SCACHESYNC_NEEDCALLBACK |
6128 CM_SCACHESYNC_READ);
6132 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6134 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6136 /* otherwise, load the buffer and try again */
6137 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6141 buf_Release(bufferp);
6145 } /* if (wrong buffer) ... */
6147 /* now we have the right buffer loaded. Copy out the
6148 * data from here to the user's buffer.
6150 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6152 /* and figure out how many bytes we want from this buffer */
6153 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6154 if (nbytes > count) nbytes = count; /* don't go past EOF */
6156 /* now copy the data */
6157 memcpy(op, bufferp->datap + bufIndex, nbytes);
6159 /* adjust counters, pointers, etc. */
6162 thyper.LowPart = nbytes;
6163 thyper.HighPart = 0;
6164 offset = LargeIntegerAdd(thyper, offset);
6168 lock_ReleaseMutex(&scp->mx);
6170 buf_Release(bufferp);
6172 if (code == 0 && sequential)
6173 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6175 cm_ReleaseSCache(scp);
6181 * smb_WriteData -- common code for Write and Raw Write
6183 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6184 cm_user_t *userp, long *writtenp)
6190 osi_hyper_t fileLength; /* file's length at start of write */
6191 osi_hyper_t minLength; /* don't read past this */
6192 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6194 osi_hyper_t thyper; /* hyper tmp variable */
6195 osi_hyper_t bufferOffset;
6196 afs_uint32 bufIndex; /* index in buffer where our data is */
6198 osi_hyper_t writeBackOffset;/* offset of region to write back when
6203 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6204 fidp->fid, offsetp->LowPart, count);
6214 lock_ObtainMutex(&fidp->mx);
6215 /* make sure we have a writable FD */
6216 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6217 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6218 fidp->fid, fidp->flags);
6219 lock_ReleaseMutex(&fidp->mx);
6220 code = CM_ERROR_BADFDOP;
6226 lock_ReleaseMutex(&fidp->mx);
6228 lock_ObtainMutex(&scp->mx);
6229 /* start by looking up the file's end */
6230 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6231 CM_SCACHESYNC_NEEDCALLBACK
6232 | CM_SCACHESYNC_SETSTATUS
6233 | CM_SCACHESYNC_GETSTATUS);
6237 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6239 /* now we have the entry locked, look up the length */
6240 fileLength = scp->length;
6241 minLength = fileLength;
6242 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6243 minLength = scp->serverLength;
6245 /* adjust file length if we extend past EOF */
6246 thyper.LowPart = count;
6247 thyper.HighPart = 0;
6248 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6249 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6250 /* we'd write past EOF, so extend the file */
6251 scp->mask |= CM_SCACHEMASK_LENGTH;
6252 scp->length = thyper;
6253 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6255 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6257 /* now, if the new position (thyper) and the old (offset) are in
6258 * different storeback windows, remember to store back the previous
6259 * storeback window when we're done with the write.
6261 if ((thyper.LowPart & (-cm_chunkSize)) !=
6262 (offset.LowPart & (-cm_chunkSize))) {
6263 /* they're different */
6265 writeBackOffset.HighPart = offset.HighPart;
6266 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6271 /* now, copy the data one buffer at a time, until we've filled the
6274 /* if we've copied all the data requested, we're done */
6278 /* handle over quota or out of space */
6279 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6280 *writtenp = written;
6281 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6285 /* otherwise, load up a buffer of data */
6286 thyper.HighPart = offset.HighPart;
6287 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6288 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6291 lock_ReleaseMutex(&bufferp->mx);
6292 buf_Release(bufferp);
6295 lock_ReleaseMutex(&scp->mx);
6297 lock_ObtainRead(&scp->bufCreateLock);
6298 code = buf_Get(scp, &thyper, &bufferp);
6299 lock_ReleaseRead(&scp->bufCreateLock);
6301 lock_ObtainMutex(&bufferp->mx);
6302 lock_ObtainMutex(&scp->mx);
6303 if (code) goto done;
6305 bufferOffset = thyper;
6307 /* now get the data in the cache */
6309 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6310 CM_SCACHESYNC_NEEDCALLBACK
6311 | CM_SCACHESYNC_WRITE
6312 | CM_SCACHESYNC_BUFLOCKED);
6316 cm_SyncOpDone(scp, bufferp,
6317 CM_SCACHESYNC_NEEDCALLBACK
6318 | CM_SCACHESYNC_WRITE
6319 | CM_SCACHESYNC_BUFLOCKED);
6321 /* If we're overwriting the entire buffer, or
6322 * if we're writing at or past EOF, mark the
6323 * buffer as current so we don't call
6324 * cm_GetBuffer. This skips the fetch from the
6325 * server in those cases where we're going to
6326 * obliterate all the data in the buffer anyway,
6327 * or in those cases where there is no useful
6328 * data at the server to start with.
6330 * Use minLength instead of scp->length, since
6331 * the latter has already been updated by this
6334 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6335 || LargeIntegerEqualTo(offset, bufferp->offset)
6336 && (count >= cm_data.buf_blockSize
6337 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6338 ConvertLongToLargeInteger(count)),
6340 if (count < cm_data.buf_blockSize
6341 && bufferp->dataVersion == -1)
6342 memset(bufferp->datap, 0,
6343 cm_data.buf_blockSize);
6344 bufferp->dataVersion = scp->dataVersion;
6347 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6349 /* otherwise, load the buffer and try again */
6350 lock_ReleaseMutex(&bufferp->mx);
6351 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6353 lock_ReleaseMutex(&scp->mx);
6354 lock_ObtainMutex(&bufferp->mx);
6355 lock_ObtainMutex(&scp->mx);
6359 lock_ReleaseMutex(&bufferp->mx);
6360 buf_Release(bufferp);
6364 } /* if (wrong buffer) ... */
6366 /* now we have the right buffer loaded. Copy out the
6367 * data from here to the user's buffer.
6369 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6371 /* and figure out how many bytes we want from this buffer */
6372 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6374 nbytes = count; /* don't go past end of request */
6376 /* now copy the data */
6377 memcpy(bufferp->datap + bufIndex, op, nbytes);
6378 buf_SetDirty(bufferp, bufIndex, nbytes);
6380 /* and record the last writer */
6381 if (bufferp->userp != userp) {
6384 cm_ReleaseUser(bufferp->userp);
6385 bufferp->userp = userp;
6388 /* adjust counters, pointers, etc. */
6392 thyper.LowPart = nbytes;
6393 thyper.HighPart = 0;
6394 offset = LargeIntegerAdd(thyper, offset);
6398 lock_ReleaseMutex(&scp->mx);
6401 lock_ReleaseMutex(&bufferp->mx);
6402 buf_Release(bufferp);
6405 lock_ObtainMutex(&fidp->mx);
6406 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6407 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6408 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6409 fidp->NTopen_dscp, fidp->NTopen_pathp,
6412 lock_ReleaseMutex(&fidp->mx);
6414 if (code == 0 && doWriteBack) {
6416 lock_ObtainMutex(&scp->mx);
6417 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6419 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6420 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6422 lock_ReleaseMutex(&scp->mx);
6423 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6424 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6425 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6428 cm_ReleaseSCache(scp);
6430 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6431 fidp->fid, code, *writtenp);
6435 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6438 unsigned short count;
6440 unsigned short hint;
6441 long written = 0, total_written = 0;
6446 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6448 int inDataBlockCount;
6450 fd = smb_GetSMBParm(inp, 0);
6451 count = smb_GetSMBParm(inp, 1);
6452 offset.HighPart = 0; /* too bad */
6453 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6454 hint = smb_GetSMBParm(inp, 4);
6456 op = smb_GetSMBData(inp, NULL);
6457 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6459 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6460 fd, offset.LowPart, count);
6462 fd = smb_ChainFID(fd, inp);
6463 fidp = smb_FindFID(vcp, fd, 0);
6465 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6466 return CM_ERROR_BADFD;
6469 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6470 smb_CloseFID(vcp, fidp, NULL, 0);
6471 smb_ReleaseFID(fidp);
6472 return CM_ERROR_NOSUCHFILE;
6475 lock_ObtainMutex(&fidp->mx);
6476 if (fidp->flags & SMB_FID_IOCTL) {
6477 lock_ReleaseMutex(&fidp->mx);
6478 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6479 smb_ReleaseFID(fidp);
6480 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6483 lock_ReleaseMutex(&fidp->mx);
6484 userp = smb_GetUserFromVCP(vcp, inp);
6488 LARGE_INTEGER LOffset;
6489 LARGE_INTEGER LLength;
6491 pid = ((smb_t *) inp)->pid;
6492 key = cm_GenerateKey(vcp->vcID, pid, fd);
6494 LOffset.HighPart = offset.HighPart;
6495 LOffset.LowPart = offset.LowPart;
6496 LLength.HighPart = 0;
6497 LLength.LowPart = count;
6499 lock_ObtainMutex(&fidp->scp->mx);
6500 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6501 lock_ReleaseMutex(&fidp->scp->mx);
6504 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6509 /* special case: 0 bytes transferred means truncate to this position */
6513 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6517 truncAttr.mask = CM_ATTRMASK_LENGTH;
6518 truncAttr.length.LowPart = offset.LowPart;
6519 truncAttr.length.HighPart = 0;
6520 lock_ObtainMutex(&fidp->mx);
6521 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6522 fidp->flags |= SMB_FID_LENGTHSETDONE;
6523 lock_ReleaseMutex(&fidp->mx);
6524 smb_SetSMBParm(outp, 0, 0 /* count */);
6525 smb_SetSMBDataLength(outp, 0);
6530 * Work around bug in NT client
6532 * When copying a file, the NT client should first copy the data,
6533 * then copy the last write time. But sometimes the NT client does
6534 * these in the wrong order, so the data copies would inadvertently
6535 * cause the last write time to be overwritten. We try to detect this,
6536 * and don't set client mod time if we think that would go against the
6539 lock_ObtainMutex(&fidp->mx);
6540 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6541 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6542 fidp->scp->clientModTime = time(NULL);
6544 lock_ReleaseMutex(&fidp->mx);
6547 while ( code == 0 && count > 0 ) {
6548 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6549 if (code == 0 && written == 0)
6550 code = CM_ERROR_PARTIALWRITE;
6552 offset = LargeIntegerAdd(offset,
6553 ConvertLongToLargeInteger(written));
6554 count -= (unsigned short)written;
6555 total_written += written;
6559 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6560 total_written, code);
6562 /* set the packet data length to 3 bytes for the data block header,
6563 * plus the size of the data.
6565 smb_SetSMBParm(outp, 0, total_written);
6566 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6567 smb_SetSMBParm(outp, 3, hint);
6568 smb_SetSMBDataLength(outp, 0);
6571 smb_ReleaseFID(fidp);
6572 cm_ReleaseUser(userp);
6577 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6578 NCB *ncbp, raw_write_cont_t *rwcp)
6587 fd = smb_GetSMBParm(inp, 0);
6588 fidp = smb_FindFID(vcp, fd, 0);
6590 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6591 smb_CloseFID(vcp, fidp, NULL, 0);
6592 smb_ReleaseFID(fidp);
6596 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6597 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6599 userp = smb_GetUserFromVCP(vcp, inp);
6602 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6604 if (rwcp->writeMode & 0x1) { /* synchronous */
6607 smb_FormatResponsePacket(vcp, inp, outp);
6608 op = (smb_t *) outp;
6609 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6610 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6611 smb_SetSMBDataLength(outp, 0);
6612 smb_SendPacket(vcp, outp);
6613 smb_FreePacket(outp);
6615 else { /* asynchronous */
6616 lock_ObtainMutex(&fidp->mx);
6617 fidp->raw_writers--;
6618 if (fidp->raw_writers == 0)
6619 thrd_SetEvent(fidp->raw_write_event);
6620 lock_ReleaseMutex(&fidp->mx);
6623 /* Give back raw buffer */
6624 lock_ObtainMutex(&smb_RawBufLock);
6625 *((char **)rawBuf) = smb_RawBufs;
6626 smb_RawBufs = rawBuf;
6627 lock_ReleaseMutex(&smb_RawBufLock);
6629 smb_ReleaseFID(fidp);
6630 cm_ReleaseUser(userp);
6633 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6638 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6641 long count, written = 0, total_written = 0;
6648 unsigned short writeMode;
6650 fd = smb_GetSMBParm(inp, 0);
6651 totalCount = smb_GetSMBParm(inp, 1);
6652 count = smb_GetSMBParm(inp, 10);
6653 writeMode = smb_GetSMBParm(inp, 7);
6655 op = (char *) inp->data;
6656 op += smb_GetSMBParm(inp, 11);
6658 offset.HighPart = 0;
6659 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6661 if (*inp->wctp == 14) {
6662 /* we received a 64-bit file offset */
6663 #ifdef AFS_LARGEFILES
6664 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6666 if (LargeIntegerLessThanZero(offset)) {
6668 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6669 offset.HighPart, offset.LowPart);
6670 return CM_ERROR_BADSMB;
6673 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6675 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6676 return CM_ERROR_BADSMB;
6679 offset.HighPart = 0;
6682 offset.HighPart = 0; /* 32-bit file offset */
6686 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6687 fd, offset.HighPart, offset.LowPart, count);
6689 " WriteRaw WriteMode 0x%x",
6692 fd = smb_ChainFID(fd, inp);
6693 fidp = smb_FindFID(vcp, fd, 0);
6695 return CM_ERROR_BADFD;
6698 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6699 smb_CloseFID(vcp, fidp, NULL, 0);
6700 smb_ReleaseFID(fidp);
6701 return CM_ERROR_NOSUCHFILE;
6707 LARGE_INTEGER LOffset;
6708 LARGE_INTEGER LLength;
6710 pid = ((smb_t *) inp)->pid;
6711 key = cm_GenerateKey(vcp->vcID, pid, fd);
6713 LOffset.HighPart = offset.HighPart;
6714 LOffset.LowPart = offset.LowPart;
6715 LLength.HighPart = 0;
6716 LLength.LowPart = count;
6718 lock_ObtainMutex(&fidp->scp->mx);
6719 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6720 lock_ReleaseMutex(&fidp->scp->mx);
6723 smb_ReleaseFID(fidp);
6728 userp = smb_GetUserFromVCP(vcp, inp);
6731 * Work around bug in NT client
6733 * When copying a file, the NT client should first copy the data,
6734 * then copy the last write time. But sometimes the NT client does
6735 * these in the wrong order, so the data copies would inadvertently
6736 * cause the last write time to be overwritten. We try to detect this,
6737 * and don't set client mod time if we think that would go against the
6740 lock_ObtainMutex(&fidp->mx);
6741 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6742 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6743 fidp->scp->clientModTime = time(NULL);
6745 lock_ReleaseMutex(&fidp->mx);
6748 while ( code == 0 && count > 0 ) {
6749 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6750 if (code == 0 && written == 0)
6751 code = CM_ERROR_PARTIALWRITE;
6753 offset = LargeIntegerAdd(offset,
6754 ConvertLongToLargeInteger(written));
6757 total_written += written;
6761 /* Get a raw buffer */
6764 lock_ObtainMutex(&smb_RawBufLock);
6766 /* Get a raw buf, from head of list */
6767 rawBuf = smb_RawBufs;
6768 smb_RawBufs = *(char **)smb_RawBufs;
6771 code = CM_ERROR_USESTD;
6773 lock_ReleaseMutex(&smb_RawBufLock);
6776 /* Don't allow a premature Close */
6777 if (code == 0 && (writeMode & 1) == 0) {
6778 lock_ObtainMutex(&fidp->mx);
6779 fidp->raw_writers++;
6780 thrd_ResetEvent(fidp->raw_write_event);
6781 lock_ReleaseMutex(&fidp->mx);
6784 smb_ReleaseFID(fidp);
6785 cm_ReleaseUser(userp);
6788 smb_SetSMBParm(outp, 0, total_written);
6789 smb_SetSMBDataLength(outp, 0);
6790 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6795 offset = LargeIntegerAdd(offset,
6796 ConvertLongToLargeInteger(count));
6800 rwcp->offset.HighPart = offset.HighPart;
6801 rwcp->offset.LowPart = offset.LowPart;
6802 rwcp->count = totalCount - count;
6803 rwcp->writeMode = writeMode;
6804 rwcp->alreadyWritten = total_written;
6806 /* set the packet data length to 3 bytes for the data block header,
6807 * plus the size of the data.
6809 smb_SetSMBParm(outp, 0, 0xffff);
6810 smb_SetSMBDataLength(outp, 0);
6815 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6818 long count, finalCount;
6826 fd = smb_GetSMBParm(inp, 0);
6827 count = smb_GetSMBParm(inp, 1);
6828 offset.HighPart = 0; /* too bad */
6829 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6831 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6832 fd, offset.LowPart, count);
6834 fd = smb_ChainFID(fd, inp);
6835 fidp = smb_FindFID(vcp, fd, 0);
6837 return CM_ERROR_BADFD;
6839 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6840 smb_CloseFID(vcp, fidp, NULL, 0);
6841 smb_ReleaseFID(fidp);
6842 return CM_ERROR_NOSUCHFILE;
6845 lock_ObtainMutex(&fidp->mx);
6846 if (fidp->flags & SMB_FID_IOCTL) {
6847 lock_ReleaseMutex(&fidp->mx);
6848 code = smb_IoctlRead(fidp, vcp, inp, outp);
6849 smb_ReleaseFID(fidp);
6852 lock_ReleaseMutex(&fidp->mx);
6855 LARGE_INTEGER LOffset, LLength;
6858 pid = ((smb_t *) inp)->pid;
6859 key = cm_GenerateKey(vcp->vcID, pid, fd);
6861 LOffset.HighPart = 0;
6862 LOffset.LowPart = offset.LowPart;
6863 LLength.HighPart = 0;
6864 LLength.LowPart = count;
6866 lock_ObtainMutex(&fidp->scp->mx);
6867 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6868 lock_ReleaseMutex(&fidp->scp->mx);
6871 smb_ReleaseFID(fidp);
6875 userp = smb_GetUserFromVCP(vcp, inp);
6877 /* remember this for final results */
6878 smb_SetSMBParm(outp, 0, count);
6879 smb_SetSMBParm(outp, 1, 0);
6880 smb_SetSMBParm(outp, 2, 0);
6881 smb_SetSMBParm(outp, 3, 0);
6882 smb_SetSMBParm(outp, 4, 0);
6884 /* set the packet data length to 3 bytes for the data block header,
6885 * plus the size of the data.
6887 smb_SetSMBDataLength(outp, count+3);
6889 /* get op ptr after putting in the parms, since otherwise we don't
6890 * know where the data really is.
6892 op = smb_GetSMBData(outp, NULL);
6894 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6895 *op++ = 1; /* data block marker */
6896 *op++ = (unsigned char) (count & 0xff);
6897 *op++ = (unsigned char) ((count >> 8) & 0xff);
6899 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6901 /* fix some things up */
6902 smb_SetSMBParm(outp, 0, finalCount);
6903 smb_SetSMBDataLength(outp, finalCount+3);
6905 smb_ReleaseFID(fidp);
6907 cm_ReleaseUser(userp);
6911 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6918 cm_scache_t *dscp; /* dir we're dealing with */
6919 cm_scache_t *scp; /* file we're creating */
6921 int initialModeBits;
6931 /* compute initial mode bits based on read-only flag in attributes */
6932 initialModeBits = 0777;
6934 tp = smb_GetSMBData(inp, NULL);
6935 pathp = smb_ParseASCIIBlock(tp, &tp);
6936 if (smb_StoreAnsiFilenames)
6937 OemToChar(pathp,pathp);
6939 if (strcmp(pathp, "\\") == 0)
6940 return CM_ERROR_EXISTS;
6942 spacep = inp->spacep;
6943 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6945 userp = smb_GetUserFromVCP(vcp, inp);
6947 caseFold = CM_FLAG_CASEFOLD;
6949 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6951 cm_ReleaseUser(userp);
6952 return CM_ERROR_NOSUCHPATH;
6955 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6956 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6957 userp, tidPathp, &req, &dscp);
6960 cm_ReleaseUser(userp);
6965 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6966 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
6967 cm_ReleaseSCache(dscp);
6968 cm_ReleaseUser(userp);
6969 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6970 return CM_ERROR_PATH_NOT_COVERED;
6972 return CM_ERROR_BADSHARENAME;
6974 #endif /* DFS_SUPPORT */
6976 /* otherwise, scp points to the parent directory. Do a lookup, and
6977 * fail if we find it. Otherwise, we do the create.
6983 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6984 if (scp) cm_ReleaseSCache(scp);
6985 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6986 if (code == 0) code = CM_ERROR_EXISTS;
6987 cm_ReleaseSCache(dscp);
6988 cm_ReleaseUser(userp);
6992 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6993 setAttr.clientModTime = time(NULL);
6994 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6995 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6996 smb_NotifyChange(FILE_ACTION_ADDED,
6997 FILE_NOTIFY_CHANGE_DIR_NAME,
6998 dscp, lastNamep, NULL, TRUE);
7000 /* we don't need this any longer */
7001 cm_ReleaseSCache(dscp);
7004 /* something went wrong creating or truncating the file */
7005 cm_ReleaseUser(userp);
7009 /* otherwise we succeeded */
7010 smb_SetSMBDataLength(outp, 0);
7011 cm_ReleaseUser(userp);
7016 BOOL smb_IsLegalFilename(char *filename)
7019 * Find the longest substring of filename that does not contain
7020 * any of the chars in illegalChars. If that substring is less
7021 * than the length of the whole string, then one or more of the
7022 * illegal chars is in filename.
7024 if (strcspn(filename, illegalChars) < strlen(filename))
7030 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7038 cm_scache_t *dscp; /* dir we're dealing with */
7039 cm_scache_t *scp; /* file we're creating */
7041 int initialModeBits;
7049 int created = 0; /* the file was new */
7054 excl = (inp->inCom == 0x03)? 0 : 1;
7056 attributes = smb_GetSMBParm(inp, 0);
7057 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7059 /* compute initial mode bits based on read-only flag in attributes */
7060 initialModeBits = 0666;
7061 if (attributes & SMB_ATTR_READONLY)
7062 initialModeBits &= ~0222;
7064 tp = smb_GetSMBData(inp, NULL);
7065 pathp = smb_ParseASCIIBlock(tp, &tp);
7066 if (smb_StoreAnsiFilenames)
7067 OemToChar(pathp,pathp);
7069 spacep = inp->spacep;
7070 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7072 userp = smb_GetUserFromVCP(vcp, inp);
7074 caseFold = CM_FLAG_CASEFOLD;
7076 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7078 cm_ReleaseUser(userp);
7079 return CM_ERROR_NOSUCHPATH;
7081 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7082 userp, tidPathp, &req, &dscp);
7085 cm_ReleaseUser(userp);
7090 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7091 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7092 cm_ReleaseSCache(dscp);
7093 cm_ReleaseUser(userp);
7094 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7095 return CM_ERROR_PATH_NOT_COVERED;
7097 return CM_ERROR_BADSHARENAME;
7099 #endif /* DFS_SUPPORT */
7101 /* otherwise, scp points to the parent directory. Do a lookup, and
7102 * truncate the file if we find it, otherwise we create the file.
7109 if (!smb_IsLegalFilename(lastNamep))
7110 return CM_ERROR_BADNTFILENAME;
7112 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7113 #ifdef DEBUG_VERBOSE
7116 hexp = osi_HexifyString( lastNamep );
7117 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7122 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7123 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7124 cm_ReleaseSCache(dscp);
7125 cm_ReleaseUser(userp);
7129 /* if we get here, if code is 0, the file exists and is represented by
7130 * scp. Otherwise, we have to create it.
7134 /* oops, file shouldn't be there */
7135 cm_ReleaseSCache(dscp);
7136 cm_ReleaseSCache(scp);
7137 cm_ReleaseUser(userp);
7138 return CM_ERROR_EXISTS;
7141 setAttr.mask = CM_ATTRMASK_LENGTH;
7142 setAttr.length.LowPart = 0;
7143 setAttr.length.HighPart = 0;
7144 code = cm_SetAttr(scp, &setAttr, userp, &req);
7147 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7148 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7149 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7153 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7154 smb_NotifyChange(FILE_ACTION_ADDED,
7155 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7156 dscp, lastNamep, NULL, TRUE);
7157 } else if (!excl && code == CM_ERROR_EXISTS) {
7158 /* not an exclusive create, and someone else tried
7159 * creating it already, then we open it anyway. We
7160 * don't bother retrying after this, since if this next
7161 * fails, that means that the file was deleted after
7162 * we started this call.
7164 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7167 setAttr.mask = CM_ATTRMASK_LENGTH;
7168 setAttr.length.LowPart = 0;
7169 setAttr.length.HighPart = 0;
7170 code = cm_SetAttr(scp, &setAttr, userp, &req);
7175 /* we don't need this any longer */
7176 cm_ReleaseSCache(dscp);
7179 /* something went wrong creating or truncating the file */
7180 if (scp) cm_ReleaseSCache(scp);
7181 cm_ReleaseUser(userp);
7185 /* make sure we only open files */
7186 if (scp->fileType != CM_SCACHETYPE_FILE) {
7187 cm_ReleaseSCache(scp);
7188 cm_ReleaseUser(userp);
7189 return CM_ERROR_ISDIR;
7192 /* now all we have to do is open the file itself */
7193 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7194 osi_assertx(fidp, "null smb_fid_t");
7198 lock_ObtainMutex(&fidp->mx);
7199 /* always create it open for read/write */
7200 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7202 /* remember that the file was newly created */
7204 fidp->flags |= SMB_FID_CREATED;
7206 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7208 /* save a pointer to the vnode */
7210 lock_ObtainMutex(&scp->mx);
7211 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7212 lock_ReleaseMutex(&scp->mx);
7215 fidp->userp = userp;
7216 lock_ReleaseMutex(&fidp->mx);
7218 smb_SetSMBParm(outp, 0, fidp->fid);
7219 smb_SetSMBDataLength(outp, 0);
7221 cm_Open(scp, 0, userp);
7223 smb_ReleaseFID(fidp);
7224 cm_ReleaseUser(userp);
7225 /* leave scp held since we put it in fidp->scp */
7229 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7232 osi_hyper_t new_offset;
7243 fd = smb_GetSMBParm(inp, 0);
7244 whence = smb_GetSMBParm(inp, 1);
7245 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7247 /* try to find the file descriptor */
7248 fd = smb_ChainFID(fd, inp);
7249 fidp = smb_FindFID(vcp, fd, 0);
7251 return CM_ERROR_BADFD;
7253 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7254 smb_CloseFID(vcp, fidp, NULL, 0);
7255 smb_ReleaseFID(fidp);
7256 return CM_ERROR_NOSUCHFILE;
7259 lock_ObtainMutex(&fidp->mx);
7260 if (fidp->flags & SMB_FID_IOCTL) {
7261 lock_ReleaseMutex(&fidp->mx);
7262 smb_ReleaseFID(fidp);
7263 return CM_ERROR_BADFD;
7265 lock_ReleaseMutex(&fidp->mx);
7267 userp = smb_GetUserFromVCP(vcp, inp);
7269 lock_ObtainMutex(&fidp->mx);
7272 lock_ReleaseMutex(&fidp->mx);
7273 lock_ObtainMutex(&scp->mx);
7274 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7275 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7277 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7279 /* offset from current offset */
7280 new_offset = LargeIntegerAdd(fidp->offset,
7281 ConvertLongToLargeInteger(offset));
7283 else if (whence == 2) {
7284 /* offset from current EOF */
7285 new_offset = LargeIntegerAdd(scp->length,
7286 ConvertLongToLargeInteger(offset));
7288 new_offset = ConvertLongToLargeInteger(offset);
7291 fidp->offset = new_offset;
7292 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7293 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7294 smb_SetSMBDataLength(outp, 0);
7296 lock_ReleaseMutex(&scp->mx);
7297 smb_ReleaseFID(fidp);
7298 cm_ReleaseSCache(scp);
7299 cm_ReleaseUser(userp);
7303 /* dispatch all of the requests received in a packet. Due to chaining, this may
7304 * be more than one request.
7306 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7307 NCB *ncbp, raw_write_cont_t *rwcp)
7311 unsigned long code = 0;
7312 unsigned char *outWctp;
7313 int nparms; /* # of bytes of parameters */
7315 int nbytes; /* bytes of data, excluding count */
7318 unsigned short errCode;
7319 unsigned long NTStatus;
7321 unsigned char errClass;
7322 unsigned int oldGen;
7323 DWORD oldTime, newTime;
7325 /* get easy pointer to the data */
7326 smbp = (smb_t *) inp->data;
7328 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7329 /* setup the basic parms for the initial request in the packet */
7330 inp->inCom = smbp->com;
7331 inp->wctp = &smbp->wct;
7333 inp->ncb_length = ncbp->ncb_length;
7338 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7339 /* log it and discard it */
7340 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7341 __FILE__, __LINE__, ncbp->ncb_length);
7342 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7346 /* We are an ongoing op */
7347 thrd_Increment(&ongoingOps);
7349 /* set up response packet for receiving output */
7350 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7351 smb_FormatResponsePacket(vcp, inp, outp);
7352 outWctp = outp->wctp;
7354 /* Remember session generation number and time */
7355 oldGen = sessionGen;
7356 oldTime = GetTickCount();
7358 while (inp->inCom != 0xff) {
7359 dp = &smb_dispatchTable[inp->inCom];
7361 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7362 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7363 code = outp->resumeCode;
7367 /* process each request in the packet; inCom, wctp and inCount
7368 * are already set up.
7370 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7373 /* now do the dispatch */
7374 /* start by formatting the response record a little, as a default */
7375 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7377 outWctp[1] = 0xff; /* no operation */
7378 outWctp[2] = 0; /* padding */
7383 /* not a chained request, this is a more reasonable default */
7384 outWctp[0] = 0; /* wct of zero */
7385 outWctp[1] = 0; /* and bcc (word) of zero */
7389 /* once set, stays set. Doesn't matter, since we never chain
7390 * "no response" calls.
7392 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7396 /* we have a recognized operation */
7398 if (inp->inCom == 0x1d)
7400 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7402 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7403 code = (*(dp->procp)) (vcp, inp, outp);
7404 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7406 if ( code == CM_ERROR_BADSMB ||
7407 code == CM_ERROR_BADOP )
7409 #endif /* LOG_PACKET */
7412 if (oldGen != sessionGen) {
7413 newTime = GetTickCount();
7414 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7415 newTime - oldTime, ncbp->ncb_length);
7416 osi_Log2(smb_logp, "Pkt straddled session startup, "
7417 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7421 /* bad opcode, fail the request, after displaying it */
7422 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7425 #endif /* LOG_PACKET */
7428 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7429 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7430 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7431 if (code == IDCANCEL)
7434 code = CM_ERROR_BADOP;
7437 /* catastrophic failure: log as much as possible */
7438 if (code == CM_ERROR_BADSMB) {
7439 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7443 #endif /* LOG_PACKET */
7444 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7447 code = CM_ERROR_INVAL;
7450 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7451 thrd_Decrement(&ongoingOps);
7456 /* now, if we failed, turn the current response into an empty
7457 * one, and fill in the response packet's error code.
7460 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7461 smb_MapNTError(code, &NTStatus);
7462 outWctp = outp->wctp;
7463 smbp = (smb_t *) &outp->data;
7464 if (code != CM_ERROR_PARTIALWRITE
7465 && code != CM_ERROR_BUFFERTOOSMALL
7466 && code != CM_ERROR_GSSCONTINUE) {
7467 /* nuke wct and bcc. For a partial
7468 * write or an in-process authentication handshake,
7469 * assume they're OK.
7475 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7476 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7477 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7478 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7479 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7483 smb_MapCoreError(code, vcp, &errCode, &errClass);
7484 outWctp = outp->wctp;
7485 smbp = (smb_t *) &outp->data;
7486 if (code != CM_ERROR_PARTIALWRITE) {
7487 /* nuke wct and bcc. For a partial
7488 * write, assume they're OK.
7494 smbp->errLow = (unsigned char) (errCode & 0xff);
7495 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7496 smbp->rcls = errClass;
7499 } /* error occurred */
7501 /* if we're here, we've finished one request. Look to see if
7502 * this is a chained opcode. If it is, setup things to process
7503 * the chained request, and setup the output buffer to hold the
7504 * chained response. Start by finding the next input record.
7506 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7507 break; /* not a chained req */
7508 tp = inp->wctp; /* points to start of last request */
7509 /* in a chained request, the first two
7510 * parm fields are required, and are
7511 * AndXCommand/AndXReserved and
7513 if (tp[0] < 2) break;
7514 if (tp[1] == 0xff) break; /* no more chained opcodes */
7516 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7519 /* and now append the next output request to the end of this
7520 * last request. Begin by finding out where the last response
7521 * ends, since that's where we'll put our new response.
7523 outWctp = outp->wctp; /* ptr to out parameters */
7524 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7525 nparms = outWctp[0] << 1;
7526 tp = outWctp + nparms + 1; /* now points to bcc field */
7527 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7528 tp += 2 /* for the count itself */ + nbytes;
7529 /* tp now points to the new output record; go back and patch the
7530 * second parameter (off2) to point to the new record.
7532 temp = (unsigned int)(tp - outp->data);
7533 outWctp[3] = (unsigned char) (temp & 0xff);
7534 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7535 outWctp[2] = 0; /* padding */
7536 outWctp[1] = inp->inCom; /* next opcode */
7538 /* finally, setup for the next iteration */
7541 } /* while loop over all requests in the packet */
7543 /* now send the output packet, and return */
7545 smb_SendPacket(vcp, outp);
7546 thrd_Decrement(&ongoingOps);
7551 /* Wait for Netbios() calls to return, and make the results available to server
7552 * threads. Note that server threads can't wait on the NCBevents array
7553 * themselves, because NCB events are manual-reset, and the servers would race
7554 * each other to reset them.
7556 void smb_ClientWaiter(void *parmp)
7561 while (smbShutdownFlag == 0) {
7562 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7564 if (code == WAIT_OBJECT_0)
7567 /* error checking */
7568 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7570 int abandonIdx = code - WAIT_ABANDONED_0;
7571 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7574 if (code == WAIT_IO_COMPLETION)
7576 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7580 if (code == WAIT_TIMEOUT)
7582 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7585 if (code == WAIT_FAILED)
7587 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7590 idx = code - WAIT_OBJECT_0;
7592 /* check idx range! */
7593 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7595 /* this is fatal - log as much as possible */
7596 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7597 osi_assertx(0, "invalid index");
7600 thrd_ResetEvent(NCBevents[idx]);
7601 thrd_SetEvent(NCBreturns[0][idx]);
7606 * Try to have one NCBRECV request waiting for every live session. Not more
7607 * than one, because if there is more than one, it's hard to handle Write Raw.
7609 void smb_ServerWaiter(void *parmp)
7612 int idx_session, idx_NCB;
7615 while (smbShutdownFlag == 0) {
7617 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7619 if (code == WAIT_OBJECT_0)
7622 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7624 int abandonIdx = code - WAIT_ABANDONED_0;
7625 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7628 if (code == WAIT_IO_COMPLETION)
7630 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7634 if (code == WAIT_TIMEOUT)
7636 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7639 if (code == WAIT_FAILED)
7641 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7644 idx_session = code - WAIT_OBJECT_0;
7646 /* check idx range! */
7647 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7649 /* this is fatal - log as much as possible */
7650 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7651 osi_assertx(0, "invalid index");
7656 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7658 if (code == WAIT_OBJECT_0) {
7659 if (smbShutdownFlag == 1)
7665 /* error checking */
7666 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7668 int abandonIdx = code - WAIT_ABANDONED_0;
7669 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7672 if (code == WAIT_IO_COMPLETION)
7674 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7678 if (code == WAIT_TIMEOUT)
7680 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7683 if (code == WAIT_FAILED)
7685 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7688 idx_NCB = code - WAIT_OBJECT_0;
7690 /* check idx range! */
7691 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7693 /* this is fatal - log as much as possible */
7694 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7695 osi_assertx(0, "invalid index");
7698 /* Link them together */
7699 NCBsessions[idx_NCB] = idx_session;
7702 ncbp = NCBs[idx_NCB];
7703 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7704 ncbp->ncb_command = NCBRECV | ASYNCH;
7705 ncbp->ncb_lana_num = lanas[idx_session];
7706 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7707 ncbp->ncb_event = NCBevents[idx_NCB];
7708 ncbp->ncb_length = SMB_PACKETSIZE;
7714 * The top level loop for handling SMB request messages. Each server thread
7715 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7716 * NCB and buffer for the incoming request are loaned to us.
7718 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7719 * to immediately send a request for the rest of the data. This must come
7720 * before any other traffic for that session, so we delay setting the session
7721 * event until that data has come in.
7723 void smb_Server(VOID *parmp)
7725 INT_PTR myIdx = (INT_PTR) parmp;
7729 smb_packet_t *outbufp;
7731 int idx_NCB, idx_session;
7733 smb_vc_t *vcp = NULL;
7736 rx_StartClientThread();
7739 outbufp = GetPacket();
7740 outbufp->ncbp = outncbp;
7748 smb_ResetServerPriority();
7750 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7753 /* terminate silently if shutdown flag is set */
7754 if (code == WAIT_OBJECT_0) {
7755 if (smbShutdownFlag == 1) {
7756 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7762 /* error checking */
7763 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7765 int abandonIdx = code - WAIT_ABANDONED_0;
7766 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7769 if (code == WAIT_IO_COMPLETION)
7771 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7775 if (code == WAIT_TIMEOUT)
7777 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7780 if (code == WAIT_FAILED)
7782 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7785 idx_NCB = code - WAIT_OBJECT_0;
7787 /* check idx range! */
7788 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7790 /* this is fatal - log as much as possible */
7791 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7792 osi_assertx(0, "invalid index");
7795 ncbp = NCBs[idx_NCB];
7796 idx_session = NCBsessions[idx_NCB];
7797 rc = ncbp->ncb_retcode;
7799 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7800 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7804 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7808 /* Can this happen? Or is it just my UNIX paranoia? */
7809 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7814 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7817 /* Client closed session */
7818 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7820 lock_ObtainMutex(&vcp->mx);
7821 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7822 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7824 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7825 lock_ReleaseMutex(&vcp->mx);
7826 lock_ObtainWrite(&smb_globalLock);
7827 dead_sessions[vcp->session] = TRUE;
7828 lock_ReleaseWrite(&smb_globalLock);
7829 smb_CleanupDeadVC(vcp);
7833 lock_ReleaseMutex(&vcp->mx);
7839 /* Treat as transient error */
7840 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7843 "dispatch smb recv failed, message incomplete, ncb_length %d",
7846 "SMB message incomplete, "
7847 "length %d", ncbp->ncb_length);
7850 * We used to discard the packet.
7851 * Instead, try handling it normally.
7855 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7859 /* A weird error code. Log it, sleep, and continue. */
7860 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7862 lock_ObtainMutex(&vcp->mx);
7863 if (vcp && vcp->errorCount++ > 3) {
7864 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7865 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7866 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7868 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7869 lock_ReleaseMutex(&vcp->mx);
7870 lock_ObtainWrite(&smb_globalLock);
7871 dead_sessions[vcp->session] = TRUE;
7872 lock_ReleaseWrite(&smb_globalLock);
7873 smb_CleanupDeadVC(vcp);
7877 lock_ReleaseMutex(&vcp->mx);
7883 lock_ReleaseMutex(&vcp->mx);
7885 thrd_SetEvent(SessionEvents[idx_session]);
7890 /* Success, so now dispatch on all the data in the packet */
7892 smb_concurrentCalls++;
7893 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7894 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7897 * If at this point vcp is NULL (implies that packet was invalid)
7898 * then we are in big trouble. This means either :
7899 * a) we have the wrong NCB.
7900 * b) Netbios screwed up the call.
7901 * c) The VC was already marked dead before we were able to
7903 * Obviously this implies that
7904 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7905 * lanas[idx_session] != ncbp->ncb_lana_num )
7906 * Either way, we can't do anything with this packet.
7907 * Log, sleep and resume.
7910 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7914 ncbp->ncb_lana_num);
7916 /* Also log in the trace log. */
7917 osi_Log4(smb_logp, "Server: VCP does not exist!"
7918 "LSNs[idx_session]=[%d],"
7919 "lanas[idx_session]=[%d],"
7920 "ncbp->ncb_lsn=[%d],"
7921 "ncbp->ncb_lana_num=[%d]",
7925 ncbp->ncb_lana_num);
7927 /* thrd_Sleep(1000); Don't bother sleeping */
7928 thrd_SetEvent(SessionEvents[idx_session]);
7929 smb_concurrentCalls--;
7933 smb_SetRequestStartTime();
7935 vcp->errorCount = 0;
7936 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7937 smbp = (smb_t *)bufp->data;
7942 if (smbp->com == 0x1d) {
7943 /* Special handling for Write Raw */
7944 raw_write_cont_t rwc;
7945 EVENT_HANDLE rwevent;
7946 char eventName[MAX_PATH];
7948 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7949 if (rwc.code == 0) {
7950 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7951 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7952 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7953 ncbp->ncb_command = NCBRECV | ASYNCH;
7954 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7955 ncbp->ncb_lana_num = vcp->lana;
7956 ncbp->ncb_buffer = rwc.buf;
7957 ncbp->ncb_length = 65535;
7958 ncbp->ncb_event = rwevent;
7960 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7961 thrd_CloseHandle(rwevent);
7963 thrd_SetEvent(SessionEvents[idx_session]);
7965 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7967 else if (smbp->com == 0xa0) {
7969 * Serialize the handling for NT Transact
7972 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7973 thrd_SetEvent(SessionEvents[idx_session]);
7975 thrd_SetEvent(SessionEvents[idx_session]);
7976 /* TODO: what else needs to be serialized? */
7977 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7980 __except( smb_ServerExceptionFilter() ) {
7983 smb_concurrentCalls--;
7986 thrd_SetEvent(NCBavails[idx_NCB]);
7993 * Exception filter for the server threads. If an exception occurs in the
7994 * dispatch routines, which is where exceptions are most common, then do a
7995 * force trace and give control to upstream exception handlers. Useful for
7998 DWORD smb_ServerExceptionFilter(void) {
7999 /* While this is not the best time to do a trace, if it succeeds, then
8000 * we have a trace (assuming tracing was enabled). Otherwise, this should
8001 * throw a second exception.
8003 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8004 afsd_ForceTrace(TRUE);
8005 buf_ForceTrace(TRUE);
8006 return EXCEPTION_CONTINUE_SEARCH;
8010 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8011 * If the number of server threads is M, and the number of live sessions is
8012 * N, then the number of NCB's in use at any time either waiting for, or
8013 * holding, received messages is M + N, so that is how many NCB's get created.
8015 void InitNCBslot(int idx)
8017 struct smb_packet *bufp;
8018 EVENT_HANDLE retHandle;
8020 char eventName[MAX_PATH];
8022 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8024 NCBs[idx] = GetNCB();
8025 sprintf(eventName,"NCBavails[%d]", idx);
8026 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8027 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8028 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8029 sprintf(eventName,"NCBevents[%d]", idx);
8030 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8031 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8032 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8033 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8034 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8035 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8036 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8037 for (i=0; i<smb_NumServerThreads; i++)
8038 NCBreturns[i][idx] = retHandle;
8040 bufp->spacep = cm_GetSpace();
8044 /* listen for new connections */
8045 void smb_Listener(void *parmp)
8051 int session, thread;
8052 smb_vc_t *vcp = NULL;
8054 char rname[NCBNAMSZ+1];
8055 char cname[MAX_COMPUTERNAME_LENGTH+1];
8056 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8057 INT_PTR lana = (INT_PTR) parmp;
8058 char eventName[MAX_PATH];
8060 sprintf(eventName,"smb_Listener_lana_%d", (char)lana);
8061 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8062 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8063 thrd_ResetEvent(ListenerShutdown[lana]);
8067 /* retrieve computer name */
8068 GetComputerName(cname, &cnamelen);
8071 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8072 memset(ncbp, 0, sizeof(NCB));
8075 ncbp->ncb_command = NCBLISTEN;
8076 ncbp->ncb_rto = 0; /* No receive timeout */
8077 ncbp->ncb_sto = 0; /* No send timeout */
8079 /* pad out with spaces instead of null termination */
8080 len = (long)strlen(smb_localNamep);
8081 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8082 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8084 strcpy(ncbp->ncb_callname, "*");
8085 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8087 ncbp->ncb_lana_num = (UCHAR)lana;
8089 code = Netbios(ncbp);
8091 if (code == NRC_NAMERR) {
8092 /* An smb shutdown or Vista resume must have taken place */
8094 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8095 ncbp->ncb_lana_num, code);
8097 if (lock_TryMutex(&smb_StartedLock)) {
8098 lana_list.lana[i] = LANA_INVALID;
8099 lock_ReleaseMutex(&smb_StartedLock);
8102 } else if (code == NRC_BRIDGE || code != 0) {
8103 int lanaRemaining = 0;
8105 while (!lock_TryMutex(&smb_StartedLock)) {
8106 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8112 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8113 ncbp->ncb_lana_num, ncb_error_string(code));
8115 for (i = 0; i < lana_list.length; i++) {
8116 if (lana_list.lana[i] == lana) {
8117 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8118 lana_list.lana[i] = LANA_INVALID;
8120 if (lana_list.lana[i] != LANA_INVALID)
8124 if (lanaRemaining == 0) {
8125 cm_VolStatus_Network_Stopped(cm_NetbiosName
8130 smb_ListenerState = SMB_LISTENER_STOPPED;
8131 smb_LANadapter = LANA_INVALID;
8132 lana_list.length = 0;
8134 lock_ReleaseMutex(&smb_StartedLock);
8138 else if (code != 0) {
8139 char tbuffer[AFSPATHMAX];
8141 /* terminate silently if shutdown flag is set */
8142 while (!lock_TryMutex(&smb_StartedLock)) {
8143 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8149 "NCBLISTEN lana=%d failed with code %d [%s]",
8150 ncbp->ncb_lana_num, code, ncb_error_string(code));
8152 "Client exiting due to network failure. Please restart client.\n");
8155 "Client exiting due to network failure. Please restart client.\n"
8156 "NCBLISTEN lana=%d failed with code %d [%s]",
8157 ncbp->ncb_lana_num, code, ncb_error_string(code));
8159 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8160 MB_OK|MB_SERVICE_NOTIFICATION);
8161 osi_panic(tbuffer, __FILE__, __LINE__);
8163 lock_ReleaseMutex(&smb_StartedLock);
8168 /* check for remote conns */
8169 /* first get remote name and insert null terminator */
8170 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8171 for (i=NCBNAMSZ; i>0; i--) {
8172 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8178 /* compare with local name */
8180 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8181 flags |= SMB_VCFLAG_REMOTECONN;
8184 lock_ObtainMutex(&smb_ListenerLock);
8186 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8187 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8189 /* now ncbp->ncb_lsn is the connection ID */
8190 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8191 if (vcp->session == 0) {
8192 /* New generation */
8193 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8196 /* Log session startup */
8198 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8199 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8200 #endif /* NOTSERVICE */
8201 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8202 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8204 if (reportSessionStartups) {
8205 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8208 lock_ObtainMutex(&vcp->mx);
8209 strcpy(vcp->rname, rname);
8210 vcp->flags |= flags;
8211 lock_ReleaseMutex(&vcp->mx);
8213 /* Allocate slot in session arrays */
8214 /* Re-use dead session if possible, otherwise add one more */
8215 /* But don't look at session[0], it is reserved */
8216 lock_ObtainWrite(&smb_globalLock);
8217 for (session = 1; session < numSessions; session++) {
8218 if (dead_sessions[session]) {
8219 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8220 dead_sessions[session] = FALSE;
8224 lock_ReleaseWrite(&smb_globalLock);
8226 /* We are re-using an existing VC because the lsn and lana
8228 session = vcp->session;
8230 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8232 /* Log session startup */
8234 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8235 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8236 #endif /* NOTSERVICE */
8237 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8238 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8240 if (reportSessionStartups) {
8241 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8245 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8246 unsigned long code = CM_ERROR_ALLBUSY;
8247 smb_packet_t * outp = GetPacket();
8248 unsigned char *outWctp;
8251 smb_FormatResponsePacket(vcp, NULL, outp);
8254 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8255 unsigned long NTStatus;
8256 smb_MapNTError(code, &NTStatus);
8257 outWctp = outp->wctp;
8258 smbp = (smb_t *) &outp->data;
8262 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8263 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8264 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8265 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8266 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8268 unsigned short errCode;
8269 unsigned char errClass;
8270 smb_MapCoreError(code, vcp, &errCode, &errClass);
8271 outWctp = outp->wctp;
8272 smbp = (smb_t *) &outp->data;
8276 smbp->errLow = (unsigned char) (errCode & 0xff);
8277 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8278 smbp->rcls = errClass;
8280 smb_SendPacket(vcp, outp);
8281 smb_FreePacket(outp);
8283 lock_ObtainMutex(&vcp->mx);
8284 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8285 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8287 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8288 lock_ReleaseMutex(&vcp->mx);
8289 lock_ObtainWrite(&smb_globalLock);
8290 dead_sessions[vcp->session] = TRUE;
8291 lock_ReleaseWrite(&smb_globalLock);
8292 smb_CleanupDeadVC(vcp);
8294 lock_ReleaseMutex(&vcp->mx);
8297 /* assert that we do not exceed the maximum number of sessions or NCBs.
8298 * we should probably want to wait for a session to be freed in case
8301 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8302 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8304 lock_ObtainMutex(&vcp->mx);
8305 vcp->session = session;
8306 lock_ReleaseMutex(&vcp->mx);
8307 lock_ObtainWrite(&smb_globalLock);
8308 LSNs[session] = ncbp->ncb_lsn;
8309 lanas[session] = ncbp->ncb_lana_num;
8310 lock_ReleaseWrite(&smb_globalLock);
8312 if (session == numSessions) {
8313 /* Add new NCB for new session */
8314 char eventName[MAX_PATH];
8316 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8318 InitNCBslot(numNCBs);
8319 lock_ObtainWrite(&smb_globalLock);
8321 lock_ReleaseWrite(&smb_globalLock);
8322 thrd_SetEvent(NCBavails[0]);
8323 thrd_SetEvent(NCBevents[0]);
8324 for (thread = 0; thread < smb_NumServerThreads; thread++)
8325 thrd_SetEvent(NCBreturns[thread][0]);
8326 /* Also add new session event */
8327 sprintf(eventName, "SessionEvents[%d]", session);
8328 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8329 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8330 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8331 lock_ObtainWrite(&smb_globalLock);
8333 lock_ReleaseWrite(&smb_globalLock);
8334 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8335 thrd_SetEvent(SessionEvents[0]);
8337 thrd_SetEvent(SessionEvents[session]);
8343 lock_ReleaseMutex(&smb_ListenerLock);
8344 } /* dispatch while loop */
8348 thrd_SetEvent(ListenerShutdown[lana]);
8352 void smb_SetLanAdapterChangeDetected(void)
8354 lock_ObtainMutex(&smb_StartedLock);
8355 smb_LanAdapterChangeDetected = 1;
8356 lock_ReleaseMutex(&smb_StartedLock);
8359 void smb_LanAdapterChange(int locked) {
8360 lana_number_t lanaNum;
8362 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
8364 LANA_ENUM temp_list;
8369 afsi_log("smb_LanAdapterChange");
8372 lock_ObtainMutex(&smb_StartedLock);
8374 smb_LanAdapterChangeDetected = 0;
8376 if (!powerStateSuspended &&
8377 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
8378 LANA_NETBIOS_NAME_FULL)) &&
8379 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
8380 if ( isGateway != bGateway ||
8381 strcmp(cm_NetbiosName, NetbiosName) ) {
8384 NCB *ncbp = GetNCB();
8385 ncbp->ncb_command = NCBENUM;
8386 ncbp->ncb_buffer = (PUCHAR)&temp_list;
8387 ncbp->ncb_length = sizeof(temp_list);
8388 code = Netbios(ncbp);
8390 if (temp_list.length != lana_list.length)
8393 for (i=0; i<lana_list.length; i++) {
8394 if ( temp_list.lana[i] != lana_list.lana[i] ) {
8406 afsi_log("Lan Adapter Change detected");
8407 smb_StopListeners(1);
8408 smb_RestartListeners(1);
8411 lock_ReleaseMutex(&smb_StartedLock);
8414 /* initialize Netbios */
8415 int smb_NetbiosInit(int locked)
8418 int i, lana, code, l;
8420 int delname_tried=0;
8423 lana_number_t lanaNum;
8426 lock_ObtainMutex(&smb_StartedLock);
8428 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
8429 smb_ListenerState != SMB_LISTENER_STOPPED) {
8432 lock_ReleaseMutex(&smb_StartedLock);
8435 /* setup the NCB system */
8438 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8439 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8440 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8442 if (smb_LANadapter != LANA_INVALID)
8443 afsi_log("LAN adapter number %d", smb_LANadapter);
8445 afsi_log("LAN adapter number not determined");
8448 afsi_log("Set for gateway service");
8450 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8452 /* something went horribly wrong. We can't proceed without a netbios name */
8454 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8455 osi_panic(buf, __FILE__, __LINE__);
8458 /* remember the name */
8459 len = (int)strlen(cm_NetbiosName);
8461 free(smb_localNamep);
8462 smb_localNamep = malloc(len+1);
8463 strcpy(smb_localNamep, cm_NetbiosName);
8464 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8467 if (smb_LANadapter == LANA_INVALID) {
8468 ncbp->ncb_command = NCBENUM;
8469 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8470 ncbp->ncb_length = sizeof(lana_list);
8471 code = Netbios(ncbp);
8473 afsi_log("Netbios NCBENUM error code %d", code);
8474 osi_panic(s, __FILE__, __LINE__);
8478 lana_list.length = 1;
8479 lana_list.lana[0] = smb_LANadapter;
8482 for (i = 0; i < lana_list.length; i++) {
8483 /* reset the adaptor: in Win32, this is required for every process, and
8484 * acts as an init call, not as a real hardware reset.
8486 ncbp->ncb_command = NCBRESET;
8487 ncbp->ncb_callname[0] = 100;
8488 ncbp->ncb_callname[2] = 100;
8489 ncbp->ncb_lana_num = lana_list.lana[i];
8490 code = Netbios(ncbp);
8492 code = ncbp->ncb_retcode;
8494 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8495 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
8497 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8501 /* and declare our name so we can receive connections */
8502 memset(ncbp, 0, sizeof(*ncbp));
8503 len=lstrlen(smb_localNamep);
8504 memset(smb_sharename,' ',NCBNAMSZ);
8505 memcpy(smb_sharename,smb_localNamep,len);
8506 afsi_log("lana_list.length %d", lana_list.length);
8508 /* Keep the name so we can unregister it later */
8509 for (l = 0; l < lana_list.length; l++) {
8510 lana = lana_list.lana[l];
8512 ncbp->ncb_command = NCBADDNAME;
8513 ncbp->ncb_lana_num = lana;
8514 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8515 code = Netbios(ncbp);
8517 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8518 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8520 char name[NCBNAMSZ+1];
8522 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8523 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8527 code = ncbp->ncb_retcode;
8530 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8533 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8534 if (code == NRC_BRIDGE) { /* invalid LANA num */
8535 lana_list.lana[l] = LANA_INVALID;
8538 else if (code == NRC_DUPNAME) {
8539 afsi_log("Name already exists; try to delete it");
8540 memset(ncbp, 0, sizeof(*ncbp));
8541 ncbp->ncb_command = NCBDELNAME;
8542 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8543 ncbp->ncb_lana_num = lana;
8544 code = Netbios(ncbp);
8546 code = ncbp->ncb_retcode;
8548 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8550 if (code != 0 || delname_tried) {
8551 lana_list.lana[l] = LANA_INVALID;
8553 else if (code == 0) {
8554 if (!delname_tried) {
8562 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8563 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8567 smb_LANadapter = lana;
8568 lana_found = 1; /* at least one worked */
8572 osi_assertx(lana_list.length >= 0, "empty lana list");
8574 afsi_log("No valid LANA numbers found!");
8575 lana_list.length = 0;
8576 smb_LANadapter = LANA_INVALID;
8577 smb_ListenerState = SMB_LISTENER_STOPPED;
8578 cm_VolStatus_Network_Stopped(cm_NetbiosName
8585 /* we're done with the NCB now */
8588 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
8589 if (lana_list.length > 0)
8590 osi_assert(smb_LANadapter != LANA_INVALID);
8593 lock_ReleaseMutex(&smb_StartedLock);
8595 return (lana_list.length > 0 ? 1 : 0);
8598 void smb_StartListeners(int locked)
8605 lock_ObtainMutex(&smb_StartedLock);
8607 if (smb_ListenerState == SMB_LISTENER_STARTED) {
8609 lock_ReleaseMutex(&smb_StartedLock);
8613 afsi_log("smb_StartListeners");
8614 smb_ListenerState = SMB_LISTENER_STARTED;
8615 cm_VolStatus_Network_Started(cm_NetbiosName
8621 for (i = 0; i < lana_list.length; i++) {
8622 if (lana_list.lana[i] == LANA_INVALID)
8624 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8625 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8626 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
8627 thrd_CloseHandle(phandle);
8630 lock_ReleaseMutex(&smb_StartedLock);
8633 void smb_RestartListeners(int locked)
8636 lock_ObtainMutex(&smb_StartedLock);
8638 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
8639 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8640 if (smb_NetbiosInit(1))
8641 smb_StartListeners(1);
8642 } else if (smb_LanAdapterChangeDetected) {
8643 smb_LanAdapterChange(1);
8647 lock_ReleaseMutex(&smb_StartedLock);
8650 void smb_StopListener(NCB *ncbp, int lana, int wait)
8654 memset(ncbp, 0, sizeof(*ncbp));
8655 ncbp->ncb_command = NCBDELNAME;
8656 ncbp->ncb_lana_num = lana;
8657 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8658 code = Netbios(ncbp);
8660 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8661 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8663 /* and then reset the LANA; this will cause the listener threads to exit */
8664 ncbp->ncb_command = NCBRESET;
8665 ncbp->ncb_callname[0] = 100;
8666 ncbp->ncb_callname[2] = 100;
8667 ncbp->ncb_lana_num = lana;
8668 code = Netbios(ncbp);
8670 code = ncbp->ncb_retcode;
8672 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8674 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8678 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
8681 void smb_StopListeners(int locked)
8687 lock_ObtainMutex(&smb_StartedLock);
8689 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8691 lock_ReleaseMutex(&smb_StartedLock);
8695 afsi_log("smb_StopListeners");
8696 smb_ListenerState = SMB_LISTENER_STOPPED;
8697 cm_VolStatus_Network_Stopped(cm_NetbiosName
8705 /* Unregister the SMB name */
8706 for (l = 0; l < lana_list.length; l++) {
8707 lana = lana_list.lana[l];
8709 if (lana != LANA_INVALID) {
8710 smb_StopListener(ncbp, lana, TRUE);
8712 /* mark the adapter invalid */
8713 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8717 /* force a re-evaluation of the network adapters */
8718 lana_list.length = 0;
8719 smb_LANadapter = LANA_INVALID;
8722 lock_ReleaseMutex(&smb_StartedLock);
8725 void smb_Init(osi_log_t *logp, int useV3,
8735 EVENT_HANDLE retHandle;
8736 char eventName[MAX_PATH];
8737 int startListeners = 0;
8739 smb_TlsRequestSlot = TlsAlloc();
8741 smb_MBfunc = aMBfunc;
8745 /* Initialize smb_localZero */
8746 myTime.tm_isdst = -1; /* compute whether on DST or not */
8747 myTime.tm_year = 70;
8753 smb_localZero = mktime(&myTime);
8755 #ifndef USE_NUMERIC_TIME_CONV
8756 /* Initialize kludge-GMT */
8757 smb_CalculateNowTZ();
8758 #endif /* USE_NUMERIC_TIME_CONV */
8759 #ifdef AFS_FREELANCE_CLIENT
8760 /* Make sure the root.afs volume has the correct time */
8761 cm_noteLocalMountPointChange();
8764 /* initialize the remote debugging log */
8767 /* and the global lock */
8768 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8769 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8771 /* Raw I/O data structures */
8772 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8774 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8775 lock_InitializeMutex(&smb_StartedLock, "smb started lock");
8777 /* 4 Raw I/O buffers */
8778 smb_RawBufs = calloc(65536,1);
8779 *((char **)smb_RawBufs) = NULL;
8780 for (i=0; i<3; i++) {
8781 char *rawBuf = calloc(65536,1);
8782 *((char **)rawBuf) = smb_RawBufs;
8783 smb_RawBufs = rawBuf;
8786 /* global free lists */
8787 smb_ncbFreeListp = NULL;
8788 smb_packetFreeListp = NULL;
8790 lock_ObtainMutex(&smb_StartedLock);
8791 startListeners = smb_NetbiosInit(1);
8793 /* Initialize listener and server structures */
8795 memset(dead_sessions, 0, sizeof(dead_sessions));
8796 sprintf(eventName, "SessionEvents[0]");
8797 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8798 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8799 afsi_log("Event Object Already Exists: %s", eventName);
8801 smb_NumServerThreads = nThreads;
8802 sprintf(eventName, "NCBavails[0]");
8803 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8804 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8805 afsi_log("Event Object Already Exists: %s", eventName);
8806 sprintf(eventName, "NCBevents[0]");
8807 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8808 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8809 afsi_log("Event Object Already Exists: %s", eventName);
8810 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8811 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8812 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8813 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8814 afsi_log("Event Object Already Exists: %s", eventName);
8815 for (i = 0; i < smb_NumServerThreads; i++) {
8816 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8817 NCBreturns[i][0] = retHandle;
8820 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8821 for (i = 0; i < smb_NumServerThreads; i++) {
8822 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8823 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8824 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8825 afsi_log("Event Object Already Exists: %s", eventName);
8826 InitNCBslot((int)(i+1));
8828 numNCBs = smb_NumServerThreads + 1;
8830 /* Initialize dispatch table */
8831 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8832 /* Prepare the table for unknown operations */
8833 for(i=0; i<= SMB_NOPCODES; i++) {
8834 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8836 /* Fill in the ones we do know */
8837 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8838 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8839 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8840 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8841 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8842 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8843 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8844 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8845 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8846 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8847 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8848 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8849 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8850 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8851 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8852 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8853 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8854 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8855 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8856 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8857 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8858 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8859 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8860 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8861 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8862 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8863 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8864 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8865 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8866 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8867 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8868 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8869 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8870 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8871 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8872 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8873 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8874 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8875 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8876 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8877 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8878 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8879 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8880 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8881 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8882 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8883 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8884 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8885 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8886 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8887 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8888 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8889 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8890 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8891 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8892 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8893 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8894 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8895 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8896 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8897 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8898 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8899 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8900 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8901 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8902 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8903 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8904 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8905 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8906 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8907 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8908 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8909 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8910 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8912 /* setup tran 2 dispatch table */
8913 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8914 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8915 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8916 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8917 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8918 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8919 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8920 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8921 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8922 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8923 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8924 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8925 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8926 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8927 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8928 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8929 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8930 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8932 /* setup the rap dispatch table */
8933 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8934 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8935 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8936 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8937 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8941 /* if we are doing SMB authentication we have register outselves as a logon process */
8942 if (smb_authType != SMB_AUTH_NONE) {
8943 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8944 LSA_STRING afsProcessName;
8945 LSA_OPERATIONAL_MODE dummy; /*junk*/
8947 afsProcessName.Buffer = "OpenAFSClientDaemon";
8948 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8949 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8951 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8953 if (nts == STATUS_SUCCESS) {
8954 LSA_STRING packageName;
8955 /* we are registered. Find out the security package id */
8956 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8957 packageName.Length = (USHORT)strlen(packageName.Buffer);
8958 packageName.MaximumLength = packageName.Length + 1;
8959 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8960 if (nts == STATUS_SUCCESS) {
8962 * This code forces Windows to authenticate against the Logon Cache
8963 * first instead of attempting to authenticate against the Domain
8964 * Controller. When the Windows logon cache is enabled this improves
8965 * performance by removing the network access and works around a bug
8966 * seen at sites which are using a MIT Kerberos principal to login
8967 * to machines joined to a non-root domain in a multi-domain forest.
8968 * MsV1_0SetProcessOption was added in Windows XP.
8970 PVOID pResponse = NULL;
8971 ULONG cbResponse = 0;
8972 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8974 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8975 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8976 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8977 OptionsRequest.DisableOptions = FALSE;
8979 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8982 sizeof(OptionsRequest),
8988 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8989 char message[AFSPATHMAX];
8990 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8992 OutputDebugString(message);
8995 OutputDebugString("MsV1_0SetProcessOption success");
8996 afsi_log("MsV1_0SetProcessOption success");
8998 /* END - code from Larry */
9000 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9001 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9002 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9004 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9006 /* something went wrong. We report the error and revert back to no authentication
9007 because we can't perform any auth requests without a successful lsa handle
9008 or sec package id. */
9009 afsi_log("Reverting to NO SMB AUTH");
9010 smb_authType = SMB_AUTH_NONE;
9013 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9015 /* something went wrong. We report the error and revert back to no authentication
9016 because we can't perform any auth requests without a successful lsa handle
9017 or sec package id. */
9018 afsi_log("Reverting to NO SMB AUTH");
9019 smb_authType = SMB_AUTH_NONE;
9023 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9024 * time prevents the failure of authentication when logged into Windows with an
9025 * external Kerberos principal mapped to a local account.
9027 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9028 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9029 * then the only option is NTLMSSP anyway; so just fallback.
9034 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9035 if (secBlobLength == 0) {
9036 smb_authType = SMB_AUTH_NTLM;
9037 afsi_log("Reverting to SMB AUTH NTLM");
9046 /* Now get ourselves a domain name. */
9047 /* For now we are using the local computer name as the domain name.
9048 * It is actually the domain for local logins, and we are acting as
9049 * a local SMB server.
9051 bufsize = sizeof(smb_ServerDomainName) - 1;
9052 GetComputerName(smb_ServerDomainName, &bufsize);
9053 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9054 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
9057 /* Start listeners, waiters, servers, and daemons */
9059 smb_StartListeners(1);
9061 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9062 NULL, 0, &lpid, "smb_ClientWaiter");
9063 osi_assertx(phandle != NULL, , "smb_ClientWaiter thread creation failure");
9064 thrd_CloseHandle(phandle);
9066 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9067 NULL, 0, &lpid, "smb_ServerWaiter");
9068 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9069 thrd_CloseHandle(phandle);
9071 for (i=0; i<smb_NumServerThreads; i++) {
9072 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9073 (void *) i, 0, &lpid, "smb_Server");
9074 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9075 thrd_CloseHandle(phandle);
9078 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9079 NULL, 0, &lpid, "smb_Daemon");
9080 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9081 thrd_CloseHandle(phandle);
9083 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9084 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9085 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9086 thrd_CloseHandle(phandle);
9088 lock_ReleaseMutex(&smb_StartedLock);
9092 void smb_Shutdown(void)
9099 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9101 /* setup the NCB system */
9104 /* Block new sessions by setting shutdown flag */
9105 smbShutdownFlag = 1;
9107 /* Hang up all sessions */
9108 memset((char *)ncbp, 0, sizeof(NCB));
9109 for (i = 1; i < numSessions; i++)
9111 if (dead_sessions[i])
9114 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9115 ncbp->ncb_command = NCBHANGUP;
9116 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9117 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9118 code = Netbios(ncbp);
9119 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9120 if (code == 0) code = ncbp->ncb_retcode;
9122 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9123 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9127 /* Trigger the shutdown of all SMB threads */
9128 for (i = 0; i < smb_NumServerThreads; i++)
9129 thrd_SetEvent(NCBreturns[i][0]);
9131 thrd_SetEvent(NCBevents[0]);
9132 thrd_SetEvent(SessionEvents[0]);
9133 thrd_SetEvent(NCBavails[0]);
9135 for (i = 0;i < smb_NumServerThreads; i++) {
9136 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9137 if (code == WAIT_OBJECT_0) {
9140 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9141 thrd_SetEvent(NCBreturns[i--][0]);
9145 /* Delete Netbios name */
9146 memset((char *)ncbp, 0, sizeof(NCB));
9147 for (i = 0; i < lana_list.length; i++) {
9148 if (lana_list.lana[i] == LANA_INVALID) continue;
9149 ncbp->ncb_command = NCBDELNAME;
9150 ncbp->ncb_lana_num = lana_list.lana[i];
9151 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9152 code = Netbios(ncbp);
9154 code = ncbp->ncb_retcode;
9156 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9157 ncbp->ncb_lana_num, code);
9162 /* Release the reference counts held by the VCs */
9163 lock_ObtainWrite(&smb_rctLock);
9164 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9169 if (vcp->magic != SMB_VC_MAGIC)
9170 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9171 __FILE__, __LINE__);
9173 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9175 if (fidp->scp != NULL) {
9178 lock_ObtainMutex(&fidp->mx);
9179 if (fidp->scp != NULL) {
9182 lock_ObtainMutex(&scp->mx);
9183 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9184 lock_ReleaseMutex(&scp->mx);
9185 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9186 cm_ReleaseSCache(scp);
9188 lock_ReleaseMutex(&fidp->mx);
9192 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9194 smb_ReleaseVCNoLock(tidp->vcp);
9196 cm_user_t *userp = tidp->userp;
9198 lock_ReleaseWrite(&smb_rctLock);
9199 cm_ReleaseUser(userp);
9200 lock_ObtainWrite(&smb_rctLock);
9204 lock_ReleaseWrite(&smb_rctLock);
9206 TlsFree(smb_TlsRequestSlot);
9209 /* Get the UNC \\<servername>\<sharename> prefix. */
9210 char *smb_GetSharename()
9214 /* Make sure we have been properly initialized. */
9215 if (smb_localNamep == NULL)
9218 /* Allocate space for \\<servername>\<sharename>, plus the
9221 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9222 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9228 void smb_LogPacket(smb_packet_t *packet)
9231 unsigned length, paramlen, datalen, i, j;
9233 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9235 if (!packet) return;
9237 osi_Log0(smb_logp, "*** SMB packet dump ***");
9239 vp = (BYTE *) packet->data;
9241 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9242 length = paramlen + 2 + datalen;
9245 for (i=0;i < length; i+=16)
9247 memset( buf, ' ', 80 );
9252 buf[strlen(buf)] = ' ';
9254 cp = (BYTE*) buf + 7;
9256 for (j=0;j < 16 && (i+j)<length; j++)
9258 *(cp++) = hex[vp[i+j] >> 4];
9259 *(cp++) = hex[vp[i+j] & 0xf];
9269 for (j=0;j < 16 && (i+j)<length;j++)
9271 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9282 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9285 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9287 #endif /* LOG_PACKET */
9290 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9298 lock_ObtainRead(&smb_rctLock);
9300 sprintf(output, "begin dumping smb_vc_t\r\n");
9301 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9303 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9307 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9308 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9309 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9311 sprintf(output, "begin dumping smb_fid_t\r\n");
9312 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9314 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9316 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",
9317 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9318 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9319 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9320 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9323 sprintf(output, "done dumping smb_fid_t\r\n");
9324 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9327 sprintf(output, "done dumping smb_vc_t\r\n");
9328 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9330 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9331 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9333 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9337 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9338 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9339 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9341 sprintf(output, "begin dumping smb_fid_t\r\n");
9342 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9344 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9346 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",
9347 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9348 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9349 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9350 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9353 sprintf(output, "done dumping smb_fid_t\r\n");
9354 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9357 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9358 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9361 lock_ReleaseRead(&smb_rctLock);
9365 long smb_IsNetworkStarted(void)
9368 lock_ObtainWrite(&smb_globalLock);
9369 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
9370 lock_ReleaseWrite(&smb_globalLock);