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>
25 #include <rx/rx_prototypes.h>
26 #include <WINNT\afsreg.h>
29 #include "lanahelper.h"
31 /* These characters are illegal in Windows filenames */
32 static char *illegalChars = "\\/:*?\"<>|";
34 static int smbShutdownFlag = 0;
35 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
37 int smb_LogoffTokenTransfer;
38 time_t smb_LogoffTransferTimeout;
40 int smb_StoreAnsiFilenames = 0;
42 DWORD last_msg_time = 0;
46 unsigned int sessionGen = 0;
48 extern void afsi_log(char *pattern, ...);
49 extern HANDLE afsi_file;
50 extern int powerStateSuspended;
52 osi_hyper_t hzero = {0, 0};
53 osi_hyper_t hones = {0xFFFFFFFF, -1};
56 osi_rwlock_t smb_globalLock;
57 osi_rwlock_t smb_rctLock;
58 osi_mutex_t smb_ListenerLock;
61 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
64 long smb_maxObsConcurrentCalls=0;
65 long smb_concurrentCalls=0;
67 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
69 smb_packet_t *smb_packetFreeListp;
70 smb_ncb_t *smb_ncbFreeListp;
72 int smb_NumServerThreads;
74 int numNCBs, numSessions, numVCs;
76 int smb_maxVCPerServer;
77 int smb_maxMpxRequests;
79 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
81 ULONG smb_lsaSecPackage;
82 LSA_STRING smb_lsaLogonOrigin;
84 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
85 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
86 EVENT_HANDLE **NCBreturns;
87 EVENT_HANDLE **NCBShutdown;
88 EVENT_HANDLE *smb_ServerShutdown;
89 DWORD NCBsessions[NCB_MAX];
91 struct smb_packet *bufs[NCB_MAX];
93 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
94 EVENT_HANDLE SessionEvents[SESSION_MAX];
95 unsigned short LSNs[SESSION_MAX];
96 int lanas[SESSION_MAX];
97 BOOL dead_sessions[SESSION_MAX];
101 osi_mutex_t smb_RawBufLock;
104 #define SMB_MASKFLAG_TILDE 1
105 #define SMB_MASKFLAG_CASEFOLD 2
107 #define RAWTIMEOUT INFINITE
110 typedef struct raw_write_cont {
119 /* dir search stuff */
120 long smb_dirSearchCounter = 1;
121 smb_dirSearch_t *smb_firstDirSearchp;
122 smb_dirSearch_t *smb_lastDirSearchp;
124 /* hide dot files? */
125 int smb_hideDotFiles;
127 /* global state about V3 protocols */
128 int smb_useV3; /* try to negotiate V3 */
130 static showErrors = 0;
131 /* MessageBox or something like it */
132 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
135 * Time in Unix format of midnight, 1/1/1970 local time.
136 * When added to dosUTime, gives Unix (AFS) time.
138 time_t smb_localZero = 0;
140 #define USE_NUMERIC_TIME_CONV 1
142 #ifndef USE_NUMERIC_TIME_CONV
143 /* Time difference for converting to kludge-GMT */
144 afs_uint32 smb_NowTZ;
145 #endif /* USE_NUMERIC_TIME_CONV */
147 char *smb_localNamep = NULL;
149 smb_vc_t *smb_allVCsp;
150 smb_vc_t *smb_deadVCsp;
152 smb_username_t *usernamesp = NULL;
154 smb_waitingLockRequest_t *smb_allWaitingLocks;
156 DWORD smb_TlsRequestSlot = -1;
159 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
160 NCB *ncbp, raw_write_cont_t *rwcp);
161 int smb_NetbiosInit(void);
164 void smb_LogPacket(smb_packet_t *packet);
165 #endif /* LOG_PACKET */
167 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
168 int smb_ServerDomainNameLength = 0;
169 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
170 int smb_ServerOSLength = sizeof(smb_ServerOS);
171 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
172 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
174 /* Faux server GUID. This is never checked. */
175 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
177 void smb_ResetServerPriority()
179 void * p = TlsGetValue(smb_TlsRequestSlot);
182 TlsSetValue(smb_TlsRequestSlot, NULL);
183 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
187 void smb_SetRequestStartTime()
189 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
191 tp = malloc(sizeof(time_t));
195 if (!TlsSetValue(smb_TlsRequestSlot, tp))
200 void smb_UpdateServerPriority()
202 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
205 time_t now = osi_Time();
207 /* Give one priority boost for each 15 seconds */
208 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
213 const char * ncb_error_string(int code)
217 case 0x01: s = "llegal buffer length"; break;
218 case 0x03: s = "illegal command"; break;
219 case 0x05: s = "command timed out"; break;
220 case 0x06: s = "message incomplete, issue another command"; break;
221 case 0x07: s = "illegal buffer address"; break;
222 case 0x08: s = "session number out of range"; break;
223 case 0x09: s = "no resource available"; break;
224 case 0x0a: s = "session closed"; break;
225 case 0x0b: s = "command cancelled"; break;
226 case 0x0d: s = "duplicate name"; break;
227 case 0x0e: s = "name table full"; break;
228 case 0x0f: s = "no deletions, name has active sessions"; break;
229 case 0x11: s = "local session table full"; break;
230 case 0x12: s = "remote session table full"; break;
231 case 0x13: s = "illegal name number"; break;
232 case 0x14: s = "no callname"; break;
233 case 0x15: s = "cannot put * in NCB_NAME"; break;
234 case 0x16: s = "name in use on remote adapter"; break;
235 case 0x17: s = "name deleted"; break;
236 case 0x18: s = "session ended abnormally"; break;
237 case 0x19: s = "name conflict detected"; break;
238 case 0x21: s = "interface busy, IRET before retrying"; break;
239 case 0x22: s = "too many commands outstanding, retry later";break;
240 case 0x23: s = "ncb_lana_num field invalid"; break;
241 case 0x24: s = "command completed while cancel occurring "; break;
242 case 0x26: s = "command not valid to cancel"; break;
243 case 0x30: s = "name defined by anther local process"; break;
244 case 0x34: s = "environment undefined. RESET required"; break;
245 case 0x35: s = "required OS resources exhausted"; break;
246 case 0x36: s = "max number of applications exceeded"; break;
247 case 0x37: s = "no saps available for netbios"; break;
248 case 0x38: s = "requested resources are not available"; break;
249 case 0x39: s = "invalid ncb address or length > segment"; break;
250 case 0x3B: s = "invalid NCB DDID"; break;
251 case 0x3C: s = "lock of user area failed"; break;
252 case 0x3f: s = "NETBIOS not loaded"; break;
253 case 0x40: s = "system error"; break;
254 default: s = "unknown error";
260 char * myCrt_Dispatch(int i)
265 return "(00)ReceiveCoreMakeDir";
267 return "(01)ReceiveCoreRemoveDir";
269 return "(02)ReceiveCoreOpen";
271 return "(03)ReceiveCoreCreate";
273 return "(04)ReceiveCoreClose";
275 return "(05)ReceiveCoreFlush";
277 return "(06)ReceiveCoreUnlink";
279 return "(07)ReceiveCoreRename";
281 return "(08)ReceiveCoreGetFileAttributes";
283 return "(09)ReceiveCoreSetFileAttributes";
285 return "(0a)ReceiveCoreRead";
287 return "(0b)ReceiveCoreWrite";
289 return "(0c)ReceiveCoreLockRecord";
291 return "(0d)ReceiveCoreUnlockRecord";
293 return "(0e)SendCoreBadOp";
295 return "(0f)ReceiveCoreCreate";
297 return "(10)ReceiveCoreCheckPath";
299 return "(11)SendCoreBadOp";
301 return "(12)ReceiveCoreSeek";
303 return "(1a)ReceiveCoreReadRaw";
305 return "(1d)ReceiveCoreWriteRawDummy";
307 return "(22)ReceiveV3SetAttributes";
309 return "(23)ReceiveV3GetAttributes";
311 return "(24)ReceiveV3LockingX";
313 return "(25)ReceiveV3Trans";
315 return "(26)ReceiveV3Trans[aux]";
317 return "(29)SendCoreBadOp";
319 return "(2b)ReceiveCoreEcho";
321 return "(2d)ReceiveV3OpenX";
323 return "(2e)ReceiveV3ReadX";
325 return "(2f)ReceiveV3WriteX";
327 return "(32)ReceiveV3Tran2A";
329 return "(33)ReceiveV3Tran2A[aux]";
331 return "(34)ReceiveV3FindClose";
333 return "(35)ReceiveV3FindNotifyClose";
335 return "(70)ReceiveCoreTreeConnect";
337 return "(71)ReceiveCoreTreeDisconnect";
339 return "(72)ReceiveNegotiate";
341 return "(73)ReceiveV3SessionSetupX";
343 return "(74)ReceiveV3UserLogoffX";
345 return "(75)ReceiveV3TreeConnectX";
347 return "(80)ReceiveCoreGetDiskAttributes";
349 return "(81)ReceiveCoreSearchDir";
353 return "(83)FindUnique";
355 return "(84)FindClose";
357 return "(A0)ReceiveNTTransact";
359 return "(A2)ReceiveNTCreateX";
361 return "(A4)ReceiveNTCancel";
363 return "(A5)ReceiveNTRename";
365 return "(C0)OpenPrintFile";
367 return "(C1)WritePrintFile";
369 return "(C2)ClosePrintFile";
371 return "(C3)GetPrintQueue";
373 return "(D8)ReadBulk";
375 return "(D9)WriteBulk";
377 return "(DA)WriteBulkData";
379 return "unknown SMB op";
383 char * myCrt_2Dispatch(int i)
388 return "unknown SMB op-2";
390 return "S(00)CreateFile_ReceiveTran2Open";
392 return "S(01)FindFirst_ReceiveTran2SearchDir";
394 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
396 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
398 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
400 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
402 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
404 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
406 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
408 return "S(09)_ReceiveTran2FSCTL";
410 return "S(0a)_ReceiveTran2IOCTL";
412 return "S(0b)_ReceiveTran2FindNotifyFirst";
414 return "S(0c)_ReceiveTran2FindNotifyNext";
416 return "S(0d)_ReceiveTran2CreateDirectory";
418 return "S(0e)_ReceiveTran2SessionSetup";
420 return "S(0f)_QueryFileSystemInformationFid";
422 return "S(10)_ReceiveTran2GetDfsReferral";
424 return "S(11)_ReceiveTran2ReportDfsInconsistency";
428 char * myCrt_RapDispatch(int i)
433 return "unknown RAP OP";
435 return "RAP(0)NetShareEnum";
437 return "RAP(1)NetShareGetInfo";
439 return "RAP(13)NetServerGetInfo";
441 return "RAP(63)NetWkStaGetInfo";
445 /* scache must be locked */
446 unsigned int smb_Attributes(cm_scache_t *scp)
450 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
451 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
452 scp->fileType == CM_SCACHETYPE_INVALID)
454 attrs = SMB_ATTR_DIRECTORY;
455 #ifdef SPECIAL_FOLDERS
456 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
457 #endif /* SPECIAL_FOLDERS */
458 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
459 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
464 * We used to mark a file RO if it was in an RO volume, but that
465 * turns out to be impolitic in NT. See defect 10007.
468 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
469 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
471 if ((scp->unixModeBits & 0222) == 0)
472 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
478 /* Check if the named file/dir is a dotfile/dotdir */
479 /* String pointed to by lastComp can have leading slashes, but otherwise should have
480 no other patch components */
481 unsigned int smb_IsDotFile(char *lastComp) {
484 /* skip over slashes */
485 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
490 /* nulls, curdir and parent dir doesn't count */
496 if(*(s+1) == '.' && !*(s + 2))
503 static int ExtractBits(WORD bits, short start, short len)
510 num = bits << (16 - end);
511 num = num >> ((16 - end) + start);
516 void ShowUnixTime(char *FuncName, time_t unixTime)
521 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
523 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
524 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
526 int day, month, year, sec, min, hour;
529 day = ExtractBits(wDate, 0, 5);
530 month = ExtractBits(wDate, 5, 4);
531 year = ExtractBits(wDate, 9, 7) + 1980;
533 sec = ExtractBits(wTime, 0, 5);
534 min = ExtractBits(wTime, 5, 6);
535 hour = ExtractBits(wTime, 11, 5);
537 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
538 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
542 /* Determine if we are observing daylight savings time */
543 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
545 TIME_ZONE_INFORMATION timeZoneInformation;
546 SYSTEMTIME utc, local, localDST;
548 /* Get the time zone info. NT uses this to calc if we are in DST. */
549 GetTimeZoneInformation(&timeZoneInformation);
551 /* Return the daylight bias */
552 *pDstBias = timeZoneInformation.DaylightBias;
554 /* Return the bias */
555 *pBias = timeZoneInformation.Bias;
557 /* Now determine if DST is being observed */
559 /* Get the UTC (GMT) time */
562 /* Convert UTC time to local time using the time zone info. If we are
563 observing DST, the calculated local time will include this.
565 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
567 /* Set the daylight bias to 0. The daylight bias is the amount of change
568 * in time that we use for daylight savings time. By setting this to 0
569 * we cause there to be no change in time during daylight savings time.
571 timeZoneInformation.DaylightBias = 0;
573 /* Convert the utc time to local time again, but this time without any
574 adjustment for daylight savings time.
576 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
578 /* If the two times are different, then it means that the localDST that
579 we calculated includes the daylight bias, and therefore we are
580 observing daylight savings time.
582 *pDST = localDST.wHour != local.wHour;
586 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
588 BOOL dst; /* Will be TRUE if observing DST */
589 LONG dstBias; /* Offset from local time if observing DST */
590 LONG bias; /* Offset from GMT for local time */
593 * This function will adjust the last write time to compensate
594 * for two bugs in the smb client:
596 * 1) During Daylight Savings Time, the LastWriteTime is ahead
597 * in time by the DaylightBias (ignoring the sign - the
598 * DaylightBias is always stored as a negative number). If
599 * the DaylightBias is -60, then the LastWriteTime will be
600 * ahead by 60 minutes.
602 * 2) If the local time zone is a positive offset from GMT, then
603 * the LastWriteTime will be the correct local time plus the
604 * Bias (ignoring the sign - a positive offset from GMT is
605 * always stored as a negative Bias). If the Bias is -120,
606 * then the LastWriteTime will be ahead by 120 minutes.
608 * These bugs can occur at the same time.
611 GetTimeZoneInfo(&dst, &dstBias, &bias);
613 /* First adjust for DST */
615 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
617 /* Now adjust for a positive offset from GMT (a negative bias). */
619 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
622 #ifndef USE_NUMERIC_TIME_CONV
624 * Calculate the difference (in seconds) between local time and GMT.
625 * This enables us to convert file times to kludge-GMT.
631 struct tm gmt_tm, local_tm;
632 int days, hours, minutes, seconds;
635 gmt_tm = *(gmtime(&t));
636 local_tm = *(localtime(&t));
638 days = local_tm.tm_yday - gmt_tm.tm_yday;
639 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
640 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
641 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
645 #endif /* USE_NUMERIC_TIME_CONV */
647 #ifdef USE_NUMERIC_TIME_CONV
648 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
650 // Note that LONGLONG is a 64-bit value
653 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
654 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
655 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
658 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
663 time_t ersatz_unixTime;
666 * Must use kludge-GMT instead of real GMT.
667 * kludge-GMT is computed by adding time zone difference to localtime.
670 * ltp = gmtime(&unixTime);
672 ersatz_unixTime = unixTime - smb_NowTZ;
673 ltp = localtime(&ersatz_unixTime);
675 /* if we fail, make up something */
678 localJunk.tm_year = 89 - 20;
679 localJunk.tm_mon = 4;
680 localJunk.tm_mday = 12;
681 localJunk.tm_hour = 0;
682 localJunk.tm_min = 0;
683 localJunk.tm_sec = 0;
686 stm.wYear = ltp->tm_year + 1900;
687 stm.wMonth = ltp->tm_mon + 1;
688 stm.wDayOfWeek = ltp->tm_wday;
689 stm.wDay = ltp->tm_mday;
690 stm.wHour = ltp->tm_hour;
691 stm.wMinute = ltp->tm_min;
692 stm.wSecond = ltp->tm_sec;
693 stm.wMilliseconds = 0;
695 SystemTimeToFileTime(&stm, largeTimep);
697 #endif /* USE_NUMERIC_TIME_CONV */
699 #ifdef USE_NUMERIC_TIME_CONV
700 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
702 // Note that LONGLONG is a 64-bit value
705 ll = largeTimep->dwHighDateTime;
707 ll += largeTimep->dwLowDateTime;
709 ll -= 116444736000000000;
712 *unixTimep = (DWORD)ll;
714 #else /* USE_NUMERIC_TIME_CONV */
715 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
721 FileTimeToSystemTime(largeTimep, &stm);
723 lt.tm_year = stm.wYear - 1900;
724 lt.tm_mon = stm.wMonth - 1;
725 lt.tm_wday = stm.wDayOfWeek;
726 lt.tm_mday = stm.wDay;
727 lt.tm_hour = stm.wHour;
728 lt.tm_min = stm.wMinute;
729 lt.tm_sec = stm.wSecond;
732 save_timezone = _timezone;
733 _timezone += smb_NowTZ;
734 *unixTimep = mktime(<);
735 _timezone = save_timezone;
737 #endif /* USE_NUMERIC_TIME_CONV */
739 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
749 /* if we fail, make up something */
752 localJunk.tm_year = 89 - 20;
753 localJunk.tm_mon = 4;
754 localJunk.tm_mday = 12;
755 localJunk.tm_hour = 0;
756 localJunk.tm_min = 0;
757 localJunk.tm_sec = 0;
760 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
761 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
762 *searchTimep = (dosDate<<16) | dosTime;
765 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
767 unsigned short dosDate;
768 unsigned short dosTime;
771 dosDate = (unsigned short) (searchTime & 0xffff);
772 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
774 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
775 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
776 localTm.tm_mday = (dosDate) & 0x1f;
777 localTm.tm_hour = (dosTime>>11) & 0x1f;
778 localTm.tm_min = (dosTime >> 5) & 0x3f;
779 localTm.tm_sec = (dosTime & 0x1f) * 2;
780 localTm.tm_isdst = -1; /* compute whether DST in effect */
782 *unixTimep = mktime(&localTm);
785 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
787 time_t diff_t = unixTime - smb_localZero;
788 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
789 osi_assert(diff_t < _UI32_MAX);
791 *dosUTimep = (afs_uint32)diff_t;
794 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
796 *unixTimep = dosTime + smb_localZero;
799 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
803 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
804 lock_ObtainWrite(&smb_rctLock);
805 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
806 if (vcp->magic != SMB_VC_MAGIC)
807 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
810 if (lsn == vcp->lsn && lana == vcp->lana &&
811 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
812 smb_HoldVCNoLock(vcp);
816 if (!vcp && (flags & SMB_FLAG_CREATE)) {
817 vcp = malloc(sizeof(*vcp));
818 memset(vcp, 0, sizeof(*vcp));
819 vcp->vcID = ++numVCs;
820 vcp->magic = SMB_VC_MAGIC;
821 vcp->refCount = 2; /* smb_allVCsp and caller */
824 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
825 vcp->nextp = smb_allVCsp;
827 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
832 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
833 /* We must obtain a challenge for extended auth
834 * in case the client negotiates smb v3
836 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
837 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
838 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
839 ULONG lsaRespSize = 0;
841 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
843 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
850 if (nts != STATUS_SUCCESS)
851 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
852 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
853 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
855 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
856 LsaFreeReturnBuffer(lsaResp);
859 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
861 if (numVCs >= CM_SESSION_RESERVED) {
863 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
866 lock_ReleaseWrite(&smb_rctLock);
867 lock_ReleaseWrite(&smb_globalLock);
871 int smb_IsStarMask(char *maskp)
876 for(i=0; i<11; i++) {
878 if (tc == '?' || tc == '*' || tc == '>')
884 void smb_ReleaseVCInternal(smb_vc_t *vcp)
891 if (vcp->refCount == 0) {
892 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
893 /* remove VCP from smb_deadVCsp */
894 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
900 lock_FinalizeMutex(&vcp->mx);
901 memset(vcp,0,sizeof(smb_vc_t));
904 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
908 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
909 avcp?"not ":"",vcp, vcp->refCount);
911 GenerateMiniDump(NULL);
913 /* This is a wrong. However, I suspect that there is an undercount
914 * and I don't want to release 1.4.1 in a state that will allow
915 * smb_vc_t objects to be deallocated while still in the
916 * smb_allVCsp list. The list is supposed to keep a reference
917 * to the smb_vc_t. Put it back.
924 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
926 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
927 smb_ReleaseVCInternal(vcp);
930 void smb_ReleaseVC(smb_vc_t *vcp)
932 lock_ObtainWrite(&smb_rctLock);
933 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
934 smb_ReleaseVCInternal(vcp);
935 lock_ReleaseWrite(&smb_rctLock);
938 void smb_HoldVCNoLock(smb_vc_t *vcp)
941 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
944 void smb_HoldVC(smb_vc_t *vcp)
946 lock_ObtainWrite(&smb_rctLock);
948 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
949 lock_ReleaseWrite(&smb_rctLock);
952 void smb_CleanupDeadVC(smb_vc_t *vcp)
960 smb_user_t *uidpIter;
961 smb_user_t *uidpNext;
965 lock_ObtainMutex(&vcp->mx);
966 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
967 lock_ReleaseMutex(&vcp->mx);
968 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
971 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
972 lock_ReleaseMutex(&vcp->mx);
973 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
975 lock_ObtainWrite(&smb_rctLock);
976 /* remove VCP from smb_allVCsp */
977 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
978 if ((*vcpp)->magic != SMB_VC_MAGIC)
979 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
983 vcp->nextp = smb_deadVCsp;
985 /* Hold onto the reference until we are done with this function */
990 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
991 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
993 if (fidpIter->delete)
997 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
999 smb_HoldFIDNoLock(fidpIter);
1000 lock_ReleaseWrite(&smb_rctLock);
1002 smb_CloseFID(vcp, fidpIter, NULL, 0);
1003 smb_ReleaseFID(fidpIter);
1005 lock_ObtainWrite(&smb_rctLock);
1006 fidpNext = vcp->fidsp;
1009 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1010 tidpNext = tidpIter->nextp;
1011 if (tidpIter->delete)
1013 tidpIter->delete = 1;
1015 tid = tidpIter->tid;
1016 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1018 smb_HoldTIDNoLock(tidpIter);
1019 lock_ReleaseWrite(&smb_rctLock);
1021 smb_ReleaseTID(tidpIter);
1023 lock_ObtainWrite(&smb_rctLock);
1024 tidpNext = vcp->tidsp;
1027 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1028 uidpNext = uidpIter->nextp;
1029 if (uidpIter->delete)
1031 uidpIter->delete = 1;
1033 /* do not add an additional reference count for the smb_user_t
1034 * as the smb_vc_t already is holding a reference */
1035 lock_ReleaseWrite(&smb_rctLock);
1037 smb_ReleaseUID(uidpIter);
1039 lock_ObtainWrite(&smb_rctLock);
1040 uidpNext = vcp->usersp;
1043 /* The vcp is now on the deadVCsp list. We intentionally drop the
1044 * reference so that the refcount can reach 0 and we can delete it */
1045 smb_ReleaseVCNoLock(vcp);
1047 lock_ReleaseWrite(&smb_rctLock);
1048 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1051 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1055 lock_ObtainWrite(&smb_rctLock);
1057 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1058 if (tidp->refCount == 0 && tidp->delete) {
1060 lock_ReleaseWrite(&smb_rctLock);
1061 smb_ReleaseTID(tidp);
1062 lock_ObtainWrite(&smb_rctLock);
1066 if (tid == tidp->tid) {
1071 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1072 tidp = malloc(sizeof(*tidp));
1073 memset(tidp, 0, sizeof(*tidp));
1074 tidp->nextp = vcp->tidsp;
1077 smb_HoldVCNoLock(vcp);
1079 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1082 lock_ReleaseWrite(&smb_rctLock);
1086 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1091 void smb_ReleaseTID(smb_tid_t *tidp)
1098 lock_ObtainWrite(&smb_rctLock);
1099 osi_assert(tidp->refCount-- > 0);
1100 if (tidp->refCount == 0 && (tidp->delete)) {
1101 ltpp = &tidp->vcp->tidsp;
1102 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1106 osi_assert(tp != NULL);
1108 lock_FinalizeMutex(&tidp->mx);
1109 userp = tidp->userp; /* remember to drop ref later */
1111 smb_ReleaseVCNoLock(tidp->vcp);
1114 lock_ReleaseWrite(&smb_rctLock);
1116 cm_ReleaseUser(userp);
1119 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1121 smb_user_t *uidp = NULL;
1123 lock_ObtainWrite(&smb_rctLock);
1124 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1125 if (uid == uidp->userID) {
1127 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1129 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1133 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1134 uidp = malloc(sizeof(*uidp));
1135 memset(uidp, 0, sizeof(*uidp));
1136 uidp->nextp = vcp->usersp;
1137 uidp->refCount = 2; /* one for the vcp and one for the caller */
1139 smb_HoldVCNoLock(vcp);
1141 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1143 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1145 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1147 lock_ReleaseWrite(&smb_rctLock);
1151 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1153 smb_username_t *unp= NULL;
1155 lock_ObtainWrite(&smb_rctLock);
1156 for(unp = usernamesp; unp; unp = unp->nextp) {
1157 if (stricmp(unp->name, usern) == 0 &&
1158 stricmp(unp->machine, machine) == 0) {
1163 if (!unp && (flags & SMB_FLAG_CREATE)) {
1164 unp = malloc(sizeof(*unp));
1165 memset(unp, 0, sizeof(*unp));
1167 unp->nextp = usernamesp;
1168 unp->name = strdup(usern);
1169 unp->machine = strdup(machine);
1171 lock_InitializeMutex(&unp->mx, "username_t mutex");
1172 if (flags & SMB_FLAG_AFSLOGON)
1173 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1176 lock_ReleaseWrite(&smb_rctLock);
1180 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1182 smb_user_t *uidp= NULL;
1184 lock_ObtainWrite(&smb_rctLock);
1185 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1188 if (stricmp(uidp->unp->name, usern) == 0) {
1190 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1191 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1196 lock_ReleaseWrite(&smb_rctLock);
1200 void smb_ReleaseUsername(smb_username_t *unp)
1203 smb_username_t **lupp;
1204 cm_user_t *userp = NULL;
1205 time_t now = osi_Time();
1207 lock_ObtainWrite(&smb_rctLock);
1208 osi_assert(unp->refCount-- > 0);
1209 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1210 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1212 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1216 osi_assert(up != NULL);
1218 up->nextp = NULL; /* do not remove this */
1219 lock_FinalizeMutex(&unp->mx);
1225 lock_ReleaseWrite(&smb_rctLock);
1228 cm_ReleaseUser(userp);
1232 void smb_HoldUIDNoLock(smb_user_t *uidp)
1237 void smb_ReleaseUID(smb_user_t *uidp)
1241 smb_username_t *unp = NULL;
1243 lock_ObtainWrite(&smb_rctLock);
1244 osi_assert(uidp->refCount-- > 0);
1245 if (uidp->refCount == 0) {
1246 lupp = &uidp->vcp->usersp;
1247 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1251 osi_assert(up != NULL);
1253 lock_FinalizeMutex(&uidp->mx);
1255 smb_ReleaseVCNoLock(uidp->vcp);
1259 lock_ReleaseWrite(&smb_rctLock);
1263 cm_ReleaseUserVCRef(unp->userp);
1264 smb_ReleaseUsername(unp);
1268 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1270 cm_user_t *up = NULL;
1275 lock_ObtainMutex(&uidp->mx);
1277 up = uidp->unp->userp;
1280 lock_ReleaseMutex(&uidp->mx);
1286 /* retrieve a held reference to a user structure corresponding to an incoming
1288 * corresponding release function is cm_ReleaseUser.
1290 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1293 cm_user_t *up = NULL;
1296 smbp = (smb_t *) inp;
1297 uidp = smb_FindUID(vcp, smbp->uid, 0);
1301 up = smb_GetUserFromUID(uidp);
1303 smb_ReleaseUID(uidp);
1308 * Return a pointer to a pathname extracted from a TID structure. The
1309 * TID structure is not held; assume it won't go away.
1311 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1316 tidp = smb_FindTID(vcp, tid, 0);
1320 if (tidp->flags & SMB_TIDFLAG_IPC) {
1321 code = CM_ERROR_TIDIPC;
1322 /* tidp->pathname would be NULL, but that's fine */
1324 *treepath = tidp->pathname;
1325 smb_ReleaseTID(tidp);
1330 /* check to see if we have a chained fid, that is, a fid that comes from an
1331 * OpenAndX message that ran earlier in this packet. In this case, the fid
1332 * field in a read, for example, request, isn't set, since the value is
1333 * supposed to be inherited from the openAndX call.
1335 int smb_ChainFID(int fid, smb_packet_t *inp)
1337 if (inp->fid == 0 || inp->inCount == 0)
1343 /* are we a priv'd user? What does this mean on NT? */
1344 int smb_SUser(cm_user_t *userp)
1349 /* find a file ID. If we pass in 0 we select an unused File ID.
1350 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1351 * smb_fid_t data structure if desired File ID cannot be found.
1353 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1358 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1361 lock_ObtainWrite(&smb_rctLock);
1362 /* figure out if we need to allocate a new file ID */
1365 fid = vcp->fidCounter;
1369 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1370 if (fidp->refCount == 0 && fidp->delete) {
1372 lock_ReleaseWrite(&smb_rctLock);
1373 smb_ReleaseFID(fidp);
1374 lock_ObtainWrite(&smb_rctLock);
1377 if (fid == fidp->fid) {
1380 if (fid == 0xFFFF) {
1382 "New FID number wraps on vcp 0x%x", vcp);
1392 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1393 char eventName[MAX_PATH];
1395 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1396 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1397 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1398 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1399 thrd_CloseHandle(event);
1401 if (fid == 0xFFFF) {
1402 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1408 fidp = malloc(sizeof(*fidp));
1409 memset(fidp, 0, sizeof(*fidp));
1410 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1413 smb_HoldVCNoLock(vcp);
1414 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1416 fidp->curr_chunk = fidp->prev_chunk = -2;
1417 fidp->raw_write_event = event;
1419 vcp->fidCounter = fid+1;
1420 if (vcp->fidCounter == 0xFFFF) {
1421 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1423 vcp->fidCounter = 1;
1428 lock_ReleaseWrite(&smb_rctLock);
1432 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1434 smb_fid_t *fidp = NULL;
1440 lock_ObtainWrite(&smb_rctLock);
1441 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1442 if (scp == fidp->scp) {
1447 lock_ReleaseWrite(&smb_rctLock);
1451 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1457 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1458 /* the sm_fid_t->mx and smb_rctLock must not be held */
1459 void smb_ReleaseFID(smb_fid_t *fidp)
1461 cm_scache_t *scp = NULL;
1462 cm_user_t *userp = NULL;
1463 smb_vc_t *vcp = NULL;
1464 smb_ioctl_t *ioctlp;
1466 lock_ObtainMutex(&fidp->mx);
1467 lock_ObtainWrite(&smb_rctLock);
1468 osi_assert(fidp->refCount-- > 0);
1469 if (fidp->refCount == 0 && (fidp->delete)) {
1472 scp = fidp->scp; /* release after lock is released */
1474 lock_ObtainMutex(&scp->mx);
1475 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1476 lock_ReleaseMutex(&scp->mx);
1477 osi_Log2(afsd_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1480 userp = fidp->userp;
1484 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1485 thrd_CloseHandle(fidp->raw_write_event);
1487 /* and see if there is ioctl stuff to free */
1488 ioctlp = fidp->ioctlp;
1491 cm_FreeSpace(ioctlp->prefix);
1492 if (ioctlp->inAllocp)
1493 free(ioctlp->inAllocp);
1494 if (ioctlp->outAllocp)
1495 free(ioctlp->outAllocp);
1498 lock_ReleaseMutex(&fidp->mx);
1499 lock_FinalizeMutex(&fidp->mx);
1503 smb_ReleaseVCNoLock(vcp);
1505 lock_ReleaseMutex(&fidp->mx);
1507 lock_ReleaseWrite(&smb_rctLock);
1509 /* now release the scache structure */
1511 cm_ReleaseSCache(scp);
1514 cm_ReleaseUser(userp);
1518 * Case-insensitive search for one string in another;
1519 * used to find variable names in submount pathnames.
1521 static char *smb_stristr(char *str1, char *str2)
1525 for (cursor = str1; *cursor; cursor++)
1526 if (stricmp(cursor, str2) == 0)
1533 * Substitute a variable value for its name in a submount pathname. Variable
1534 * name has been identified by smb_stristr() and is in substr. Variable name
1535 * length (plus one) is in substr_size. Variable value is in newstr.
1537 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1542 strcpy(temp, substr + substr_size - 1);
1543 strcpy(substr, newstr);
1547 char VNUserName[] = "%USERNAME%";
1548 char VNLCUserName[] = "%LCUSERNAME%";
1549 char VNComputerName[] = "%COMPUTERNAME%";
1550 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1553 typedef struct smb_findShare_rock {
1557 } smb_findShare_rock_t;
1559 #define SMB_FINDSHARE_EXACT_MATCH 1
1560 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1562 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1566 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1567 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1568 if(!stricmp(dep->name, vrock->shareName))
1569 matchType = SMB_FINDSHARE_EXACT_MATCH;
1571 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1572 if(vrock->match) free(vrock->match);
1573 vrock->match = strdup(dep->name);
1574 vrock->matchType = matchType;
1576 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1577 return CM_ERROR_STOPNOW;
1583 /* find a shareName in the table of submounts */
1584 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1588 char pathName[1024];
1595 DWORD allSubmount = 1;
1597 /* if allSubmounts == 0, only return the //mountRoot/all share
1598 * if in fact it has been been created in the subMounts table.
1599 * This is to allow sites that want to restrict access to the
1602 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1603 0, KEY_QUERY_VALUE, &parmKey);
1604 if (code == ERROR_SUCCESS) {
1605 len = sizeof(allSubmount);
1606 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1607 (BYTE *) &allSubmount, &len);
1608 if (code != ERROR_SUCCESS) {
1611 RegCloseKey (parmKey);
1614 if (allSubmount && _stricmp(shareName, "all") == 0) {
1619 /* In case, the all share is disabled we need to still be able
1620 * to handle ioctl requests
1622 if (_stricmp(shareName, "ioctl$") == 0) {
1623 *pathNamep = strdup("/.__ioctl__");
1627 if (_stricmp(shareName, "IPC$") == 0 ||
1628 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1629 _stricmp(shareName, "DESKTOP.INI") == 0
1635 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1636 0, KEY_QUERY_VALUE, &parmKey);
1637 if (code == ERROR_SUCCESS) {
1638 len = sizeof(pathName);
1639 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1640 (BYTE *) pathName, &len);
1641 if (code != ERROR_SUCCESS)
1643 RegCloseKey (parmKey);
1647 if (len != 0 && len != sizeof(pathName) - 1) {
1648 /* We can accept either unix or PC style AFS pathnames. Convert
1649 * Unix-style to PC style here for internal use.
1652 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1653 p += strlen(cm_mountRoot); /* skip mount path */
1656 if (*q == '/') *q = '\\'; /* change to \ */
1662 if (var = smb_stristr(p, VNUserName)) {
1663 if (uidp && uidp->unp)
1664 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1666 smb_subst(p, var, sizeof(VNUserName)," ");
1668 else if (var = smb_stristr(p, VNLCUserName))
1670 if (uidp && uidp->unp)
1671 strcpy(temp, uidp->unp->name);
1675 smb_subst(p, var, sizeof(VNLCUserName), temp);
1677 else if (var = smb_stristr(p, VNComputerName))
1679 sizeTemp = sizeof(temp);
1680 GetComputerName((LPTSTR)temp, &sizeTemp);
1681 smb_subst(p, var, sizeof(VNComputerName), temp);
1683 else if (var = smb_stristr(p, VNLCComputerName))
1685 sizeTemp = sizeof(temp);
1686 GetComputerName((LPTSTR)temp, &sizeTemp);
1688 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1693 *pathNamep = strdup(p);
1698 /* First lookup shareName in root.afs */
1700 smb_findShare_rock_t vrock;
1702 char * p = shareName;
1705 /* attempt to locate a partial match in root.afs. This is because
1706 when using the ANSI RAP calls, the share name is limited to 13 chars
1707 and hence is truncated. Of course we prefer exact matches. */
1709 thyper.HighPart = 0;
1712 vrock.shareName = shareName;
1714 vrock.matchType = 0;
1716 cm_HoldSCache(cm_data.rootSCachep);
1717 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1718 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1719 cm_ReleaseSCache(cm_data.rootSCachep);
1721 if (vrock.matchType) {
1722 sprintf(pathName,"/%s/",vrock.match);
1723 *pathNamep = strdup(strlwr(pathName));
1728 /* if we get here, there was no match for the share in root.afs */
1729 /* so try to create \\<netbiosName>\<cellname> */
1734 /* Get the full name for this cell */
1735 code = cm_SearchCellFile(p, temp, 0, 0);
1736 #ifdef AFS_AFSDB_ENV
1737 if (code && cm_dnsEnabled) {
1739 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1742 /* construct the path */
1744 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1745 *pathNamep = strdup(strlwr(pathName));
1754 /* Client-side offline caching policy types */
1755 #define CSC_POLICY_MANUAL 0
1756 #define CSC_POLICY_DOCUMENTS 1
1757 #define CSC_POLICY_PROGRAMS 2
1758 #define CSC_POLICY_DISABLE 3
1760 int smb_FindShareCSCPolicy(char *shareName)
1766 int retval = CSC_POLICY_MANUAL;
1768 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1769 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1772 REG_OPTION_NON_VOLATILE,
1778 len = sizeof(policy);
1779 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1781 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1783 else if (stricmp(policy, "documents") == 0)
1785 retval = CSC_POLICY_DOCUMENTS;
1787 else if (stricmp(policy, "programs") == 0)
1789 retval = CSC_POLICY_PROGRAMS;
1791 else if (stricmp(policy, "disable") == 0)
1793 retval = CSC_POLICY_DISABLE;
1796 RegCloseKey(hkCSCPolicy);
1800 /* find a dir search structure by cookie value, and return it held.
1801 * Must be called with smb_globalLock held.
1803 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1805 smb_dirSearch_t *dsp;
1807 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1808 if (dsp->cookie == cookie) {
1809 if (dsp != smb_firstDirSearchp) {
1810 /* move to head of LRU queue, too, if we're not already there */
1811 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1812 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1813 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1814 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1815 if (!smb_lastDirSearchp)
1816 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1818 lock_ObtainMutex(&dsp->mx);
1820 lock_ReleaseMutex(&dsp->mx);
1826 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1827 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1828 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1834 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1836 lock_ObtainWrite(&smb_globalLock);
1837 lock_ObtainMutex(&dsp->mx);
1838 osi_Log3(afsd_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1839 dsp->cookie, dsp, dsp->scp);
1840 dsp->flags |= SMB_DIRSEARCH_DELETE;
1841 if (dsp->scp != NULL) {
1842 lock_ObtainMutex(&dsp->scp->mx);
1843 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1844 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1845 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1846 dsp->scp->bulkStatProgress = hzero;
1848 lock_ReleaseMutex(&dsp->scp->mx);
1850 lock_ReleaseMutex(&dsp->mx);
1851 lock_ReleaseWrite(&smb_globalLock);
1854 /* Must be called with the smb_globalLock held */
1855 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1857 cm_scache_t *scp = NULL;
1859 lock_ObtainMutex(&dsp->mx);
1860 osi_assert(dsp->refCount-- > 0);
1861 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1862 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1863 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1864 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1865 lock_ReleaseMutex(&dsp->mx);
1866 lock_FinalizeMutex(&dsp->mx);
1868 osi_Log3(afsd_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1869 dsp->cookie, dsp, scp);
1872 lock_ReleaseMutex(&dsp->mx);
1874 /* do this now to avoid spurious locking hierarchy creation */
1876 cm_ReleaseSCache(scp);
1879 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1881 lock_ObtainWrite(&smb_globalLock);
1882 smb_ReleaseDirSearchNoLock(dsp);
1883 lock_ReleaseWrite(&smb_globalLock);
1886 /* find a dir search structure by cookie value, and return it held */
1887 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1889 smb_dirSearch_t *dsp;
1891 lock_ObtainWrite(&smb_globalLock);
1892 dsp = smb_FindDirSearchNoLock(cookie);
1893 lock_ReleaseWrite(&smb_globalLock);
1897 /* GC some dir search entries, in the address space expected by the specific protocol.
1898 * Must be called with smb_globalLock held; release the lock temporarily.
1900 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1901 void smb_GCDirSearches(int isV3)
1903 smb_dirSearch_t *prevp;
1904 smb_dirSearch_t *tp;
1905 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1909 victimCount = 0; /* how many have we got so far */
1910 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1911 /* we'll move tp from queue, so
1914 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1915 /* if no one is using this guy, and we're either in the new protocol,
1916 * or we're in the old one and this is a small enough ID to be useful
1917 * to the old protocol, GC this guy.
1919 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1920 /* hold and delete */
1921 lock_ObtainMutex(&tp->mx);
1922 tp->flags |= SMB_DIRSEARCH_DELETE;
1923 lock_ReleaseMutex(&tp->mx);
1924 victimsp[victimCount++] = tp;
1928 /* don't do more than this */
1929 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1933 /* now release them */
1934 for (i = 0; i < victimCount; i++) {
1935 smb_ReleaseDirSearchNoLock(victimsp[i]);
1939 /* function for allocating a dir search entry. We need these to remember enough context
1940 * since we don't get passed the path from call to call during a directory search.
1942 * Returns a held dir search structure, and bumps the reference count on the vnode,
1943 * since it saves a pointer to the vnode.
1945 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1947 smb_dirSearch_t *dsp;
1953 lock_ObtainWrite(&smb_globalLock);
1956 /* what's the biggest ID allowed in this version of the protocol */
1957 /* TODO: do we really want a non v3 dir search request to wrap
1958 smb_dirSearchCounter? */
1959 maxAllowed = isV3 ? 65535 : 255;
1960 if (smb_dirSearchCounter > maxAllowed)
1961 smb_dirSearchCounter = 1;
1963 start = smb_dirSearchCounter;
1966 /* twice so we have enough tries to find guys we GC after one pass;
1967 * 10 extra is just in case I mis-counted.
1969 if (++counter > 2*maxAllowed+10)
1970 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1972 if (smb_dirSearchCounter > maxAllowed) {
1973 smb_dirSearchCounter = 1;
1975 if (smb_dirSearchCounter == start) {
1977 smb_GCDirSearches(isV3);
1980 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1982 /* don't need to watch for refcount zero and deleted, since
1983 * we haven't dropped the global lock.
1985 lock_ObtainMutex(&dsp->mx);
1987 lock_ReleaseMutex(&dsp->mx);
1988 ++smb_dirSearchCounter;
1992 dsp = malloc(sizeof(*dsp));
1993 memset(dsp, 0, sizeof(*dsp));
1994 dsp->cookie = smb_dirSearchCounter;
1995 ++smb_dirSearchCounter;
1997 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1998 dsp->lastTime = osi_Time();
1999 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2000 if (!smb_lastDirSearchp)
2001 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2003 osi_Log2(afsd_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2007 lock_ReleaseWrite(&smb_globalLock);
2011 static smb_packet_t *GetPacket(void)
2015 lock_ObtainWrite(&smb_globalLock);
2016 tbp = smb_packetFreeListp;
2018 smb_packetFreeListp = tbp->nextp;
2019 lock_ReleaseWrite(&smb_globalLock);
2021 tbp = calloc(65540,1);
2022 tbp->magic = SMB_PACKETMAGIC;
2025 tbp->resumeCode = 0;
2031 tbp->ncb_length = 0;
2036 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2041 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2045 memcpy(tbp, pkt, sizeof(smb_packet_t));
2046 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2048 smb_HoldVC(tbp->vcp);
2052 static NCB *GetNCB(void)
2057 lock_ObtainWrite(&smb_globalLock);
2058 tbp = smb_ncbFreeListp;
2060 smb_ncbFreeListp = tbp->nextp;
2061 lock_ReleaseWrite(&smb_globalLock);
2063 tbp = calloc(sizeof(*tbp),1);
2064 tbp->magic = SMB_NCBMAGIC;
2067 osi_assert(tbp->magic == SMB_NCBMAGIC);
2069 memset(&tbp->ncb, 0, sizeof(NCB));
2074 void smb_FreePacket(smb_packet_t *tbp)
2076 smb_vc_t * vcp = NULL;
2077 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2079 lock_ObtainWrite(&smb_globalLock);
2080 tbp->nextp = smb_packetFreeListp;
2081 smb_packetFreeListp = tbp;
2082 tbp->magic = SMB_PACKETMAGIC;
2086 tbp->resumeCode = 0;
2092 tbp->ncb_length = 0;
2094 lock_ReleaseWrite(&smb_globalLock);
2100 static void FreeNCB(NCB *bufferp)
2104 tbp = (smb_ncb_t *) bufferp;
2105 osi_assert(tbp->magic == SMB_NCBMAGIC);
2107 lock_ObtainWrite(&smb_globalLock);
2108 tbp->nextp = smb_ncbFreeListp;
2109 smb_ncbFreeListp = tbp;
2110 lock_ReleaseWrite(&smb_globalLock);
2113 /* get a ptr to the data part of a packet, and its count */
2114 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2118 unsigned char *afterParmsp;
2120 parmBytes = *smbp->wctp << 1;
2121 afterParmsp = smbp->wctp + parmBytes + 1;
2123 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2124 if (nbytesp) *nbytesp = dataBytes;
2126 /* don't forget to skip the data byte count, since it follows
2127 * the parameters; that's where the "2" comes from below.
2129 return (unsigned char *) (afterParmsp + 2);
2132 /* must set all the returned parameters before playing around with the
2133 * data region, since the data region is located past the end of the
2134 * variable number of parameters.
2136 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2138 unsigned char *afterParmsp;
2140 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2142 *afterParmsp++ = dsize & 0xff;
2143 *afterParmsp = (dsize>>8) & 0xff;
2146 /* return the parm'th parameter in the smbp packet */
2147 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2150 unsigned char *parmDatap;
2152 parmCount = *smbp->wctp;
2154 if (parm >= parmCount) {
2157 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2158 parm, parmCount, smbp->ncb_length);
2159 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2160 parm, parmCount, smbp->ncb_length);
2161 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2162 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2163 osi_panic(s, __FILE__, __LINE__);
2165 parmDatap = smbp->wctp + (2*parm) + 1;
2167 return parmDatap[0] + (parmDatap[1] << 8);
2170 /* return the parm'th parameter in the smbp packet */
2171 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2174 unsigned char *parmDatap;
2176 parmCount = *smbp->wctp;
2178 if (parm >= parmCount) {
2181 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2182 parm, parmCount, smbp->ncb_length);
2183 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2184 parm, parmCount, smbp->ncb_length);
2185 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2186 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2187 osi_panic(s, __FILE__, __LINE__);
2189 parmDatap = smbp->wctp + (2*parm) + 1;
2191 return parmDatap[0];
2194 /* return the parm'th parameter in the smbp packet */
2195 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2198 unsigned char *parmDatap;
2200 parmCount = *smbp->wctp;
2202 if (parm + 1 >= parmCount) {
2205 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2206 parm, parmCount, smbp->ncb_length);
2207 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2208 parm, parmCount, smbp->ncb_length);
2209 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2210 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2211 osi_panic(s, __FILE__, __LINE__);
2213 parmDatap = smbp->wctp + (2*parm) + 1;
2215 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2218 /* return the parm'th parameter in the smbp packet */
2219 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2222 unsigned char *parmDatap;
2224 parmCount = *smbp->wctp;
2226 if (parm * 2 + offset >= parmCount * 2) {
2229 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2230 parm, offset, parmCount, smbp->ncb_length);
2231 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2232 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2233 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2234 parm, offset, parmCount, smbp->ncb_length);
2235 osi_panic(s, __FILE__, __LINE__);
2237 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2239 return parmDatap[0] + (parmDatap[1] << 8);
2242 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2246 /* make sure we have enough slots */
2247 if (*smbp->wctp <= slot)
2248 *smbp->wctp = slot+1;
2250 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2251 *parmDatap++ = parmValue & 0xff;
2252 *parmDatap = (parmValue>>8) & 0xff;
2255 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2259 /* make sure we have enough slots */
2260 if (*smbp->wctp <= slot)
2261 *smbp->wctp = slot+2;
2263 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2264 *parmDatap++ = parmValue & 0xff;
2265 *parmDatap++ = (parmValue>>8) & 0xff;
2266 *parmDatap++ = (parmValue>>16) & 0xff;
2267 *parmDatap = (parmValue>>24) & 0xff;
2270 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2275 /* make sure we have enough slots */
2276 if (*smbp->wctp <= slot)
2277 *smbp->wctp = slot+4;
2279 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2281 *parmDatap++ = *parmValuep++;
2284 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2288 /* make sure we have enough slots */
2289 if (*smbp->wctp <= slot) {
2290 if (smbp->oddByte) {
2292 *smbp->wctp = slot+1;
2297 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2298 *parmDatap++ = parmValue & 0xff;
2301 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2305 lastSlashp = strrchr(inPathp, '\\');
2307 *lastComponentp = lastSlashp;
2310 if (inPathp == lastSlashp)
2312 *outPathp++ = *inPathp++;
2321 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2326 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2331 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2337 tlen = inp[0] + (inp[1]<<8);
2338 inp += 2; /* skip length field */
2341 *chainpp = inp + tlen;
2350 /* format a packet as a response */
2351 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2356 outp = (smb_t *) op;
2358 /* zero the basic structure through the smb_wct field, and zero the data
2359 * size field, assuming that wct stays zero; otherwise, you have to
2360 * explicitly set the data size field, too.
2362 inSmbp = (smb_t *) inp;
2363 memset(outp, 0, sizeof(smb_t)+2);
2369 outp->com = inSmbp->com;
2370 outp->tid = inSmbp->tid;
2371 outp->pid = inSmbp->pid;
2372 outp->uid = inSmbp->uid;
2373 outp->mid = inSmbp->mid;
2374 outp->res[0] = inSmbp->res[0];
2375 outp->res[1] = inSmbp->res[1];
2376 op->inCom = inSmbp->com;
2378 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2379 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2381 /* copy fields in generic packet area */
2382 op->wctp = &outp->wct;
2385 /* send a (probably response) packet; vcp tells us to whom to send it.
2386 * we compute the length by looking at wct and bcc fields.
2388 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2402 memset((char *)ncbp, 0, sizeof(NCB));
2404 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2405 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2406 extra += tp[0] + (tp[1]<<8);
2407 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2408 extra += 3; /* wct and length fields */
2410 ncbp->ncb_length = extra; /* bytes to send */
2411 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2412 ncbp->ncb_lana_num = vcp->lana;
2413 ncbp->ncb_command = NCBSEND; /* op means send data */
2414 ncbp->ncb_buffer = (char *) inp;/* packet */
2415 code = Netbios(ncbp);
2418 const char * s = ncb_error_string(code);
2419 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2420 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2422 lock_ObtainMutex(&vcp->mx);
2423 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2424 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2426 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2427 lock_ReleaseMutex(&vcp->mx);
2428 lock_ObtainWrite(&smb_globalLock);
2429 dead_sessions[vcp->session] = TRUE;
2430 lock_ReleaseWrite(&smb_globalLock);
2431 smb_CleanupDeadVC(vcp);
2433 lock_ReleaseMutex(&vcp->mx);
2441 void smb_MapNTError(long code, unsigned long *NTStatusp)
2443 unsigned long NTStatus;
2445 /* map CM_ERROR_* errors to NT 32-bit status codes */
2446 /* NT Status codes are listed in ntstatus.h not winerror.h */
2447 if (code == CM_ERROR_NOSUCHCELL) {
2448 NTStatus = 0xC000000FL; /* No such file */
2450 else if (code == CM_ERROR_NOSUCHVOLUME) {
2451 NTStatus = 0xC000000FL; /* No such file */
2453 else if (code == CM_ERROR_TIMEDOUT) {
2455 NTStatus = 0xC00000CFL; /* Sharing Paused */
2457 NTStatus = 0x00000102L; /* Timeout */
2460 else if (code == CM_ERROR_RETRY) {
2461 NTStatus = 0xC000022DL; /* Retry */
2463 else if (code == CM_ERROR_NOACCESS) {
2464 NTStatus = 0xC0000022L; /* Access denied */
2466 else if (code == CM_ERROR_READONLY) {
2467 NTStatus = 0xC00000A2L; /* Write protected */
2469 else if (code == CM_ERROR_NOSUCHFILE) {
2470 NTStatus = 0xC000000FL; /* No such file */
2472 else if (code == CM_ERROR_NOSUCHPATH) {
2473 NTStatus = 0xC000003AL; /* Object path not found */
2475 else if (code == CM_ERROR_TOOBIG) {
2476 NTStatus = 0xC000007BL; /* Invalid image format */
2478 else if (code == CM_ERROR_INVAL) {
2479 NTStatus = 0xC000000DL; /* Invalid parameter */
2481 else if (code == CM_ERROR_BADFD) {
2482 NTStatus = 0xC0000008L; /* Invalid handle */
2484 else if (code == CM_ERROR_BADFDOP) {
2485 NTStatus = 0xC0000022L; /* Access denied */
2487 else if (code == CM_ERROR_EXISTS) {
2488 NTStatus = 0xC0000035L; /* Object name collision */
2490 else if (code == CM_ERROR_NOTEMPTY) {
2491 NTStatus = 0xC0000101L; /* Directory not empty */
2493 else if (code == CM_ERROR_CROSSDEVLINK) {
2494 NTStatus = 0xC00000D4L; /* Not same device */
2496 else if (code == CM_ERROR_NOTDIR) {
2497 NTStatus = 0xC0000103L; /* Not a directory */
2499 else if (code == CM_ERROR_ISDIR) {
2500 NTStatus = 0xC00000BAL; /* File is a directory */
2502 else if (code == CM_ERROR_BADOP) {
2504 /* I have no idea where this comes from */
2505 NTStatus = 0xC09820FFL; /* SMB no support */
2507 NTStatus = 0xC00000BBL; /* Not supported */
2508 #endif /* COMMENT */
2510 else if (code == CM_ERROR_BADSHARENAME) {
2511 NTStatus = 0xC00000CCL; /* Bad network name */
2513 else if (code == CM_ERROR_NOIPC) {
2515 NTStatus = 0xC0000022L; /* Access Denied */
2517 NTStatus = 0xC000013DL; /* Remote Resources */
2520 else if (code == CM_ERROR_CLOCKSKEW) {
2521 NTStatus = 0xC0000133L; /* Time difference at DC */
2523 else if (code == CM_ERROR_BADTID) {
2524 NTStatus = 0xC0982005L; /* SMB bad TID */
2526 else if (code == CM_ERROR_USESTD) {
2527 NTStatus = 0xC09820FBL; /* SMB use standard */
2529 else if (code == CM_ERROR_QUOTA) {
2531 NTStatus = 0xC0000044L; /* Quota exceeded */
2533 NTStatus = 0xC000007FL; /* Disk full */
2536 else if (code == CM_ERROR_SPACE) {
2537 NTStatus = 0xC000007FL; /* Disk full */
2539 else if (code == CM_ERROR_ATSYS) {
2540 NTStatus = 0xC0000033L; /* Object name invalid */
2542 else if (code == CM_ERROR_BADNTFILENAME) {
2543 NTStatus = 0xC0000033L; /* Object name invalid */
2545 else if (code == CM_ERROR_WOULDBLOCK) {
2546 NTStatus = 0xC0000055L; /* Lock not granted */
2548 else if (code == CM_ERROR_SHARING_VIOLATION) {
2549 NTStatus = 0xC0000043L; /* Sharing violation */
2551 else if (code == CM_ERROR_LOCK_CONFLICT) {
2552 NTStatus = 0xC0000054L; /* Lock conflict */
2554 else if (code == CM_ERROR_PARTIALWRITE) {
2555 NTStatus = 0xC000007FL; /* Disk full */
2557 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2558 NTStatus = 0xC0000023L; /* Buffer too small */
2560 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2561 NTStatus = 0xC0000035L; /* Object name collision */
2563 else if (code == CM_ERROR_BADPASSWORD) {
2564 NTStatus = 0xC000006DL; /* unknown username or bad password */
2566 else if (code == CM_ERROR_BADLOGONTYPE) {
2567 NTStatus = 0xC000015BL; /* logon type not granted */
2569 else if (code == CM_ERROR_GSSCONTINUE) {
2570 NTStatus = 0xC0000016L; /* more processing required */
2572 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2574 NTStatus = 0xC0000280L; /* reparse point not resolved */
2576 NTStatus = 0xC0000022L; /* Access Denied */
2579 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2580 NTStatus = 0xC0000257L; /* Path Not Covered */
2583 else if (code == CM_ERROR_ALLBUSY) {
2584 NTStatus = 0xC00000BFL; /* Network Busy */
2586 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2587 NTStatus = 0xC0000350L; /* Remote Host Down */
2590 /* we do not want to be telling the SMB/CIFS client that
2591 * the AFS Client Service is busy or down.
2593 else if (code == CM_ERROR_ALLBUSY ||
2594 code == CM_ERROR_ALLOFFLINE ||
2595 code == CM_ERROR_ALLDOWN) {
2596 NTStatus = 0xC00000BEL; /* Bad Network Path */
2599 else if (code == RXKADUNKNOWNKEY) {
2600 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2602 NTStatus = 0xC0982001L; /* SMB non-specific error */
2605 *NTStatusp = NTStatus;
2606 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2609 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2610 unsigned char *classp)
2612 unsigned char class;
2613 unsigned short error;
2615 /* map CM_ERROR_* errors to SMB errors */
2616 if (code == CM_ERROR_NOSUCHCELL) {
2618 error = 3; /* bad path */
2620 else if (code == CM_ERROR_NOSUCHVOLUME) {
2622 error = 3; /* bad path */
2624 else if (code == CM_ERROR_TIMEDOUT) {
2626 error = 81; /* server is paused */
2628 else if (code == CM_ERROR_RETRY) {
2629 class = 2; /* shouldn't happen */
2632 else if (code == CM_ERROR_NOACCESS) {
2634 error = 4; /* bad access */
2636 else if (code == CM_ERROR_READONLY) {
2638 error = 19; /* read only */
2640 else if (code == CM_ERROR_NOSUCHFILE) {
2642 error = 2; /* ENOENT! */
2644 else if (code == CM_ERROR_NOSUCHPATH) {
2646 error = 3; /* Bad path */
2648 else if (code == CM_ERROR_TOOBIG) {
2650 error = 11; /* bad format */
2652 else if (code == CM_ERROR_INVAL) {
2653 class = 2; /* server non-specific error code */
2656 else if (code == CM_ERROR_BADFD) {
2658 error = 6; /* invalid file handle */
2660 else if (code == CM_ERROR_BADFDOP) {
2661 class = 1; /* invalid op on FD */
2664 else if (code == CM_ERROR_EXISTS) {
2666 error = 80; /* file already exists */
2668 else if (code == CM_ERROR_NOTEMPTY) {
2670 error = 5; /* delete directory not empty */
2672 else if (code == CM_ERROR_CROSSDEVLINK) {
2674 error = 17; /* EXDEV */
2676 else if (code == CM_ERROR_NOTDIR) {
2677 class = 1; /* bad path */
2680 else if (code == CM_ERROR_ISDIR) {
2681 class = 1; /* access denied; DOS doesn't have a good match */
2684 else if (code == CM_ERROR_BADOP) {
2688 else if (code == CM_ERROR_BADSHARENAME) {
2692 else if (code == CM_ERROR_NOIPC) {
2694 error = 4; /* bad access */
2696 else if (code == CM_ERROR_CLOCKSKEW) {
2697 class = 1; /* invalid function */
2700 else if (code == CM_ERROR_BADTID) {
2704 else if (code == CM_ERROR_USESTD) {
2708 else if (code == CM_ERROR_REMOTECONN) {
2712 else if (code == CM_ERROR_QUOTA) {
2713 if (vcp->flags & SMB_VCFLAG_USEV3) {
2715 error = 39; /* disk full */
2719 error = 5; /* access denied */
2722 else if (code == CM_ERROR_SPACE) {
2723 if (vcp->flags & SMB_VCFLAG_USEV3) {
2725 error = 39; /* disk full */
2729 error = 5; /* access denied */
2732 else if (code == CM_ERROR_PARTIALWRITE) {
2734 error = 39; /* disk full */
2736 else if (code == CM_ERROR_ATSYS) {
2738 error = 2; /* ENOENT */
2740 else if (code == CM_ERROR_WOULDBLOCK) {
2742 error = 33; /* lock conflict */
2744 else if (code == CM_ERROR_LOCK_CONFLICT) {
2746 error = 33; /* lock conflict */
2748 else if (code == CM_ERROR_SHARING_VIOLATION) {
2750 error = 33; /* lock conflict */
2752 else if (code == CM_ERROR_NOFILES) {
2754 error = 18; /* no files in search */
2756 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2758 error = 183; /* Samba uses this */
2760 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2761 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2763 error = 2; /* bad password */
2765 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2767 error = 3; /* bad path */
2776 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2779 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2781 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2782 return CM_ERROR_BADOP;
2785 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2787 unsigned short EchoCount, i;
2788 char *data, *outdata;
2791 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2793 for (i=1; i<=EchoCount; i++) {
2794 data = smb_GetSMBData(inp, &dataSize);
2795 smb_SetSMBParm(outp, 0, i);
2796 smb_SetSMBDataLength(outp, dataSize);
2797 outdata = smb_GetSMBData(outp, NULL);
2798 memcpy(outdata, data, dataSize);
2799 smb_SendPacket(vcp, outp);
2805 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2808 long count, minCount, finalCount;
2813 cm_user_t *userp = NULL;
2816 char *rawBuf = NULL;
2821 fd = smb_GetSMBParm(inp, 0);
2822 count = smb_GetSMBParm(inp, 3);
2823 minCount = smb_GetSMBParm(inp, 4);
2824 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2826 if (*inp->wctp == 10) {
2827 /* we were sent a request with 64-bit file offsets */
2828 #ifdef AFS_LARGEFILES
2829 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2831 if (LargeIntegerLessThanZero(offset)) {
2832 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2836 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2837 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2840 offset.HighPart = 0;
2844 /* we were sent a request with 32-bit file offsets */
2845 offset.HighPart = 0;
2848 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2849 fd, offset.HighPart, offset.LowPart, count);
2851 fidp = smb_FindFID(vcp, fd, 0);
2855 pid = ((smb_t *) inp)->pid;
2857 LARGE_INTEGER LOffset, LLength;
2860 key = cm_GenerateKey(vcp->vcID, pid, fd);
2862 LOffset.HighPart = offset.HighPart;
2863 LOffset.LowPart = offset.LowPart;
2864 LLength.HighPart = 0;
2865 LLength.LowPart = count;
2867 lock_ObtainMutex(&fidp->scp->mx);
2868 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2869 lock_ReleaseMutex(&fidp->scp->mx);
2875 lock_ObtainMutex(&smb_RawBufLock);
2877 /* Get a raw buf, from head of list */
2878 rawBuf = smb_RawBufs;
2879 smb_RawBufs = *(char **)smb_RawBufs;
2881 lock_ReleaseMutex(&smb_RawBufLock);
2885 lock_ObtainMutex(&fidp->mx);
2886 if (fidp->flags & SMB_FID_IOCTL)
2888 lock_ReleaseMutex(&fidp->mx);
2889 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2891 /* Give back raw buffer */
2892 lock_ObtainMutex(&smb_RawBufLock);
2893 *((char **) rawBuf) = smb_RawBufs;
2895 smb_RawBufs = rawBuf;
2896 lock_ReleaseMutex(&smb_RawBufLock);
2899 smb_ReleaseFID(fidp);
2902 lock_ReleaseMutex(&fidp->mx);
2904 userp = smb_GetUserFromVCP(vcp, inp);
2906 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2912 cm_ReleaseUser(userp);
2915 smb_ReleaseFID(fidp);
2919 memset((char *)ncbp, 0, sizeof(NCB));
2921 ncbp->ncb_length = (unsigned short) finalCount;
2922 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2923 ncbp->ncb_lana_num = vcp->lana;
2924 ncbp->ncb_command = NCBSEND;
2925 ncbp->ncb_buffer = rawBuf;
2927 code = Netbios(ncbp);
2929 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2932 /* Give back raw buffer */
2933 lock_ObtainMutex(&smb_RawBufLock);
2934 *((char **) rawBuf) = smb_RawBufs;
2936 smb_RawBufs = rawBuf;
2937 lock_ReleaseMutex(&smb_RawBufLock);
2943 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2945 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2950 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2952 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2957 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2964 int VistaProtoIndex;
2965 int protoIndex; /* index we're using */
2970 char protocol_array[10][1024]; /* protocol signature of the client */
2971 int caps; /* capabilities */
2974 TIME_ZONE_INFORMATION tzi;
2976 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2979 namep = smb_GetSMBData(inp, &dbytes);
2982 coreProtoIndex = -1; /* not found */
2985 VistaProtoIndex = -1;
2986 while(namex < dbytes) {
2987 osi_Log1(smb_logp, "Protocol %s",
2988 osi_LogSaveString(smb_logp, namep+1));
2989 strcpy(protocol_array[tcounter], namep+1);
2991 /* namep points at the first protocol, or really, a 0x02
2992 * byte preceding the null-terminated ASCII name.
2994 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2995 coreProtoIndex = tcounter;
2997 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2998 v3ProtoIndex = tcounter;
3000 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3001 NTProtoIndex = tcounter;
3003 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3004 VistaProtoIndex = tcounter;
3007 /* compute size of protocol entry */
3008 entryLength = (int)strlen(namep+1);
3009 entryLength += 2; /* 0x02 bytes and null termination */
3011 /* advance over this protocol entry */
3012 namex += entryLength;
3013 namep += entryLength;
3014 tcounter++; /* which proto entry we're looking at */
3017 lock_ObtainMutex(&vcp->mx);
3019 if (VistaProtoIndex != -1) {
3020 protoIndex = VistaProtoIndex;
3021 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3024 if (NTProtoIndex != -1) {
3025 protoIndex = NTProtoIndex;
3026 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3028 else if (v3ProtoIndex != -1) {
3029 protoIndex = v3ProtoIndex;
3030 vcp->flags |= SMB_VCFLAG_USEV3;
3032 else if (coreProtoIndex != -1) {
3033 protoIndex = coreProtoIndex;
3034 vcp->flags |= SMB_VCFLAG_USECORE;
3036 else protoIndex = -1;
3037 lock_ReleaseMutex(&vcp->mx);
3039 if (protoIndex == -1)
3040 return CM_ERROR_INVAL;
3041 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3042 smb_SetSMBParm(outp, 0, protoIndex);
3043 if (smb_authType != SMB_AUTH_NONE) {
3044 smb_SetSMBParmByte(outp, 1,
3045 NEGOTIATE_SECURITY_USER_LEVEL |
3046 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3048 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3050 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3051 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3052 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3053 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3054 /* The session key is not a well documented field however most clients
3055 * will echo back the session key to the server. Currently we are using
3056 * the same value for all sessions. We should generate a random value
3057 * and store it into the vcp
3059 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3060 smb_SetSMBParm(outp, 8, 1);
3062 * Tried changing the capabilities to support for W2K - defect 117695
3063 * Maybe something else needs to be changed here?
3067 smb_SetSMBParmLong(outp, 9, 0x43fd);
3069 smb_SetSMBParmLong(outp, 9, 0x251);
3072 * 32-bit error codes *
3077 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3079 NTNEGOTIATE_CAPABILITY_DFS |
3081 #ifdef AFS_LARGEFILES
3082 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3084 NTNEGOTIATE_CAPABILITY_NTFIND |
3085 NTNEGOTIATE_CAPABILITY_RAWMODE |
3086 NTNEGOTIATE_CAPABILITY_NTSMB;
3088 if ( smb_authType == SMB_AUTH_EXTENDED )
3089 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3091 smb_SetSMBParmLong(outp, 9, caps);
3093 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3094 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3095 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3097 GetTimeZoneInformation(&tzi);
3098 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3100 if (smb_authType == SMB_AUTH_NTLM) {
3101 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3102 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3103 /* paste in encryption key */
3104 datap = smb_GetSMBData(outp, NULL);
3105 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3106 /* and the faux domain name */
3107 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3108 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3112 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3114 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3116 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3118 datap = smb_GetSMBData(outp, NULL);
3119 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3122 datap += sizeof(smb_ServerGUID);
3123 memcpy(datap, secBlob, secBlobLength);
3127 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3128 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3131 else if (v3ProtoIndex != -1) {
3132 smb_SetSMBParm(outp, 0, protoIndex);
3134 /* NOTE: Extended authentication cannot be negotiated with v3
3135 * therefore we fail over to NTLM
3137 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3138 smb_SetSMBParm(outp, 1,
3139 NEGOTIATE_SECURITY_USER_LEVEL |
3140 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3142 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3144 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3145 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3146 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3147 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3148 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3149 smb_SetSMBParm(outp, 7, 1);
3151 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3152 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3153 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3155 GetTimeZoneInformation(&tzi);
3156 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3158 /* NOTE: Extended authentication cannot be negotiated with v3
3159 * therefore we fail over to NTLM
3161 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3162 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3163 smb_SetSMBParm(outp, 12, 0); /* resvd */
3164 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3165 datap = smb_GetSMBData(outp, NULL);
3166 /* paste in a new encryption key */
3167 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3168 /* and the faux domain name */
3169 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3171 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3172 smb_SetSMBParm(outp, 12, 0); /* resvd */
3173 smb_SetSMBDataLength(outp, 0);
3176 else if (coreProtoIndex != -1) { /* not really supported anymore */
3177 smb_SetSMBParm(outp, 0, protoIndex);
3178 smb_SetSMBDataLength(outp, 0);
3183 void smb_CheckVCs(void)
3185 smb_vc_t * vcp, *nextp;
3186 smb_packet_t * outp = GetPacket();
3189 lock_ObtainWrite(&smb_rctLock);
3190 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3192 if (vcp->magic != SMB_VC_MAGIC)
3193 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3194 __FILE__, __LINE__);
3198 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3201 smb_HoldVCNoLock(vcp);
3203 smb_HoldVCNoLock(nextp);
3204 smb_FormatResponsePacket(vcp, NULL, outp);
3205 smbp = (smb_t *)outp;
3206 outp->inCom = smbp->com = 0x2b /* Echo */;
3214 smb_SetSMBParm(outp, 0, 0);
3215 smb_SetSMBDataLength(outp, 0);
3216 lock_ReleaseWrite(&smb_rctLock);
3218 smb_SendPacket(vcp, outp);
3220 lock_ObtainWrite(&smb_rctLock);
3221 smb_ReleaseVCNoLock(vcp);
3223 smb_ReleaseVCNoLock(nextp);
3225 lock_ReleaseWrite(&smb_rctLock);
3226 smb_FreePacket(outp);
3229 void smb_Daemon(void *parmp)
3231 afs_uint32 count = 0;
3232 smb_username_t **unpp;
3235 while(smbShutdownFlag == 0) {
3239 if (smbShutdownFlag == 1)
3242 if ((count % 72) == 0) { /* every five minutes */
3244 time_t old_localZero = smb_localZero;
3246 /* Initialize smb_localZero */
3247 myTime.tm_isdst = -1; /* compute whether on DST or not */
3248 myTime.tm_year = 70;
3254 smb_localZero = mktime(&myTime);
3256 #ifndef USE_NUMERIC_TIME_CONV
3257 smb_CalculateNowTZ();
3258 #endif /* USE_NUMERIC_TIME_CONV */
3259 #ifdef AFS_FREELANCE
3260 if ( smb_localZero != old_localZero )
3261 cm_noteLocalMountPointChange();
3267 /* GC smb_username_t objects that will no longer be used */
3269 lock_ObtainWrite(&smb_rctLock);
3270 for ( unpp=&usernamesp; *unpp; ) {
3272 smb_username_t *unp;
3274 lock_ObtainMutex(&(*unpp)->mx);
3275 if ( (*unpp)->refCount > 0 ||
3276 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3277 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3279 else if (!smb_LogoffTokenTransfer ||
3280 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3282 lock_ReleaseMutex(&(*unpp)->mx);
3290 lock_FinalizeMutex(&unp->mx);
3296 lock_ReleaseWrite(&smb_rctLock);
3297 cm_ReleaseUser(userp);
3298 lock_ObtainWrite(&smb_rctLock);
3301 unpp = &(*unpp)->nextp;
3304 lock_ReleaseWrite(&smb_rctLock);
3306 /* XXX GC dir search entries */
3310 void smb_WaitingLocksDaemon()
3312 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3313 smb_waitingLock_t *wl, *wlNext;
3316 smb_packet_t *inp, *outp;
3320 while (smbShutdownFlag == 0) {
3321 lock_ObtainWrite(&smb_globalLock);
3322 nwlRequest = smb_allWaitingLocks;
3323 if (nwlRequest == NULL) {
3324 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3329 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3336 lock_ObtainWrite(&smb_globalLock);
3338 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3340 wlRequest = nwlRequest;
3341 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3342 lock_ReleaseWrite(&smb_globalLock);
3346 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3347 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3350 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3352 /* wl->state is either _DONE or _WAITING. _ERROR
3353 would no longer be on the queue. */
3354 code = cm_RetryLock( wl->lockp,
3355 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3358 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3359 } else if (code != CM_ERROR_WOULDBLOCK) {
3360 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3365 if (code == CM_ERROR_WOULDBLOCK) {
3368 if (wlRequest->timeRemaining != 0xffffffff
3369 && (wlRequest->timeRemaining -= 1000) < 0)
3381 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3384 scp = wlRequest->scp;
3385 osi_Log2(afsd_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3389 lock_ObtainMutex(&scp->mx);
3391 for (wl = wlRequest->locks; wl; wl = wlNext) {
3392 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3394 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3395 wl->LLength, wl->key, NULL, &req);
3397 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3402 lock_ReleaseMutex(&scp->mx);
3406 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3409 for (wl = wlRequest->locks; wl; wl = wlNext) {
3410 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3411 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3416 vcp = wlRequest->vcp;
3417 inp = wlRequest->inp;
3418 outp = wlRequest->outp;
3420 ncbp->ncb_length = inp->ncb_length;
3421 inp->spacep = cm_GetSpace();
3423 /* Remove waitingLock from list */
3424 lock_ObtainWrite(&smb_globalLock);
3425 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3427 lock_ReleaseWrite(&smb_globalLock);
3429 /* Resume packet processing */
3431 smb_SetSMBDataLength(outp, 0);
3432 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3433 outp->resumeCode = code;
3435 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3438 cm_FreeSpace(inp->spacep);
3439 smb_FreePacket(inp);
3440 smb_FreePacket(outp);
3442 cm_ReleaseSCache(wlRequest->scp);
3445 } while (nwlRequest && smbShutdownFlag == 0);
3450 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3452 osi_Log0(smb_logp, "SMB receive get disk attributes");
3454 smb_SetSMBParm(outp, 0, 32000);
3455 smb_SetSMBParm(outp, 1, 64);
3456 smb_SetSMBParm(outp, 2, 1024);
3457 smb_SetSMBParm(outp, 3, 30000);
3458 smb_SetSMBParm(outp, 4, 0);
3459 smb_SetSMBDataLength(outp, 0);
3463 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3467 unsigned short newTid;
3468 char shareName[256];
3476 osi_Log0(smb_logp, "SMB receive tree connect");
3478 /* parse input parameters */
3479 tp = smb_GetSMBData(inp, NULL);
3480 pathp = smb_ParseASCIIBlock(tp, &tp);
3481 if (smb_StoreAnsiFilenames)
3482 OemToChar(pathp,pathp);
3483 passwordp = smb_ParseASCIIBlock(tp, &tp);
3484 tp = strrchr(pathp, '\\');
3486 return CM_ERROR_BADSMB;
3487 strcpy(shareName, tp+1);
3489 lock_ObtainMutex(&vcp->mx);
3490 newTid = vcp->tidCounter++;
3491 lock_ReleaseMutex(&vcp->mx);
3493 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3494 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3495 userp = smb_GetUserFromUID(uidp);
3496 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3498 smb_ReleaseUID(uidp);
3500 smb_ReleaseTID(tidp);
3501 return CM_ERROR_BADSHARENAME;
3503 lock_ObtainMutex(&tidp->mx);
3504 tidp->userp = userp;
3505 tidp->pathname = sharePath;
3506 lock_ReleaseMutex(&tidp->mx);
3507 smb_ReleaseTID(tidp);
3509 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3510 smb_SetSMBParm(rsp, 1, newTid);
3511 smb_SetSMBDataLength(rsp, 0);
3513 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3517 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3521 if (*inp++ != 0x1) return NULL;
3522 tlen = inp[0] + (inp[1]<<8);
3523 inp += 2; /* skip length field */
3526 *chainpp = inp + tlen;
3529 if (lengthp) *lengthp = tlen;
3534 /* set maskp to the mask part of the incoming path.
3535 * Mask is 11 bytes long (8.3 with the dot elided).
3536 * Returns true if succeeds with a valid name, otherwise it does
3537 * its best, but returns false.
3539 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3547 /* starts off valid */
3550 /* mask starts out all blanks */
3551 memset(maskp, ' ', 11);
3553 /* find last backslash, or use whole thing if there is none */
3554 tp = strrchr(pathp, '\\');
3555 if (!tp) tp = pathp;
3556 else tp++; /* skip slash */
3560 /* names starting with a dot are illegal */
3561 if (*tp == '.') valid8Dot3 = 0;
3565 if (tc == 0) return valid8Dot3;
3566 if (tc == '.' || tc == '"') break;
3567 if (i < 8) *up++ = tc;
3568 else valid8Dot3 = 0;
3571 /* if we get here, tp point after the dot */
3572 up = maskp+8; /* ext goes here */
3579 if (tc == '.' || tc == '"')
3582 /* copy extension if not too long */
3592 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3602 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3604 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3608 /* otherwise, we have a valid 8.3 name; see if we have a match,
3609 * treating '?' as a wildcard in maskp (but not in the file name).
3611 tp1 = umask; /* real name, in mask format */
3612 tp2 = maskp; /* mask, in mask format */
3613 for(i=0; i<11; i++) {
3614 tc1 = *tp1++; /* char from real name */
3615 tc2 = *tp2++; /* char from mask */
3616 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3617 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3620 if (tc2 == '?' && tc1 != ' ')
3627 /* we got a match */
3631 char *smb_FindMask(char *pathp)
3635 tp = strrchr(pathp, '\\'); /* find last slash */
3638 return tp+1; /* skip the slash */
3640 return pathp; /* no slash, return the entire path */
3643 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3645 unsigned char *pathp;
3647 unsigned char mask[11];
3648 unsigned char *statBlockp;
3649 unsigned char initStatBlock[21];
3652 osi_Log0(smb_logp, "SMB receive search volume");
3654 /* pull pathname and stat block out of request */
3655 tp = smb_GetSMBData(inp, NULL);
3656 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3657 osi_assert(pathp != NULL);
3658 if (smb_StoreAnsiFilenames)
3659 OemToChar(pathp,pathp);
3660 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3661 osi_assert(statBlockp != NULL);
3663 statBlockp = initStatBlock;
3667 /* for returning to caller */
3668 smb_Get8Dot3MaskFromPath(mask, pathp);
3670 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3671 tp = smb_GetSMBData(outp, NULL);
3673 *tp++ = 43; /* bytes in a dir entry */
3674 *tp++ = 0; /* high byte in counter */
3676 /* now marshall the dir entry, starting with the search status */
3677 *tp++ = statBlockp[0]; /* Reserved */
3678 memcpy(tp, mask, 11); tp += 11; /* FileName */
3680 /* now pass back server use info, with 1st byte non-zero */
3682 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3684 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3686 *tp++ = 0x8; /* attribute: volume */
3696 /* 4 byte file size */
3702 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3703 memset(tp, ' ', 13);
3706 /* set the length of the data part of the packet to 43 + 3, for the dir
3707 * entry plus the 5 and the length fields.
3709 smb_SetSMBDataLength(outp, 46);
3713 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3714 cm_user_t *userp, cm_req_t *reqp)
3722 smb_dirListPatch_t *patchp;
3723 smb_dirListPatch_t *npatchp;
3725 for (patchp = *dirPatchespp; patchp; patchp =
3726 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3728 dptr = patchp->dptr;
3730 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3732 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3733 *dptr++ = SMB_ATTR_HIDDEN;
3736 lock_ObtainMutex(&scp->mx);
3737 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3738 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3740 lock_ReleaseMutex(&scp->mx);
3741 cm_ReleaseSCache(scp);
3742 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3743 *dptr++ = SMB_ATTR_HIDDEN;
3747 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3749 attr = smb_Attributes(scp);
3750 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3751 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3752 attr |= SMB_ATTR_HIDDEN;
3756 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3759 shortTemp = (unsigned short) (dosTime & 0xffff);
3760 *((u_short *)dptr) = shortTemp;
3763 /* and copy out date */
3764 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3765 *((u_short *)dptr) = shortTemp;
3768 /* copy out file length */
3769 *((u_long *)dptr) = scp->length.LowPart;
3771 lock_ReleaseMutex(&scp->mx);
3772 cm_ReleaseSCache(scp);
3775 /* now free the patches */
3776 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3777 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3781 /* and mark the list as empty */
3782 *dirPatchespp = NULL;
3787 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3796 smb_dirListPatch_t *dirListPatchesp;
3797 smb_dirListPatch_t *curPatchp;
3801 osi_hyper_t dirLength;
3802 osi_hyper_t bufferOffset;
3803 osi_hyper_t curOffset;
3805 unsigned char *inCookiep;
3806 smb_dirSearch_t *dsp;
3810 unsigned long clientCookie;
3811 cm_pageHeader_t *pageHeaderp;
3812 cm_user_t *userp = NULL;
3819 long nextEntryCookie;
3820 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3821 char resByte; /* reserved byte from the cookie */
3822 char *op; /* output data ptr */
3823 char *origOp; /* original value of op */
3824 cm_space_t *spacep; /* for pathname buffer */
3835 maxCount = smb_GetSMBParm(inp, 0);
3837 dirListPatchesp = NULL;
3839 caseFold = CM_FLAG_CASEFOLD;
3841 tp = smb_GetSMBData(inp, NULL);
3842 pathp = smb_ParseASCIIBlock(tp, &tp);
3843 if (smb_StoreAnsiFilenames)
3844 OemToChar(pathp,pathp);
3845 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3847 /* bail out if request looks bad */
3848 if (!tp || !pathp) {
3849 return CM_ERROR_BADSMB;
3852 /* We can handle long names */
3853 if (vcp->flags & SMB_VCFLAG_USENT)
3854 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3856 /* make sure we got a whole search status */
3857 if (dataLength < 21) {
3858 nextCookie = 0; /* start at the beginning of the dir */
3861 attribute = smb_GetSMBParm(inp, 1);
3863 /* handle volume info in another function */
3864 if (attribute & 0x8)
3865 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3867 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3868 maxCount, osi_LogSaveString(smb_logp, pathp));
3870 if (*pathp == 0) { /* null pathp, treat as root dir */
3871 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3872 return CM_ERROR_NOFILES;
3876 dsp = smb_NewDirSearch(0);
3877 dsp->attribute = attribute;
3878 smb_Get8Dot3MaskFromPath(mask, pathp);
3879 memcpy(dsp->mask, mask, 11);
3881 /* track if this is likely to match a lot of entries */
3882 if (smb_IsStarMask(mask))
3887 /* pull the next cookie value out of the search status block */
3888 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3889 + (inCookiep[16]<<24);
3890 dsp = smb_FindDirSearch(inCookiep[12]);
3892 /* can't find dir search status; fatal error */
3893 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3894 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3895 return CM_ERROR_BADFD;
3897 attribute = dsp->attribute;
3898 resByte = inCookiep[0];
3900 /* copy out client cookie, in host byte order. Don't bother
3901 * interpreting it, since we're just passing it through, anyway.
3903 memcpy(&clientCookie, &inCookiep[17], 4);
3905 memcpy(mask, dsp->mask, 11);
3907 /* assume we're doing a star match if it has continued for more
3913 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3914 nextCookie, dsp->cookie, attribute);
3916 userp = smb_GetUserFromVCP(vcp, inp);
3918 /* try to get the vnode for the path name next */
3919 lock_ObtainMutex(&dsp->mx);
3922 osi_Log2(afsd_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3926 spacep = inp->spacep;
3927 smb_StripLastComponent(spacep->data, NULL, pathp);
3928 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3930 lock_ReleaseMutex(&dsp->mx);
3931 cm_ReleaseUser(userp);
3932 smb_DeleteDirSearch(dsp);
3933 smb_ReleaseDirSearch(dsp);
3934 return CM_ERROR_NOFILES;
3936 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3937 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3940 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3941 cm_ReleaseSCache(scp);
3942 lock_ReleaseMutex(&dsp->mx);
3943 cm_ReleaseUser(userp);
3944 smb_DeleteDirSearch(dsp);
3945 smb_ReleaseDirSearch(dsp);
3946 if ( WANTS_DFS_PATHNAMES(inp) )
3947 return CM_ERROR_PATH_NOT_COVERED;
3949 return CM_ERROR_BADSHARENAME;
3951 #endif /* DFS_SUPPORT */
3954 osi_Log2(afsd_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
3955 /* we need one hold for the entry we just stored into,
3956 * and one for our own processing. When we're done with this
3957 * function, we'll drop the one for our own processing.
3958 * We held it once from the namei call, and so we do another hold
3962 lock_ObtainMutex(&scp->mx);
3963 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3964 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3965 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3966 dsp->flags |= SMB_DIRSEARCH_BULKST;
3967 dsp->scp->bulkStatProgress = hzero;
3969 lock_ReleaseMutex(&scp->mx);
3972 lock_ReleaseMutex(&dsp->mx);
3974 cm_ReleaseUser(userp);
3975 smb_DeleteDirSearch(dsp);
3976 smb_ReleaseDirSearch(dsp);
3980 /* reserves space for parameter; we'll adjust it again later to the
3981 * real count of the # of entries we returned once we've actually
3982 * assembled the directory listing.
3984 smb_SetSMBParm(outp, 0, 0);
3986 /* get the directory size */
3987 lock_ObtainMutex(&scp->mx);
3988 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3989 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3991 lock_ReleaseMutex(&scp->mx);
3992 cm_ReleaseSCache(scp);
3993 cm_ReleaseUser(userp);
3994 smb_DeleteDirSearch(dsp);
3995 smb_ReleaseDirSearch(dsp);
3999 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4001 dirLength = scp->length;
4003 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4004 curOffset.HighPart = 0;
4005 curOffset.LowPart = nextCookie;
4006 origOp = op = smb_GetSMBData(outp, NULL);
4007 /* and write out the basic header */
4008 *op++ = 5; /* variable block */
4009 op += 2; /* skip vbl block length; we'll fill it in later */
4013 /* make sure that curOffset.LowPart doesn't point to the first
4014 * 32 bytes in the 2nd through last dir page, and that it doesn't
4015 * point at the first 13 32-byte chunks in the first dir page,
4016 * since those are dir and page headers, and don't contain useful
4019 temp = curOffset.LowPart & (2048-1);
4020 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4021 /* we're in the first page */
4022 if (temp < 13*32) temp = 13*32;
4025 /* we're in a later dir page */
4026 if (temp < 32) temp = 32;
4029 /* make sure the low order 5 bits are zero */
4032 /* now put temp bits back ito curOffset.LowPart */
4033 curOffset.LowPart &= ~(2048-1);
4034 curOffset.LowPart |= temp;
4036 /* check if we've returned all the names that will fit in the
4039 if (returnedNames >= maxCount) {
4040 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4041 returnedNames, maxCount);
4045 /* check if we've passed the dir's EOF */
4046 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4048 /* see if we can use the bufferp we have now; compute in which page
4049 * the current offset would be, and check whether that's the offset
4050 * of the buffer we have. If not, get the buffer.
4052 thyper.HighPart = curOffset.HighPart;
4053 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4054 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4057 buf_Release(bufferp);
4060 lock_ReleaseMutex(&scp->mx);
4061 lock_ObtainRead(&scp->bufCreateLock);
4062 code = buf_Get(scp, &thyper, &bufferp);
4063 lock_ReleaseRead(&scp->bufCreateLock);
4064 lock_ObtainMutex(&dsp->mx);
4066 /* now, if we're doing a star match, do bulk fetching of all of
4067 * the status info for files in the dir.
4070 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4071 lock_ObtainMutex(&scp->mx);
4072 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4073 LargeIntegerGreaterThanOrEqualTo(thyper,
4074 scp->bulkStatProgress)) {
4075 /* Don't bulk stat if risking timeout */
4076 int now = GetTickCount();
4077 if (now - req.startTime > RDRtimeout) {
4078 scp->bulkStatProgress = thyper;
4079 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4080 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4081 dsp->scp->bulkStatProgress = hzero;
4083 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4086 lock_ObtainMutex(&scp->mx);
4088 lock_ReleaseMutex(&dsp->mx);
4090 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4094 bufferOffset = thyper;
4096 /* now get the data in the cache */
4098 code = cm_SyncOp(scp, bufferp, userp, &req,
4100 CM_SCACHESYNC_NEEDCALLBACK |
4101 CM_SCACHESYNC_READ);
4103 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4107 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4109 if (cm_HaveBuffer(scp, bufferp, 0)) {
4110 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4114 /* otherwise, load the buffer and try again */
4115 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4117 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4118 scp, bufferp, code);
4123 buf_Release(bufferp);
4127 } /* if (wrong buffer) ... */
4129 /* now we have the buffer containing the entry we're interested in; copy
4130 * it out if it represents a non-deleted entry.
4132 entryInDir = curOffset.LowPart & (2048-1);
4133 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4135 /* page header will help tell us which entries are free. Page header
4136 * can change more often than once per buffer, since AFS 3 dir page size
4137 * may be less than (but not more than a buffer package buffer.
4139 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4140 temp &= ~(2048 - 1); /* turn off intra-page bits */
4141 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4143 /* now determine which entry we're looking at in the page. If it is
4144 * free (there's a free bitmap at the start of the dir), we should
4145 * skip these 32 bytes.
4147 slotInPage = (entryInDir & 0x7e0) >> 5;
4148 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4149 /* this entry is free */
4150 numDirChunks = 1; /* only skip this guy */
4154 tp = bufferp->datap + entryInBuffer;
4155 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4157 /* while we're here, compute the next entry's location, too,
4158 * since we'll need it when writing out the cookie into the dir
4161 * XXXX Probably should do more sanity checking.
4163 numDirChunks = cm_NameEntries(dep->name, NULL);
4165 /* compute the offset of the cookie representing the next entry */
4166 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4168 /* Compute 8.3 name if necessary */
4169 actualName = dep->name;
4170 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4171 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4172 actualName = shortName;
4175 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4176 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4177 osi_LogSaveString(smb_logp, actualName));
4179 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4180 /* this is one of the entries to use: it is not deleted
4181 * and it matches the star pattern we're looking for.
4184 /* Eliminate entries that don't match requested
4187 /* no hidden files */
4188 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4189 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4193 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4195 /* We have already done the cm_TryBulkStat above */
4196 fid.cell = scp->fid.cell;
4197 fid.volume = scp->fid.volume;
4198 fid.vnode = ntohl(dep->fid.vnode);
4199 fid.unique = ntohl(dep->fid.unique);
4200 fileType = cm_FindFileType(&fid);
4201 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4202 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4204 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4205 fileType == CM_SCACHETYPE_DFSLINK ||
4206 fileType == CM_SCACHETYPE_INVALID)
4207 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4212 memcpy(op, mask, 11); op += 11;
4213 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4214 *op++ = (char)(nextEntryCookie & 0xff);
4215 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4216 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4217 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4218 memcpy(op, &clientCookie, 4); op += 4;
4220 /* now we emit the attribute. This is sort of tricky,
4221 * since we need to really stat the file to find out
4222 * what type of entry we've got. Right now, we're
4223 * copying out data from a buffer, while holding the
4224 * scp locked, so it isn't really convenient to stat
4225 * something now. We'll put in a place holder now,
4226 * and make a second pass before returning this to get
4227 * the real attributes. So, we just skip the data for
4228 * now, and adjust it later. We allocate a patch
4229 * record to make it easy to find this point later.
4230 * The replay will happen at a time when it is safe to
4231 * unlock the directory.
4233 curPatchp = malloc(sizeof(*curPatchp));
4234 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4235 curPatchp->dptr = op;
4236 curPatchp->fid.cell = scp->fid.cell;
4237 curPatchp->fid.volume = scp->fid.volume;
4238 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4239 curPatchp->fid.unique = ntohl(dep->fid.unique);
4241 /* do hidden attribute here since name won't be around when applying
4245 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4246 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4248 curPatchp->flags = 0;
4250 op += 9; /* skip attr, time, date and size */
4252 /* zero out name area. The spec says to pad with
4253 * spaces, but Samba doesn't, and neither do we.
4257 /* finally, we get to copy out the name; we know that
4258 * it fits in 8.3 or the pattern wouldn't match, but it
4259 * never hurts to be sure.
4261 strncpy(op, actualName, 13);
4262 if (smb_StoreAnsiFilenames)
4265 /* Uppercase if requested by client */
4266 if (!KNOWS_LONG_NAMES(inp))
4271 /* now, adjust the # of entries copied */
4273 } /* if we're including this name */
4276 /* and adjust curOffset to be where the new cookie is */
4277 thyper.HighPart = 0;
4278 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4279 curOffset = LargeIntegerAdd(thyper, curOffset);
4280 } /* while copying data for dir listing */
4282 /* release the mutex */
4283 lock_ReleaseMutex(&scp->mx);
4285 buf_Release(bufferp);
4289 /* apply and free last set of patches; if not doing a star match, this
4290 * will be empty, but better safe (and freeing everything) than sorry.
4292 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4294 /* special return code for unsuccessful search */
4295 if (code == 0 && dataLength < 21 && returnedNames == 0)
4296 code = CM_ERROR_NOFILES;
4298 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4299 returnedNames, code);
4302 smb_DeleteDirSearch(dsp);
4303 smb_ReleaseDirSearch(dsp);
4304 cm_ReleaseSCache(scp);
4305 cm_ReleaseUser(userp);
4309 /* finalize the output buffer */
4310 smb_SetSMBParm(outp, 0, returnedNames);
4311 temp = (long) (op - origOp);
4312 smb_SetSMBDataLength(outp, temp);
4314 /* the data area is a variable block, which has a 5 (already there)
4315 * followed by the length of the # of data bytes. We now know this to
4316 * be "temp," although that includes the 3 bytes of vbl block header.
4317 * Deduct for them and fill in the length field.
4319 temp -= 3; /* deduct vbl block info */
4320 osi_assert(temp == (43 * returnedNames));
4321 origOp[1] = (char)(temp & 0xff);
4322 origOp[2] = (char)((temp>>8) & 0xff);
4323 if (returnedNames == 0)
4324 smb_DeleteDirSearch(dsp);
4325 smb_ReleaseDirSearch(dsp);
4326 cm_ReleaseSCache(scp);
4327 cm_ReleaseUser(userp);
4331 /* verify that this is a valid path to a directory. I don't know why they
4332 * don't use the get file attributes call.
4334 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4338 cm_scache_t *rootScp;
4339 cm_scache_t *newScp;
4348 pathp = smb_GetSMBData(inp, NULL);
4349 pathp = smb_ParseASCIIBlock(pathp, NULL);
4351 return CM_ERROR_BADFD;
4352 if (smb_StoreAnsiFilenames)
4353 OemToChar(pathp,pathp);
4354 osi_Log1(smb_logp, "SMB receive check path %s",
4355 osi_LogSaveString(smb_logp, pathp));
4357 rootScp = cm_data.rootSCachep;
4359 userp = smb_GetUserFromVCP(vcp, inp);
4361 caseFold = CM_FLAG_CASEFOLD;
4363 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4365 cm_ReleaseUser(userp);
4366 return CM_ERROR_NOSUCHPATH;
4368 code = cm_NameI(rootScp, pathp,
4369 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4370 userp, tidPathp, &req, &newScp);
4373 cm_ReleaseUser(userp);
4378 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4379 cm_ReleaseSCache(newScp);
4380 cm_ReleaseUser(userp);
4381 if ( WANTS_DFS_PATHNAMES(inp) )
4382 return CM_ERROR_PATH_NOT_COVERED;
4384 return CM_ERROR_BADSHARENAME;
4386 #endif /* DFS_SUPPORT */
4388 /* now lock the vnode with a callback; returns with newScp locked */
4389 lock_ObtainMutex(&newScp->mx);
4390 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4391 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4393 if (code != CM_ERROR_NOACCESS) {
4394 lock_ReleaseMutex(&newScp->mx);
4395 cm_ReleaseSCache(newScp);
4396 cm_ReleaseUser(userp);
4400 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4403 attrs = smb_Attributes(newScp);
4405 if (!(attrs & SMB_ATTR_DIRECTORY))
4406 code = CM_ERROR_NOTDIR;
4408 lock_ReleaseMutex(&newScp->mx);
4410 cm_ReleaseSCache(newScp);
4411 cm_ReleaseUser(userp);
4415 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4419 cm_scache_t *rootScp;
4420 unsigned short attribute;
4422 cm_scache_t *newScp;
4431 /* decode basic attributes we're passed */
4432 attribute = smb_GetSMBParm(inp, 0);
4433 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4435 pathp = smb_GetSMBData(inp, NULL);
4436 pathp = smb_ParseASCIIBlock(pathp, NULL);
4438 return CM_ERROR_BADSMB;
4439 if (smb_StoreAnsiFilenames)
4440 OemToChar(pathp,pathp);
4442 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4443 dosTime, attribute);
4445 rootScp = cm_data.rootSCachep;
4447 userp = smb_GetUserFromVCP(vcp, inp);
4449 caseFold = CM_FLAG_CASEFOLD;
4451 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4453 cm_ReleaseUser(userp);
4454 return CM_ERROR_NOSUCHFILE;
4456 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4457 tidPathp, &req, &newScp);
4460 cm_ReleaseUser(userp);
4465 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4466 cm_ReleaseSCache(newScp);
4467 cm_ReleaseUser(userp);
4468 if ( WANTS_DFS_PATHNAMES(inp) )
4469 return CM_ERROR_PATH_NOT_COVERED;
4471 return CM_ERROR_BADSHARENAME;
4473 #endif /* DFS_SUPPORT */
4475 /* now lock the vnode with a callback; returns with newScp locked; we
4476 * need the current status to determine what the new status is, in some
4479 lock_ObtainMutex(&newScp->mx);
4480 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4481 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4483 lock_ReleaseMutex(&newScp->mx);
4484 cm_ReleaseSCache(newScp);
4485 cm_ReleaseUser(userp);
4489 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4491 /* Check for RO volume */
4492 if (newScp->flags & CM_SCACHEFLAG_RO) {
4493 lock_ReleaseMutex(&newScp->mx);
4494 cm_ReleaseSCache(newScp);
4495 cm_ReleaseUser(userp);
4496 return CM_ERROR_READONLY;
4499 /* prepare for setattr call */
4502 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4503 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4505 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4506 /* we're told to make a writable file read-only */
4507 attr.unixModeBits = newScp->unixModeBits & ~0222;
4508 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4510 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4511 /* we're told to make a read-only file writable */
4512 attr.unixModeBits = newScp->unixModeBits | 0222;
4513 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4515 lock_ReleaseMutex(&newScp->mx);
4517 /* now call setattr */
4519 code = cm_SetAttr(newScp, &attr, userp, &req);
4523 cm_ReleaseSCache(newScp);
4524 cm_ReleaseUser(userp);
4529 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4533 cm_scache_t *rootScp;
4534 cm_scache_t *newScp, *dscp;
4546 pathp = smb_GetSMBData(inp, NULL);
4547 pathp = smb_ParseASCIIBlock(pathp, NULL);
4549 return CM_ERROR_BADSMB;
4551 if (*pathp == 0) /* null path */
4554 if (smb_StoreAnsiFilenames)
4555 OemToChar(pathp,pathp);
4557 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4558 osi_LogSaveString(smb_logp, pathp));
4560 rootScp = cm_data.rootSCachep;
4562 userp = smb_GetUserFromVCP(vcp, inp);
4564 /* we shouldn't need this for V3 requests, but we seem to */
4565 caseFold = CM_FLAG_CASEFOLD;
4567 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4569 cm_ReleaseUser(userp);
4570 return CM_ERROR_NOSUCHFILE;
4574 * XXX Strange hack XXX
4576 * As of Patch 5 (16 July 97), we are having the following problem:
4577 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4578 * requests to look up "desktop.ini" in all the subdirectories.
4579 * This can cause zillions of timeouts looking up non-existent cells
4580 * and volumes, especially in the top-level directory.
4582 * We have not found any way to avoid this or work around it except
4583 * to explicitly ignore the requests for mount points that haven't
4584 * yet been evaluated and for directories that haven't yet been
4587 * We should modify this hack to provide a fake desktop.ini file
4588 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4590 spacep = inp->spacep;
4591 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4592 #ifndef SPECIAL_FOLDERS
4593 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4594 code = cm_NameI(rootScp, spacep->data,
4595 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4596 userp, tidPathp, &req, &dscp);
4599 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4600 if ( WANTS_DFS_PATHNAMES(inp) )
4601 return CM_ERROR_PATH_NOT_COVERED;
4603 return CM_ERROR_BADSHARENAME;
4605 #endif /* DFS_SUPPORT */
4606 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4607 code = CM_ERROR_NOSUCHFILE;
4608 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4609 cm_buf_t *bp = buf_Find(dscp, &hzero);
4614 code = CM_ERROR_NOSUCHFILE;
4616 cm_ReleaseSCache(dscp);
4618 cm_ReleaseUser(userp);
4623 #endif /* SPECIAL_FOLDERS */
4625 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4626 tidPathp, &req, &newScp);
4628 cm_ReleaseUser(userp);
4633 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4634 cm_ReleaseSCache(newScp);
4635 cm_ReleaseUser(userp);
4636 if ( WANTS_DFS_PATHNAMES(inp) )
4637 return CM_ERROR_PATH_NOT_COVERED;
4639 return CM_ERROR_BADSHARENAME;
4641 #endif /* DFS_SUPPORT */
4643 /* now lock the vnode with a callback; returns with newScp locked */
4644 lock_ObtainMutex(&newScp->mx);
4645 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4646 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4648 lock_ReleaseMutex(&newScp->mx);
4649 cm_ReleaseSCache(newScp);
4650 cm_ReleaseUser(userp);
4654 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4657 /* use smb_Attributes instead. Also the fact that a file is
4658 * in a readonly volume doesn't mean it shojuld be marked as RO
4660 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4661 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4662 newScp->fileType == CM_SCACHETYPE_INVALID)
4663 attrs = SMB_ATTR_DIRECTORY;
4666 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4667 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4669 attrs = smb_Attributes(newScp);
4672 smb_SetSMBParm(outp, 0, attrs);
4674 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4675 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4676 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4677 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4678 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4679 smb_SetSMBParm(outp, 5, 0);
4680 smb_SetSMBParm(outp, 6, 0);
4681 smb_SetSMBParm(outp, 7, 0);
4682 smb_SetSMBParm(outp, 8, 0);
4683 smb_SetSMBParm(outp, 9, 0);
4684 smb_SetSMBDataLength(outp, 0);
4685 lock_ReleaseMutex(&newScp->mx);
4687 cm_ReleaseSCache(newScp);
4688 cm_ReleaseUser(userp);
4693 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4697 osi_Log0(smb_logp, "SMB receive tree disconnect");
4699 /* find the tree and free it */
4700 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4702 lock_ObtainWrite(&smb_rctLock);
4704 lock_ReleaseWrite(&smb_rctLock);
4705 smb_ReleaseTID(tidp);
4711 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4729 pathp = smb_GetSMBData(inp, NULL);
4730 pathp = smb_ParseASCIIBlock(pathp, NULL);
4731 if (smb_StoreAnsiFilenames)
4732 OemToChar(pathp,pathp);
4734 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4736 #ifdef DEBUG_VERBOSE
4740 hexpath = osi_HexifyString( pathp );
4741 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4746 share = smb_GetSMBParm(inp, 0);
4747 attribute = smb_GetSMBParm(inp, 1);
4749 spacep = inp->spacep;
4750 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4751 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4752 /* special case magic file name for receiving IOCTL requests
4753 * (since IOCTL calls themselves aren't getting through).
4755 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4756 smb_SetupIoctlFid(fidp, spacep);
4757 smb_SetSMBParm(outp, 0, fidp->fid);
4758 smb_SetSMBParm(outp, 1, 0); /* attrs */
4759 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4760 smb_SetSMBParm(outp, 3, 0);
4761 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4762 smb_SetSMBParm(outp, 5, 0x7fff);
4763 /* pass the open mode back */
4764 smb_SetSMBParm(outp, 6, (share & 0xf));
4765 smb_SetSMBDataLength(outp, 0);
4766 smb_ReleaseFID(fidp);
4770 userp = smb_GetUserFromVCP(vcp, inp);
4772 caseFold = CM_FLAG_CASEFOLD;
4774 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4776 cm_ReleaseUser(userp);
4777 return CM_ERROR_NOSUCHPATH;
4779 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4780 tidPathp, &req, &scp);
4783 cm_ReleaseUser(userp);
4788 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4789 cm_ReleaseSCache(scp);
4790 cm_ReleaseUser(userp);
4791 if ( WANTS_DFS_PATHNAMES(inp) )
4792 return CM_ERROR_PATH_NOT_COVERED;
4794 return CM_ERROR_BADSHARENAME;
4796 #endif /* DFS_SUPPORT */
4798 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4800 cm_ReleaseSCache(scp);
4801 cm_ReleaseUser(userp);
4805 /* don't need callback to check file type, since file types never
4806 * change, and namei and cm_Lookup all stat the object at least once on
4807 * a successful return.
4809 if (scp->fileType != CM_SCACHETYPE_FILE) {
4810 cm_ReleaseSCache(scp);
4811 cm_ReleaseUser(userp);
4812 return CM_ERROR_ISDIR;
4815 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4818 /* save a pointer to the vnode */
4820 osi_Log2(afsd_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4821 lock_ObtainMutex(&scp->mx);
4822 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4823 lock_ReleaseMutex(&scp->mx);
4827 fidp->userp = userp;
4829 lock_ObtainMutex(&fidp->mx);
4830 if ((share & 0xf) == 0)
4831 fidp->flags |= SMB_FID_OPENREAD;
4832 else if ((share & 0xf) == 1)
4833 fidp->flags |= SMB_FID_OPENWRITE;
4835 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4836 lock_ReleaseMutex(&fidp->mx);
4838 lock_ObtainMutex(&scp->mx);
4839 smb_SetSMBParm(outp, 0, fidp->fid);
4840 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4841 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4842 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4843 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4844 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4845 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4846 /* pass the open mode back; XXXX add access checks */
4847 smb_SetSMBParm(outp, 6, (share & 0xf));
4848 smb_SetSMBDataLength(outp, 0);
4849 lock_ReleaseMutex(&scp->mx);
4852 cm_Open(scp, 0, userp);
4854 /* send and free packet */
4855 smb_ReleaseFID(fidp);
4856 cm_ReleaseUser(userp);
4857 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4861 typedef struct smb_unlinkRock {
4866 char *maskp; /* pointer to the star pattern */
4871 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4874 smb_unlinkRock_t *rockp;
4882 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4883 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4884 caseFold |= CM_FLAG_8DOT3;
4886 matchName = dep->name;
4887 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4889 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4890 !cm_Is8Dot3(dep->name)) {
4891 cm_Gen8Dot3Name(dep, shortName, NULL);
4892 matchName = shortName;
4893 /* 8.3 matches are always case insensitive */
4894 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4897 osi_Log1(smb_logp, "Unlinking %s",
4898 osi_LogSaveString(smb_logp, matchName));
4899 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4900 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4901 smb_NotifyChange(FILE_ACTION_REMOVED,
4902 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
4903 dscp, dep->name, NULL, TRUE);
4907 /* If we made a case sensitive exact match, we might as well quit now. */
4908 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4909 code = CM_ERROR_STOPNOW;
4917 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4926 smb_unlinkRock_t rock;
4935 attribute = smb_GetSMBParm(inp, 0);
4937 tp = smb_GetSMBData(inp, NULL);
4938 pathp = smb_ParseASCIIBlock(tp, &tp);
4939 if (smb_StoreAnsiFilenames)
4940 OemToChar(pathp,pathp);
4942 osi_Log1(smb_logp, "SMB receive unlink %s",
4943 osi_LogSaveString(smb_logp, pathp));
4945 spacep = inp->spacep;
4946 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4948 userp = smb_GetUserFromVCP(vcp, inp);
4950 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4952 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4954 cm_ReleaseUser(userp);
4955 return CM_ERROR_NOSUCHPATH;
4957 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4960 cm_ReleaseUser(userp);
4965 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4966 cm_ReleaseSCache(dscp);
4967 cm_ReleaseUser(userp);
4968 if ( WANTS_DFS_PATHNAMES(inp) )
4969 return CM_ERROR_PATH_NOT_COVERED;
4971 return CM_ERROR_BADSHARENAME;
4973 #endif /* DFS_SUPPORT */
4975 /* otherwise, scp points to the parent directory. */
4982 rock.maskp = smb_FindMask(pathp);
4983 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4986 thyper.HighPart = 0;
4992 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4993 * match. If that fails, we do a case insensitve match.
4995 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4996 !smb_IsStarMask(rock.maskp)) {
4997 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5000 thyper.HighPart = 0;
5001 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5006 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5008 if (code == CM_ERROR_STOPNOW)
5011 cm_ReleaseUser(userp);
5013 cm_ReleaseSCache(dscp);
5015 if (code == 0 && !rock.any)
5016 code = CM_ERROR_NOSUCHFILE;
5020 typedef struct smb_renameRock {
5021 cm_scache_t *odscp; /* old dir */
5022 cm_scache_t *ndscp; /* new dir */
5023 cm_user_t *userp; /* user */
5024 cm_req_t *reqp; /* request struct */
5025 smb_vc_t *vcp; /* virtual circuit */
5026 char *maskp; /* pointer to star pattern of old file name */
5027 int flags; /* tilde, casefold, etc */
5028 char *newNamep; /* ptr to the new file's name */
5032 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5035 smb_renameRock_t *rockp;
5038 char shortName[13]="";
5040 rockp = (smb_renameRock_t *) vrockp;
5042 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5043 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5044 caseFold |= CM_FLAG_8DOT3;
5046 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5048 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5049 !cm_Is8Dot3(dep->name)) {
5050 cm_Gen8Dot3Name(dep, shortName, NULL);
5051 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5056 code = cm_Rename(rockp->odscp, dep->name,
5057 rockp->ndscp, rockp->newNamep, rockp->userp,
5059 /* if the call worked, stop doing the search now, since we
5060 * really only want to rename one file.
5062 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5064 code = CM_ERROR_STOPNOW;
5074 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5077 cm_space_t *spacep = NULL;
5078 smb_renameRock_t rock;
5079 cm_scache_t *oldDscp = NULL;
5080 cm_scache_t *newDscp = NULL;
5081 cm_scache_t *tmpscp= NULL;
5082 cm_scache_t *tmpscp2 = NULL;
5092 userp = smb_GetUserFromVCP(vcp, inp);
5093 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5095 cm_ReleaseUser(userp);
5096 return CM_ERROR_NOSUCHPATH;
5100 spacep = inp->spacep;
5101 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5103 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5104 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5105 userp, tidPathp, &req, &oldDscp);
5107 cm_ReleaseUser(userp);
5112 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5113 cm_ReleaseSCache(oldDscp);
5114 cm_ReleaseUser(userp);
5115 if ( WANTS_DFS_PATHNAMES(inp) )
5116 return CM_ERROR_PATH_NOT_COVERED;
5118 return CM_ERROR_BADSHARENAME;
5120 #endif /* DFS_SUPPORT */
5122 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5123 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5124 userp, tidPathp, &req, &newDscp);
5127 cm_ReleaseSCache(oldDscp);
5128 cm_ReleaseUser(userp);
5133 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5134 cm_ReleaseSCache(oldDscp);
5135 cm_ReleaseSCache(newDscp);
5136 cm_ReleaseUser(userp);
5137 if ( WANTS_DFS_PATHNAMES(inp) )
5138 return CM_ERROR_PATH_NOT_COVERED;
5140 return CM_ERROR_BADSHARENAME;
5142 #endif /* DFS_SUPPORT */
5145 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5146 * next, get the component names, and lower case them.
5149 /* handle the old name first */
5151 oldLastNamep = oldPathp;
5155 /* and handle the new name, too */
5157 newLastNamep = newPathp;
5161 /* TODO: The old name could be a wildcard. The new name must not be */
5163 /* do the vnode call */
5164 rock.odscp = oldDscp;
5165 rock.ndscp = newDscp;
5169 rock.maskp = oldLastNamep;
5170 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5171 rock.newNamep = newLastNamep;
5174 /* Check if the file already exists; if so return error */
5175 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5176 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5177 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5178 osi_LogSaveString(afsd_logp, newLastNamep));
5180 /* Check if the old and the new names differ only in case. If so return
5181 * success, else return CM_ERROR_EXISTS
5183 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5185 /* This would be a success only if the old file is *as same as* the new file */
5186 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5188 if (tmpscp == tmpscp2)
5191 code = CM_ERROR_EXISTS;
5192 cm_ReleaseSCache(tmpscp2);
5195 code = CM_ERROR_NOSUCHFILE;
5198 /* file exist, do not rename, also fixes move */
5199 osi_Log0(smb_logp, "Can't rename. Target already exists");
5200 code = CM_ERROR_EXISTS;
5204 cm_ReleaseSCache(tmpscp);
5205 cm_ReleaseSCache(newDscp);
5206 cm_ReleaseSCache(oldDscp);
5207 cm_ReleaseUser(userp);
5211 /* Now search the directory for the pattern, and do the appropriate rename when found */
5212 thyper.LowPart = 0; /* search dir from here */
5213 thyper.HighPart = 0;
5215 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5216 if (code == 0 && !rock.any) {
5218 thyper.HighPart = 0;
5219 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5220 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5222 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5224 if (code == CM_ERROR_STOPNOW)
5227 code = CM_ERROR_NOSUCHFILE;
5229 /* Handle Change Notification */
5231 * Being lazy, not distinguishing between files and dirs in this
5232 * filter, since we'd have to do a lookup.
5234 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5235 if (oldDscp == newDscp) {
5236 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5237 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5238 filter, oldDscp, oldLastNamep,
5239 newLastNamep, TRUE);
5241 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5242 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5243 filter, oldDscp, oldLastNamep,
5245 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5246 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5247 filter, newDscp, newLastNamep,
5252 cm_ReleaseSCache(tmpscp);
5253 cm_ReleaseUser(userp);
5254 cm_ReleaseSCache(oldDscp);
5255 cm_ReleaseSCache(newDscp);
5260 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5263 cm_space_t *spacep = NULL;
5264 cm_scache_t *oldDscp = NULL;
5265 cm_scache_t *newDscp = NULL;
5266 cm_scache_t *tmpscp= NULL;
5267 cm_scache_t *tmpscp2 = NULL;
5268 cm_scache_t *sscp = NULL;
5277 userp = smb_GetUserFromVCP(vcp, inp);
5279 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5281 cm_ReleaseUser(userp);
5282 return CM_ERROR_NOSUCHPATH;
5287 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5289 spacep = inp->spacep;
5290 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5292 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5293 userp, tidPathp, &req, &oldDscp);
5295 cm_ReleaseUser(userp);
5300 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5301 cm_ReleaseSCache(oldDscp);
5302 cm_ReleaseUser(userp);
5303 if ( WANTS_DFS_PATHNAMES(inp) )
5304 return CM_ERROR_PATH_NOT_COVERED;
5306 return CM_ERROR_BADSHARENAME;
5308 #endif /* DFS_SUPPORT */
5310 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5311 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5312 userp, tidPathp, &req, &newDscp);
5314 cm_ReleaseSCache(oldDscp);
5315 cm_ReleaseUser(userp);
5320 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5321 cm_ReleaseSCache(newDscp);
5322 cm_ReleaseSCache(oldDscp);
5323 cm_ReleaseUser(userp);
5324 if ( WANTS_DFS_PATHNAMES(inp) )
5325 return CM_ERROR_PATH_NOT_COVERED;
5327 return CM_ERROR_BADSHARENAME;
5329 #endif /* DFS_SUPPORT */
5331 /* Now, although we did two lookups for the two directories (because the same
5332 * directory can be referenced through different paths), we only allow hard links
5333 * within the same directory. */
5334 if (oldDscp != newDscp) {
5335 cm_ReleaseSCache(oldDscp);
5336 cm_ReleaseSCache(newDscp);
5337 cm_ReleaseUser(userp);
5338 return CM_ERROR_CROSSDEVLINK;
5341 /* handle the old name first */
5343 oldLastNamep = oldPathp;
5347 /* and handle the new name, too */
5349 newLastNamep = newPathp;
5353 /* now lookup the old name */
5354 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5355 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5357 cm_ReleaseSCache(oldDscp);
5358 cm_ReleaseSCache(newDscp);
5359 cm_ReleaseUser(userp);
5363 /* Check if the file already exists; if so return error */
5364 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5365 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5366 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5367 osi_LogSaveString(afsd_logp, newLastNamep));
5369 /* if the existing link is to the same file, then we return success */
5371 if(sscp == tmpscp) {
5374 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5375 code = CM_ERROR_EXISTS;
5380 cm_ReleaseSCache(tmpscp);
5381 cm_ReleaseSCache(sscp);
5382 cm_ReleaseSCache(newDscp);
5383 cm_ReleaseSCache(oldDscp);
5384 cm_ReleaseUser(userp);
5388 /* now create the hardlink */
5389 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5390 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5391 osi_Log1(smb_logp," Link returns 0x%x", code);
5393 /* Handle Change Notification */
5395 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5396 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5397 smb_NotifyChange(FILE_ACTION_ADDED,
5398 filter, newDscp, newLastNamep,
5403 cm_ReleaseSCache(tmpscp);
5404 cm_ReleaseUser(userp);
5405 cm_ReleaseSCache(sscp);
5406 cm_ReleaseSCache(oldDscp);
5407 cm_ReleaseSCache(newDscp);
5412 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5419 tp = smb_GetSMBData(inp, NULL);
5420 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5421 if (smb_StoreAnsiFilenames)
5422 OemToChar(oldPathp,oldPathp);
5423 newPathp = smb_ParseASCIIBlock(tp, &tp);
5424 if (smb_StoreAnsiFilenames)
5425 OemToChar(newPathp,newPathp);
5427 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5428 osi_LogSaveString(smb_logp, oldPathp),
5429 osi_LogSaveString(smb_logp, newPathp));
5431 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5433 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5439 typedef struct smb_rmdirRock {
5443 char *maskp; /* pointer to the star pattern */
5448 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5451 smb_rmdirRock_t *rockp;
5456 rockp = (smb_rmdirRock_t *) vrockp;
5458 matchName = dep->name;
5459 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5460 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5462 match = (strcmp(matchName, rockp->maskp) == 0);
5464 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5465 !cm_Is8Dot3(dep->name)) {
5466 cm_Gen8Dot3Name(dep, shortName, NULL);
5467 matchName = shortName;
5468 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5471 osi_Log1(smb_logp, "Removing directory %s",
5472 osi_LogSaveString(smb_logp, matchName));
5473 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5474 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5475 smb_NotifyChange(FILE_ACTION_REMOVED,
5476 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5477 dscp, dep->name, NULL, TRUE);
5486 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5494 smb_rmdirRock_t rock;
5503 tp = smb_GetSMBData(inp, NULL);
5504 pathp = smb_ParseASCIIBlock(tp, &tp);
5505 if (smb_StoreAnsiFilenames)
5506 OemToChar(pathp,pathp);
5508 spacep = inp->spacep;
5509 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5511 userp = smb_GetUserFromVCP(vcp, inp);
5513 caseFold = CM_FLAG_CASEFOLD;
5515 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5517 cm_ReleaseUser(userp);
5518 return CM_ERROR_NOSUCHPATH;
5520 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5521 userp, tidPathp, &req, &dscp);
5524 cm_ReleaseUser(userp);
5529 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5530 cm_ReleaseSCache(dscp);
5531 cm_ReleaseUser(userp);
5532 if ( WANTS_DFS_PATHNAMES(inp) )
5533 return CM_ERROR_PATH_NOT_COVERED;
5535 return CM_ERROR_BADSHARENAME;
5537 #endif /* DFS_SUPPORT */
5539 /* otherwise, scp points to the parent directory. */
5546 rock.maskp = lastNamep;
5547 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5550 thyper.HighPart = 0;
5555 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5556 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5557 if (code == 0 && !rock.any) {
5559 thyper.HighPart = 0;
5560 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5561 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5564 cm_ReleaseUser(userp);
5566 cm_ReleaseSCache(dscp);
5568 if (code == 0 && !rock.any)
5569 code = CM_ERROR_NOSUCHFILE;
5573 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5583 fid = smb_GetSMBParm(inp, 0);
5585 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5587 fid = smb_ChainFID(fid, inp);
5588 fidp = smb_FindFID(vcp, fid, 0);
5590 return CM_ERROR_BADFD;
5592 lock_ObtainMutex(&fidp->mx);
5593 if (fidp->flags & SMB_FID_IOCTL) {
5594 lock_ReleaseMutex(&fidp->mx);
5595 smb_ReleaseFID(fidp);
5596 return CM_ERROR_BADFD;
5598 lock_ReleaseMutex(&fidp->mx);
5600 userp = smb_GetUserFromVCP(vcp, inp);
5602 lock_ObtainMutex(&fidp->mx);
5603 if (fidp->flags & SMB_FID_OPENWRITE) {
5604 cm_scache_t * scp = fidp->scp;
5606 lock_ReleaseMutex(&fidp->mx);
5607 code = cm_FSync(scp, userp, &req);
5608 cm_ReleaseSCache(scp);
5611 lock_ReleaseMutex(&fidp->mx);
5614 smb_ReleaseFID(fidp);
5616 cm_ReleaseUser(userp);
5621 struct smb_FullNameRock {
5627 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5631 struct smb_FullNameRock *vrockp;
5633 vrockp = (struct smb_FullNameRock *)rockp;
5635 if (!cm_Is8Dot3(dep->name)) {
5636 cm_Gen8Dot3Name(dep, shortName, NULL);
5638 if (cm_stricmp(shortName, vrockp->name) == 0) {
5639 vrockp->fullName = strdup(dep->name);
5640 return CM_ERROR_STOPNOW;
5643 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5644 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5645 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5646 vrockp->fullName = strdup(dep->name);
5647 return CM_ERROR_STOPNOW;
5652 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5653 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5655 struct smb_FullNameRock rock;
5661 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5662 if (code == CM_ERROR_STOPNOW)
5663 *newPathp = rock.fullName;
5665 *newPathp = strdup(pathp);
5668 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5669 afs_uint32 dosTime) {
5672 cm_scache_t *dscp = NULL;
5674 cm_scache_t * scp = NULL;
5676 int nullcreator = 0;
5678 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5679 fidp, fidp->fid, scp, vcp);
5682 lock_ObtainMutex(&fidp->mx);
5683 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5684 lock_ReleaseMutex(&fidp->mx);
5685 osi_Log0(smb_logp, " No user specified. Not closing fid");
5686 return CM_ERROR_BADFD;
5689 userp = fidp->userp; /* no hold required since fidp is held
5690 throughout the function */
5691 lock_ReleaseMutex(&fidp->mx);
5696 lock_ObtainWrite(&smb_rctLock);
5698 osi_Log0(smb_logp, " Fid already closed.");
5699 lock_ReleaseWrite(&smb_rctLock);
5700 return CM_ERROR_BADFD;
5703 lock_ReleaseWrite(&smb_rctLock);
5705 lock_ObtainMutex(&fidp->mx);
5706 if (fidp->NTopen_dscp) {
5707 dscp = fidp->NTopen_dscp;
5708 cm_HoldSCache(dscp);
5711 if (fidp->NTopen_pathp) {
5712 pathp = strdup(fidp->NTopen_pathp);
5720 /* Don't jump the gun on an async raw write */
5721 while (fidp->raw_writers) {
5722 lock_ReleaseMutex(&fidp->mx);
5723 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5724 lock_ObtainMutex(&fidp->mx);
5727 /* watch for ioctl closes, and read-only opens */
5729 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5730 == SMB_FID_OPENWRITE) {
5731 if (dosTime != 0 && dosTime != -1) {
5732 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5733 /* This fixes defect 10958 */
5734 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5735 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5737 lock_ReleaseMutex(&fidp->mx);
5738 code = cm_FSync(scp, userp, &req);
5739 lock_ObtainMutex(&fidp->mx);
5744 /* unlock any pending locks */
5745 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5746 scp->fileType == CM_SCACHETYPE_FILE) {
5750 lock_ReleaseMutex(&fidp->mx);
5752 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5754 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5755 lock_ObtainMutex(&scp->mx);
5757 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5758 CM_SCACHESYNC_NEEDCALLBACK
5759 | CM_SCACHESYNC_GETSTATUS
5760 | CM_SCACHESYNC_LOCK);
5764 "smb CoreClose SyncOp failure code 0x%x", tcode);
5765 goto post_syncopdone;
5768 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5770 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5774 lock_ReleaseMutex(&scp->mx);
5775 lock_ObtainMutex(&fidp->mx);
5778 if (fidp->flags & SMB_FID_DELONCLOSE) {
5781 lock_ReleaseMutex(&fidp->mx);
5782 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5783 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5784 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5787 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5788 smb_NotifyChange(FILE_ACTION_REMOVED,
5789 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5790 dscp, fullPathp, NULL, TRUE);
5793 code = cm_Unlink(dscp, fullPathp, userp, &req);
5796 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5797 smb_NotifyChange(FILE_ACTION_REMOVED,
5798 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5799 dscp, fullPathp, NULL, TRUE);
5803 lock_ObtainMutex(&fidp->mx);
5804 fidp->flags &= ~SMB_FID_DELONCLOSE;
5807 /* if this was a newly created file, then clear the creator
5808 * in the stat cache entry. */
5809 if (fidp->flags & SMB_FID_CREATED) {
5811 fidp->flags &= ~SMB_FID_CREATED;
5814 if (fidp->flags & SMB_FID_NTOPEN) {
5815 cm_ReleaseSCache(fidp->NTopen_dscp);
5816 fidp->NTopen_dscp = NULL;
5817 free(fidp->NTopen_pathp);
5818 fidp->NTopen_pathp = NULL;
5819 fidp->flags &= ~SMB_FID_NTOPEN;
5821 osi_assert(fidp->NTopen_dscp == NULL);
5822 osi_assert(fidp->NTopen_pathp == NULL);
5825 if (fidp->NTopen_wholepathp) {
5826 free(fidp->NTopen_wholepathp);
5827 fidp->NTopen_wholepathp = NULL;
5831 cm_ReleaseSCache(fidp->scp);
5834 lock_ReleaseMutex(&fidp->mx);
5837 cm_ReleaseSCache(dscp);
5840 if (deleted || nullcreator) {
5841 lock_ObtainMutex(&scp->mx);
5842 if (nullcreator && scp->creator == userp)
5843 scp->creator = NULL;
5845 scp->flags |= CM_SCACHEFLAG_DELETED;
5846 lock_ReleaseMutex(&scp->mx);
5848 lock_ObtainMutex(&scp->mx);
5849 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5850 lock_ReleaseMutex(&scp->mx);
5851 cm_ReleaseSCache(scp);
5860 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5868 fid = smb_GetSMBParm(inp, 0);
5869 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5871 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5873 fid = smb_ChainFID(fid, inp);
5874 fidp = smb_FindFID(vcp, fid, 0);
5876 return CM_ERROR_BADFD;
5879 userp = smb_GetUserFromVCP(vcp, inp);
5881 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5883 smb_ReleaseFID(fidp);
5884 cm_ReleaseUser(userp);
5889 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5891 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5892 cm_user_t *userp, long *readp)
5898 osi_hyper_t fileLength;
5900 osi_hyper_t lastByte;
5901 osi_hyper_t bufferOffset;
5902 long bufIndex, nbytes;
5904 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
5912 lock_ObtainMutex(&fidp->mx);
5915 lock_ObtainMutex(&scp->mx);
5917 if (offset.HighPart == 0) {
5918 chunk = offset.LowPart >> cm_logChunkSize;
5919 if (chunk != fidp->curr_chunk) {
5920 fidp->prev_chunk = fidp->curr_chunk;
5921 fidp->curr_chunk = chunk;
5923 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
5926 lock_ReleaseMutex(&fidp->mx);
5928 /* start by looking up the file's end */
5929 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5930 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5934 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5936 /* now we have the entry locked, look up the length */
5937 fileLength = scp->length;
5939 /* adjust count down so that it won't go past EOF */
5940 thyper.LowPart = count;
5941 thyper.HighPart = 0;
5942 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5944 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5945 /* we'd read past EOF, so just stop at fileLength bytes.
5946 * Start by computing how many bytes remain in the file.
5948 thyper = LargeIntegerSubtract(fileLength, offset);
5950 /* if we are past EOF, read 0 bytes */
5951 if (LargeIntegerLessThanZero(thyper))
5954 count = thyper.LowPart;
5959 /* now, copy the data one buffer at a time,
5960 * until we've filled the request packet
5963 /* if we've copied all the data requested, we're done */
5964 if (count <= 0) break;
5966 /* otherwise, load up a buffer of data */
5967 thyper.HighPart = offset.HighPart;
5968 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5969 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5972 buf_Release(bufferp);
5975 lock_ReleaseMutex(&scp->mx);
5977 lock_ObtainRead(&scp->bufCreateLock);
5978 code = buf_Get(scp, &thyper, &bufferp);
5979 lock_ReleaseRead(&scp->bufCreateLock);
5981 lock_ObtainMutex(&scp->mx);
5982 if (code) goto done;
5983 bufferOffset = thyper;
5985 /* now get the data in the cache */
5987 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5988 CM_SCACHESYNC_NEEDCALLBACK |
5989 CM_SCACHESYNC_READ);
5993 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5995 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5997 /* otherwise, load the buffer and try again */
5998 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6002 buf_Release(bufferp);
6006 } /* if (wrong buffer) ... */
6008 /* now we have the right buffer loaded. Copy out the
6009 * data from here to the user's buffer.
6011 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6013 /* and figure out how many bytes we want from this buffer */
6014 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6015 if (nbytes > count) nbytes = count; /* don't go past EOF */
6017 /* now copy the data */
6018 memcpy(op, bufferp->datap + bufIndex, nbytes);
6020 /* adjust counters, pointers, etc. */
6023 thyper.LowPart = nbytes;
6024 thyper.HighPart = 0;
6025 offset = LargeIntegerAdd(thyper, offset);
6029 lock_ReleaseMutex(&scp->mx);
6031 buf_Release(bufferp);
6033 if (code == 0 && sequential)
6034 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6036 cm_ReleaseSCache(scp);
6042 * smb_WriteData -- common code for Write and Raw Write
6044 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6045 cm_user_t *userp, long *writtenp)
6051 osi_hyper_t fileLength; /* file's length at start of write */
6052 osi_hyper_t minLength; /* don't read past this */
6053 long nbytes; /* # of bytes to transfer this iteration */
6055 osi_hyper_t thyper; /* hyper tmp variable */
6056 osi_hyper_t bufferOffset;
6057 long bufIndex; /* index in buffer where our data is */
6059 osi_hyper_t writeBackOffset;/* offset of region to write back when
6064 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6065 fidp->fid, offsetp->LowPart, count);
6075 lock_ObtainMutex(&fidp->mx);
6076 /* make sure we have a writable FD */
6077 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6078 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6079 fidp->fid, fidp->flags);
6080 lock_ReleaseMutex(&fidp->mx);
6081 code = CM_ERROR_BADFDOP;
6087 lock_ReleaseMutex(&fidp->mx);
6089 lock_ObtainMutex(&scp->mx);
6090 /* start by looking up the file's end */
6091 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6092 CM_SCACHESYNC_NEEDCALLBACK
6093 | CM_SCACHESYNC_SETSTATUS
6094 | CM_SCACHESYNC_GETSTATUS);
6098 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6100 /* now we have the entry locked, look up the length */
6101 fileLength = scp->length;
6102 minLength = fileLength;
6103 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6104 minLength = scp->serverLength;
6106 /* adjust file length if we extend past EOF */
6107 thyper.LowPart = count;
6108 thyper.HighPart = 0;
6109 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6110 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6111 /* we'd write past EOF, so extend the file */
6112 scp->mask |= CM_SCACHEMASK_LENGTH;
6113 scp->length = thyper;
6114 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6116 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6118 /* now, if the new position (thyper) and the old (offset) are in
6119 * different storeback windows, remember to store back the previous
6120 * storeback window when we're done with the write.
6122 if ((thyper.LowPart & (-cm_chunkSize)) !=
6123 (offset.LowPart & (-cm_chunkSize))) {
6124 /* they're different */
6126 writeBackOffset.HighPart = offset.HighPart;
6127 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6132 /* now, copy the data one buffer at a time, until we've filled the
6135 /* if we've copied all the data requested, we're done */
6139 /* handle over quota or out of space */
6140 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6141 *writtenp = written;
6142 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6146 /* otherwise, load up a buffer of data */
6147 thyper.HighPart = offset.HighPart;
6148 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6149 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6152 lock_ReleaseMutex(&bufferp->mx);
6153 buf_Release(bufferp);
6156 lock_ReleaseMutex(&scp->mx);
6158 lock_ObtainRead(&scp->bufCreateLock);
6159 code = buf_Get(scp, &thyper, &bufferp);
6160 lock_ReleaseRead(&scp->bufCreateLock);
6162 lock_ObtainMutex(&bufferp->mx);
6163 lock_ObtainMutex(&scp->mx);
6164 if (code) goto done;
6166 bufferOffset = thyper;
6168 /* now get the data in the cache */
6170 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6171 CM_SCACHESYNC_NEEDCALLBACK
6172 | CM_SCACHESYNC_WRITE
6173 | CM_SCACHESYNC_BUFLOCKED);
6177 cm_SyncOpDone(scp, bufferp,
6178 CM_SCACHESYNC_NEEDCALLBACK
6179 | CM_SCACHESYNC_WRITE
6180 | CM_SCACHESYNC_BUFLOCKED);
6182 /* If we're overwriting the entire buffer, or
6183 * if we're writing at or past EOF, mark the
6184 * buffer as current so we don't call
6185 * cm_GetBuffer. This skips the fetch from the
6186 * server in those cases where we're going to
6187 * obliterate all the data in the buffer anyway,
6188 * or in those cases where there is no useful
6189 * data at the server to start with.
6191 * Use minLength instead of scp->length, since
6192 * the latter has already been updated by this
6195 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6196 || LargeIntegerEqualTo(offset, bufferp->offset)
6197 && (count >= cm_data.buf_blockSize
6198 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6199 ConvertLongToLargeInteger(count)),
6201 if (count < cm_data.buf_blockSize
6202 && bufferp->dataVersion == -1)
6203 memset(bufferp->datap, 0,
6204 cm_data.buf_blockSize);
6205 bufferp->dataVersion = scp->dataVersion;
6208 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6210 /* otherwise, load the buffer and try again */
6211 lock_ReleaseMutex(&bufferp->mx);
6212 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6214 lock_ReleaseMutex(&scp->mx);
6215 lock_ObtainMutex(&bufferp->mx);
6216 lock_ObtainMutex(&scp->mx);
6220 lock_ReleaseMutex(&bufferp->mx);
6221 buf_Release(bufferp);
6225 } /* if (wrong buffer) ... */
6227 /* now we have the right buffer loaded. Copy out the
6228 * data from here to the user's buffer.
6230 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6232 /* and figure out how many bytes we want from this buffer */
6233 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6235 nbytes = count; /* don't go past end of request */
6237 /* now copy the data */
6238 memcpy(bufferp->datap + bufIndex, op, nbytes);
6239 buf_SetDirty(bufferp);
6241 /* and record the last writer */
6242 if (bufferp->userp != userp) {
6245 cm_ReleaseUser(bufferp->userp);
6246 bufferp->userp = userp;
6249 /* adjust counters, pointers, etc. */
6253 thyper.LowPart = nbytes;
6254 thyper.HighPart = 0;
6255 offset = LargeIntegerAdd(thyper, offset);
6259 lock_ReleaseMutex(&scp->mx);
6262 lock_ReleaseMutex(&bufferp->mx);
6263 buf_Release(bufferp);
6266 lock_ObtainMutex(&fidp->mx);
6267 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6268 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6269 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6270 fidp->NTopen_dscp, fidp->NTopen_pathp,
6273 lock_ReleaseMutex(&fidp->mx);
6275 if (code == 0 && doWriteBack) {
6277 lock_ObtainMutex(&scp->mx);
6278 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6280 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6281 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6283 lock_ReleaseMutex(&scp->mx);
6284 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6285 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6286 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6289 cm_ReleaseSCache(scp);
6291 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6292 fidp->fid, code, *writtenp);
6296 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6299 unsigned short count;
6301 unsigned short hint;
6302 long written = 0, total_written = 0;
6307 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6309 int inDataBlockCount;
6311 fd = smb_GetSMBParm(inp, 0);
6312 count = smb_GetSMBParm(inp, 1);
6313 offset.HighPart = 0; /* too bad */
6314 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6315 hint = smb_GetSMBParm(inp, 4);
6317 op = smb_GetSMBData(inp, NULL);
6318 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6320 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6321 fd, offset.LowPart, count);
6323 fd = smb_ChainFID(fd, inp);
6324 fidp = smb_FindFID(vcp, fd, 0);
6326 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6327 return CM_ERROR_BADFD;
6330 lock_ObtainMutex(&fidp->mx);
6331 if (fidp->flags & SMB_FID_IOCTL) {
6332 lock_ReleaseMutex(&fidp->mx);
6333 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6334 smb_ReleaseFID(fidp);
6335 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6338 lock_ReleaseMutex(&fidp->mx);
6339 userp = smb_GetUserFromVCP(vcp, inp);
6343 LARGE_INTEGER LOffset;
6344 LARGE_INTEGER LLength;
6346 pid = ((smb_t *) inp)->pid;
6347 key = cm_GenerateKey(vcp->vcID, pid, fd);
6349 LOffset.HighPart = offset.HighPart;
6350 LOffset.LowPart = offset.LowPart;
6351 LLength.HighPart = 0;
6352 LLength.LowPart = count;
6354 lock_ObtainMutex(&fidp->scp->mx);
6355 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6356 lock_ReleaseMutex(&fidp->scp->mx);
6359 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6364 /* special case: 0 bytes transferred means truncate to this position */
6368 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6372 truncAttr.mask = CM_ATTRMASK_LENGTH;
6373 truncAttr.length.LowPart = offset.LowPart;
6374 truncAttr.length.HighPart = 0;
6375 lock_ObtainMutex(&fidp->mx);
6376 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6377 fidp->flags |= SMB_FID_LENGTHSETDONE;
6378 lock_ReleaseMutex(&fidp->mx);
6379 smb_SetSMBParm(outp, 0, 0 /* count */);
6380 smb_SetSMBDataLength(outp, 0);
6385 * Work around bug in NT client
6387 * When copying a file, the NT client should first copy the data,
6388 * then copy the last write time. But sometimes the NT client does
6389 * these in the wrong order, so the data copies would inadvertently
6390 * cause the last write time to be overwritten. We try to detect this,
6391 * and don't set client mod time if we think that would go against the
6394 lock_ObtainMutex(&fidp->mx);
6395 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6396 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6397 fidp->scp->clientModTime = time(NULL);
6399 lock_ReleaseMutex(&fidp->mx);
6402 while ( code == 0 && count > 0 ) {
6403 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6404 if (code == 0 && written == 0)
6405 code = CM_ERROR_PARTIALWRITE;
6407 offset = LargeIntegerAdd(offset,
6408 ConvertLongToLargeInteger(written));
6410 total_written += written;
6414 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6415 total_written, code);
6417 /* set the packet data length to 3 bytes for the data block header,
6418 * plus the size of the data.
6420 smb_SetSMBParm(outp, 0, total_written);
6421 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6422 smb_SetSMBParm(outp, 3, hint);
6423 smb_SetSMBDataLength(outp, 0);
6426 smb_ReleaseFID(fidp);
6427 cm_ReleaseUser(userp);
6432 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6433 NCB *ncbp, raw_write_cont_t *rwcp)
6442 fd = smb_GetSMBParm(inp, 0);
6443 fidp = smb_FindFID(vcp, fd, 0);
6445 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6446 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6448 userp = smb_GetUserFromVCP(vcp, inp);
6451 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6453 if (rwcp->writeMode & 0x1) { /* synchronous */
6456 smb_FormatResponsePacket(vcp, inp, outp);
6457 op = (smb_t *) outp;
6458 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6459 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6460 smb_SetSMBDataLength(outp, 0);
6461 smb_SendPacket(vcp, outp);
6462 smb_FreePacket(outp);
6464 else { /* asynchronous */
6465 lock_ObtainMutex(&fidp->mx);
6466 fidp->raw_writers--;
6467 if (fidp->raw_writers == 0)
6468 thrd_SetEvent(fidp->raw_write_event);
6469 lock_ReleaseMutex(&fidp->mx);
6472 /* Give back raw buffer */
6473 lock_ObtainMutex(&smb_RawBufLock);
6474 *((char **)rawBuf) = smb_RawBufs;
6475 smb_RawBufs = rawBuf;
6476 lock_ReleaseMutex(&smb_RawBufLock);
6478 smb_ReleaseFID(fidp);
6479 cm_ReleaseUser(userp);
6482 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6487 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6490 long count, written = 0, total_written = 0;
6497 unsigned short writeMode;
6499 fd = smb_GetSMBParm(inp, 0);
6500 totalCount = smb_GetSMBParm(inp, 1);
6501 count = smb_GetSMBParm(inp, 10);
6502 writeMode = smb_GetSMBParm(inp, 7);
6504 op = (char *) inp->data;
6505 op += smb_GetSMBParm(inp, 11);
6507 offset.HighPart = 0;
6508 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6510 if (*inp->wctp == 14) {
6511 /* we received a 64-bit file offset */
6512 #ifdef AFS_LARGEFILES
6513 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6515 if (LargeIntegerLessThanZero(offset)) {
6517 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6518 offset.HighPart, offset.LowPart);
6519 return CM_ERROR_BADSMB;
6522 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6524 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6525 return CM_ERROR_BADSMB;
6528 offset.HighPart = 0;
6531 offset.HighPart = 0; /* 32-bit file offset */
6535 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6536 fd, offset.HighPart, offset.LowPart, count);
6538 " WriteRaw WriteMode 0x%x",
6541 fd = smb_ChainFID(fd, inp);
6542 fidp = smb_FindFID(vcp, fd, 0);
6544 return CM_ERROR_BADFD;
6550 LARGE_INTEGER LOffset;
6551 LARGE_INTEGER LLength;
6553 pid = ((smb_t *) inp)->pid;
6554 key = cm_GenerateKey(vcp->vcID, pid, fd);
6556 LOffset.HighPart = offset.HighPart;
6557 LOffset.LowPart = offset.LowPart;
6558 LLength.HighPart = 0;
6559 LLength.LowPart = count;
6561 lock_ObtainMutex(&fidp->scp->mx);
6562 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6563 lock_ReleaseMutex(&fidp->scp->mx);
6566 smb_ReleaseFID(fidp);
6571 userp = smb_GetUserFromVCP(vcp, inp);
6574 * Work around bug in NT client
6576 * When copying a file, the NT client should first copy the data,
6577 * then copy the last write time. But sometimes the NT client does
6578 * these in the wrong order, so the data copies would inadvertently
6579 * cause the last write time to be overwritten. We try to detect this,
6580 * and don't set client mod time if we think that would go against the
6583 lock_ObtainMutex(&fidp->mx);
6584 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6585 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6586 fidp->scp->clientModTime = time(NULL);
6588 lock_ReleaseMutex(&fidp->mx);
6591 while ( code == 0 && count > 0 ) {
6592 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6593 if (code == 0 && written == 0)
6594 code = CM_ERROR_PARTIALWRITE;
6596 offset = LargeIntegerAdd(offset,
6597 ConvertLongToLargeInteger(written));
6600 total_written += written;
6604 /* Get a raw buffer */
6607 lock_ObtainMutex(&smb_RawBufLock);
6609 /* Get a raw buf, from head of list */
6610 rawBuf = smb_RawBufs;
6611 smb_RawBufs = *(char **)smb_RawBufs;
6614 code = CM_ERROR_USESTD;
6616 lock_ReleaseMutex(&smb_RawBufLock);
6619 /* Don't allow a premature Close */
6620 if (code == 0 && (writeMode & 1) == 0) {
6621 lock_ObtainMutex(&fidp->mx);
6622 fidp->raw_writers++;
6623 thrd_ResetEvent(fidp->raw_write_event);
6624 lock_ReleaseMutex(&fidp->mx);
6627 smb_ReleaseFID(fidp);
6628 cm_ReleaseUser(userp);
6631 smb_SetSMBParm(outp, 0, total_written);
6632 smb_SetSMBDataLength(outp, 0);
6633 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6638 offset = LargeIntegerAdd(offset,
6639 ConvertLongToLargeInteger(count));
6643 rwcp->offset.HighPart = offset.HighPart;
6644 rwcp->offset.LowPart = offset.LowPart;
6645 rwcp->count = totalCount - count;
6646 rwcp->writeMode = writeMode;
6647 rwcp->alreadyWritten = total_written;
6649 /* set the packet data length to 3 bytes for the data block header,
6650 * plus the size of the data.
6652 smb_SetSMBParm(outp, 0, 0xffff);
6653 smb_SetSMBDataLength(outp, 0);
6658 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6661 long count, finalCount;
6669 fd = smb_GetSMBParm(inp, 0);
6670 count = smb_GetSMBParm(inp, 1);
6671 offset.HighPart = 0; /* too bad */
6672 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6674 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6675 fd, offset.LowPart, count);
6677 fd = smb_ChainFID(fd, inp);
6678 fidp = smb_FindFID(vcp, fd, 0);
6680 return CM_ERROR_BADFD;
6682 lock_ObtainMutex(&fidp->mx);
6683 if (fidp->flags & SMB_FID_IOCTL) {
6684 lock_ReleaseMutex(&fidp->mx);
6685 code = smb_IoctlRead(fidp, vcp, inp, outp);
6686 smb_ReleaseFID(fidp);
6689 lock_ReleaseMutex(&fidp->mx);
6692 LARGE_INTEGER LOffset, LLength;
6695 pid = ((smb_t *) inp)->pid;
6696 key = cm_GenerateKey(vcp->vcID, pid, fd);
6698 LOffset.HighPart = 0;
6699 LOffset.LowPart = offset.LowPart;
6700 LLength.HighPart = 0;
6701 LLength.LowPart = count;
6703 lock_ObtainMutex(&fidp->scp->mx);
6704 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6705 lock_ReleaseMutex(&fidp->scp->mx);
6708 smb_ReleaseFID(fidp);
6712 userp = smb_GetUserFromVCP(vcp, inp);
6714 /* remember this for final results */
6715 smb_SetSMBParm(outp, 0, count);
6716 smb_SetSMBParm(outp, 1, 0);
6717 smb_SetSMBParm(outp, 2, 0);
6718 smb_SetSMBParm(outp, 3, 0);
6719 smb_SetSMBParm(outp, 4, 0);
6721 /* set the packet data length to 3 bytes for the data block header,
6722 * plus the size of the data.
6724 smb_SetSMBDataLength(outp, count+3);
6726 /* get op ptr after putting in the parms, since otherwise we don't
6727 * know where the data really is.
6729 op = smb_GetSMBData(outp, NULL);
6731 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6732 *op++ = 1; /* data block marker */
6733 *op++ = (unsigned char) (count & 0xff);
6734 *op++ = (unsigned char) ((count >> 8) & 0xff);
6736 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6738 /* fix some things up */
6739 smb_SetSMBParm(outp, 0, finalCount);
6740 smb_SetSMBDataLength(outp, finalCount+3);
6742 smb_ReleaseFID(fidp);
6744 cm_ReleaseUser(userp);
6748 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6755 cm_scache_t *dscp; /* dir we're dealing with */
6756 cm_scache_t *scp; /* file we're creating */
6758 int initialModeBits;
6768 /* compute initial mode bits based on read-only flag in attributes */
6769 initialModeBits = 0777;
6771 tp = smb_GetSMBData(inp, NULL);
6772 pathp = smb_ParseASCIIBlock(tp, &tp);
6773 if (smb_StoreAnsiFilenames)
6774 OemToChar(pathp,pathp);
6776 if (strcmp(pathp, "\\") == 0)
6777 return CM_ERROR_EXISTS;
6779 spacep = inp->spacep;
6780 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6782 userp = smb_GetUserFromVCP(vcp, inp);
6784 caseFold = CM_FLAG_CASEFOLD;
6786 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6788 cm_ReleaseUser(userp);
6789 return CM_ERROR_NOSUCHPATH;
6792 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6793 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6794 userp, tidPathp, &req, &dscp);
6797 cm_ReleaseUser(userp);
6802 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6803 cm_ReleaseSCache(dscp);
6804 cm_ReleaseUser(userp);
6805 if ( WANTS_DFS_PATHNAMES(inp) )
6806 return CM_ERROR_PATH_NOT_COVERED;
6808 return CM_ERROR_BADSHARENAME;
6810 #endif /* DFS_SUPPORT */
6812 /* otherwise, scp points to the parent directory. Do a lookup, and
6813 * fail if we find it. Otherwise, we do the create.
6819 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6820 if (scp) cm_ReleaseSCache(scp);
6821 if (code != CM_ERROR_NOSUCHFILE) {
6822 if (code == 0) code = CM_ERROR_EXISTS;
6823 cm_ReleaseSCache(dscp);
6824 cm_ReleaseUser(userp);
6828 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6829 setAttr.clientModTime = time(NULL);
6830 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6831 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6832 smb_NotifyChange(FILE_ACTION_ADDED,
6833 FILE_NOTIFY_CHANGE_DIR_NAME,
6834 dscp, lastNamep, NULL, TRUE);
6836 /* we don't need this any longer */
6837 cm_ReleaseSCache(dscp);
6840 /* something went wrong creating or truncating the file */
6841 cm_ReleaseUser(userp);
6845 /* otherwise we succeeded */
6846 smb_SetSMBDataLength(outp, 0);
6847 cm_ReleaseUser(userp);
6852 BOOL smb_IsLegalFilename(char *filename)
6855 * Find the longest substring of filename that does not contain
6856 * any of the chars in illegalChars. If that substring is less
6857 * than the length of the whole string, then one or more of the
6858 * illegal chars is in filename.
6860 if (strcspn(filename, illegalChars) < strlen(filename))
6866 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6874 cm_scache_t *dscp; /* dir we're dealing with */
6875 cm_scache_t *scp; /* file we're creating */
6877 int initialModeBits;
6885 int created = 0; /* the file was new */
6890 excl = (inp->inCom == 0x03)? 0 : 1;
6892 attributes = smb_GetSMBParm(inp, 0);
6893 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6895 /* compute initial mode bits based on read-only flag in attributes */
6896 initialModeBits = 0666;
6897 if (attributes & SMB_ATTR_READONLY)
6898 initialModeBits &= ~0222;
6900 tp = smb_GetSMBData(inp, NULL);
6901 pathp = smb_ParseASCIIBlock(tp, &tp);
6902 if (smb_StoreAnsiFilenames)
6903 OemToChar(pathp,pathp);
6905 spacep = inp->spacep;
6906 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6908 userp = smb_GetUserFromVCP(vcp, inp);
6910 caseFold = CM_FLAG_CASEFOLD;
6912 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6914 cm_ReleaseUser(userp);
6915 return CM_ERROR_NOSUCHPATH;
6917 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6918 userp, tidPathp, &req, &dscp);
6921 cm_ReleaseUser(userp);
6926 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6927 cm_ReleaseSCache(dscp);
6928 cm_ReleaseUser(userp);
6929 if ( WANTS_DFS_PATHNAMES(inp) )
6930 return CM_ERROR_PATH_NOT_COVERED;
6932 return CM_ERROR_BADSHARENAME;
6934 #endif /* DFS_SUPPORT */
6936 /* otherwise, scp points to the parent directory. Do a lookup, and
6937 * truncate the file if we find it, otherwise we create the file.
6944 if (!smb_IsLegalFilename(lastNamep))
6945 return CM_ERROR_BADNTFILENAME;
6947 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6948 #ifdef DEBUG_VERBOSE
6951 hexp = osi_HexifyString( lastNamep );
6952 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6957 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6958 if (code && code != CM_ERROR_NOSUCHFILE) {
6959 cm_ReleaseSCache(dscp);
6960 cm_ReleaseUser(userp);
6964 /* if we get here, if code is 0, the file exists and is represented by
6965 * scp. Otherwise, we have to create it.
6969 /* oops, file shouldn't be there */
6970 cm_ReleaseSCache(dscp);
6971 cm_ReleaseSCache(scp);
6972 cm_ReleaseUser(userp);
6973 return CM_ERROR_EXISTS;
6976 setAttr.mask = CM_ATTRMASK_LENGTH;
6977 setAttr.length.LowPart = 0;
6978 setAttr.length.HighPart = 0;
6979 code = cm_SetAttr(scp, &setAttr, userp, &req);
6982 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6983 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6984 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6988 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6989 smb_NotifyChange(FILE_ACTION_ADDED,
6990 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6991 dscp, lastNamep, NULL, TRUE);
6992 } else if (!excl && code == CM_ERROR_EXISTS) {
6993 /* not an exclusive create, and someone else tried
6994 * creating it already, then we open it anyway. We
6995 * don't bother retrying after this, since if this next
6996 * fails, that means that the file was deleted after
6997 * we started this call.
6999 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7002 setAttr.mask = CM_ATTRMASK_LENGTH;
7003 setAttr.length.LowPart = 0;
7004 setAttr.length.HighPart = 0;
7005 code = cm_SetAttr(scp, &setAttr, userp, &req);
7010 /* we don't need this any longer */
7011 cm_ReleaseSCache(dscp);
7014 /* something went wrong creating or truncating the file */
7015 if (scp) cm_ReleaseSCache(scp);
7016 cm_ReleaseUser(userp);
7020 /* make sure we only open files */
7021 if (scp->fileType != CM_SCACHETYPE_FILE) {
7022 cm_ReleaseSCache(scp);
7023 cm_ReleaseUser(userp);
7024 return CM_ERROR_ISDIR;
7027 /* now all we have to do is open the file itself */
7028 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7033 lock_ObtainMutex(&fidp->mx);
7034 /* always create it open for read/write */
7035 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
7037 /* remember that the file was newly created */
7039 fidp->flags |= SMB_FID_CREATED;
7041 osi_Log2(afsd_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7043 /* save a pointer to the vnode */
7045 lock_ObtainMutex(&scp->mx);
7046 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7047 lock_ReleaseMutex(&scp->mx);
7050 fidp->userp = userp;
7051 lock_ReleaseMutex(&fidp->mx);
7053 smb_SetSMBParm(outp, 0, fidp->fid);
7054 smb_SetSMBDataLength(outp, 0);
7056 cm_Open(scp, 0, userp);
7058 smb_ReleaseFID(fidp);
7059 cm_ReleaseUser(userp);
7060 /* leave scp held since we put it in fidp->scp */
7064 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7067 osi_hyper_t new_offset;
7078 fd = smb_GetSMBParm(inp, 0);
7079 whence = smb_GetSMBParm(inp, 1);
7080 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7082 /* try to find the file descriptor */
7083 fd = smb_ChainFID(fd, inp);
7084 fidp = smb_FindFID(vcp, fd, 0);
7087 return CM_ERROR_BADFD;
7089 lock_ObtainMutex(&fidp->mx);
7090 if (fidp->flags & SMB_FID_IOCTL) {
7091 lock_ReleaseMutex(&fidp->mx);
7092 smb_ReleaseFID(fidp);
7093 return CM_ERROR_BADFD;
7095 lock_ReleaseMutex(&fidp->mx);
7097 userp = smb_GetUserFromVCP(vcp, inp);
7099 lock_ObtainMutex(&fidp->mx);
7102 lock_ReleaseMutex(&fidp->mx);
7103 lock_ObtainMutex(&scp->mx);
7104 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7105 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7107 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7109 /* offset from current offset */
7110 new_offset = LargeIntegerAdd(fidp->offset,
7111 ConvertLongToLargeInteger(offset));
7113 else if (whence == 2) {
7114 /* offset from current EOF */
7115 new_offset = LargeIntegerAdd(scp->length,
7116 ConvertLongToLargeInteger(offset));
7118 new_offset = ConvertLongToLargeInteger(offset);
7121 fidp->offset = new_offset;
7122 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7123 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7124 smb_SetSMBDataLength(outp, 0);
7126 lock_ReleaseMutex(&scp->mx);
7127 smb_ReleaseFID(fidp);
7128 cm_ReleaseSCache(scp);
7129 cm_ReleaseUser(userp);
7133 /* dispatch all of the requests received in a packet. Due to chaining, this may
7134 * be more than one request.
7136 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7137 NCB *ncbp, raw_write_cont_t *rwcp)
7141 unsigned long code = 0;
7142 unsigned char *outWctp;
7143 int nparms; /* # of bytes of parameters */
7145 int nbytes; /* bytes of data, excluding count */
7148 unsigned short errCode;
7149 unsigned long NTStatus;
7151 unsigned char errClass;
7152 unsigned int oldGen;
7153 DWORD oldTime, newTime;
7155 /* get easy pointer to the data */
7156 smbp = (smb_t *) inp->data;
7158 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7159 /* setup the basic parms for the initial request in the packet */
7160 inp->inCom = smbp->com;
7161 inp->wctp = &smbp->wct;
7163 inp->ncb_length = ncbp->ncb_length;
7168 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7169 /* log it and discard it */
7170 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7171 __FILE__, __LINE__, ncbp->ncb_length);
7172 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7176 /* We are an ongoing op */
7177 thrd_Increment(&ongoingOps);
7179 /* set up response packet for receiving output */
7180 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7181 smb_FormatResponsePacket(vcp, inp, outp);
7182 outWctp = outp->wctp;
7184 /* Remember session generation number and time */
7185 oldGen = sessionGen;
7186 oldTime = GetTickCount();
7188 while (inp->inCom != 0xff) {
7189 dp = &smb_dispatchTable[inp->inCom];
7191 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7192 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7193 code = outp->resumeCode;
7197 /* process each request in the packet; inCom, wctp and inCount
7198 * are already set up.
7200 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7203 /* now do the dispatch */
7204 /* start by formatting the response record a little, as a default */
7205 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7207 outWctp[1] = 0xff; /* no operation */
7208 outWctp[2] = 0; /* padding */
7213 /* not a chained request, this is a more reasonable default */
7214 outWctp[0] = 0; /* wct of zero */
7215 outWctp[1] = 0; /* and bcc (word) of zero */
7219 /* once set, stays set. Doesn't matter, since we never chain
7220 * "no response" calls.
7222 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7226 /* we have a recognized operation */
7228 if (inp->inCom == 0x1d)
7230 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7232 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7233 code = (*(dp->procp)) (vcp, inp, outp);
7234 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7236 if ( code == CM_ERROR_BADSMB ||
7237 code == CM_ERROR_BADOP )
7239 #endif /* LOG_PACKET */
7242 if (oldGen != sessionGen) {
7243 newTime = GetTickCount();
7244 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7245 newTime - oldTime, ncbp->ncb_length);
7246 osi_Log2(smb_logp, "Pkt straddled session startup, "
7247 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7251 /* bad opcode, fail the request, after displaying it */
7252 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7255 #endif /* LOG_PACKET */
7258 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7259 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7260 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7261 if (code == IDCANCEL)
7264 code = CM_ERROR_BADOP;
7267 /* catastrophic failure: log as much as possible */
7268 if (code == CM_ERROR_BADSMB) {
7269 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7273 #endif /* LOG_PACKET */
7274 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7277 code = CM_ERROR_INVAL;
7280 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7281 thrd_Decrement(&ongoingOps);
7286 /* now, if we failed, turn the current response into an empty
7287 * one, and fill in the response packet's error code.
7290 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7291 smb_MapNTError(code, &NTStatus);
7292 outWctp = outp->wctp;
7293 smbp = (smb_t *) &outp->data;
7294 if (code != CM_ERROR_PARTIALWRITE
7295 && code != CM_ERROR_BUFFERTOOSMALL
7296 && code != CM_ERROR_GSSCONTINUE) {
7297 /* nuke wct and bcc. For a partial
7298 * write or an in-process authentication handshake,
7299 * assume they're OK.
7305 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7306 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7307 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7308 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7309 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7313 smb_MapCoreError(code, vcp, &errCode, &errClass);
7314 outWctp = outp->wctp;
7315 smbp = (smb_t *) &outp->data;
7316 if (code != CM_ERROR_PARTIALWRITE) {
7317 /* nuke wct and bcc. For a partial
7318 * write, assume they're OK.
7324 smbp->errLow = (unsigned char) (errCode & 0xff);
7325 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7326 smbp->rcls = errClass;
7329 } /* error occurred */
7331 /* if we're here, we've finished one request. Look to see if
7332 * this is a chained opcode. If it is, setup things to process
7333 * the chained request, and setup the output buffer to hold the
7334 * chained response. Start by finding the next input record.
7336 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7337 break; /* not a chained req */
7338 tp = inp->wctp; /* points to start of last request */
7339 /* in a chained request, the first two
7340 * parm fields are required, and are
7341 * AndXCommand/AndXReserved and
7343 if (tp[0] < 2) break;
7344 if (tp[1] == 0xff) break; /* no more chained opcodes */
7346 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7349 /* and now append the next output request to the end of this
7350 * last request. Begin by finding out where the last response
7351 * ends, since that's where we'll put our new response.
7353 outWctp = outp->wctp; /* ptr to out parameters */
7354 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7355 nparms = outWctp[0] << 1;
7356 tp = outWctp + nparms + 1; /* now points to bcc field */
7357 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7358 tp += 2 /* for the count itself */ + nbytes;
7359 /* tp now points to the new output record; go back and patch the
7360 * second parameter (off2) to point to the new record.
7362 temp = (unsigned int)(tp - outp->data);
7363 outWctp[3] = (unsigned char) (temp & 0xff);
7364 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7365 outWctp[2] = 0; /* padding */
7366 outWctp[1] = inp->inCom; /* next opcode */
7368 /* finally, setup for the next iteration */
7371 } /* while loop over all requests in the packet */
7373 /* now send the output packet, and return */
7375 smb_SendPacket(vcp, outp);
7376 thrd_Decrement(&ongoingOps);
7381 /* Wait for Netbios() calls to return, and make the results available to server
7382 * threads. Note that server threads can't wait on the NCBevents array
7383 * themselves, because NCB events are manual-reset, and the servers would race
7384 * each other to reset them.
7386 void smb_ClientWaiter(void *parmp)
7391 while (smbShutdownFlag == 0) {
7392 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7394 if (code == WAIT_OBJECT_0)
7397 /* error checking */
7398 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7400 int abandonIdx = code - WAIT_ABANDONED_0;
7401 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7404 if (code == WAIT_IO_COMPLETION)
7406 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7410 if (code == WAIT_TIMEOUT)
7412 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7415 if (code == WAIT_FAILED)
7417 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7420 idx = code - WAIT_OBJECT_0;
7422 /* check idx range! */
7423 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7425 /* this is fatal - log as much as possible */
7426 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7430 thrd_ResetEvent(NCBevents[idx]);
7431 thrd_SetEvent(NCBreturns[0][idx]);
7436 * Try to have one NCBRECV request waiting for every live session. Not more
7437 * than one, because if there is more than one, it's hard to handle Write Raw.
7439 void smb_ServerWaiter(void *parmp)
7442 int idx_session, idx_NCB;
7445 while (smbShutdownFlag == 0) {
7447 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7449 if (code == WAIT_OBJECT_0)
7452 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7454 int abandonIdx = code - WAIT_ABANDONED_0;
7455 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7458 if (code == WAIT_IO_COMPLETION)
7460 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7464 if (code == WAIT_TIMEOUT)
7466 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7469 if (code == WAIT_FAILED)
7471 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7474 idx_session = code - WAIT_OBJECT_0;
7476 /* check idx range! */
7477 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7479 /* this is fatal - log as much as possible */
7480 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7486 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7488 if (code == WAIT_OBJECT_0) {
7489 if (smbShutdownFlag == 1)
7495 /* error checking */
7496 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7498 int abandonIdx = code - WAIT_ABANDONED_0;
7499 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7502 if (code == WAIT_IO_COMPLETION)
7504 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7508 if (code == WAIT_TIMEOUT)
7510 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7513 if (code == WAIT_FAILED)
7515 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7518 idx_NCB = code - WAIT_OBJECT_0;
7520 /* check idx range! */
7521 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7523 /* this is fatal - log as much as possible */
7524 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7528 /* Link them together */
7529 NCBsessions[idx_NCB] = idx_session;
7532 ncbp = NCBs[idx_NCB];
7533 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7534 ncbp->ncb_command = NCBRECV | ASYNCH;
7535 ncbp->ncb_lana_num = lanas[idx_session];
7536 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7537 ncbp->ncb_event = NCBevents[idx_NCB];
7538 ncbp->ncb_length = SMB_PACKETSIZE;
7544 * The top level loop for handling SMB request messages. Each server thread
7545 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7546 * NCB and buffer for the incoming request are loaned to us.
7548 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7549 * to immediately send a request for the rest of the data. This must come
7550 * before any other traffic for that session, so we delay setting the session
7551 * event until that data has come in.
7553 void smb_Server(VOID *parmp)
7555 INT_PTR myIdx = (INT_PTR) parmp;
7559 smb_packet_t *outbufp;
7561 int idx_NCB, idx_session;
7563 smb_vc_t *vcp = NULL;
7566 rx_StartClientThread();
7569 outbufp = GetPacket();
7570 outbufp->ncbp = outncbp;
7578 smb_ResetServerPriority();
7580 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7583 /* terminate silently if shutdown flag is set */
7584 if (code == WAIT_OBJECT_0) {
7585 if (smbShutdownFlag == 1) {
7586 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7592 /* error checking */
7593 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7595 int abandonIdx = code - WAIT_ABANDONED_0;
7596 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7599 if (code == WAIT_IO_COMPLETION)
7601 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7605 if (code == WAIT_TIMEOUT)
7607 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7610 if (code == WAIT_FAILED)
7612 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7615 idx_NCB = code - WAIT_OBJECT_0;
7617 /* check idx range! */
7618 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7620 /* this is fatal - log as much as possible */
7621 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7625 ncbp = NCBs[idx_NCB];
7626 idx_session = NCBsessions[idx_NCB];
7627 rc = ncbp->ncb_retcode;
7629 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7630 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7634 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7638 /* Can this happen? Or is it just my UNIX paranoia? */
7639 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7644 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7647 /* Client closed session */
7648 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7650 lock_ObtainMutex(&vcp->mx);
7651 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7652 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7654 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7655 lock_ReleaseMutex(&vcp->mx);
7656 lock_ObtainWrite(&smb_globalLock);
7657 dead_sessions[vcp->session] = TRUE;
7658 lock_ReleaseWrite(&smb_globalLock);
7659 smb_CleanupDeadVC(vcp);
7663 lock_ReleaseMutex(&vcp->mx);
7669 /* Treat as transient error */
7670 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7673 "dispatch smb recv failed, message incomplete, ncb_length %d",
7676 "SMB message incomplete, "
7677 "length %d", ncbp->ncb_length);
7680 * We used to discard the packet.
7681 * Instead, try handling it normally.
7685 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7689 /* A weird error code. Log it, sleep, and continue. */
7690 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7692 lock_ObtainMutex(&vcp->mx);
7693 if (vcp && vcp->errorCount++ > 3) {
7694 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7695 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7696 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7698 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7699 lock_ReleaseMutex(&vcp->mx);
7700 lock_ObtainWrite(&smb_globalLock);
7701 dead_sessions[vcp->session] = TRUE;
7702 lock_ReleaseWrite(&smb_globalLock);
7703 smb_CleanupDeadVC(vcp);
7707 lock_ReleaseMutex(&vcp->mx);
7713 lock_ReleaseMutex(&vcp->mx);
7715 thrd_SetEvent(SessionEvents[idx_session]);
7720 /* Success, so now dispatch on all the data in the packet */
7722 smb_concurrentCalls++;
7723 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7724 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7727 * If at this point vcp is NULL (implies that packet was invalid)
7728 * then we are in big trouble. This means either :
7729 * a) we have the wrong NCB.
7730 * b) Netbios screwed up the call.
7731 * c) The VC was already marked dead before we were able to
7733 * Obviously this implies that
7734 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7735 * lanas[idx_session] != ncbp->ncb_lana_num )
7736 * Either way, we can't do anything with this packet.
7737 * Log, sleep and resume.
7740 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7744 ncbp->ncb_lana_num);
7746 /* Also log in the trace log. */
7747 osi_Log4(smb_logp, "Server: VCP does not exist!"
7748 "LSNs[idx_session]=[%d],"
7749 "lanas[idx_session]=[%d],"
7750 "ncbp->ncb_lsn=[%d],"
7751 "ncbp->ncb_lana_num=[%d]",
7755 ncbp->ncb_lana_num);
7757 /* thrd_Sleep(1000); Don't bother sleeping */
7758 thrd_SetEvent(SessionEvents[idx_session]);
7759 smb_concurrentCalls--;
7763 smb_SetRequestStartTime();
7765 vcp->errorCount = 0;
7766 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7767 smbp = (smb_t *)bufp->data;
7772 if (smbp->com == 0x1d) {
7773 /* Special handling for Write Raw */
7774 raw_write_cont_t rwc;
7775 EVENT_HANDLE rwevent;
7776 char eventName[MAX_PATH];
7778 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7779 if (rwc.code == 0) {
7780 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7781 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7782 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7783 ncbp->ncb_command = NCBRECV | ASYNCH;
7784 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7785 ncbp->ncb_lana_num = vcp->lana;
7786 ncbp->ncb_buffer = rwc.buf;
7787 ncbp->ncb_length = 65535;
7788 ncbp->ncb_event = rwevent;
7790 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7791 thrd_CloseHandle(rwevent);
7793 thrd_SetEvent(SessionEvents[idx_session]);
7795 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7797 else if (smbp->com == 0xa0) {
7799 * Serialize the handling for NT Transact
7802 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7803 thrd_SetEvent(SessionEvents[idx_session]);
7805 thrd_SetEvent(SessionEvents[idx_session]);
7806 /* TODO: what else needs to be serialized? */
7807 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7810 __except( smb_ServerExceptionFilter() ) {
7813 smb_concurrentCalls--;
7816 thrd_SetEvent(NCBavails[idx_NCB]);
7823 * Exception filter for the server threads. If an exception occurs in the
7824 * dispatch routines, which is where exceptions are most common, then do a
7825 * force trace and give control to upstream exception handlers. Useful for
7828 DWORD smb_ServerExceptionFilter(void) {
7829 /* While this is not the best time to do a trace, if it succeeds, then
7830 * we have a trace (assuming tracing was enabled). Otherwise, this should
7831 * throw a second exception.
7833 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7834 afsd_ForceTrace(TRUE);
7835 buf_ForceTrace(TRUE);
7836 return EXCEPTION_CONTINUE_SEARCH;
7840 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7841 * If the number of server threads is M, and the number of live sessions is
7842 * N, then the number of NCB's in use at any time either waiting for, or
7843 * holding, received messages is M + N, so that is how many NCB's get created.
7845 void InitNCBslot(int idx)
7847 struct smb_packet *bufp;
7848 EVENT_HANDLE retHandle;
7850 char eventName[MAX_PATH];
7852 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7854 NCBs[idx] = GetNCB();
7855 sprintf(eventName,"NCBavails[%d]", idx);
7856 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7857 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7858 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7859 sprintf(eventName,"NCBevents[%d]", idx);
7860 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7861 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7862 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7863 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7864 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7865 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7866 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7867 for (i=0; i<smb_NumServerThreads; i++)
7868 NCBreturns[i][idx] = retHandle;
7870 bufp->spacep = cm_GetSpace();
7874 /* listen for new connections */
7875 void smb_Listener(void *parmp)
7881 int session, thread;
7882 smb_vc_t *vcp = NULL;
7884 char rname[NCBNAMSZ+1];
7885 char cname[MAX_COMPUTERNAME_LENGTH+1];
7886 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7887 INT_PTR lana = (INT_PTR) parmp;
7891 /* retrieve computer name */
7892 GetComputerName(cname, &cnamelen);
7895 while (smb_ListenerState == SMB_LISTENER_STARTED) {
7896 memset(ncbp, 0, sizeof(NCB));
7899 ncbp->ncb_command = NCBLISTEN;
7900 ncbp->ncb_rto = 0; /* No receive timeout */
7901 ncbp->ncb_sto = 0; /* No send timeout */
7903 /* pad out with spaces instead of null termination */
7904 len = (long)strlen(smb_localNamep);
7905 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7906 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7908 strcpy(ncbp->ncb_callname, "*");
7909 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7911 ncbp->ncb_lana_num = (UCHAR)lana;
7913 code = Netbios(ncbp);
7915 if (code == NRC_BRIDGE) {
7916 int lanaRemaining = 0;
7918 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
7923 "NCBLISTEN lana=%d failed with NRC_BRIDGE. Listener thread exiting.",
7924 ncbp->ncb_lana_num, code);
7926 for (i = 0; i < lana_list.length; i++) {
7927 if (lana_list.lana[i] == ncbp->ncb_lana_num) {
7928 smb_StopListener(ncbp, lana_list.lana[i]);
7929 lana_list.lana[i] = 255;
7931 if (lana_list.lana[i] != 255)
7935 if (lanaRemaining == 0) {
7936 smb_ListenerState = SMB_LISTENER_STOPPED;
7937 smb_LANadapter = -1;
7938 lana_list.length = 0;
7942 } else if (code != 0) {
7945 /* terminate silently if shutdown flag is set */
7946 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
7951 "NCBLISTEN lana=%d failed with code %d",
7952 ncbp->ncb_lana_num, code);
7954 "Client exiting due to network failure. Please restart client.\n");
7957 "Client exiting due to network failure. Please restart client.\n"
7958 "NCBLISTEN lana=%d failed with code %d",
7959 ncbp->ncb_lana_num, code);
7961 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7962 MB_OK|MB_SERVICE_NOTIFICATION);
7963 osi_panic(tbuffer, __FILE__, __LINE__);
7966 /* check for remote conns */
7967 /* first get remote name and insert null terminator */
7968 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7969 for (i=NCBNAMSZ; i>0; i--) {
7970 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7976 /* compare with local name */
7978 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7979 flags |= SMB_VCFLAG_REMOTECONN;
7982 lock_ObtainMutex(&smb_ListenerLock);
7984 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7985 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
7987 /* now ncbp->ncb_lsn is the connection ID */
7988 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7989 if (vcp->session == 0) {
7990 /* New generation */
7991 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7994 /* Log session startup */
7996 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
7997 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7998 #endif /* NOTSERVICE */
7999 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8000 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8002 if (reportSessionStartups) {
8003 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8006 lock_ObtainMutex(&vcp->mx);
8007 strcpy(vcp->rname, rname);
8008 vcp->flags |= flags;
8009 lock_ReleaseMutex(&vcp->mx);
8011 /* Allocate slot in session arrays */
8012 /* Re-use dead session if possible, otherwise add one more */
8013 /* But don't look at session[0], it is reserved */
8014 lock_ObtainWrite(&smb_globalLock);
8015 for (session = 1; session < numSessions; session++) {
8016 if (dead_sessions[session]) {
8017 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8018 dead_sessions[session] = FALSE;
8022 lock_ReleaseWrite(&smb_globalLock);
8024 /* We are re-using an existing VC because the lsn and lana
8026 session = vcp->session;
8028 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8030 /* Log session startup */
8032 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8033 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8034 #endif /* NOTSERVICE */
8035 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8036 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8038 if (reportSessionStartups) {
8039 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8043 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8044 unsigned long code = CM_ERROR_ALLBUSY;
8045 smb_packet_t * outp = GetPacket();
8046 unsigned char *outWctp;
8049 smb_FormatResponsePacket(vcp, NULL, outp);
8052 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8053 unsigned long NTStatus;
8054 smb_MapNTError(code, &NTStatus);
8055 outWctp = outp->wctp;
8056 smbp = (smb_t *) &outp->data;
8060 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8061 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8062 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8063 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8064 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8066 unsigned short errCode;
8067 unsigned char errClass;
8068 smb_MapCoreError(code, vcp, &errCode, &errClass);
8069 outWctp = outp->wctp;
8070 smbp = (smb_t *) &outp->data;
8074 smbp->errLow = (unsigned char) (errCode & 0xff);
8075 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8076 smbp->rcls = errClass;
8078 smb_SendPacket(vcp, outp);
8079 smb_FreePacket(outp);
8081 lock_ObtainMutex(&vcp->mx);
8082 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8083 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8085 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8086 lock_ReleaseMutex(&vcp->mx);
8087 lock_ObtainWrite(&smb_globalLock);
8088 dead_sessions[vcp->session] = TRUE;
8089 lock_ReleaseWrite(&smb_globalLock);
8090 smb_CleanupDeadVC(vcp);
8092 lock_ReleaseMutex(&vcp->mx);
8095 /* assert that we do not exceed the maximum number of sessions or NCBs.
8096 * we should probably want to wait for a session to be freed in case
8099 osi_assert(session < SESSION_MAX - 1);
8100 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8102 lock_ObtainMutex(&vcp->mx);
8103 vcp->session = session;
8104 lock_ReleaseMutex(&vcp->mx);
8105 lock_ObtainWrite(&smb_globalLock);
8106 LSNs[session] = ncbp->ncb_lsn;
8107 lanas[session] = ncbp->ncb_lana_num;
8108 lock_ReleaseWrite(&smb_globalLock);
8110 if (session == numSessions) {
8111 /* Add new NCB for new session */
8112 char eventName[MAX_PATH];
8114 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8116 InitNCBslot(numNCBs);
8117 lock_ObtainWrite(&smb_globalLock);
8119 lock_ReleaseWrite(&smb_globalLock);
8120 thrd_SetEvent(NCBavails[0]);
8121 thrd_SetEvent(NCBevents[0]);
8122 for (thread = 0; thread < smb_NumServerThreads; thread++)
8123 thrd_SetEvent(NCBreturns[thread][0]);
8124 /* Also add new session event */
8125 sprintf(eventName, "SessionEvents[%d]", session);
8126 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8127 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8128 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8129 lock_ObtainWrite(&smb_globalLock);
8131 lock_ReleaseWrite(&smb_globalLock);
8132 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8133 thrd_SetEvent(SessionEvents[0]);
8135 thrd_SetEvent(SessionEvents[session]);
8141 lock_ReleaseMutex(&smb_ListenerLock);
8142 } /* dispatch while loop */
8147 /* initialize Netbios */
8148 int smb_NetbiosInit(void)
8151 int i, lana, code, l;
8153 int delname_tried=0;
8157 /* setup the NCB system */
8160 if (smb_LANadapter == -1) {
8161 ncbp->ncb_command = NCBENUM;
8162 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8163 ncbp->ncb_length = sizeof(lana_list);
8164 code = Netbios(ncbp);
8166 afsi_log("Netbios NCBENUM error code %d", code);
8167 osi_panic(s, __FILE__, __LINE__);
8171 lana_list.length = 1;
8172 lana_list.lana[0] = smb_LANadapter;
8175 for (i = 0; i < lana_list.length; i++) {
8176 /* reset the adaptor: in Win32, this is required for every process, and
8177 * acts as an init call, not as a real hardware reset.
8179 ncbp->ncb_command = NCBRESET;
8180 ncbp->ncb_callname[0] = 100;
8181 ncbp->ncb_callname[2] = 100;
8182 ncbp->ncb_lana_num = lana_list.lana[i];
8183 code = Netbios(ncbp);
8185 code = ncbp->ncb_retcode;
8187 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8188 lana_list.lana[i] = 255; /* invalid lana */
8190 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8194 /* and declare our name so we can receive connections */
8195 memset(ncbp, 0, sizeof(*ncbp));
8196 len=lstrlen(smb_localNamep);
8197 memset(smb_sharename,' ',NCBNAMSZ);
8198 memcpy(smb_sharename,smb_localNamep,len);
8199 afsi_log("lana_list.length %d", lana_list.length);
8201 /* Keep the name so we can unregister it later */
8202 for (l = 0; l < lana_list.length; l++) {
8203 lana = lana_list.lana[l];
8205 ncbp->ncb_command = NCBADDNAME;
8206 ncbp->ncb_lana_num = lana;
8207 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8208 code = Netbios(ncbp);
8210 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8211 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8213 char name[NCBNAMSZ+1];
8215 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8216 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8220 code = ncbp->ncb_retcode;
8223 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8226 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8227 if (code == NRC_BRIDGE) { /* invalid LANA num */
8228 lana_list.lana[l] = 255;
8231 else if (code == NRC_DUPNAME) {
8232 afsi_log("Name already exists; try to delete it");
8233 memset(ncbp, 0, sizeof(*ncbp));
8234 ncbp->ncb_command = NCBDELNAME;
8235 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8236 ncbp->ncb_lana_num = lana;
8237 code = Netbios(ncbp);
8239 code = ncbp->ncb_retcode;
8241 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8243 if (code != 0 || delname_tried) {
8244 lana_list.lana[l] = 255;
8246 else if (code == 0) {
8247 if (!delname_tried) {
8255 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8256 lana_list.lana[l] = 255; /* invalid lana */
8260 lana_found = 1; /* at least one worked */
8264 osi_assert(lana_list.length >= 0);
8266 afsi_log("No valid LANA numbers found!");
8267 lana_list.length = 0;
8268 smb_LANadapter = -1;
8269 smb_ListenerState = SMB_LISTENER_STOPPED;
8272 /* we're done with the NCB now */
8275 return (lana_list.length > 0 ? 1 : 0);
8278 void smb_StartListeners()
8284 if (smb_ListenerState == SMB_LISTENER_STARTED)
8287 smb_ListenerState = SMB_LISTENER_STARTED;
8289 for (i = 0; i < lana_list.length; i++) {
8290 if (lana_list.lana[i] == 255)
8292 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8293 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8294 osi_assert(phandle != NULL);
8295 thrd_CloseHandle(phandle);
8299 void smb_RestartListeners()
8301 if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
8302 if (smb_NetbiosInit())
8303 smb_StartListeners();
8307 void smb_StopListener(NCB *ncbp, int lana)
8311 memset(ncbp, 0, sizeof(*ncbp));
8312 ncbp->ncb_command = NCBDELNAME;
8313 ncbp->ncb_lana_num = lana;
8314 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8315 code = Netbios(ncbp);
8317 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8318 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8320 /* and then reset the LANA; this will cause the listener threads to exit */
8321 ncbp->ncb_command = NCBRESET;
8322 ncbp->ncb_callname[0] = 100;
8323 ncbp->ncb_callname[2] = 100;
8324 ncbp->ncb_lana_num = lana;
8325 code = Netbios(ncbp);
8327 code = ncbp->ncb_retcode;
8329 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8331 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8335 void smb_StopListeners(void)
8340 if (smb_ListenerState == SMB_LISTENER_STOPPED)
8343 smb_ListenerState = SMB_LISTENER_STOPPED;
8347 /* Unregister the SMB name */
8348 for (l = 0; l < lana_list.length; l++) {
8349 lana = lana_list.lana[l];
8352 smb_StopListener(ncbp, lana);
8354 /* mark the adapter invalid */
8355 lana_list.lana[l] = 255; /* invalid lana */
8359 /* force a re-evaluation of the network adapters */
8360 lana_list.length = 0;
8361 smb_LANadapter = -1;
8363 Sleep(1000); /* give the listener threads a chance to exit */
8366 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
8377 EVENT_HANDLE retHandle;
8378 char eventName[MAX_PATH];
8380 smb_TlsRequestSlot = TlsAlloc();
8382 smb_MBfunc = aMBfunc;
8385 smb_LANadapter = LANadapt;
8387 /* Initialize smb_localZero */
8388 myTime.tm_isdst = -1; /* compute whether on DST or not */
8389 myTime.tm_year = 70;
8395 smb_localZero = mktime(&myTime);
8397 #ifndef USE_NUMERIC_TIME_CONV
8398 /* Initialize kludge-GMT */
8399 smb_CalculateNowTZ();
8400 #endif /* USE_NUMERIC_TIME_CONV */
8401 #ifdef AFS_FREELANCE_CLIENT
8402 /* Make sure the root.afs volume has the correct time */
8403 cm_noteLocalMountPointChange();
8406 /* initialize the remote debugging log */
8409 /* remember the name */
8410 len = (int)strlen(snamep);
8411 smb_localNamep = malloc(len+1);
8412 strcpy(smb_localNamep, snamep);
8413 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8415 /* and the global lock */
8416 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8417 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8419 /* Raw I/O data structures */
8420 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8422 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8424 /* 4 Raw I/O buffers */
8425 smb_RawBufs = calloc(65536,1);
8426 *((char **)smb_RawBufs) = NULL;
8427 for (i=0; i<3; i++) {
8428 char *rawBuf = calloc(65536,1);
8429 *((char **)rawBuf) = smb_RawBufs;
8430 smb_RawBufs = rawBuf;
8433 /* global free lists */
8434 smb_ncbFreeListp = NULL;
8435 smb_packetFreeListp = NULL;
8439 /* Initialize listener and server structures */
8441 memset(dead_sessions, 0, sizeof(dead_sessions));
8442 sprintf(eventName, "SessionEvents[0]");
8443 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8444 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8445 afsi_log("Event Object Already Exists: %s", eventName);
8447 smb_NumServerThreads = nThreads;
8448 sprintf(eventName, "NCBavails[0]");
8449 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8450 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8451 afsi_log("Event Object Already Exists: %s", eventName);
8452 sprintf(eventName, "NCBevents[0]");
8453 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8454 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8455 afsi_log("Event Object Already Exists: %s", eventName);
8456 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8457 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8458 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8459 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8460 afsi_log("Event Object Already Exists: %s", eventName);
8461 for (i = 0; i < smb_NumServerThreads; i++) {
8462 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8463 NCBreturns[i][0] = retHandle;
8466 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8467 for (i = 0; i < smb_NumServerThreads; i++) {
8468 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8469 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8470 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8471 afsi_log("Event Object Already Exists: %s", eventName);
8472 InitNCBslot((int)(i+1));
8474 numNCBs = smb_NumServerThreads + 1;
8476 /* Initialize dispatch table */
8477 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8478 /* Prepare the table for unknown operations */
8479 for(i=0; i<= SMB_NOPCODES; i++) {
8480 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8482 /* Fill in the ones we do know */
8483 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8484 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8485 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8486 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8487 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8488 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8489 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8490 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8491 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8492 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8493 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8494 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8495 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8496 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8497 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8498 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8499 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8500 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8501 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8502 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8503 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8504 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8505 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8506 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8507 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8508 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8509 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8510 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8511 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8512 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8513 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8514 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8515 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8516 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8517 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8518 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8519 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8520 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8521 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8522 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8523 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8524 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8525 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8526 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8527 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8528 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8529 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8530 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8531 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8532 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8533 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8534 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8535 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8536 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8537 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8538 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8539 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8540 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8541 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8542 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8543 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8544 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8545 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8546 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8547 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8548 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8549 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8550 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8551 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8552 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8553 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8554 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8555 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8556 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8558 /* setup tran 2 dispatch table */
8559 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8560 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8561 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8562 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8563 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8564 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8565 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8566 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8567 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8568 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8569 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8570 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8571 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8572 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8573 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8574 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8575 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8576 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8578 /* setup the rap dispatch table */
8579 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8580 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8581 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8582 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8583 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8587 /* if we are doing SMB authentication we have register outselves as a logon process */
8588 if (smb_authType != SMB_AUTH_NONE) {
8589 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8590 LSA_STRING afsProcessName;
8591 LSA_OPERATIONAL_MODE dummy; /*junk*/
8593 afsProcessName.Buffer = "OpenAFSClientDaemon";
8594 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8595 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8597 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8599 if (nts == STATUS_SUCCESS) {
8600 LSA_STRING packageName;
8601 /* we are registered. Find out the security package id */
8602 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8603 packageName.Length = (USHORT)strlen(packageName.Buffer);
8604 packageName.MaximumLength = packageName.Length + 1;
8605 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8606 if (nts == STATUS_SUCCESS) {
8608 * This code forces Windows to authenticate against the Logon Cache
8609 * first instead of attempting to authenticate against the Domain
8610 * Controller. When the Windows logon cache is enabled this improves
8611 * performance by removing the network access and works around a bug
8612 * seen at sites which are using a MIT Kerberos principal to login
8613 * to machines joined to a non-root domain in a multi-domain forest.
8614 * MsV1_0SetProcessOption was added in Windows XP.
8616 PVOID pResponse = NULL;
8617 ULONG cbResponse = 0;
8618 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8620 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8621 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8622 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8623 OptionsRequest.DisableOptions = FALSE;
8625 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8628 sizeof(OptionsRequest),
8634 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8636 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8638 OutputDebugString(message);
8641 OutputDebugString("MsV1_0SetProcessOption success");
8642 afsi_log("MsV1_0SetProcessOption success");
8644 /* END - code from Larry */
8646 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8647 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8648 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8650 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8652 /* something went wrong. We report the error and revert back to no authentication
8653 because we can't perform any auth requests without a successful lsa handle
8654 or sec package id. */
8655 afsi_log("Reverting to NO SMB AUTH");
8656 smb_authType = SMB_AUTH_NONE;
8659 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8661 /* something went wrong. We report the error and revert back to no authentication
8662 because we can't perform any auth requests without a successful lsa handle
8663 or sec package id. */
8664 afsi_log("Reverting to NO SMB AUTH");
8665 smb_authType = SMB_AUTH_NONE;
8669 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8670 * time prevents the failure of authentication when logged into Windows with an
8671 * external Kerberos principal mapped to a local account.
8673 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8674 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8675 * then the only option is NTLMSSP anyway; so just fallback.
8680 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8681 if (secBlobLength == 0) {
8682 smb_authType = SMB_AUTH_NTLM;
8683 afsi_log("Reverting to SMB AUTH NTLM");
8692 /* Now get ourselves a domain name. */
8693 /* For now we are using the local computer name as the domain name.
8694 * It is actually the domain for local logins, and we are acting as
8695 * a local SMB server.
8697 bufsize = sizeof(smb_ServerDomainName) - 1;
8698 GetComputerName(smb_ServerDomainName, &bufsize);
8699 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8700 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8703 /* Start listeners, waiters, servers, and daemons */
8705 smb_StartListeners();
8707 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8708 NULL, 0, &lpid, "smb_ClientWaiter");
8709 osi_assert(phandle != NULL);
8710 thrd_CloseHandle(phandle);
8712 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8713 NULL, 0, &lpid, "smb_ServerWaiter");
8714 osi_assert(phandle != NULL);
8715 thrd_CloseHandle(phandle);
8717 for (i=0; i<smb_NumServerThreads; i++) {
8718 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8719 (void *) i, 0, &lpid, "smb_Server");
8720 osi_assert(phandle != NULL);
8721 thrd_CloseHandle(phandle);
8724 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8725 NULL, 0, &lpid, "smb_Daemon");
8726 osi_assert(phandle != NULL);
8727 thrd_CloseHandle(phandle);
8729 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8730 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8731 osi_assert(phandle != NULL);
8732 thrd_CloseHandle(phandle);
8737 void smb_Shutdown(void)
8744 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8746 /* setup the NCB system */
8749 /* Block new sessions by setting shutdown flag */
8750 smbShutdownFlag = 1;
8752 /* Hang up all sessions */
8753 memset((char *)ncbp, 0, sizeof(NCB));
8754 for (i = 1; i < numSessions; i++)
8756 if (dead_sessions[i])
8759 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8760 ncbp->ncb_command = NCBHANGUP;
8761 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8762 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8763 code = Netbios(ncbp);
8764 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8765 if (code == 0) code = ncbp->ncb_retcode;
8767 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8768 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8772 /* Trigger the shutdown of all SMB threads */
8773 for (i = 0; i < smb_NumServerThreads; i++)
8774 thrd_SetEvent(NCBreturns[i][0]);
8776 thrd_SetEvent(NCBevents[0]);
8777 thrd_SetEvent(SessionEvents[0]);
8778 thrd_SetEvent(NCBavails[0]);
8780 for (i = 0;i < smb_NumServerThreads; i++) {
8781 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8782 if (code == WAIT_OBJECT_0) {
8785 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8786 thrd_SetEvent(NCBreturns[i--][0]);
8790 /* Delete Netbios name */
8791 memset((char *)ncbp, 0, sizeof(NCB));
8792 for (i = 0; i < lana_list.length; i++) {
8793 if (lana_list.lana[i] == 255) continue;
8794 ncbp->ncb_command = NCBDELNAME;
8795 ncbp->ncb_lana_num = lana_list.lana[i];
8796 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8797 code = Netbios(ncbp);
8799 code = ncbp->ncb_retcode;
8801 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8802 ncbp->ncb_lana_num, code);
8807 /* Release the reference counts held by the VCs */
8808 lock_ObtainWrite(&smb_rctLock);
8809 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8814 if (vcp->magic != SMB_VC_MAGIC)
8815 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8816 __FILE__, __LINE__);
8818 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8820 if (fidp->scp != NULL) {
8823 lock_ObtainMutex(&fidp->mx);
8824 if (fidp->scp != NULL) {
8827 lock_ObtainMutex(&scp->mx);
8828 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
8829 lock_ReleaseMutex(&scp->mx);
8830 osi_Log2(afsd_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
8831 cm_ReleaseSCache(scp);
8833 lock_ReleaseMutex(&fidp->mx);
8837 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8839 smb_ReleaseVCNoLock(tidp->vcp);
8841 cm_user_t *userp = tidp->userp;
8843 lock_ReleaseWrite(&smb_rctLock);
8844 cm_ReleaseUser(userp);
8845 lock_ObtainWrite(&smb_rctLock);
8849 lock_ReleaseWrite(&smb_rctLock);
8851 TlsFree(smb_TlsRequestSlot);
8854 /* Get the UNC \\<servername>\<sharename> prefix. */
8855 char *smb_GetSharename()
8859 /* Make sure we have been properly initialized. */
8860 if (smb_localNamep == NULL)
8863 /* Allocate space for \\<servername>\<sharename>, plus the
8866 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8867 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8873 void smb_LogPacket(smb_packet_t *packet)
8876 unsigned length, paramlen, datalen, i, j;
8878 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8880 if (!packet) return;
8882 osi_Log0(smb_logp, "*** SMB packet dump ***");
8884 vp = (BYTE *) packet->data;
8886 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8887 length = paramlen + 2 + datalen;
8890 for (i=0;i < length; i+=16)
8892 memset( buf, ' ', 80 );
8897 buf[strlen(buf)] = ' ';
8899 cp = (BYTE*) buf + 7;
8901 for (j=0;j < 16 && (i+j)<length; j++)
8903 *(cp++) = hex[vp[i+j] >> 4];
8904 *(cp++) = hex[vp[i+j] & 0xf];
8914 for (j=0;j < 16 && (i+j)<length;j++)
8916 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8927 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
8930 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8932 #endif /* LOG_PACKET */
8935 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8943 lock_ObtainRead(&smb_rctLock);
8945 sprintf(output, "begin dumping smb_vc_t\n");
8946 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8948 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8952 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8953 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8954 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8956 sprintf(output, "begin dumping smb_fid_t\n");
8957 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8959 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8961 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\n",
8962 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8963 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8964 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8965 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8968 sprintf(output, "done dumping smb_fid_t\n");
8969 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8972 sprintf(output, "done dumping smb_vc_t\n");
8973 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8975 sprintf(output, "begin dumping DEAD smb_vc_t\n");
8976 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8978 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
8982 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8983 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8984 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8986 sprintf(output, "begin dumping smb_fid_t\n");
8987 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8989 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8991 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\n",
8992 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8993 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8994 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8995 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
8998 sprintf(output, "done dumping smb_fid_t\n");
8999 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9002 sprintf(output, "done dumping DEAD smb_vc_t\n");
9003 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9005 sprintf(output, "begin dumping DEAD smb_vc_t\n");
9006 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9008 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9012 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
9013 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9014 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9016 sprintf(output, "begin dumping smb_fid_t\n");
9017 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9019 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9021 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\n",
9022 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9023 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9024 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9025 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9028 sprintf(output, "done dumping smb_fid_t\n");
9029 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9032 sprintf(output, "done dumping DEAD smb_vc_t\n");
9033 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9036 lock_ReleaseRead(&smb_rctLock);