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};
63 BOOL isGateway = FALSE;
66 long smb_maxObsConcurrentCalls=0;
67 long smb_concurrentCalls=0;
69 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
71 smb_packet_t *smb_packetFreeListp;
72 smb_ncb_t *smb_ncbFreeListp;
74 int smb_NumServerThreads;
76 int numNCBs, numSessions, numVCs;
78 int smb_maxVCPerServer;
79 int smb_maxMpxRequests;
81 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
83 ULONG smb_lsaSecPackage;
84 LSA_STRING smb_lsaLogonOrigin;
86 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
87 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
88 EVENT_HANDLE **NCBreturns;
89 EVENT_HANDLE **NCBShutdown;
90 EVENT_HANDLE *smb_ServerShutdown;
91 DWORD NCBsessions[NCB_MAX];
93 struct smb_packet *bufs[NCB_MAX];
95 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
96 EVENT_HANDLE SessionEvents[SESSION_MAX];
97 unsigned short LSNs[SESSION_MAX];
98 int lanas[SESSION_MAX];
99 BOOL dead_sessions[SESSION_MAX];
103 osi_mutex_t smb_RawBufLock;
106 #define SMB_MASKFLAG_TILDE 1
107 #define SMB_MASKFLAG_CASEFOLD 2
109 #define RAWTIMEOUT INFINITE
112 typedef struct raw_write_cont {
121 /* dir search stuff */
122 long smb_dirSearchCounter = 1;
123 smb_dirSearch_t *smb_firstDirSearchp;
124 smb_dirSearch_t *smb_lastDirSearchp;
126 /* hide dot files? */
127 int smb_hideDotFiles;
129 /* global state about V3 protocols */
130 int smb_useV3; /* try to negotiate V3 */
132 static showErrors = 0;
133 /* MessageBox or something like it */
134 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
137 * Time in Unix format of midnight, 1/1/1970 local time.
138 * When added to dosUTime, gives Unix (AFS) time.
140 time_t smb_localZero = 0;
142 #define USE_NUMERIC_TIME_CONV 1
144 #ifndef USE_NUMERIC_TIME_CONV
145 /* Time difference for converting to kludge-GMT */
146 afs_uint32 smb_NowTZ;
147 #endif /* USE_NUMERIC_TIME_CONV */
149 char *smb_localNamep = NULL;
151 smb_vc_t *smb_allVCsp;
152 smb_vc_t *smb_deadVCsp;
154 smb_username_t *usernamesp = NULL;
156 smb_waitingLockRequest_t *smb_allWaitingLocks;
158 DWORD smb_TlsRequestSlot = -1;
161 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
162 NCB *ncbp, raw_write_cont_t *rwcp);
163 int smb_NetbiosInit(void);
166 void smb_LogPacket(smb_packet_t *packet);
167 #endif /* LOG_PACKET */
169 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
170 int smb_ServerDomainNameLength = 0;
171 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
172 int smb_ServerOSLength = sizeof(smb_ServerOS);
173 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
174 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
176 /* Faux server GUID. This is never checked. */
177 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
179 void smb_ResetServerPriority()
181 void * p = TlsGetValue(smb_TlsRequestSlot);
184 TlsSetValue(smb_TlsRequestSlot, NULL);
185 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
189 void smb_SetRequestStartTime()
191 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
193 tp = malloc(sizeof(time_t));
197 if (!TlsSetValue(smb_TlsRequestSlot, tp))
202 void smb_UpdateServerPriority()
204 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
207 time_t now = osi_Time();
209 /* Give one priority boost for each 15 seconds */
210 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
215 const char * ncb_error_string(int code)
219 case 0x01: s = "llegal buffer length"; break;
220 case 0x03: s = "illegal command"; break;
221 case 0x05: s = "command timed out"; break;
222 case 0x06: s = "message incomplete, issue another command"; break;
223 case 0x07: s = "illegal buffer address"; break;
224 case 0x08: s = "session number out of range"; break;
225 case 0x09: s = "no resource available"; break;
226 case 0x0a: s = "session closed"; break;
227 case 0x0b: s = "command cancelled"; break;
228 case 0x0d: s = "duplicate name"; break;
229 case 0x0e: s = "name table full"; break;
230 case 0x0f: s = "no deletions, name has active sessions"; break;
231 case 0x11: s = "local session table full"; break;
232 case 0x12: s = "remote session table full"; break;
233 case 0x13: s = "illegal name number"; break;
234 case 0x14: s = "no callname"; break;
235 case 0x15: s = "cannot put * in NCB_NAME"; break;
236 case 0x16: s = "name in use on remote adapter"; break;
237 case 0x17: s = "name deleted"; break;
238 case 0x18: s = "session ended abnormally"; break;
239 case 0x19: s = "name conflict detected"; break;
240 case 0x21: s = "interface busy, IRET before retrying"; break;
241 case 0x22: s = "too many commands outstanding, retry later";break;
242 case 0x23: s = "ncb_lana_num field invalid"; break;
243 case 0x24: s = "command completed while cancel occurring "; break;
244 case 0x26: s = "command not valid to cancel"; break;
245 case 0x30: s = "name defined by anther local process"; break;
246 case 0x34: s = "environment undefined. RESET required"; break;
247 case 0x35: s = "required OS resources exhausted"; break;
248 case 0x36: s = "max number of applications exceeded"; break;
249 case 0x37: s = "no saps available for netbios"; break;
250 case 0x38: s = "requested resources are not available"; break;
251 case 0x39: s = "invalid ncb address or length > segment"; break;
252 case 0x3B: s = "invalid NCB DDID"; break;
253 case 0x3C: s = "lock of user area failed"; break;
254 case 0x3f: s = "NETBIOS not loaded"; break;
255 case 0x40: s = "system error"; break;
256 default: s = "unknown error";
262 char * myCrt_Dispatch(int i)
267 return "(00)ReceiveCoreMakeDir";
269 return "(01)ReceiveCoreRemoveDir";
271 return "(02)ReceiveCoreOpen";
273 return "(03)ReceiveCoreCreate";
275 return "(04)ReceiveCoreClose";
277 return "(05)ReceiveCoreFlush";
279 return "(06)ReceiveCoreUnlink";
281 return "(07)ReceiveCoreRename";
283 return "(08)ReceiveCoreGetFileAttributes";
285 return "(09)ReceiveCoreSetFileAttributes";
287 return "(0a)ReceiveCoreRead";
289 return "(0b)ReceiveCoreWrite";
291 return "(0c)ReceiveCoreLockRecord";
293 return "(0d)ReceiveCoreUnlockRecord";
295 return "(0e)SendCoreBadOp";
297 return "(0f)ReceiveCoreCreate";
299 return "(10)ReceiveCoreCheckPath";
301 return "(11)SendCoreBadOp";
303 return "(12)ReceiveCoreSeek";
305 return "(1a)ReceiveCoreReadRaw";
307 return "(1d)ReceiveCoreWriteRawDummy";
309 return "(22)ReceiveV3SetAttributes";
311 return "(23)ReceiveV3GetAttributes";
313 return "(24)ReceiveV3LockingX";
315 return "(25)ReceiveV3Trans";
317 return "(26)ReceiveV3Trans[aux]";
319 return "(29)SendCoreBadOp";
321 return "(2b)ReceiveCoreEcho";
323 return "(2d)ReceiveV3OpenX";
325 return "(2e)ReceiveV3ReadX";
327 return "(2f)ReceiveV3WriteX";
329 return "(32)ReceiveV3Tran2A";
331 return "(33)ReceiveV3Tran2A[aux]";
333 return "(34)ReceiveV3FindClose";
335 return "(35)ReceiveV3FindNotifyClose";
337 return "(70)ReceiveCoreTreeConnect";
339 return "(71)ReceiveCoreTreeDisconnect";
341 return "(72)ReceiveNegotiate";
343 return "(73)ReceiveV3SessionSetupX";
345 return "(74)ReceiveV3UserLogoffX";
347 return "(75)ReceiveV3TreeConnectX";
349 return "(80)ReceiveCoreGetDiskAttributes";
351 return "(81)ReceiveCoreSearchDir";
355 return "(83)FindUnique";
357 return "(84)FindClose";
359 return "(A0)ReceiveNTTransact";
361 return "(A2)ReceiveNTCreateX";
363 return "(A4)ReceiveNTCancel";
365 return "(A5)ReceiveNTRename";
367 return "(C0)OpenPrintFile";
369 return "(C1)WritePrintFile";
371 return "(C2)ClosePrintFile";
373 return "(C3)GetPrintQueue";
375 return "(D8)ReadBulk";
377 return "(D9)WriteBulk";
379 return "(DA)WriteBulkData";
381 return "unknown SMB op";
385 char * myCrt_2Dispatch(int i)
390 return "unknown SMB op-2";
392 return "S(00)CreateFile_ReceiveTran2Open";
394 return "S(01)FindFirst_ReceiveTran2SearchDir";
396 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
398 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
400 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
402 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
404 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
406 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
408 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
410 return "S(09)_ReceiveTran2FSCTL";
412 return "S(0a)_ReceiveTran2IOCTL";
414 return "S(0b)_ReceiveTran2FindNotifyFirst";
416 return "S(0c)_ReceiveTran2FindNotifyNext";
418 return "S(0d)_ReceiveTran2CreateDirectory";
420 return "S(0e)_ReceiveTran2SessionSetup";
422 return "S(0f)_QueryFileSystemInformationFid";
424 return "S(10)_ReceiveTran2GetDfsReferral";
426 return "S(11)_ReceiveTran2ReportDfsInconsistency";
430 char * myCrt_RapDispatch(int i)
435 return "unknown RAP OP";
437 return "RAP(0)NetShareEnum";
439 return "RAP(1)NetShareGetInfo";
441 return "RAP(13)NetServerGetInfo";
443 return "RAP(63)NetWkStaGetInfo";
447 /* scache must be locked */
448 unsigned int smb_Attributes(cm_scache_t *scp)
452 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
453 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
454 scp->fileType == CM_SCACHETYPE_INVALID)
456 attrs = SMB_ATTR_DIRECTORY;
457 #ifdef SPECIAL_FOLDERS
458 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
459 #endif /* SPECIAL_FOLDERS */
460 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
461 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
466 * We used to mark a file RO if it was in an RO volume, but that
467 * turns out to be impolitic in NT. See defect 10007.
470 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
471 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
473 if ((scp->unixModeBits & 0222) == 0)
474 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
480 /* Check if the named file/dir is a dotfile/dotdir */
481 /* String pointed to by lastComp can have leading slashes, but otherwise should have
482 no other patch components */
483 unsigned int smb_IsDotFile(char *lastComp) {
486 /* skip over slashes */
487 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
492 /* nulls, curdir and parent dir doesn't count */
498 if(*(s+1) == '.' && !*(s + 2))
505 static int ExtractBits(WORD bits, short start, short len)
512 num = bits << (16 - end);
513 num = num >> ((16 - end) + start);
518 void ShowUnixTime(char *FuncName, time_t unixTime)
523 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
525 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
526 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
528 int day, month, year, sec, min, hour;
531 day = ExtractBits(wDate, 0, 5);
532 month = ExtractBits(wDate, 5, 4);
533 year = ExtractBits(wDate, 9, 7) + 1980;
535 sec = ExtractBits(wTime, 0, 5);
536 min = ExtractBits(wTime, 5, 6);
537 hour = ExtractBits(wTime, 11, 5);
539 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
540 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
544 /* Determine if we are observing daylight savings time */
545 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
547 TIME_ZONE_INFORMATION timeZoneInformation;
548 SYSTEMTIME utc, local, localDST;
550 /* Get the time zone info. NT uses this to calc if we are in DST. */
551 GetTimeZoneInformation(&timeZoneInformation);
553 /* Return the daylight bias */
554 *pDstBias = timeZoneInformation.DaylightBias;
556 /* Return the bias */
557 *pBias = timeZoneInformation.Bias;
559 /* Now determine if DST is being observed */
561 /* Get the UTC (GMT) time */
564 /* Convert UTC time to local time using the time zone info. If we are
565 observing DST, the calculated local time will include this.
567 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
569 /* Set the daylight bias to 0. The daylight bias is the amount of change
570 * in time that we use for daylight savings time. By setting this to 0
571 * we cause there to be no change in time during daylight savings time.
573 timeZoneInformation.DaylightBias = 0;
575 /* Convert the utc time to local time again, but this time without any
576 adjustment for daylight savings time.
578 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
580 /* If the two times are different, then it means that the localDST that
581 we calculated includes the daylight bias, and therefore we are
582 observing daylight savings time.
584 *pDST = localDST.wHour != local.wHour;
588 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
590 BOOL dst; /* Will be TRUE if observing DST */
591 LONG dstBias; /* Offset from local time if observing DST */
592 LONG bias; /* Offset from GMT for local time */
595 * This function will adjust the last write time to compensate
596 * for two bugs in the smb client:
598 * 1) During Daylight Savings Time, the LastWriteTime is ahead
599 * in time by the DaylightBias (ignoring the sign - the
600 * DaylightBias is always stored as a negative number). If
601 * the DaylightBias is -60, then the LastWriteTime will be
602 * ahead by 60 minutes.
604 * 2) If the local time zone is a positive offset from GMT, then
605 * the LastWriteTime will be the correct local time plus the
606 * Bias (ignoring the sign - a positive offset from GMT is
607 * always stored as a negative Bias). If the Bias is -120,
608 * then the LastWriteTime will be ahead by 120 minutes.
610 * These bugs can occur at the same time.
613 GetTimeZoneInfo(&dst, &dstBias, &bias);
615 /* First adjust for DST */
617 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
619 /* Now adjust for a positive offset from GMT (a negative bias). */
621 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
624 #ifndef USE_NUMERIC_TIME_CONV
626 * Calculate the difference (in seconds) between local time and GMT.
627 * This enables us to convert file times to kludge-GMT.
633 struct tm gmt_tm, local_tm;
634 int days, hours, minutes, seconds;
637 gmt_tm = *(gmtime(&t));
638 local_tm = *(localtime(&t));
640 days = local_tm.tm_yday - gmt_tm.tm_yday;
641 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
642 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
643 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
647 #endif /* USE_NUMERIC_TIME_CONV */
649 #ifdef USE_NUMERIC_TIME_CONV
650 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
652 // Note that LONGLONG is a 64-bit value
655 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
656 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
657 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
660 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
665 time_t ersatz_unixTime;
668 * Must use kludge-GMT instead of real GMT.
669 * kludge-GMT is computed by adding time zone difference to localtime.
672 * ltp = gmtime(&unixTime);
674 ersatz_unixTime = unixTime - smb_NowTZ;
675 ltp = localtime(&ersatz_unixTime);
677 /* if we fail, make up something */
680 localJunk.tm_year = 89 - 20;
681 localJunk.tm_mon = 4;
682 localJunk.tm_mday = 12;
683 localJunk.tm_hour = 0;
684 localJunk.tm_min = 0;
685 localJunk.tm_sec = 0;
688 stm.wYear = ltp->tm_year + 1900;
689 stm.wMonth = ltp->tm_mon + 1;
690 stm.wDayOfWeek = ltp->tm_wday;
691 stm.wDay = ltp->tm_mday;
692 stm.wHour = ltp->tm_hour;
693 stm.wMinute = ltp->tm_min;
694 stm.wSecond = ltp->tm_sec;
695 stm.wMilliseconds = 0;
697 SystemTimeToFileTime(&stm, largeTimep);
699 #endif /* USE_NUMERIC_TIME_CONV */
701 #ifdef USE_NUMERIC_TIME_CONV
702 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
704 // Note that LONGLONG is a 64-bit value
707 ll = largeTimep->dwHighDateTime;
709 ll += largeTimep->dwLowDateTime;
711 ll -= 116444736000000000;
714 *unixTimep = (DWORD)ll;
716 #else /* USE_NUMERIC_TIME_CONV */
717 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
723 FileTimeToSystemTime(largeTimep, &stm);
725 lt.tm_year = stm.wYear - 1900;
726 lt.tm_mon = stm.wMonth - 1;
727 lt.tm_wday = stm.wDayOfWeek;
728 lt.tm_mday = stm.wDay;
729 lt.tm_hour = stm.wHour;
730 lt.tm_min = stm.wMinute;
731 lt.tm_sec = stm.wSecond;
734 save_timezone = _timezone;
735 _timezone += smb_NowTZ;
736 *unixTimep = mktime(<);
737 _timezone = save_timezone;
739 #endif /* USE_NUMERIC_TIME_CONV */
741 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
751 /* if we fail, make up something */
754 localJunk.tm_year = 89 - 20;
755 localJunk.tm_mon = 4;
756 localJunk.tm_mday = 12;
757 localJunk.tm_hour = 0;
758 localJunk.tm_min = 0;
759 localJunk.tm_sec = 0;
762 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
763 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
764 *searchTimep = (dosDate<<16) | dosTime;
767 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
769 unsigned short dosDate;
770 unsigned short dosTime;
773 dosDate = (unsigned short) (searchTime & 0xffff);
774 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
776 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
777 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
778 localTm.tm_mday = (dosDate) & 0x1f;
779 localTm.tm_hour = (dosTime>>11) & 0x1f;
780 localTm.tm_min = (dosTime >> 5) & 0x3f;
781 localTm.tm_sec = (dosTime & 0x1f) * 2;
782 localTm.tm_isdst = -1; /* compute whether DST in effect */
784 *unixTimep = mktime(&localTm);
787 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
789 time_t diff_t = unixTime - smb_localZero;
790 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
791 osi_assert(diff_t < _UI32_MAX);
793 *dosUTimep = (afs_uint32)diff_t;
796 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
798 *unixTimep = dosTime + smb_localZero;
801 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
805 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
806 lock_ObtainWrite(&smb_rctLock);
807 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
808 if (vcp->magic != SMB_VC_MAGIC)
809 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
812 if (lsn == vcp->lsn && lana == vcp->lana &&
813 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
814 smb_HoldVCNoLock(vcp);
818 if (!vcp && (flags & SMB_FLAG_CREATE)) {
819 vcp = malloc(sizeof(*vcp));
820 memset(vcp, 0, sizeof(*vcp));
821 vcp->vcID = ++numVCs;
822 vcp->magic = SMB_VC_MAGIC;
823 vcp->refCount = 2; /* smb_allVCsp and caller */
826 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
827 vcp->nextp = smb_allVCsp;
829 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
834 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
835 /* We must obtain a challenge for extended auth
836 * in case the client negotiates smb v3
838 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
839 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
840 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
841 ULONG lsaRespSize = 0;
843 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
845 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
852 if (nts != STATUS_SUCCESS)
853 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
854 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
855 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
857 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
858 LsaFreeReturnBuffer(lsaResp);
861 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
863 if (numVCs >= CM_SESSION_RESERVED) {
865 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
868 lock_ReleaseWrite(&smb_rctLock);
869 lock_ReleaseWrite(&smb_globalLock);
873 int smb_IsStarMask(char *maskp)
878 for(i=0; i<11; i++) {
880 if (tc == '?' || tc == '*' || tc == '>')
886 void smb_ReleaseVCInternal(smb_vc_t *vcp)
893 if (vcp->refCount == 0) {
894 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
895 /* remove VCP from smb_deadVCsp */
896 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
902 lock_FinalizeMutex(&vcp->mx);
903 memset(vcp,0,sizeof(smb_vc_t));
906 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
910 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
911 avcp?"not ":"",vcp, vcp->refCount);
913 GenerateMiniDump(NULL);
915 /* This is a wrong. However, I suspect that there is an undercount
916 * and I don't want to release 1.4.1 in a state that will allow
917 * smb_vc_t objects to be deallocated while still in the
918 * smb_allVCsp list. The list is supposed to keep a reference
919 * to the smb_vc_t. Put it back.
926 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
928 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
929 smb_ReleaseVCInternal(vcp);
932 void smb_ReleaseVC(smb_vc_t *vcp)
934 lock_ObtainWrite(&smb_rctLock);
935 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
936 smb_ReleaseVCInternal(vcp);
937 lock_ReleaseWrite(&smb_rctLock);
940 void smb_HoldVCNoLock(smb_vc_t *vcp)
943 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
946 void smb_HoldVC(smb_vc_t *vcp)
948 lock_ObtainWrite(&smb_rctLock);
950 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
951 lock_ReleaseWrite(&smb_rctLock);
954 void smb_CleanupDeadVC(smb_vc_t *vcp)
962 smb_user_t *uidpIter;
963 smb_user_t *uidpNext;
967 lock_ObtainMutex(&vcp->mx);
968 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
969 lock_ReleaseMutex(&vcp->mx);
970 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
973 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
974 lock_ReleaseMutex(&vcp->mx);
975 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
977 lock_ObtainWrite(&smb_rctLock);
978 /* remove VCP from smb_allVCsp */
979 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
980 if ((*vcpp)->magic != SMB_VC_MAGIC)
981 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
985 vcp->nextp = smb_deadVCsp;
987 /* Hold onto the reference until we are done with this function */
992 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
993 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
995 if (fidpIter->delete)
999 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1001 smb_HoldFIDNoLock(fidpIter);
1002 lock_ReleaseWrite(&smb_rctLock);
1004 smb_CloseFID(vcp, fidpIter, NULL, 0);
1005 smb_ReleaseFID(fidpIter);
1007 lock_ObtainWrite(&smb_rctLock);
1008 fidpNext = vcp->fidsp;
1011 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1012 tidpNext = tidpIter->nextp;
1013 if (tidpIter->delete)
1015 tidpIter->delete = 1;
1017 tid = tidpIter->tid;
1018 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1020 smb_HoldTIDNoLock(tidpIter);
1021 lock_ReleaseWrite(&smb_rctLock);
1023 smb_ReleaseTID(tidpIter);
1025 lock_ObtainWrite(&smb_rctLock);
1026 tidpNext = vcp->tidsp;
1029 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1030 uidpNext = uidpIter->nextp;
1031 if (uidpIter->delete)
1033 uidpIter->delete = 1;
1035 /* do not add an additional reference count for the smb_user_t
1036 * as the smb_vc_t already is holding a reference */
1037 lock_ReleaseWrite(&smb_rctLock);
1039 smb_ReleaseUID(uidpIter);
1041 lock_ObtainWrite(&smb_rctLock);
1042 uidpNext = vcp->usersp;
1045 /* The vcp is now on the deadVCsp list. We intentionally drop the
1046 * reference so that the refcount can reach 0 and we can delete it */
1047 smb_ReleaseVCNoLock(vcp);
1049 lock_ReleaseWrite(&smb_rctLock);
1050 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1053 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1057 lock_ObtainWrite(&smb_rctLock);
1059 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1060 if (tidp->refCount == 0 && tidp->delete) {
1062 lock_ReleaseWrite(&smb_rctLock);
1063 smb_ReleaseTID(tidp);
1064 lock_ObtainWrite(&smb_rctLock);
1068 if (tid == tidp->tid) {
1073 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1074 tidp = malloc(sizeof(*tidp));
1075 memset(tidp, 0, sizeof(*tidp));
1076 tidp->nextp = vcp->tidsp;
1079 smb_HoldVCNoLock(vcp);
1081 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1084 lock_ReleaseWrite(&smb_rctLock);
1088 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1093 void smb_ReleaseTID(smb_tid_t *tidp)
1100 lock_ObtainWrite(&smb_rctLock);
1101 osi_assert(tidp->refCount-- > 0);
1102 if (tidp->refCount == 0 && (tidp->delete)) {
1103 ltpp = &tidp->vcp->tidsp;
1104 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1108 osi_assert(tp != NULL);
1110 lock_FinalizeMutex(&tidp->mx);
1111 userp = tidp->userp; /* remember to drop ref later */
1113 smb_ReleaseVCNoLock(tidp->vcp);
1116 lock_ReleaseWrite(&smb_rctLock);
1118 cm_ReleaseUser(userp);
1121 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1123 smb_user_t *uidp = NULL;
1125 lock_ObtainWrite(&smb_rctLock);
1126 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1127 if (uid == uidp->userID) {
1129 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1131 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1135 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1136 uidp = malloc(sizeof(*uidp));
1137 memset(uidp, 0, sizeof(*uidp));
1138 uidp->nextp = vcp->usersp;
1139 uidp->refCount = 2; /* one for the vcp and one for the caller */
1141 smb_HoldVCNoLock(vcp);
1143 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1145 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1147 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1149 lock_ReleaseWrite(&smb_rctLock);
1153 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1155 smb_username_t *unp= NULL;
1157 lock_ObtainWrite(&smb_rctLock);
1158 for(unp = usernamesp; unp; unp = unp->nextp) {
1159 if (stricmp(unp->name, usern) == 0 &&
1160 stricmp(unp->machine, machine) == 0) {
1165 if (!unp && (flags & SMB_FLAG_CREATE)) {
1166 unp = malloc(sizeof(*unp));
1167 memset(unp, 0, sizeof(*unp));
1169 unp->nextp = usernamesp;
1170 unp->name = strdup(usern);
1171 unp->machine = strdup(machine);
1173 lock_InitializeMutex(&unp->mx, "username_t mutex");
1174 if (flags & SMB_FLAG_AFSLOGON)
1175 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1178 lock_ReleaseWrite(&smb_rctLock);
1182 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1184 smb_user_t *uidp= NULL;
1186 lock_ObtainWrite(&smb_rctLock);
1187 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1190 if (stricmp(uidp->unp->name, usern) == 0) {
1192 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1193 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1198 lock_ReleaseWrite(&smb_rctLock);
1202 void smb_ReleaseUsername(smb_username_t *unp)
1205 smb_username_t **lupp;
1206 cm_user_t *userp = NULL;
1207 time_t now = osi_Time();
1209 lock_ObtainWrite(&smb_rctLock);
1210 osi_assert(unp->refCount-- > 0);
1211 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1212 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1214 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1218 osi_assert(up != NULL);
1220 up->nextp = NULL; /* do not remove this */
1221 lock_FinalizeMutex(&unp->mx);
1227 lock_ReleaseWrite(&smb_rctLock);
1230 cm_ReleaseUser(userp);
1234 void smb_HoldUIDNoLock(smb_user_t *uidp)
1239 void smb_ReleaseUID(smb_user_t *uidp)
1243 smb_username_t *unp = NULL;
1245 lock_ObtainWrite(&smb_rctLock);
1246 osi_assert(uidp->refCount-- > 0);
1247 if (uidp->refCount == 0) {
1248 lupp = &uidp->vcp->usersp;
1249 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1253 osi_assert(up != NULL);
1255 lock_FinalizeMutex(&uidp->mx);
1257 smb_ReleaseVCNoLock(uidp->vcp);
1261 lock_ReleaseWrite(&smb_rctLock);
1265 cm_ReleaseUserVCRef(unp->userp);
1266 smb_ReleaseUsername(unp);
1270 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1272 cm_user_t *up = NULL;
1277 lock_ObtainMutex(&uidp->mx);
1279 up = uidp->unp->userp;
1282 lock_ReleaseMutex(&uidp->mx);
1288 /* retrieve a held reference to a user structure corresponding to an incoming
1290 * corresponding release function is cm_ReleaseUser.
1292 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1295 cm_user_t *up = NULL;
1298 smbp = (smb_t *) inp;
1299 uidp = smb_FindUID(vcp, smbp->uid, 0);
1303 up = smb_GetUserFromUID(uidp);
1305 smb_ReleaseUID(uidp);
1310 * Return a pointer to a pathname extracted from a TID structure. The
1311 * TID structure is not held; assume it won't go away.
1313 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1318 tidp = smb_FindTID(vcp, tid, 0);
1322 if (tidp->flags & SMB_TIDFLAG_IPC) {
1323 code = CM_ERROR_TIDIPC;
1324 /* tidp->pathname would be NULL, but that's fine */
1326 *treepath = tidp->pathname;
1327 smb_ReleaseTID(tidp);
1332 /* check to see if we have a chained fid, that is, a fid that comes from an
1333 * OpenAndX message that ran earlier in this packet. In this case, the fid
1334 * field in a read, for example, request, isn't set, since the value is
1335 * supposed to be inherited from the openAndX call.
1337 int smb_ChainFID(int fid, smb_packet_t *inp)
1339 if (inp->fid == 0 || inp->inCount == 0)
1345 /* are we a priv'd user? What does this mean on NT? */
1346 int smb_SUser(cm_user_t *userp)
1351 /* find a file ID. If we pass in 0 we select an unused File ID.
1352 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1353 * smb_fid_t data structure if desired File ID cannot be found.
1355 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1360 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1363 lock_ObtainWrite(&smb_rctLock);
1364 /* figure out if we need to allocate a new file ID */
1367 fid = vcp->fidCounter;
1371 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1372 if (fidp->refCount == 0 && fidp->delete) {
1374 lock_ReleaseWrite(&smb_rctLock);
1375 smb_ReleaseFID(fidp);
1376 lock_ObtainWrite(&smb_rctLock);
1379 if (fid == fidp->fid) {
1382 if (fid == 0xFFFF) {
1384 "New FID number wraps on vcp 0x%x", vcp);
1394 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1395 char eventName[MAX_PATH];
1397 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1398 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1399 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1400 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1401 thrd_CloseHandle(event);
1403 if (fid == 0xFFFF) {
1404 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1410 fidp = malloc(sizeof(*fidp));
1411 memset(fidp, 0, sizeof(*fidp));
1412 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1415 smb_HoldVCNoLock(vcp);
1416 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1418 fidp->curr_chunk = fidp->prev_chunk = -2;
1419 fidp->raw_write_event = event;
1421 vcp->fidCounter = fid+1;
1422 if (vcp->fidCounter == 0xFFFF) {
1423 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1425 vcp->fidCounter = 1;
1430 lock_ReleaseWrite(&smb_rctLock);
1434 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1436 smb_fid_t *fidp = NULL;
1442 lock_ObtainWrite(&smb_rctLock);
1443 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1444 if (scp == fidp->scp) {
1449 lock_ReleaseWrite(&smb_rctLock);
1453 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1459 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1460 /* the sm_fid_t->mx and smb_rctLock must not be held */
1461 void smb_ReleaseFID(smb_fid_t *fidp)
1463 cm_scache_t *scp = NULL;
1464 cm_user_t *userp = NULL;
1465 smb_vc_t *vcp = NULL;
1466 smb_ioctl_t *ioctlp;
1468 lock_ObtainMutex(&fidp->mx);
1469 lock_ObtainWrite(&smb_rctLock);
1470 osi_assert(fidp->refCount-- > 0);
1471 if (fidp->refCount == 0 && (fidp->delete)) {
1474 scp = fidp->scp; /* release after lock is released */
1476 lock_ObtainMutex(&scp->mx);
1477 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1478 lock_ReleaseMutex(&scp->mx);
1479 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1482 userp = fidp->userp;
1486 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1487 thrd_CloseHandle(fidp->raw_write_event);
1489 /* and see if there is ioctl stuff to free */
1490 ioctlp = fidp->ioctlp;
1493 cm_FreeSpace(ioctlp->prefix);
1494 if (ioctlp->inAllocp)
1495 free(ioctlp->inAllocp);
1496 if (ioctlp->outAllocp)
1497 free(ioctlp->outAllocp);
1500 lock_ReleaseMutex(&fidp->mx);
1501 lock_FinalizeMutex(&fidp->mx);
1505 smb_ReleaseVCNoLock(vcp);
1507 lock_ReleaseMutex(&fidp->mx);
1509 lock_ReleaseWrite(&smb_rctLock);
1511 /* now release the scache structure */
1513 cm_ReleaseSCache(scp);
1516 cm_ReleaseUser(userp);
1520 * Case-insensitive search for one string in another;
1521 * used to find variable names in submount pathnames.
1523 static char *smb_stristr(char *str1, char *str2)
1527 for (cursor = str1; *cursor; cursor++)
1528 if (stricmp(cursor, str2) == 0)
1535 * Substitute a variable value for its name in a submount pathname. Variable
1536 * name has been identified by smb_stristr() and is in substr. Variable name
1537 * length (plus one) is in substr_size. Variable value is in newstr.
1539 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1544 strcpy(temp, substr + substr_size - 1);
1545 strcpy(substr, newstr);
1549 char VNUserName[] = "%USERNAME%";
1550 char VNLCUserName[] = "%LCUSERNAME%";
1551 char VNComputerName[] = "%COMPUTERNAME%";
1552 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1555 typedef struct smb_findShare_rock {
1559 } smb_findShare_rock_t;
1561 #define SMB_FINDSHARE_EXACT_MATCH 1
1562 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1564 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1568 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1569 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1570 if(!stricmp(dep->name, vrock->shareName))
1571 matchType = SMB_FINDSHARE_EXACT_MATCH;
1573 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1574 if(vrock->match) free(vrock->match);
1575 vrock->match = strdup(dep->name);
1576 vrock->matchType = matchType;
1578 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1579 return CM_ERROR_STOPNOW;
1585 /* find a shareName in the table of submounts */
1586 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1590 char pathName[1024];
1597 DWORD allSubmount = 1;
1599 /* if allSubmounts == 0, only return the //mountRoot/all share
1600 * if in fact it has been been created in the subMounts table.
1601 * This is to allow sites that want to restrict access to the
1604 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1605 0, KEY_QUERY_VALUE, &parmKey);
1606 if (code == ERROR_SUCCESS) {
1607 len = sizeof(allSubmount);
1608 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1609 (BYTE *) &allSubmount, &len);
1610 if (code != ERROR_SUCCESS) {
1613 RegCloseKey (parmKey);
1616 if (allSubmount && _stricmp(shareName, "all") == 0) {
1621 /* In case, the all share is disabled we need to still be able
1622 * to handle ioctl requests
1624 if (_stricmp(shareName, "ioctl$") == 0) {
1625 *pathNamep = strdup("/.__ioctl__");
1629 if (_stricmp(shareName, "IPC$") == 0 ||
1630 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1631 _stricmp(shareName, "DESKTOP.INI") == 0
1637 /* Check for volume references
1639 * They look like <cell>{%,#}<volume>
1641 if (strchr(shareName, '%') != NULL ||
1642 strchr(shareName, '#') != NULL) {
1643 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1644 /* make room for '/@vol:' + mountchar + NULL terminator*/
1646 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1647 osi_LogSaveString(smb_logp, shareName));
1649 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1650 "/" CM_PREFIX_VOL "%s", shareName);
1651 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1652 len = strlen(pathstr);
1654 *pathNamep = malloc(len);
1656 strcpy(*pathNamep, pathstr);
1658 osi_Log1(smb_logp, " returning pathname [%s]",
1659 osi_LogSaveString(smb_logp, *pathNamep));
1667 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1668 0, KEY_QUERY_VALUE, &parmKey);
1669 if (code == ERROR_SUCCESS) {
1670 len = sizeof(pathName);
1671 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1672 (BYTE *) pathName, &len);
1673 if (code != ERROR_SUCCESS)
1675 RegCloseKey (parmKey);
1679 if (len != 0 && len != sizeof(pathName) - 1) {
1680 /* We can accept either unix or PC style AFS pathnames. Convert
1681 * Unix-style to PC style here for internal use.
1684 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1685 p += strlen(cm_mountRoot); /* skip mount path */
1688 if (*q == '/') *q = '\\'; /* change to \ */
1694 if (var = smb_stristr(p, VNUserName)) {
1695 if (uidp && uidp->unp)
1696 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1698 smb_subst(p, var, sizeof(VNUserName)," ");
1700 else if (var = smb_stristr(p, VNLCUserName))
1702 if (uidp && uidp->unp)
1703 strcpy(temp, uidp->unp->name);
1707 smb_subst(p, var, sizeof(VNLCUserName), temp);
1709 else if (var = smb_stristr(p, VNComputerName))
1711 sizeTemp = sizeof(temp);
1712 GetComputerName((LPTSTR)temp, &sizeTemp);
1713 smb_subst(p, var, sizeof(VNComputerName), temp);
1715 else if (var = smb_stristr(p, VNLCComputerName))
1717 sizeTemp = sizeof(temp);
1718 GetComputerName((LPTSTR)temp, &sizeTemp);
1720 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1725 *pathNamep = strdup(p);
1730 /* First lookup shareName in root.afs */
1732 smb_findShare_rock_t vrock;
1734 char * p = shareName;
1737 /* attempt to locate a partial match in root.afs. This is because
1738 when using the ANSI RAP calls, the share name is limited to 13 chars
1739 and hence is truncated. Of course we prefer exact matches. */
1741 thyper.HighPart = 0;
1744 vrock.shareName = shareName;
1746 vrock.matchType = 0;
1748 cm_HoldSCache(cm_data.rootSCachep);
1749 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1750 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1751 cm_ReleaseSCache(cm_data.rootSCachep);
1753 if (vrock.matchType) {
1754 sprintf(pathName,"/%s/",vrock.match);
1755 *pathNamep = strdup(strlwr(pathName));
1760 /* if we get here, there was no match for the share in root.afs */
1761 /* so try to create \\<netbiosName>\<cellname> */
1766 /* Get the full name for this cell */
1767 code = cm_SearchCellFile(p, temp, 0, 0);
1768 #ifdef AFS_AFSDB_ENV
1769 if (code && cm_dnsEnabled) {
1771 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1774 /* construct the path */
1776 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1777 *pathNamep = strdup(strlwr(pathName));
1786 /* Client-side offline caching policy types */
1787 #define CSC_POLICY_MANUAL 0
1788 #define CSC_POLICY_DOCUMENTS 1
1789 #define CSC_POLICY_PROGRAMS 2
1790 #define CSC_POLICY_DISABLE 3
1792 int smb_FindShareCSCPolicy(char *shareName)
1798 int retval = CSC_POLICY_MANUAL;
1800 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1801 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1804 REG_OPTION_NON_VOLATILE,
1810 len = sizeof(policy);
1811 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1813 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1815 else if (stricmp(policy, "documents") == 0)
1817 retval = CSC_POLICY_DOCUMENTS;
1819 else if (stricmp(policy, "programs") == 0)
1821 retval = CSC_POLICY_PROGRAMS;
1823 else if (stricmp(policy, "disable") == 0)
1825 retval = CSC_POLICY_DISABLE;
1828 RegCloseKey(hkCSCPolicy);
1832 /* find a dir search structure by cookie value, and return it held.
1833 * Must be called with smb_globalLock held.
1835 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1837 smb_dirSearch_t *dsp;
1839 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1840 if (dsp->cookie == cookie) {
1841 if (dsp != smb_firstDirSearchp) {
1842 /* move to head of LRU queue, too, if we're not already there */
1843 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1844 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1845 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1846 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1847 if (!smb_lastDirSearchp)
1848 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1850 lock_ObtainMutex(&dsp->mx);
1852 lock_ReleaseMutex(&dsp->mx);
1858 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1859 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1860 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1866 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1868 lock_ObtainWrite(&smb_globalLock);
1869 lock_ObtainMutex(&dsp->mx);
1870 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1871 dsp->cookie, dsp, dsp->scp);
1872 dsp->flags |= SMB_DIRSEARCH_DELETE;
1873 if (dsp->scp != NULL) {
1874 lock_ObtainMutex(&dsp->scp->mx);
1875 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1876 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1877 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1878 dsp->scp->bulkStatProgress = hzero;
1880 lock_ReleaseMutex(&dsp->scp->mx);
1882 lock_ReleaseMutex(&dsp->mx);
1883 lock_ReleaseWrite(&smb_globalLock);
1886 /* Must be called with the smb_globalLock held */
1887 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1889 cm_scache_t *scp = NULL;
1891 lock_ObtainMutex(&dsp->mx);
1892 osi_assert(dsp->refCount-- > 0);
1893 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1894 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1895 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1896 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1897 lock_ReleaseMutex(&dsp->mx);
1898 lock_FinalizeMutex(&dsp->mx);
1900 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1901 dsp->cookie, dsp, scp);
1904 lock_ReleaseMutex(&dsp->mx);
1906 /* do this now to avoid spurious locking hierarchy creation */
1908 cm_ReleaseSCache(scp);
1911 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1913 lock_ObtainWrite(&smb_globalLock);
1914 smb_ReleaseDirSearchNoLock(dsp);
1915 lock_ReleaseWrite(&smb_globalLock);
1918 /* find a dir search structure by cookie value, and return it held */
1919 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1921 smb_dirSearch_t *dsp;
1923 lock_ObtainWrite(&smb_globalLock);
1924 dsp = smb_FindDirSearchNoLock(cookie);
1925 lock_ReleaseWrite(&smb_globalLock);
1929 /* GC some dir search entries, in the address space expected by the specific protocol.
1930 * Must be called with smb_globalLock held; release the lock temporarily.
1932 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1933 void smb_GCDirSearches(int isV3)
1935 smb_dirSearch_t *prevp;
1936 smb_dirSearch_t *tp;
1937 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1941 victimCount = 0; /* how many have we got so far */
1942 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1943 /* we'll move tp from queue, so
1946 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1947 /* if no one is using this guy, and we're either in the new protocol,
1948 * or we're in the old one and this is a small enough ID to be useful
1949 * to the old protocol, GC this guy.
1951 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1952 /* hold and delete */
1953 lock_ObtainMutex(&tp->mx);
1954 tp->flags |= SMB_DIRSEARCH_DELETE;
1955 lock_ReleaseMutex(&tp->mx);
1956 victimsp[victimCount++] = tp;
1960 /* don't do more than this */
1961 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1965 /* now release them */
1966 for (i = 0; i < victimCount; i++) {
1967 smb_ReleaseDirSearchNoLock(victimsp[i]);
1971 /* function for allocating a dir search entry. We need these to remember enough context
1972 * since we don't get passed the path from call to call during a directory search.
1974 * Returns a held dir search structure, and bumps the reference count on the vnode,
1975 * since it saves a pointer to the vnode.
1977 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1979 smb_dirSearch_t *dsp;
1985 lock_ObtainWrite(&smb_globalLock);
1988 /* what's the biggest ID allowed in this version of the protocol */
1989 /* TODO: do we really want a non v3 dir search request to wrap
1990 smb_dirSearchCounter? */
1991 maxAllowed = isV3 ? 65535 : 255;
1992 if (smb_dirSearchCounter > maxAllowed)
1993 smb_dirSearchCounter = 1;
1995 start = smb_dirSearchCounter;
1998 /* twice so we have enough tries to find guys we GC after one pass;
1999 * 10 extra is just in case I mis-counted.
2001 if (++counter > 2*maxAllowed+10)
2002 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2004 if (smb_dirSearchCounter > maxAllowed) {
2005 smb_dirSearchCounter = 1;
2007 if (smb_dirSearchCounter == start) {
2009 smb_GCDirSearches(isV3);
2012 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2014 /* don't need to watch for refcount zero and deleted, since
2015 * we haven't dropped the global lock.
2017 lock_ObtainMutex(&dsp->mx);
2019 lock_ReleaseMutex(&dsp->mx);
2020 ++smb_dirSearchCounter;
2024 dsp = malloc(sizeof(*dsp));
2025 memset(dsp, 0, sizeof(*dsp));
2026 dsp->cookie = smb_dirSearchCounter;
2027 ++smb_dirSearchCounter;
2029 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2030 dsp->lastTime = osi_Time();
2031 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2032 if (!smb_lastDirSearchp)
2033 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2035 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2039 lock_ReleaseWrite(&smb_globalLock);
2043 static smb_packet_t *GetPacket(void)
2047 lock_ObtainWrite(&smb_globalLock);
2048 tbp = smb_packetFreeListp;
2050 smb_packetFreeListp = tbp->nextp;
2051 lock_ReleaseWrite(&smb_globalLock);
2053 tbp = calloc(65540,1);
2054 tbp->magic = SMB_PACKETMAGIC;
2057 tbp->resumeCode = 0;
2063 tbp->ncb_length = 0;
2068 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2073 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2077 memcpy(tbp, pkt, sizeof(smb_packet_t));
2078 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2080 smb_HoldVC(tbp->vcp);
2084 static NCB *GetNCB(void)
2089 lock_ObtainWrite(&smb_globalLock);
2090 tbp = smb_ncbFreeListp;
2092 smb_ncbFreeListp = tbp->nextp;
2093 lock_ReleaseWrite(&smb_globalLock);
2095 tbp = calloc(sizeof(*tbp),1);
2096 tbp->magic = SMB_NCBMAGIC;
2099 osi_assert(tbp->magic == SMB_NCBMAGIC);
2101 memset(&tbp->ncb, 0, sizeof(NCB));
2106 void smb_FreePacket(smb_packet_t *tbp)
2108 smb_vc_t * vcp = NULL;
2109 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2111 lock_ObtainWrite(&smb_globalLock);
2112 tbp->nextp = smb_packetFreeListp;
2113 smb_packetFreeListp = tbp;
2114 tbp->magic = SMB_PACKETMAGIC;
2118 tbp->resumeCode = 0;
2124 tbp->ncb_length = 0;
2126 lock_ReleaseWrite(&smb_globalLock);
2132 static void FreeNCB(NCB *bufferp)
2136 tbp = (smb_ncb_t *) bufferp;
2137 osi_assert(tbp->magic == SMB_NCBMAGIC);
2139 lock_ObtainWrite(&smb_globalLock);
2140 tbp->nextp = smb_ncbFreeListp;
2141 smb_ncbFreeListp = tbp;
2142 lock_ReleaseWrite(&smb_globalLock);
2145 /* get a ptr to the data part of a packet, and its count */
2146 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2150 unsigned char *afterParmsp;
2152 parmBytes = *smbp->wctp << 1;
2153 afterParmsp = smbp->wctp + parmBytes + 1;
2155 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2156 if (nbytesp) *nbytesp = dataBytes;
2158 /* don't forget to skip the data byte count, since it follows
2159 * the parameters; that's where the "2" comes from below.
2161 return (unsigned char *) (afterParmsp + 2);
2164 /* must set all the returned parameters before playing around with the
2165 * data region, since the data region is located past the end of the
2166 * variable number of parameters.
2168 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2170 unsigned char *afterParmsp;
2172 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2174 *afterParmsp++ = dsize & 0xff;
2175 *afterParmsp = (dsize>>8) & 0xff;
2178 /* return the parm'th parameter in the smbp packet */
2179 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2182 unsigned char *parmDatap;
2184 parmCount = *smbp->wctp;
2186 if (parm >= parmCount) {
2189 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2190 parm, parmCount, smbp->ncb_length);
2191 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2192 parm, parmCount, smbp->ncb_length);
2193 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2194 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2195 osi_panic(s, __FILE__, __LINE__);
2197 parmDatap = smbp->wctp + (2*parm) + 1;
2199 return parmDatap[0] + (parmDatap[1] << 8);
2202 /* return the parm'th parameter in the smbp packet */
2203 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2206 unsigned char *parmDatap;
2208 parmCount = *smbp->wctp;
2210 if (parm >= parmCount) {
2213 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2214 parm, parmCount, smbp->ncb_length);
2215 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2216 parm, parmCount, smbp->ncb_length);
2217 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2218 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2219 osi_panic(s, __FILE__, __LINE__);
2221 parmDatap = smbp->wctp + (2*parm) + 1;
2223 return parmDatap[0];
2226 /* return the parm'th parameter in the smbp packet */
2227 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2230 unsigned char *parmDatap;
2232 parmCount = *smbp->wctp;
2234 if (parm + 1 >= parmCount) {
2237 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2238 parm, parmCount, smbp->ncb_length);
2239 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2240 parm, parmCount, smbp->ncb_length);
2241 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2242 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2243 osi_panic(s, __FILE__, __LINE__);
2245 parmDatap = smbp->wctp + (2*parm) + 1;
2247 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2250 /* return the parm'th parameter in the smbp packet */
2251 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2254 unsigned char *parmDatap;
2256 parmCount = *smbp->wctp;
2258 if (parm * 2 + offset >= parmCount * 2) {
2261 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2262 parm, offset, parmCount, smbp->ncb_length);
2263 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2264 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2265 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2266 parm, offset, parmCount, smbp->ncb_length);
2267 osi_panic(s, __FILE__, __LINE__);
2269 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2271 return parmDatap[0] + (parmDatap[1] << 8);
2274 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2278 /* make sure we have enough slots */
2279 if (*smbp->wctp <= slot)
2280 *smbp->wctp = slot+1;
2282 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2283 *parmDatap++ = parmValue & 0xff;
2284 *parmDatap = (parmValue>>8) & 0xff;
2287 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2291 /* make sure we have enough slots */
2292 if (*smbp->wctp <= slot)
2293 *smbp->wctp = slot+2;
2295 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2296 *parmDatap++ = parmValue & 0xff;
2297 *parmDatap++ = (parmValue>>8) & 0xff;
2298 *parmDatap++ = (parmValue>>16) & 0xff;
2299 *parmDatap = (parmValue>>24) & 0xff;
2302 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2307 /* make sure we have enough slots */
2308 if (*smbp->wctp <= slot)
2309 *smbp->wctp = slot+4;
2311 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2313 *parmDatap++ = *parmValuep++;
2316 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2320 /* make sure we have enough slots */
2321 if (*smbp->wctp <= slot) {
2322 if (smbp->oddByte) {
2324 *smbp->wctp = slot+1;
2329 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2330 *parmDatap++ = parmValue & 0xff;
2333 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2337 lastSlashp = strrchr(inPathp, '\\');
2339 *lastComponentp = lastSlashp;
2342 if (inPathp == lastSlashp)
2344 *outPathp++ = *inPathp++;
2353 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2358 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2363 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2369 tlen = inp[0] + (inp[1]<<8);
2370 inp += 2; /* skip length field */
2373 *chainpp = inp + tlen;
2382 /* format a packet as a response */
2383 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2388 outp = (smb_t *) op;
2390 /* zero the basic structure through the smb_wct field, and zero the data
2391 * size field, assuming that wct stays zero; otherwise, you have to
2392 * explicitly set the data size field, too.
2394 inSmbp = (smb_t *) inp;
2395 memset(outp, 0, sizeof(smb_t)+2);
2401 outp->com = inSmbp->com;
2402 outp->tid = inSmbp->tid;
2403 outp->pid = inSmbp->pid;
2404 outp->uid = inSmbp->uid;
2405 outp->mid = inSmbp->mid;
2406 outp->res[0] = inSmbp->res[0];
2407 outp->res[1] = inSmbp->res[1];
2408 op->inCom = inSmbp->com;
2410 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2411 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2413 /* copy fields in generic packet area */
2414 op->wctp = &outp->wct;
2417 /* send a (probably response) packet; vcp tells us to whom to send it.
2418 * we compute the length by looking at wct and bcc fields.
2420 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2434 memset((char *)ncbp, 0, sizeof(NCB));
2436 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2437 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2438 extra += tp[0] + (tp[1]<<8);
2439 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2440 extra += 3; /* wct and length fields */
2442 ncbp->ncb_length = extra; /* bytes to send */
2443 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2444 ncbp->ncb_lana_num = vcp->lana;
2445 ncbp->ncb_command = NCBSEND; /* op means send data */
2446 ncbp->ncb_buffer = (char *) inp;/* packet */
2447 code = Netbios(ncbp);
2450 const char * s = ncb_error_string(code);
2451 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2452 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2454 lock_ObtainMutex(&vcp->mx);
2455 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2456 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2458 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2459 lock_ReleaseMutex(&vcp->mx);
2460 lock_ObtainWrite(&smb_globalLock);
2461 dead_sessions[vcp->session] = TRUE;
2462 lock_ReleaseWrite(&smb_globalLock);
2463 smb_CleanupDeadVC(vcp);
2465 lock_ReleaseMutex(&vcp->mx);
2473 void smb_MapNTError(long code, unsigned long *NTStatusp)
2475 unsigned long NTStatus;
2477 /* map CM_ERROR_* errors to NT 32-bit status codes */
2478 /* NT Status codes are listed in ntstatus.h not winerror.h */
2479 if (code == CM_ERROR_NOSUCHCELL) {
2480 NTStatus = 0xC000000FL; /* No such file */
2482 else if (code == CM_ERROR_NOSUCHVOLUME) {
2483 NTStatus = 0xC000000FL; /* No such file */
2485 else if (code == CM_ERROR_TIMEDOUT) {
2487 NTStatus = 0xC00000CFL; /* Sharing Paused */
2489 NTStatus = 0x00000102L; /* Timeout */
2492 else if (code == CM_ERROR_RETRY) {
2493 NTStatus = 0xC000022DL; /* Retry */
2495 else if (code == CM_ERROR_NOACCESS) {
2496 NTStatus = 0xC0000022L; /* Access denied */
2498 else if (code == CM_ERROR_READONLY) {
2499 NTStatus = 0xC00000A2L; /* Write protected */
2501 else if (code == CM_ERROR_NOSUCHFILE) {
2502 NTStatus = 0xC000000FL; /* No such file */
2504 else if (code == CM_ERROR_NOSUCHPATH) {
2505 NTStatus = 0xC000003AL; /* Object path not found */
2507 else if (code == CM_ERROR_TOOBIG) {
2508 NTStatus = 0xC000007BL; /* Invalid image format */
2510 else if (code == CM_ERROR_INVAL) {
2511 NTStatus = 0xC000000DL; /* Invalid parameter */
2513 else if (code == CM_ERROR_BADFD) {
2514 NTStatus = 0xC0000008L; /* Invalid handle */
2516 else if (code == CM_ERROR_BADFDOP) {
2517 NTStatus = 0xC0000022L; /* Access denied */
2519 else if (code == CM_ERROR_EXISTS) {
2520 NTStatus = 0xC0000035L; /* Object name collision */
2522 else if (code == CM_ERROR_NOTEMPTY) {
2523 NTStatus = 0xC0000101L; /* Directory not empty */
2525 else if (code == CM_ERROR_CROSSDEVLINK) {
2526 NTStatus = 0xC00000D4L; /* Not same device */
2528 else if (code == CM_ERROR_NOTDIR) {
2529 NTStatus = 0xC0000103L; /* Not a directory */
2531 else if (code == CM_ERROR_ISDIR) {
2532 NTStatus = 0xC00000BAL; /* File is a directory */
2534 else if (code == CM_ERROR_BADOP) {
2536 /* I have no idea where this comes from */
2537 NTStatus = 0xC09820FFL; /* SMB no support */
2539 NTStatus = 0xC00000BBL; /* Not supported */
2540 #endif /* COMMENT */
2542 else if (code == CM_ERROR_BADSHARENAME) {
2543 NTStatus = 0xC00000CCL; /* Bad network name */
2545 else if (code == CM_ERROR_NOIPC) {
2547 NTStatus = 0xC0000022L; /* Access Denied */
2549 NTStatus = 0xC000013DL; /* Remote Resources */
2552 else if (code == CM_ERROR_CLOCKSKEW) {
2553 NTStatus = 0xC0000133L; /* Time difference at DC */
2555 else if (code == CM_ERROR_BADTID) {
2556 NTStatus = 0xC0982005L; /* SMB bad TID */
2558 else if (code == CM_ERROR_USESTD) {
2559 NTStatus = 0xC09820FBL; /* SMB use standard */
2561 else if (code == CM_ERROR_QUOTA) {
2563 NTStatus = 0xC0000044L; /* Quota exceeded */
2565 NTStatus = 0xC000007FL; /* Disk full */
2568 else if (code == CM_ERROR_SPACE) {
2569 NTStatus = 0xC000007FL; /* Disk full */
2571 else if (code == CM_ERROR_ATSYS) {
2572 NTStatus = 0xC0000033L; /* Object name invalid */
2574 else if (code == CM_ERROR_BADNTFILENAME) {
2575 NTStatus = 0xC0000033L; /* Object name invalid */
2577 else if (code == CM_ERROR_WOULDBLOCK) {
2578 NTStatus = 0xC0000055L; /* Lock not granted */
2580 else if (code == CM_ERROR_SHARING_VIOLATION) {
2581 NTStatus = 0xC0000043L; /* Sharing violation */
2583 else if (code == CM_ERROR_LOCK_CONFLICT) {
2584 NTStatus = 0xC0000054L; /* Lock conflict */
2586 else if (code == CM_ERROR_PARTIALWRITE) {
2587 NTStatus = 0xC000007FL; /* Disk full */
2589 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2590 NTStatus = 0xC0000023L; /* Buffer too small */
2592 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2593 NTStatus = 0xC0000035L; /* Object name collision */
2595 else if (code == CM_ERROR_BADPASSWORD) {
2596 NTStatus = 0xC000006DL; /* unknown username or bad password */
2598 else if (code == CM_ERROR_BADLOGONTYPE) {
2599 NTStatus = 0xC000015BL; /* logon type not granted */
2601 else if (code == CM_ERROR_GSSCONTINUE) {
2602 NTStatus = 0xC0000016L; /* more processing required */
2604 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2606 NTStatus = 0xC0000280L; /* reparse point not resolved */
2608 NTStatus = 0xC0000022L; /* Access Denied */
2611 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2612 NTStatus = 0xC0000257L; /* Path Not Covered */
2615 else if (code == CM_ERROR_ALLBUSY) {
2616 NTStatus = 0xC00000BFL; /* Network Busy */
2618 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2619 NTStatus = 0xC0000350L; /* Remote Host Down */
2622 /* we do not want to be telling the SMB/CIFS client that
2623 * the AFS Client Service is busy or down.
2625 else if (code == CM_ERROR_ALLBUSY ||
2626 code == CM_ERROR_ALLOFFLINE ||
2627 code == CM_ERROR_ALLDOWN) {
2628 NTStatus = 0xC00000BEL; /* Bad Network Path */
2631 else if (code == RXKADUNKNOWNKEY) {
2632 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2634 else if (code == CM_ERROR_BAD_LEVEL) {
2635 NTStatus = 0xC0000148L; /* Invalid Level */
2637 NTStatus = 0xC0982001L; /* SMB non-specific error */
2640 *NTStatusp = NTStatus;
2641 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2644 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2645 unsigned char *classp)
2647 unsigned char class;
2648 unsigned short error;
2650 /* map CM_ERROR_* errors to SMB errors */
2651 if (code == CM_ERROR_NOSUCHCELL) {
2653 error = 3; /* bad path */
2655 else if (code == CM_ERROR_NOSUCHVOLUME) {
2657 error = 3; /* bad path */
2659 else if (code == CM_ERROR_TIMEDOUT) {
2661 error = 81; /* server is paused */
2663 else if (code == CM_ERROR_RETRY) {
2664 class = 2; /* shouldn't happen */
2667 else if (code == CM_ERROR_NOACCESS) {
2669 error = 4; /* bad access */
2671 else if (code == CM_ERROR_READONLY) {
2673 error = 19; /* read only */
2675 else if (code == CM_ERROR_NOSUCHFILE) {
2677 error = 2; /* ENOENT! */
2679 else if (code == CM_ERROR_NOSUCHPATH) {
2681 error = 3; /* Bad path */
2683 else if (code == CM_ERROR_TOOBIG) {
2685 error = 11; /* bad format */
2687 else if (code == CM_ERROR_INVAL) {
2688 class = 2; /* server non-specific error code */
2691 else if (code == CM_ERROR_BADFD) {
2693 error = 6; /* invalid file handle */
2695 else if (code == CM_ERROR_BADFDOP) {
2696 class = 1; /* invalid op on FD */
2699 else if (code == CM_ERROR_EXISTS) {
2701 error = 80; /* file already exists */
2703 else if (code == CM_ERROR_NOTEMPTY) {
2705 error = 5; /* delete directory not empty */
2707 else if (code == CM_ERROR_CROSSDEVLINK) {
2709 error = 17; /* EXDEV */
2711 else if (code == CM_ERROR_NOTDIR) {
2712 class = 1; /* bad path */
2715 else if (code == CM_ERROR_ISDIR) {
2716 class = 1; /* access denied; DOS doesn't have a good match */
2719 else if (code == CM_ERROR_BADOP) {
2723 else if (code == CM_ERROR_BADSHARENAME) {
2727 else if (code == CM_ERROR_NOIPC) {
2729 error = 4; /* bad access */
2731 else if (code == CM_ERROR_CLOCKSKEW) {
2732 class = 1; /* invalid function */
2735 else if (code == CM_ERROR_BADTID) {
2739 else if (code == CM_ERROR_USESTD) {
2743 else if (code == CM_ERROR_REMOTECONN) {
2747 else if (code == CM_ERROR_QUOTA) {
2748 if (vcp->flags & SMB_VCFLAG_USEV3) {
2750 error = 39; /* disk full */
2754 error = 5; /* access denied */
2757 else if (code == CM_ERROR_SPACE) {
2758 if (vcp->flags & SMB_VCFLAG_USEV3) {
2760 error = 39; /* disk full */
2764 error = 5; /* access denied */
2767 else if (code == CM_ERROR_PARTIALWRITE) {
2769 error = 39; /* disk full */
2771 else if (code == CM_ERROR_ATSYS) {
2773 error = 2; /* ENOENT */
2775 else if (code == CM_ERROR_WOULDBLOCK) {
2777 error = 33; /* lock conflict */
2779 else if (code == CM_ERROR_LOCK_CONFLICT) {
2781 error = 33; /* lock conflict */
2783 else if (code == CM_ERROR_SHARING_VIOLATION) {
2785 error = 33; /* lock conflict */
2787 else if (code == CM_ERROR_NOFILES) {
2789 error = 18; /* no files in search */
2791 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2793 error = 183; /* Samba uses this */
2795 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2796 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2798 error = 2; /* bad password */
2800 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2802 error = 3; /* bad path */
2811 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2814 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2816 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2817 return CM_ERROR_BADOP;
2820 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2822 unsigned short EchoCount, i;
2823 char *data, *outdata;
2826 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2828 for (i=1; i<=EchoCount; i++) {
2829 data = smb_GetSMBData(inp, &dataSize);
2830 smb_SetSMBParm(outp, 0, i);
2831 smb_SetSMBDataLength(outp, dataSize);
2832 outdata = smb_GetSMBData(outp, NULL);
2833 memcpy(outdata, data, dataSize);
2834 smb_SendPacket(vcp, outp);
2840 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2843 long count, minCount, finalCount;
2848 cm_user_t *userp = NULL;
2851 char *rawBuf = NULL;
2856 fd = smb_GetSMBParm(inp, 0);
2857 count = smb_GetSMBParm(inp, 3);
2858 minCount = smb_GetSMBParm(inp, 4);
2859 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2861 if (*inp->wctp == 10) {
2862 /* we were sent a request with 64-bit file offsets */
2863 #ifdef AFS_LARGEFILES
2864 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2866 if (LargeIntegerLessThanZero(offset)) {
2867 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2871 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2872 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2875 offset.HighPart = 0;
2879 /* we were sent a request with 32-bit file offsets */
2880 offset.HighPart = 0;
2883 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2884 fd, offset.HighPart, offset.LowPart, count);
2886 fidp = smb_FindFID(vcp, fd, 0);
2890 pid = ((smb_t *) inp)->pid;
2892 LARGE_INTEGER LOffset, LLength;
2895 key = cm_GenerateKey(vcp->vcID, pid, fd);
2897 LOffset.HighPart = offset.HighPart;
2898 LOffset.LowPart = offset.LowPart;
2899 LLength.HighPart = 0;
2900 LLength.LowPart = count;
2902 lock_ObtainMutex(&fidp->scp->mx);
2903 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2904 lock_ReleaseMutex(&fidp->scp->mx);
2910 lock_ObtainMutex(&smb_RawBufLock);
2912 /* Get a raw buf, from head of list */
2913 rawBuf = smb_RawBufs;
2914 smb_RawBufs = *(char **)smb_RawBufs;
2916 lock_ReleaseMutex(&smb_RawBufLock);
2920 lock_ObtainMutex(&fidp->mx);
2921 if (fidp->flags & SMB_FID_IOCTL)
2923 lock_ReleaseMutex(&fidp->mx);
2924 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2926 /* Give back raw buffer */
2927 lock_ObtainMutex(&smb_RawBufLock);
2928 *((char **) rawBuf) = smb_RawBufs;
2930 smb_RawBufs = rawBuf;
2931 lock_ReleaseMutex(&smb_RawBufLock);
2934 smb_ReleaseFID(fidp);
2937 lock_ReleaseMutex(&fidp->mx);
2939 userp = smb_GetUserFromVCP(vcp, inp);
2941 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2947 cm_ReleaseUser(userp);
2950 smb_ReleaseFID(fidp);
2954 memset((char *)ncbp, 0, sizeof(NCB));
2956 ncbp->ncb_length = (unsigned short) finalCount;
2957 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2958 ncbp->ncb_lana_num = vcp->lana;
2959 ncbp->ncb_command = NCBSEND;
2960 ncbp->ncb_buffer = rawBuf;
2962 code = Netbios(ncbp);
2964 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2967 /* Give back raw buffer */
2968 lock_ObtainMutex(&smb_RawBufLock);
2969 *((char **) rawBuf) = smb_RawBufs;
2971 smb_RawBufs = rawBuf;
2972 lock_ReleaseMutex(&smb_RawBufLock);
2978 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2980 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2985 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2987 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2992 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2999 int VistaProtoIndex;
3000 int protoIndex; /* index we're using */
3005 char protocol_array[10][1024]; /* protocol signature of the client */
3006 int caps; /* capabilities */
3009 TIME_ZONE_INFORMATION tzi;
3011 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3014 namep = smb_GetSMBData(inp, &dbytes);
3017 coreProtoIndex = -1; /* not found */
3020 VistaProtoIndex = -1;
3021 while(namex < dbytes) {
3022 osi_Log1(smb_logp, "Protocol %s",
3023 osi_LogSaveString(smb_logp, namep+1));
3024 strcpy(protocol_array[tcounter], namep+1);
3026 /* namep points at the first protocol, or really, a 0x02
3027 * byte preceding the null-terminated ASCII name.
3029 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3030 coreProtoIndex = tcounter;
3032 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3033 v3ProtoIndex = tcounter;
3035 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3036 NTProtoIndex = tcounter;
3038 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3039 VistaProtoIndex = tcounter;
3042 /* compute size of protocol entry */
3043 entryLength = (int)strlen(namep+1);
3044 entryLength += 2; /* 0x02 bytes and null termination */
3046 /* advance over this protocol entry */
3047 namex += entryLength;
3048 namep += entryLength;
3049 tcounter++; /* which proto entry we're looking at */
3052 lock_ObtainMutex(&vcp->mx);
3054 if (VistaProtoIndex != -1) {
3055 protoIndex = VistaProtoIndex;
3056 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3059 if (NTProtoIndex != -1) {
3060 protoIndex = NTProtoIndex;
3061 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3063 else if (v3ProtoIndex != -1) {
3064 protoIndex = v3ProtoIndex;
3065 vcp->flags |= SMB_VCFLAG_USEV3;
3067 else if (coreProtoIndex != -1) {
3068 protoIndex = coreProtoIndex;
3069 vcp->flags |= SMB_VCFLAG_USECORE;
3071 else protoIndex = -1;
3072 lock_ReleaseMutex(&vcp->mx);
3074 if (protoIndex == -1)
3075 return CM_ERROR_INVAL;
3076 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3077 smb_SetSMBParm(outp, 0, protoIndex);
3078 if (smb_authType != SMB_AUTH_NONE) {
3079 smb_SetSMBParmByte(outp, 1,
3080 NEGOTIATE_SECURITY_USER_LEVEL |
3081 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3083 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3085 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3086 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3087 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3088 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3089 /* The session key is not a well documented field however most clients
3090 * will echo back the session key to the server. Currently we are using
3091 * the same value for all sessions. We should generate a random value
3092 * and store it into the vcp
3094 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3095 smb_SetSMBParm(outp, 8, 1);
3097 * Tried changing the capabilities to support for W2K - defect 117695
3098 * Maybe something else needs to be changed here?
3102 smb_SetSMBParmLong(outp, 9, 0x43fd);
3104 smb_SetSMBParmLong(outp, 9, 0x251);
3107 * 32-bit error codes *
3112 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3114 NTNEGOTIATE_CAPABILITY_DFS |
3116 #ifdef AFS_LARGEFILES
3117 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3119 NTNEGOTIATE_CAPABILITY_NTFIND |
3120 NTNEGOTIATE_CAPABILITY_RAWMODE |
3121 NTNEGOTIATE_CAPABILITY_NTSMB;
3123 if ( smb_authType == SMB_AUTH_EXTENDED )
3124 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3126 smb_SetSMBParmLong(outp, 9, caps);
3128 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3129 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3130 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3132 GetTimeZoneInformation(&tzi);
3133 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3135 if (smb_authType == SMB_AUTH_NTLM) {
3136 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3137 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3138 /* paste in encryption key */
3139 datap = smb_GetSMBData(outp, NULL);
3140 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3141 /* and the faux domain name */
3142 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3143 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3147 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3149 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3151 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3153 datap = smb_GetSMBData(outp, NULL);
3154 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3157 datap += sizeof(smb_ServerGUID);
3158 memcpy(datap, secBlob, secBlobLength);
3162 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3163 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3166 else if (v3ProtoIndex != -1) {
3167 smb_SetSMBParm(outp, 0, protoIndex);
3169 /* NOTE: Extended authentication cannot be negotiated with v3
3170 * therefore we fail over to NTLM
3172 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3173 smb_SetSMBParm(outp, 1,
3174 NEGOTIATE_SECURITY_USER_LEVEL |
3175 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3177 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3179 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3180 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3181 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3182 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3183 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3184 smb_SetSMBParm(outp, 7, 1);
3186 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3187 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3188 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3190 GetTimeZoneInformation(&tzi);
3191 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3193 /* NOTE: Extended authentication cannot be negotiated with v3
3194 * therefore we fail over to NTLM
3196 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3197 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3198 smb_SetSMBParm(outp, 12, 0); /* resvd */
3199 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3200 datap = smb_GetSMBData(outp, NULL);
3201 /* paste in a new encryption key */
3202 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3203 /* and the faux domain name */
3204 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3206 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3207 smb_SetSMBParm(outp, 12, 0); /* resvd */
3208 smb_SetSMBDataLength(outp, 0);
3211 else if (coreProtoIndex != -1) { /* not really supported anymore */
3212 smb_SetSMBParm(outp, 0, protoIndex);
3213 smb_SetSMBDataLength(outp, 0);
3218 void smb_CheckVCs(void)
3220 smb_vc_t * vcp, *nextp;
3221 smb_packet_t * outp = GetPacket();
3224 lock_ObtainWrite(&smb_rctLock);
3225 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3227 if (vcp->magic != SMB_VC_MAGIC)
3228 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3229 __FILE__, __LINE__);
3233 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3236 smb_HoldVCNoLock(vcp);
3238 smb_HoldVCNoLock(nextp);
3239 smb_FormatResponsePacket(vcp, NULL, outp);
3240 smbp = (smb_t *)outp;
3241 outp->inCom = smbp->com = 0x2b /* Echo */;
3249 smb_SetSMBParm(outp, 0, 0);
3250 smb_SetSMBDataLength(outp, 0);
3251 lock_ReleaseWrite(&smb_rctLock);
3253 smb_SendPacket(vcp, outp);
3255 lock_ObtainWrite(&smb_rctLock);
3256 smb_ReleaseVCNoLock(vcp);
3258 smb_ReleaseVCNoLock(nextp);
3260 lock_ReleaseWrite(&smb_rctLock);
3261 smb_FreePacket(outp);
3264 void smb_Daemon(void *parmp)
3266 afs_uint32 count = 0;
3267 smb_username_t **unpp;
3270 while(smbShutdownFlag == 0) {
3274 if (smbShutdownFlag == 1)
3277 if ((count % 72) == 0) { /* every five minutes */
3279 time_t old_localZero = smb_localZero;
3281 /* Initialize smb_localZero */
3282 myTime.tm_isdst = -1; /* compute whether on DST or not */
3283 myTime.tm_year = 70;
3289 smb_localZero = mktime(&myTime);
3291 #ifndef USE_NUMERIC_TIME_CONV
3292 smb_CalculateNowTZ();
3293 #endif /* USE_NUMERIC_TIME_CONV */
3294 #ifdef AFS_FREELANCE
3295 if ( smb_localZero != old_localZero )
3296 cm_noteLocalMountPointChange();
3302 /* GC smb_username_t objects that will no longer be used */
3304 lock_ObtainWrite(&smb_rctLock);
3305 for ( unpp=&usernamesp; *unpp; ) {
3307 smb_username_t *unp;
3309 lock_ObtainMutex(&(*unpp)->mx);
3310 if ( (*unpp)->refCount > 0 ||
3311 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3312 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3314 else if (!smb_LogoffTokenTransfer ||
3315 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3317 lock_ReleaseMutex(&(*unpp)->mx);
3325 lock_FinalizeMutex(&unp->mx);
3331 lock_ReleaseWrite(&smb_rctLock);
3332 cm_ReleaseUser(userp);
3333 lock_ObtainWrite(&smb_rctLock);
3336 unpp = &(*unpp)->nextp;
3339 lock_ReleaseWrite(&smb_rctLock);
3341 /* XXX GC dir search entries */
3345 void smb_WaitingLocksDaemon()
3347 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3348 smb_waitingLock_t *wl, *wlNext;
3351 smb_packet_t *inp, *outp;
3355 while (smbShutdownFlag == 0) {
3356 lock_ObtainWrite(&smb_globalLock);
3357 nwlRequest = smb_allWaitingLocks;
3358 if (nwlRequest == NULL) {
3359 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3364 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3371 lock_ObtainWrite(&smb_globalLock);
3373 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3375 wlRequest = nwlRequest;
3376 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3377 lock_ReleaseWrite(&smb_globalLock);
3381 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3382 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3385 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3387 /* wl->state is either _DONE or _WAITING. _ERROR
3388 would no longer be on the queue. */
3389 code = cm_RetryLock( wl->lockp,
3390 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3393 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3394 } else if (code != CM_ERROR_WOULDBLOCK) {
3395 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3400 if (code == CM_ERROR_WOULDBLOCK) {
3403 if (wlRequest->timeRemaining != 0xffffffff
3404 && (wlRequest->timeRemaining -= 1000) < 0)
3416 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3419 scp = wlRequest->scp;
3420 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3424 lock_ObtainMutex(&scp->mx);
3426 for (wl = wlRequest->locks; wl; wl = wlNext) {
3427 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3429 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3430 wl->LLength, wl->key, NULL, &req);
3432 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3437 lock_ReleaseMutex(&scp->mx);
3441 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3444 for (wl = wlRequest->locks; wl; wl = wlNext) {
3445 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3446 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3451 vcp = wlRequest->vcp;
3452 inp = wlRequest->inp;
3453 outp = wlRequest->outp;
3455 ncbp->ncb_length = inp->ncb_length;
3456 inp->spacep = cm_GetSpace();
3458 /* Remove waitingLock from list */
3459 lock_ObtainWrite(&smb_globalLock);
3460 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3462 lock_ReleaseWrite(&smb_globalLock);
3464 /* Resume packet processing */
3466 smb_SetSMBDataLength(outp, 0);
3467 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3468 outp->resumeCode = code;
3470 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3473 cm_FreeSpace(inp->spacep);
3474 smb_FreePacket(inp);
3475 smb_FreePacket(outp);
3477 cm_ReleaseSCache(wlRequest->scp);
3480 } while (nwlRequest && smbShutdownFlag == 0);
3485 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3487 osi_Log0(smb_logp, "SMB receive get disk attributes");
3489 smb_SetSMBParm(outp, 0, 32000);
3490 smb_SetSMBParm(outp, 1, 64);
3491 smb_SetSMBParm(outp, 2, 1024);
3492 smb_SetSMBParm(outp, 3, 30000);
3493 smb_SetSMBParm(outp, 4, 0);
3494 smb_SetSMBDataLength(outp, 0);
3498 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3502 unsigned short newTid;
3503 char shareName[256];
3511 osi_Log0(smb_logp, "SMB receive tree connect");
3513 /* parse input parameters */
3514 tp = smb_GetSMBData(inp, NULL);
3515 pathp = smb_ParseASCIIBlock(tp, &tp);
3516 if (smb_StoreAnsiFilenames)
3517 OemToChar(pathp,pathp);
3518 passwordp = smb_ParseASCIIBlock(tp, &tp);
3519 tp = strrchr(pathp, '\\');
3521 return CM_ERROR_BADSMB;
3522 strcpy(shareName, tp+1);
3524 lock_ObtainMutex(&vcp->mx);
3525 newTid = vcp->tidCounter++;
3526 lock_ReleaseMutex(&vcp->mx);
3528 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3529 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3530 userp = smb_GetUserFromUID(uidp);
3531 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3533 smb_ReleaseUID(uidp);
3535 smb_ReleaseTID(tidp);
3536 return CM_ERROR_BADSHARENAME;
3538 lock_ObtainMutex(&tidp->mx);
3539 tidp->userp = userp;
3540 tidp->pathname = sharePath;
3541 lock_ReleaseMutex(&tidp->mx);
3542 smb_ReleaseTID(tidp);
3544 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3545 smb_SetSMBParm(rsp, 1, newTid);
3546 smb_SetSMBDataLength(rsp, 0);
3548 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3552 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3556 if (*inp++ != 0x1) return NULL;
3557 tlen = inp[0] + (inp[1]<<8);
3558 inp += 2; /* skip length field */
3561 *chainpp = inp + tlen;
3564 if (lengthp) *lengthp = tlen;
3569 /* set maskp to the mask part of the incoming path.
3570 * Mask is 11 bytes long (8.3 with the dot elided).
3571 * Returns true if succeeds with a valid name, otherwise it does
3572 * its best, but returns false.
3574 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3582 /* starts off valid */
3585 /* mask starts out all blanks */
3586 memset(maskp, ' ', 11);
3588 /* find last backslash, or use whole thing if there is none */
3589 tp = strrchr(pathp, '\\');
3590 if (!tp) tp = pathp;
3591 else tp++; /* skip slash */
3595 /* names starting with a dot are illegal */
3596 if (*tp == '.') valid8Dot3 = 0;
3600 if (tc == 0) return valid8Dot3;
3601 if (tc == '.' || tc == '"') break;
3602 if (i < 8) *up++ = tc;
3603 else valid8Dot3 = 0;
3606 /* if we get here, tp point after the dot */
3607 up = maskp+8; /* ext goes here */
3614 if (tc == '.' || tc == '"')
3617 /* copy extension if not too long */
3627 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3637 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3639 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3643 /* otherwise, we have a valid 8.3 name; see if we have a match,
3644 * treating '?' as a wildcard in maskp (but not in the file name).
3646 tp1 = umask; /* real name, in mask format */
3647 tp2 = maskp; /* mask, in mask format */
3648 for(i=0; i<11; i++) {
3649 tc1 = *tp1++; /* char from real name */
3650 tc2 = *tp2++; /* char from mask */
3651 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3652 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3655 if (tc2 == '?' && tc1 != ' ')
3662 /* we got a match */
3666 char *smb_FindMask(char *pathp)
3670 tp = strrchr(pathp, '\\'); /* find last slash */
3673 return tp+1; /* skip the slash */
3675 return pathp; /* no slash, return the entire path */
3678 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3680 unsigned char *pathp;
3682 unsigned char mask[11];
3683 unsigned char *statBlockp;
3684 unsigned char initStatBlock[21];
3687 osi_Log0(smb_logp, "SMB receive search volume");
3689 /* pull pathname and stat block out of request */
3690 tp = smb_GetSMBData(inp, NULL);
3691 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3692 osi_assert(pathp != NULL);
3693 if (smb_StoreAnsiFilenames)
3694 OemToChar(pathp,pathp);
3695 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3696 osi_assert(statBlockp != NULL);
3698 statBlockp = initStatBlock;
3702 /* for returning to caller */
3703 smb_Get8Dot3MaskFromPath(mask, pathp);
3705 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3706 tp = smb_GetSMBData(outp, NULL);
3708 *tp++ = 43; /* bytes in a dir entry */
3709 *tp++ = 0; /* high byte in counter */
3711 /* now marshall the dir entry, starting with the search status */
3712 *tp++ = statBlockp[0]; /* Reserved */
3713 memcpy(tp, mask, 11); tp += 11; /* FileName */
3715 /* now pass back server use info, with 1st byte non-zero */
3717 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3719 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3721 *tp++ = 0x8; /* attribute: volume */
3731 /* 4 byte file size */
3737 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3738 memset(tp, ' ', 13);
3741 /* set the length of the data part of the packet to 43 + 3, for the dir
3742 * entry plus the 5 and the length fields.
3744 smb_SetSMBDataLength(outp, 46);
3748 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3749 cm_user_t *userp, cm_req_t *reqp)
3757 smb_dirListPatch_t *patchp;
3758 smb_dirListPatch_t *npatchp;
3760 for (patchp = *dirPatchespp; patchp; patchp =
3761 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3763 dptr = patchp->dptr;
3765 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3767 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3768 *dptr++ = SMB_ATTR_HIDDEN;
3771 lock_ObtainMutex(&scp->mx);
3772 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3773 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3775 lock_ReleaseMutex(&scp->mx);
3776 cm_ReleaseSCache(scp);
3777 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3778 *dptr++ = SMB_ATTR_HIDDEN;
3782 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3784 attr = smb_Attributes(scp);
3785 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3786 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3787 attr |= SMB_ATTR_HIDDEN;
3791 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3794 shortTemp = (unsigned short) (dosTime & 0xffff);
3795 *((u_short *)dptr) = shortTemp;
3798 /* and copy out date */
3799 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3800 *((u_short *)dptr) = shortTemp;
3803 /* copy out file length */
3804 *((u_long *)dptr) = scp->length.LowPart;
3806 lock_ReleaseMutex(&scp->mx);
3807 cm_ReleaseSCache(scp);
3810 /* now free the patches */
3811 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3812 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3816 /* and mark the list as empty */
3817 *dirPatchespp = NULL;
3822 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3831 smb_dirListPatch_t *dirListPatchesp;
3832 smb_dirListPatch_t *curPatchp;
3836 osi_hyper_t dirLength;
3837 osi_hyper_t bufferOffset;
3838 osi_hyper_t curOffset;
3840 unsigned char *inCookiep;
3841 smb_dirSearch_t *dsp;
3845 unsigned long clientCookie;
3846 cm_pageHeader_t *pageHeaderp;
3847 cm_user_t *userp = NULL;
3854 long nextEntryCookie;
3855 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3856 char resByte; /* reserved byte from the cookie */
3857 char *op; /* output data ptr */
3858 char *origOp; /* original value of op */
3859 cm_space_t *spacep; /* for pathname buffer */
3870 maxCount = smb_GetSMBParm(inp, 0);
3872 dirListPatchesp = NULL;
3874 caseFold = CM_FLAG_CASEFOLD;
3876 tp = smb_GetSMBData(inp, NULL);
3877 pathp = smb_ParseASCIIBlock(tp, &tp);
3878 if (smb_StoreAnsiFilenames)
3879 OemToChar(pathp,pathp);
3880 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3882 /* bail out if request looks bad */
3883 if (!tp || !pathp) {
3884 return CM_ERROR_BADSMB;
3887 /* We can handle long names */
3888 if (vcp->flags & SMB_VCFLAG_USENT)
3889 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3891 /* make sure we got a whole search status */
3892 if (dataLength < 21) {
3893 nextCookie = 0; /* start at the beginning of the dir */
3896 attribute = smb_GetSMBParm(inp, 1);
3898 /* handle volume info in another function */
3899 if (attribute & 0x8)
3900 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3902 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3903 maxCount, osi_LogSaveString(smb_logp, pathp));
3905 if (*pathp == 0) { /* null pathp, treat as root dir */
3906 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3907 return CM_ERROR_NOFILES;
3911 dsp = smb_NewDirSearch(0);
3912 dsp->attribute = attribute;
3913 smb_Get8Dot3MaskFromPath(mask, pathp);
3914 memcpy(dsp->mask, mask, 11);
3916 /* track if this is likely to match a lot of entries */
3917 if (smb_IsStarMask(mask))
3922 /* pull the next cookie value out of the search status block */
3923 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3924 + (inCookiep[16]<<24);
3925 dsp = smb_FindDirSearch(inCookiep[12]);
3927 /* can't find dir search status; fatal error */
3928 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3929 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3930 return CM_ERROR_BADFD;
3932 attribute = dsp->attribute;
3933 resByte = inCookiep[0];
3935 /* copy out client cookie, in host byte order. Don't bother
3936 * interpreting it, since we're just passing it through, anyway.
3938 memcpy(&clientCookie, &inCookiep[17], 4);
3940 memcpy(mask, dsp->mask, 11);
3942 /* assume we're doing a star match if it has continued for more
3948 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3949 nextCookie, dsp->cookie, attribute);
3951 userp = smb_GetUserFromVCP(vcp, inp);
3953 /* try to get the vnode for the path name next */
3954 lock_ObtainMutex(&dsp->mx);
3957 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3961 spacep = inp->spacep;
3962 smb_StripLastComponent(spacep->data, NULL, pathp);
3963 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3965 lock_ReleaseMutex(&dsp->mx);
3966 cm_ReleaseUser(userp);
3967 smb_DeleteDirSearch(dsp);
3968 smb_ReleaseDirSearch(dsp);
3969 return CM_ERROR_NOFILES;
3971 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3972 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3975 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3976 cm_ReleaseSCache(scp);
3977 lock_ReleaseMutex(&dsp->mx);
3978 cm_ReleaseUser(userp);
3979 smb_DeleteDirSearch(dsp);
3980 smb_ReleaseDirSearch(dsp);
3981 if ( WANTS_DFS_PATHNAMES(inp) )
3982 return CM_ERROR_PATH_NOT_COVERED;
3984 return CM_ERROR_BADSHARENAME;
3986 #endif /* DFS_SUPPORT */
3989 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
3990 /* we need one hold for the entry we just stored into,
3991 * and one for our own processing. When we're done with this
3992 * function, we'll drop the one for our own processing.
3993 * We held it once from the namei call, and so we do another hold
3997 lock_ObtainMutex(&scp->mx);
3998 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3999 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4000 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4001 dsp->flags |= SMB_DIRSEARCH_BULKST;
4002 dsp->scp->bulkStatProgress = hzero;
4004 lock_ReleaseMutex(&scp->mx);
4007 lock_ReleaseMutex(&dsp->mx);
4009 cm_ReleaseUser(userp);
4010 smb_DeleteDirSearch(dsp);
4011 smb_ReleaseDirSearch(dsp);
4015 /* reserves space for parameter; we'll adjust it again later to the
4016 * real count of the # of entries we returned once we've actually
4017 * assembled the directory listing.
4019 smb_SetSMBParm(outp, 0, 0);
4021 /* get the directory size */
4022 lock_ObtainMutex(&scp->mx);
4023 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4024 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4026 lock_ReleaseMutex(&scp->mx);
4027 cm_ReleaseSCache(scp);
4028 cm_ReleaseUser(userp);
4029 smb_DeleteDirSearch(dsp);
4030 smb_ReleaseDirSearch(dsp);
4034 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4036 dirLength = scp->length;
4038 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4039 curOffset.HighPart = 0;
4040 curOffset.LowPart = nextCookie;
4041 origOp = op = smb_GetSMBData(outp, NULL);
4042 /* and write out the basic header */
4043 *op++ = 5; /* variable block */
4044 op += 2; /* skip vbl block length; we'll fill it in later */
4048 /* make sure that curOffset.LowPart doesn't point to the first
4049 * 32 bytes in the 2nd through last dir page, and that it doesn't
4050 * point at the first 13 32-byte chunks in the first dir page,
4051 * since those are dir and page headers, and don't contain useful
4054 temp = curOffset.LowPart & (2048-1);
4055 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4056 /* we're in the first page */
4057 if (temp < 13*32) temp = 13*32;
4060 /* we're in a later dir page */
4061 if (temp < 32) temp = 32;
4064 /* make sure the low order 5 bits are zero */
4067 /* now put temp bits back ito curOffset.LowPart */
4068 curOffset.LowPart &= ~(2048-1);
4069 curOffset.LowPart |= temp;
4071 /* check if we've returned all the names that will fit in the
4074 if (returnedNames >= maxCount) {
4075 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4076 returnedNames, maxCount);
4080 /* check if we've passed the dir's EOF */
4081 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4083 /* see if we can use the bufferp we have now; compute in which page
4084 * the current offset would be, and check whether that's the offset
4085 * of the buffer we have. If not, get the buffer.
4087 thyper.HighPart = curOffset.HighPart;
4088 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4089 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4092 buf_Release(bufferp);
4095 lock_ReleaseMutex(&scp->mx);
4096 lock_ObtainRead(&scp->bufCreateLock);
4097 code = buf_Get(scp, &thyper, &bufferp);
4098 lock_ReleaseRead(&scp->bufCreateLock);
4099 lock_ObtainMutex(&dsp->mx);
4101 /* now, if we're doing a star match, do bulk fetching of all of
4102 * the status info for files in the dir.
4105 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4106 lock_ObtainMutex(&scp->mx);
4107 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4108 LargeIntegerGreaterThanOrEqualTo(thyper,
4109 scp->bulkStatProgress)) {
4110 /* Don't bulk stat if risking timeout */
4111 int now = GetTickCount();
4112 if (now - req.startTime > RDRtimeout) {
4113 scp->bulkStatProgress = thyper;
4114 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4115 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4116 dsp->scp->bulkStatProgress = hzero;
4118 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4121 lock_ObtainMutex(&scp->mx);
4123 lock_ReleaseMutex(&dsp->mx);
4125 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4129 bufferOffset = thyper;
4131 /* now get the data in the cache */
4133 code = cm_SyncOp(scp, bufferp, userp, &req,
4135 CM_SCACHESYNC_NEEDCALLBACK |
4136 CM_SCACHESYNC_READ);
4138 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4142 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4144 if (cm_HaveBuffer(scp, bufferp, 0)) {
4145 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4149 /* otherwise, load the buffer and try again */
4150 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4152 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4153 scp, bufferp, code);
4158 buf_Release(bufferp);
4162 } /* if (wrong buffer) ... */
4164 /* now we have the buffer containing the entry we're interested in; copy
4165 * it out if it represents a non-deleted entry.
4167 entryInDir = curOffset.LowPart & (2048-1);
4168 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4170 /* page header will help tell us which entries are free. Page header
4171 * can change more often than once per buffer, since AFS 3 dir page size
4172 * may be less than (but not more than a buffer package buffer.
4174 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4175 temp &= ~(2048 - 1); /* turn off intra-page bits */
4176 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4178 /* now determine which entry we're looking at in the page. If it is
4179 * free (there's a free bitmap at the start of the dir), we should
4180 * skip these 32 bytes.
4182 slotInPage = (entryInDir & 0x7e0) >> 5;
4183 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4184 /* this entry is free */
4185 numDirChunks = 1; /* only skip this guy */
4189 tp = bufferp->datap + entryInBuffer;
4190 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4192 /* while we're here, compute the next entry's location, too,
4193 * since we'll need it when writing out the cookie into the dir
4196 * XXXX Probably should do more sanity checking.
4198 numDirChunks = cm_NameEntries(dep->name, NULL);
4200 /* compute the offset of the cookie representing the next entry */
4201 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4203 /* Compute 8.3 name if necessary */
4204 actualName = dep->name;
4205 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4206 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4207 actualName = shortName;
4210 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4211 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4212 osi_LogSaveString(smb_logp, actualName));
4214 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4215 /* this is one of the entries to use: it is not deleted
4216 * and it matches the star pattern we're looking for.
4219 /* Eliminate entries that don't match requested
4222 /* no hidden files */
4223 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4224 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4228 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4230 /* We have already done the cm_TryBulkStat above */
4231 fid.cell = scp->fid.cell;
4232 fid.volume = scp->fid.volume;
4233 fid.vnode = ntohl(dep->fid.vnode);
4234 fid.unique = ntohl(dep->fid.unique);
4235 fileType = cm_FindFileType(&fid);
4236 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4237 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4239 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4240 fileType == CM_SCACHETYPE_DFSLINK ||
4241 fileType == CM_SCACHETYPE_INVALID)
4242 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4247 memcpy(op, mask, 11); op += 11;
4248 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4249 *op++ = (char)(nextEntryCookie & 0xff);
4250 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4251 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4252 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4253 memcpy(op, &clientCookie, 4); op += 4;
4255 /* now we emit the attribute. This is sort of tricky,
4256 * since we need to really stat the file to find out
4257 * what type of entry we've got. Right now, we're
4258 * copying out data from a buffer, while holding the
4259 * scp locked, so it isn't really convenient to stat
4260 * something now. We'll put in a place holder now,
4261 * and make a second pass before returning this to get
4262 * the real attributes. So, we just skip the data for
4263 * now, and adjust it later. We allocate a patch
4264 * record to make it easy to find this point later.
4265 * The replay will happen at a time when it is safe to
4266 * unlock the directory.
4268 curPatchp = malloc(sizeof(*curPatchp));
4269 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4270 curPatchp->dptr = op;
4271 curPatchp->fid.cell = scp->fid.cell;
4272 curPatchp->fid.volume = scp->fid.volume;
4273 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4274 curPatchp->fid.unique = ntohl(dep->fid.unique);
4276 /* do hidden attribute here since name won't be around when applying
4280 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4281 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4283 curPatchp->flags = 0;
4285 op += 9; /* skip attr, time, date and size */
4287 /* zero out name area. The spec says to pad with
4288 * spaces, but Samba doesn't, and neither do we.
4292 /* finally, we get to copy out the name; we know that
4293 * it fits in 8.3 or the pattern wouldn't match, but it
4294 * never hurts to be sure.
4296 strncpy(op, actualName, 13);
4297 if (smb_StoreAnsiFilenames)
4300 /* Uppercase if requested by client */
4301 if (!KNOWS_LONG_NAMES(inp))
4306 /* now, adjust the # of entries copied */
4308 } /* if we're including this name */
4311 /* and adjust curOffset to be where the new cookie is */
4312 thyper.HighPart = 0;
4313 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4314 curOffset = LargeIntegerAdd(thyper, curOffset);
4315 } /* while copying data for dir listing */
4317 /* release the mutex */
4318 lock_ReleaseMutex(&scp->mx);
4320 buf_Release(bufferp);
4324 /* apply and free last set of patches; if not doing a star match, this
4325 * will be empty, but better safe (and freeing everything) than sorry.
4327 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4329 /* special return code for unsuccessful search */
4330 if (code == 0 && dataLength < 21 && returnedNames == 0)
4331 code = CM_ERROR_NOFILES;
4333 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4334 returnedNames, code);
4337 smb_DeleteDirSearch(dsp);
4338 smb_ReleaseDirSearch(dsp);
4339 cm_ReleaseSCache(scp);
4340 cm_ReleaseUser(userp);
4344 /* finalize the output buffer */
4345 smb_SetSMBParm(outp, 0, returnedNames);
4346 temp = (long) (op - origOp);
4347 smb_SetSMBDataLength(outp, temp);
4349 /* the data area is a variable block, which has a 5 (already there)
4350 * followed by the length of the # of data bytes. We now know this to
4351 * be "temp," although that includes the 3 bytes of vbl block header.
4352 * Deduct for them and fill in the length field.
4354 temp -= 3; /* deduct vbl block info */
4355 osi_assert(temp == (43 * returnedNames));
4356 origOp[1] = (char)(temp & 0xff);
4357 origOp[2] = (char)((temp>>8) & 0xff);
4358 if (returnedNames == 0)
4359 smb_DeleteDirSearch(dsp);
4360 smb_ReleaseDirSearch(dsp);
4361 cm_ReleaseSCache(scp);
4362 cm_ReleaseUser(userp);
4366 /* verify that this is a valid path to a directory. I don't know why they
4367 * don't use the get file attributes call.
4369 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4373 cm_scache_t *rootScp;
4374 cm_scache_t *newScp;
4383 pathp = smb_GetSMBData(inp, NULL);
4384 pathp = smb_ParseASCIIBlock(pathp, NULL);
4386 return CM_ERROR_BADFD;
4387 if (smb_StoreAnsiFilenames)
4388 OemToChar(pathp,pathp);
4389 osi_Log1(smb_logp, "SMB receive check path %s",
4390 osi_LogSaveString(smb_logp, pathp));
4392 rootScp = cm_data.rootSCachep;
4394 userp = smb_GetUserFromVCP(vcp, inp);
4396 caseFold = CM_FLAG_CASEFOLD;
4398 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4400 cm_ReleaseUser(userp);
4401 return CM_ERROR_NOSUCHPATH;
4403 code = cm_NameI(rootScp, pathp,
4404 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4405 userp, tidPathp, &req, &newScp);
4408 cm_ReleaseUser(userp);
4413 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4414 cm_ReleaseSCache(newScp);
4415 cm_ReleaseUser(userp);
4416 if ( WANTS_DFS_PATHNAMES(inp) )
4417 return CM_ERROR_PATH_NOT_COVERED;
4419 return CM_ERROR_BADSHARENAME;
4421 #endif /* DFS_SUPPORT */
4423 /* now lock the vnode with a callback; returns with newScp locked */
4424 lock_ObtainMutex(&newScp->mx);
4425 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4426 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4428 if (code != CM_ERROR_NOACCESS) {
4429 lock_ReleaseMutex(&newScp->mx);
4430 cm_ReleaseSCache(newScp);
4431 cm_ReleaseUser(userp);
4435 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4438 attrs = smb_Attributes(newScp);
4440 if (!(attrs & SMB_ATTR_DIRECTORY))
4441 code = CM_ERROR_NOTDIR;
4443 lock_ReleaseMutex(&newScp->mx);
4445 cm_ReleaseSCache(newScp);
4446 cm_ReleaseUser(userp);
4450 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4454 cm_scache_t *rootScp;
4455 unsigned short attribute;
4457 cm_scache_t *newScp;
4466 /* decode basic attributes we're passed */
4467 attribute = smb_GetSMBParm(inp, 0);
4468 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4470 pathp = smb_GetSMBData(inp, NULL);
4471 pathp = smb_ParseASCIIBlock(pathp, NULL);
4473 return CM_ERROR_BADSMB;
4474 if (smb_StoreAnsiFilenames)
4475 OemToChar(pathp,pathp);
4477 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4478 dosTime, attribute);
4480 rootScp = cm_data.rootSCachep;
4482 userp = smb_GetUserFromVCP(vcp, inp);
4484 caseFold = CM_FLAG_CASEFOLD;
4486 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4488 cm_ReleaseUser(userp);
4489 return CM_ERROR_NOSUCHFILE;
4491 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4492 tidPathp, &req, &newScp);
4495 cm_ReleaseUser(userp);
4500 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4501 cm_ReleaseSCache(newScp);
4502 cm_ReleaseUser(userp);
4503 if ( WANTS_DFS_PATHNAMES(inp) )
4504 return CM_ERROR_PATH_NOT_COVERED;
4506 return CM_ERROR_BADSHARENAME;
4508 #endif /* DFS_SUPPORT */
4510 /* now lock the vnode with a callback; returns with newScp locked; we
4511 * need the current status to determine what the new status is, in some
4514 lock_ObtainMutex(&newScp->mx);
4515 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4516 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4518 lock_ReleaseMutex(&newScp->mx);
4519 cm_ReleaseSCache(newScp);
4520 cm_ReleaseUser(userp);
4524 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4526 /* Check for RO volume */
4527 if (newScp->flags & CM_SCACHEFLAG_RO) {
4528 lock_ReleaseMutex(&newScp->mx);
4529 cm_ReleaseSCache(newScp);
4530 cm_ReleaseUser(userp);
4531 return CM_ERROR_READONLY;
4534 /* prepare for setattr call */
4537 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4538 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4540 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4541 /* we're told to make a writable file read-only */
4542 attr.unixModeBits = newScp->unixModeBits & ~0222;
4543 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4545 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4546 /* we're told to make a read-only file writable */
4547 attr.unixModeBits = newScp->unixModeBits | 0222;
4548 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4550 lock_ReleaseMutex(&newScp->mx);
4552 /* now call setattr */
4554 code = cm_SetAttr(newScp, &attr, userp, &req);
4558 cm_ReleaseSCache(newScp);
4559 cm_ReleaseUser(userp);
4564 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4568 cm_scache_t *rootScp;
4569 cm_scache_t *newScp, *dscp;
4581 pathp = smb_GetSMBData(inp, NULL);
4582 pathp = smb_ParseASCIIBlock(pathp, NULL);
4584 return CM_ERROR_BADSMB;
4586 if (*pathp == 0) /* null path */
4589 if (smb_StoreAnsiFilenames)
4590 OemToChar(pathp,pathp);
4592 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4593 osi_LogSaveString(smb_logp, pathp));
4595 rootScp = cm_data.rootSCachep;
4597 userp = smb_GetUserFromVCP(vcp, inp);
4599 /* we shouldn't need this for V3 requests, but we seem to */
4600 caseFold = CM_FLAG_CASEFOLD;
4602 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4604 cm_ReleaseUser(userp);
4605 return CM_ERROR_NOSUCHFILE;
4609 * XXX Strange hack XXX
4611 * As of Patch 5 (16 July 97), we are having the following problem:
4612 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4613 * requests to look up "desktop.ini" in all the subdirectories.
4614 * This can cause zillions of timeouts looking up non-existent cells
4615 * and volumes, especially in the top-level directory.
4617 * We have not found any way to avoid this or work around it except
4618 * to explicitly ignore the requests for mount points that haven't
4619 * yet been evaluated and for directories that haven't yet been
4622 * We should modify this hack to provide a fake desktop.ini file
4623 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4625 spacep = inp->spacep;
4626 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4627 #ifndef SPECIAL_FOLDERS
4628 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4629 code = cm_NameI(rootScp, spacep->data,
4630 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4631 userp, tidPathp, &req, &dscp);
4634 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4635 if ( WANTS_DFS_PATHNAMES(inp) )
4636 return CM_ERROR_PATH_NOT_COVERED;
4638 return CM_ERROR_BADSHARENAME;
4640 #endif /* DFS_SUPPORT */
4641 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4642 code = CM_ERROR_NOSUCHFILE;
4643 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4644 cm_buf_t *bp = buf_Find(dscp, &hzero);
4649 code = CM_ERROR_NOSUCHFILE;
4651 cm_ReleaseSCache(dscp);
4653 cm_ReleaseUser(userp);
4658 #endif /* SPECIAL_FOLDERS */
4660 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4661 tidPathp, &req, &newScp);
4663 cm_ReleaseUser(userp);
4668 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4669 cm_ReleaseSCache(newScp);
4670 cm_ReleaseUser(userp);
4671 if ( WANTS_DFS_PATHNAMES(inp) )
4672 return CM_ERROR_PATH_NOT_COVERED;
4674 return CM_ERROR_BADSHARENAME;
4676 #endif /* DFS_SUPPORT */
4678 /* now lock the vnode with a callback; returns with newScp locked */
4679 lock_ObtainMutex(&newScp->mx);
4680 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4681 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4683 lock_ReleaseMutex(&newScp->mx);
4684 cm_ReleaseSCache(newScp);
4685 cm_ReleaseUser(userp);
4689 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4692 /* use smb_Attributes instead. Also the fact that a file is
4693 * in a readonly volume doesn't mean it shojuld be marked as RO
4695 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4696 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4697 newScp->fileType == CM_SCACHETYPE_INVALID)
4698 attrs = SMB_ATTR_DIRECTORY;
4701 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4702 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4704 attrs = smb_Attributes(newScp);
4707 smb_SetSMBParm(outp, 0, attrs);
4709 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4710 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4711 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4712 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4713 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4714 smb_SetSMBParm(outp, 5, 0);
4715 smb_SetSMBParm(outp, 6, 0);
4716 smb_SetSMBParm(outp, 7, 0);
4717 smb_SetSMBParm(outp, 8, 0);
4718 smb_SetSMBParm(outp, 9, 0);
4719 smb_SetSMBDataLength(outp, 0);
4720 lock_ReleaseMutex(&newScp->mx);
4722 cm_ReleaseSCache(newScp);
4723 cm_ReleaseUser(userp);
4728 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4732 osi_Log0(smb_logp, "SMB receive tree disconnect");
4734 /* find the tree and free it */
4735 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4737 lock_ObtainWrite(&smb_rctLock);
4739 lock_ReleaseWrite(&smb_rctLock);
4740 smb_ReleaseTID(tidp);
4746 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4764 pathp = smb_GetSMBData(inp, NULL);
4765 pathp = smb_ParseASCIIBlock(pathp, NULL);
4766 if (smb_StoreAnsiFilenames)
4767 OemToChar(pathp,pathp);
4769 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4771 #ifdef DEBUG_VERBOSE
4775 hexpath = osi_HexifyString( pathp );
4776 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4781 share = smb_GetSMBParm(inp, 0);
4782 attribute = smb_GetSMBParm(inp, 1);
4784 spacep = inp->spacep;
4785 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4786 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4787 /* special case magic file name for receiving IOCTL requests
4788 * (since IOCTL calls themselves aren't getting through).
4790 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4791 smb_SetupIoctlFid(fidp, spacep);
4792 smb_SetSMBParm(outp, 0, fidp->fid);
4793 smb_SetSMBParm(outp, 1, 0); /* attrs */
4794 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4795 smb_SetSMBParm(outp, 3, 0);
4796 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4797 smb_SetSMBParm(outp, 5, 0x7fff);
4798 /* pass the open mode back */
4799 smb_SetSMBParm(outp, 6, (share & 0xf));
4800 smb_SetSMBDataLength(outp, 0);
4801 smb_ReleaseFID(fidp);
4805 userp = smb_GetUserFromVCP(vcp, inp);
4807 caseFold = CM_FLAG_CASEFOLD;
4809 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4811 cm_ReleaseUser(userp);
4812 return CM_ERROR_NOSUCHPATH;
4814 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4815 tidPathp, &req, &scp);
4818 cm_ReleaseUser(userp);
4823 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4824 cm_ReleaseSCache(scp);
4825 cm_ReleaseUser(userp);
4826 if ( WANTS_DFS_PATHNAMES(inp) )
4827 return CM_ERROR_PATH_NOT_COVERED;
4829 return CM_ERROR_BADSHARENAME;
4831 #endif /* DFS_SUPPORT */
4833 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4835 cm_ReleaseSCache(scp);
4836 cm_ReleaseUser(userp);
4840 /* don't need callback to check file type, since file types never
4841 * change, and namei and cm_Lookup all stat the object at least once on
4842 * a successful return.
4844 if (scp->fileType != CM_SCACHETYPE_FILE) {
4845 cm_ReleaseSCache(scp);
4846 cm_ReleaseUser(userp);
4847 return CM_ERROR_ISDIR;
4850 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4853 /* save a pointer to the vnode */
4855 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4856 lock_ObtainMutex(&scp->mx);
4857 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4858 lock_ReleaseMutex(&scp->mx);
4862 fidp->userp = userp;
4864 lock_ObtainMutex(&fidp->mx);
4865 if ((share & 0xf) == 0)
4866 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4867 else if ((share & 0xf) == 1)
4868 fidp->flags |= SMB_FID_OPENWRITE;
4870 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4871 lock_ReleaseMutex(&fidp->mx);
4873 lock_ObtainMutex(&scp->mx);
4874 smb_SetSMBParm(outp, 0, fidp->fid);
4875 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4876 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4877 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4878 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4879 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4880 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4881 /* pass the open mode back; XXXX add access checks */
4882 smb_SetSMBParm(outp, 6, (share & 0xf));
4883 smb_SetSMBDataLength(outp, 0);
4884 lock_ReleaseMutex(&scp->mx);
4887 cm_Open(scp, 0, userp);
4889 /* send and free packet */
4890 smb_ReleaseFID(fidp);
4891 cm_ReleaseUser(userp);
4892 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4896 typedef struct smb_unlinkRock {
4901 char *maskp; /* pointer to the star pattern */
4906 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4909 smb_unlinkRock_t *rockp;
4917 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4918 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4919 caseFold |= CM_FLAG_8DOT3;
4921 matchName = dep->name;
4922 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4924 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4925 !cm_Is8Dot3(dep->name)) {
4926 cm_Gen8Dot3Name(dep, shortName, NULL);
4927 matchName = shortName;
4928 /* 8.3 matches are always case insensitive */
4929 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4932 osi_Log1(smb_logp, "Unlinking %s",
4933 osi_LogSaveString(smb_logp, matchName));
4934 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4935 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4936 smb_NotifyChange(FILE_ACTION_REMOVED,
4937 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
4938 dscp, dep->name, NULL, TRUE);
4942 /* If we made a case sensitive exact match, we might as well quit now. */
4943 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4944 code = CM_ERROR_STOPNOW;
4952 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4961 smb_unlinkRock_t rock;
4970 attribute = smb_GetSMBParm(inp, 0);
4972 tp = smb_GetSMBData(inp, NULL);
4973 pathp = smb_ParseASCIIBlock(tp, &tp);
4974 if (smb_StoreAnsiFilenames)
4975 OemToChar(pathp,pathp);
4977 osi_Log1(smb_logp, "SMB receive unlink %s",
4978 osi_LogSaveString(smb_logp, pathp));
4980 spacep = inp->spacep;
4981 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4983 userp = smb_GetUserFromVCP(vcp, inp);
4985 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4987 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4989 cm_ReleaseUser(userp);
4990 return CM_ERROR_NOSUCHPATH;
4992 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4995 cm_ReleaseUser(userp);
5000 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5001 cm_ReleaseSCache(dscp);
5002 cm_ReleaseUser(userp);
5003 if ( WANTS_DFS_PATHNAMES(inp) )
5004 return CM_ERROR_PATH_NOT_COVERED;
5006 return CM_ERROR_BADSHARENAME;
5008 #endif /* DFS_SUPPORT */
5010 /* otherwise, scp points to the parent directory. */
5017 rock.maskp = smb_FindMask(pathp);
5018 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5021 thyper.HighPart = 0;
5027 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5028 * match. If that fails, we do a case insensitve match.
5030 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5031 !smb_IsStarMask(rock.maskp)) {
5032 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5035 thyper.HighPart = 0;
5036 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5041 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5043 if (code == CM_ERROR_STOPNOW)
5046 cm_ReleaseUser(userp);
5048 cm_ReleaseSCache(dscp);
5050 if (code == 0 && !rock.any)
5051 code = CM_ERROR_NOSUCHFILE;
5055 typedef struct smb_renameRock {
5056 cm_scache_t *odscp; /* old dir */
5057 cm_scache_t *ndscp; /* new dir */
5058 cm_user_t *userp; /* user */
5059 cm_req_t *reqp; /* request struct */
5060 smb_vc_t *vcp; /* virtual circuit */
5061 char *maskp; /* pointer to star pattern of old file name */
5062 int flags; /* tilde, casefold, etc */
5063 char *newNamep; /* ptr to the new file's name */
5067 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5070 smb_renameRock_t *rockp;
5073 char shortName[13]="";
5075 rockp = (smb_renameRock_t *) vrockp;
5077 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5078 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5079 caseFold |= CM_FLAG_8DOT3;
5081 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5083 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5084 !cm_Is8Dot3(dep->name)) {
5085 cm_Gen8Dot3Name(dep, shortName, NULL);
5086 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5091 code = cm_Rename(rockp->odscp, dep->name,
5092 rockp->ndscp, rockp->newNamep, rockp->userp,
5094 /* if the call worked, stop doing the search now, since we
5095 * really only want to rename one file.
5097 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5099 code = CM_ERROR_STOPNOW;
5109 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5112 cm_space_t *spacep = NULL;
5113 smb_renameRock_t rock;
5114 cm_scache_t *oldDscp = NULL;
5115 cm_scache_t *newDscp = NULL;
5116 cm_scache_t *tmpscp= NULL;
5117 cm_scache_t *tmpscp2 = NULL;
5127 userp = smb_GetUserFromVCP(vcp, inp);
5128 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5130 cm_ReleaseUser(userp);
5131 return CM_ERROR_NOSUCHPATH;
5135 spacep = inp->spacep;
5136 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5138 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5139 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5140 userp, tidPathp, &req, &oldDscp);
5142 cm_ReleaseUser(userp);
5147 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5148 cm_ReleaseSCache(oldDscp);
5149 cm_ReleaseUser(userp);
5150 if ( WANTS_DFS_PATHNAMES(inp) )
5151 return CM_ERROR_PATH_NOT_COVERED;
5153 return CM_ERROR_BADSHARENAME;
5155 #endif /* DFS_SUPPORT */
5157 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5158 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5159 userp, tidPathp, &req, &newDscp);
5162 cm_ReleaseSCache(oldDscp);
5163 cm_ReleaseUser(userp);
5168 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5169 cm_ReleaseSCache(oldDscp);
5170 cm_ReleaseSCache(newDscp);
5171 cm_ReleaseUser(userp);
5172 if ( WANTS_DFS_PATHNAMES(inp) )
5173 return CM_ERROR_PATH_NOT_COVERED;
5175 return CM_ERROR_BADSHARENAME;
5177 #endif /* DFS_SUPPORT */
5180 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5181 * next, get the component names, and lower case them.
5184 /* handle the old name first */
5186 oldLastNamep = oldPathp;
5190 /* and handle the new name, too */
5192 newLastNamep = newPathp;
5196 /* TODO: The old name could be a wildcard. The new name must not be */
5198 /* do the vnode call */
5199 rock.odscp = oldDscp;
5200 rock.ndscp = newDscp;
5204 rock.maskp = oldLastNamep;
5205 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5206 rock.newNamep = newLastNamep;
5209 /* Check if the file already exists; if so return error */
5210 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5211 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5212 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5213 osi_LogSaveString(smb_logp, newLastNamep));
5215 /* Check if the old and the new names differ only in case. If so return
5216 * success, else return CM_ERROR_EXISTS
5218 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5220 /* This would be a success only if the old file is *as same as* the new file */
5221 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5223 if (tmpscp == tmpscp2)
5226 code = CM_ERROR_EXISTS;
5227 cm_ReleaseSCache(tmpscp2);
5230 code = CM_ERROR_NOSUCHFILE;
5233 /* file exist, do not rename, also fixes move */
5234 osi_Log0(smb_logp, "Can't rename. Target already exists");
5235 code = CM_ERROR_EXISTS;
5239 cm_ReleaseSCache(tmpscp);
5240 cm_ReleaseSCache(newDscp);
5241 cm_ReleaseSCache(oldDscp);
5242 cm_ReleaseUser(userp);
5246 /* Now search the directory for the pattern, and do the appropriate rename when found */
5247 thyper.LowPart = 0; /* search dir from here */
5248 thyper.HighPart = 0;
5250 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5251 if (code == 0 && !rock.any) {
5253 thyper.HighPart = 0;
5254 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5255 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5257 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5259 if (code == CM_ERROR_STOPNOW)
5262 code = CM_ERROR_NOSUCHFILE;
5264 /* Handle Change Notification */
5266 * Being lazy, not distinguishing between files and dirs in this
5267 * filter, since we'd have to do a lookup.
5269 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5270 if (oldDscp == newDscp) {
5271 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5272 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5273 filter, oldDscp, oldLastNamep,
5274 newLastNamep, TRUE);
5276 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5277 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5278 filter, oldDscp, oldLastNamep,
5280 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5281 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5282 filter, newDscp, newLastNamep,
5287 cm_ReleaseSCache(tmpscp);
5288 cm_ReleaseUser(userp);
5289 cm_ReleaseSCache(oldDscp);
5290 cm_ReleaseSCache(newDscp);
5295 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5298 cm_space_t *spacep = NULL;
5299 cm_scache_t *oldDscp = NULL;
5300 cm_scache_t *newDscp = NULL;
5301 cm_scache_t *tmpscp= NULL;
5302 cm_scache_t *tmpscp2 = NULL;
5303 cm_scache_t *sscp = NULL;
5312 userp = smb_GetUserFromVCP(vcp, inp);
5314 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5316 cm_ReleaseUser(userp);
5317 return CM_ERROR_NOSUCHPATH;
5322 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5324 spacep = inp->spacep;
5325 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5327 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5328 userp, tidPathp, &req, &oldDscp);
5330 cm_ReleaseUser(userp);
5335 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5336 cm_ReleaseSCache(oldDscp);
5337 cm_ReleaseUser(userp);
5338 if ( WANTS_DFS_PATHNAMES(inp) )
5339 return CM_ERROR_PATH_NOT_COVERED;
5341 return CM_ERROR_BADSHARENAME;
5343 #endif /* DFS_SUPPORT */
5345 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5346 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5347 userp, tidPathp, &req, &newDscp);
5349 cm_ReleaseSCache(oldDscp);
5350 cm_ReleaseUser(userp);
5355 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5356 cm_ReleaseSCache(newDscp);
5357 cm_ReleaseSCache(oldDscp);
5358 cm_ReleaseUser(userp);
5359 if ( WANTS_DFS_PATHNAMES(inp) )
5360 return CM_ERROR_PATH_NOT_COVERED;
5362 return CM_ERROR_BADSHARENAME;
5364 #endif /* DFS_SUPPORT */
5366 /* Now, although we did two lookups for the two directories (because the same
5367 * directory can be referenced through different paths), we only allow hard links
5368 * within the same directory. */
5369 if (oldDscp != newDscp) {
5370 cm_ReleaseSCache(oldDscp);
5371 cm_ReleaseSCache(newDscp);
5372 cm_ReleaseUser(userp);
5373 return CM_ERROR_CROSSDEVLINK;
5376 /* handle the old name first */
5378 oldLastNamep = oldPathp;
5382 /* and handle the new name, too */
5384 newLastNamep = newPathp;
5388 /* now lookup the old name */
5389 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5390 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5392 cm_ReleaseSCache(oldDscp);
5393 cm_ReleaseSCache(newDscp);
5394 cm_ReleaseUser(userp);
5398 /* Check if the file already exists; if so return error */
5399 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5400 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5401 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5402 osi_LogSaveString(smb_logp, newLastNamep));
5404 /* if the existing link is to the same file, then we return success */
5406 if(sscp == tmpscp) {
5409 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5410 code = CM_ERROR_EXISTS;
5415 cm_ReleaseSCache(tmpscp);
5416 cm_ReleaseSCache(sscp);
5417 cm_ReleaseSCache(newDscp);
5418 cm_ReleaseSCache(oldDscp);
5419 cm_ReleaseUser(userp);
5423 /* now create the hardlink */
5424 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5425 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5426 osi_Log1(smb_logp," Link returns 0x%x", code);
5428 /* Handle Change Notification */
5430 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5431 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5432 smb_NotifyChange(FILE_ACTION_ADDED,
5433 filter, newDscp, newLastNamep,
5438 cm_ReleaseSCache(tmpscp);
5439 cm_ReleaseUser(userp);
5440 cm_ReleaseSCache(sscp);
5441 cm_ReleaseSCache(oldDscp);
5442 cm_ReleaseSCache(newDscp);
5447 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5454 tp = smb_GetSMBData(inp, NULL);
5455 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5456 if (smb_StoreAnsiFilenames)
5457 OemToChar(oldPathp,oldPathp);
5458 newPathp = smb_ParseASCIIBlock(tp, &tp);
5459 if (smb_StoreAnsiFilenames)
5460 OemToChar(newPathp,newPathp);
5462 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5463 osi_LogSaveString(smb_logp, oldPathp),
5464 osi_LogSaveString(smb_logp, newPathp));
5466 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5468 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5474 typedef struct smb_rmdirRock {
5478 char *maskp; /* pointer to the star pattern */
5483 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5486 smb_rmdirRock_t *rockp;
5491 rockp = (smb_rmdirRock_t *) vrockp;
5493 matchName = dep->name;
5494 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5495 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5497 match = (strcmp(matchName, rockp->maskp) == 0);
5499 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5500 !cm_Is8Dot3(dep->name)) {
5501 cm_Gen8Dot3Name(dep, shortName, NULL);
5502 matchName = shortName;
5503 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5506 osi_Log1(smb_logp, "Removing directory %s",
5507 osi_LogSaveString(smb_logp, matchName));
5508 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5509 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5510 smb_NotifyChange(FILE_ACTION_REMOVED,
5511 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5512 dscp, dep->name, NULL, TRUE);
5521 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5529 smb_rmdirRock_t rock;
5538 tp = smb_GetSMBData(inp, NULL);
5539 pathp = smb_ParseASCIIBlock(tp, &tp);
5540 if (smb_StoreAnsiFilenames)
5541 OemToChar(pathp,pathp);
5543 spacep = inp->spacep;
5544 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5546 userp = smb_GetUserFromVCP(vcp, inp);
5548 caseFold = CM_FLAG_CASEFOLD;
5550 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5552 cm_ReleaseUser(userp);
5553 return CM_ERROR_NOSUCHPATH;
5555 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5556 userp, tidPathp, &req, &dscp);
5559 cm_ReleaseUser(userp);
5564 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5565 cm_ReleaseSCache(dscp);
5566 cm_ReleaseUser(userp);
5567 if ( WANTS_DFS_PATHNAMES(inp) )
5568 return CM_ERROR_PATH_NOT_COVERED;
5570 return CM_ERROR_BADSHARENAME;
5572 #endif /* DFS_SUPPORT */
5574 /* otherwise, scp points to the parent directory. */
5581 rock.maskp = lastNamep;
5582 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5585 thyper.HighPart = 0;
5590 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5591 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5592 if (code == 0 && !rock.any) {
5594 thyper.HighPart = 0;
5595 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5596 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5599 cm_ReleaseUser(userp);
5601 cm_ReleaseSCache(dscp);
5603 if (code == 0 && !rock.any)
5604 code = CM_ERROR_NOSUCHFILE;
5608 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5618 fid = smb_GetSMBParm(inp, 0);
5620 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5622 fid = smb_ChainFID(fid, inp);
5623 fidp = smb_FindFID(vcp, fid, 0);
5625 return CM_ERROR_BADFD;
5627 lock_ObtainMutex(&fidp->mx);
5628 if (fidp->flags & SMB_FID_IOCTL) {
5629 lock_ReleaseMutex(&fidp->mx);
5630 smb_ReleaseFID(fidp);
5631 return CM_ERROR_BADFD;
5633 lock_ReleaseMutex(&fidp->mx);
5635 userp = smb_GetUserFromVCP(vcp, inp);
5637 lock_ObtainMutex(&fidp->mx);
5638 if (fidp->flags & SMB_FID_OPENWRITE) {
5639 cm_scache_t * scp = fidp->scp;
5641 lock_ReleaseMutex(&fidp->mx);
5642 code = cm_FSync(scp, userp, &req);
5643 cm_ReleaseSCache(scp);
5646 lock_ReleaseMutex(&fidp->mx);
5649 smb_ReleaseFID(fidp);
5651 cm_ReleaseUser(userp);
5656 struct smb_FullNameRock {
5662 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5666 struct smb_FullNameRock *vrockp;
5668 vrockp = (struct smb_FullNameRock *)rockp;
5670 if (!cm_Is8Dot3(dep->name)) {
5671 cm_Gen8Dot3Name(dep, shortName, NULL);
5673 if (cm_stricmp(shortName, vrockp->name) == 0) {
5674 vrockp->fullName = strdup(dep->name);
5675 return CM_ERROR_STOPNOW;
5678 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5679 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5680 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5681 vrockp->fullName = strdup(dep->name);
5682 return CM_ERROR_STOPNOW;
5687 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5688 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5690 struct smb_FullNameRock rock;
5696 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5697 if (code == CM_ERROR_STOPNOW)
5698 *newPathp = rock.fullName;
5700 *newPathp = strdup(pathp);
5703 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5704 afs_uint32 dosTime) {
5707 cm_scache_t *dscp = NULL;
5709 cm_scache_t * scp = NULL;
5711 int nullcreator = 0;
5713 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5714 fidp, fidp->fid, scp, vcp);
5717 lock_ObtainMutex(&fidp->mx);
5718 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5719 lock_ReleaseMutex(&fidp->mx);
5720 osi_Log0(smb_logp, " No user specified. Not closing fid");
5721 return CM_ERROR_BADFD;
5724 userp = fidp->userp; /* no hold required since fidp is held
5725 throughout the function */
5726 lock_ReleaseMutex(&fidp->mx);
5731 lock_ObtainWrite(&smb_rctLock);
5733 osi_Log0(smb_logp, " Fid already closed.");
5734 lock_ReleaseWrite(&smb_rctLock);
5735 return CM_ERROR_BADFD;
5738 lock_ReleaseWrite(&smb_rctLock);
5740 lock_ObtainMutex(&fidp->mx);
5741 if (fidp->NTopen_dscp) {
5742 dscp = fidp->NTopen_dscp;
5743 cm_HoldSCache(dscp);
5746 if (fidp->NTopen_pathp) {
5747 pathp = strdup(fidp->NTopen_pathp);
5755 /* Don't jump the gun on an async raw write */
5756 while (fidp->raw_writers) {
5757 lock_ReleaseMutex(&fidp->mx);
5758 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5759 lock_ObtainMutex(&fidp->mx);
5762 /* watch for ioctl closes, and read-only opens */
5764 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5765 == SMB_FID_OPENWRITE) {
5766 if (dosTime != 0 && dosTime != -1) {
5767 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5768 /* This fixes defect 10958 */
5769 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5770 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5772 lock_ReleaseMutex(&fidp->mx);
5773 code = cm_FSync(scp, userp, &req);
5774 lock_ObtainMutex(&fidp->mx);
5779 /* unlock any pending locks */
5780 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5781 scp->fileType == CM_SCACHETYPE_FILE) {
5785 lock_ReleaseMutex(&fidp->mx);
5787 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5789 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5790 lock_ObtainMutex(&scp->mx);
5792 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5793 CM_SCACHESYNC_NEEDCALLBACK
5794 | CM_SCACHESYNC_GETSTATUS
5795 | CM_SCACHESYNC_LOCK);
5799 "smb CoreClose SyncOp failure code 0x%x", tcode);
5800 goto post_syncopdone;
5803 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5805 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5809 lock_ReleaseMutex(&scp->mx);
5810 lock_ObtainMutex(&fidp->mx);
5813 if (fidp->flags & SMB_FID_DELONCLOSE) {
5816 lock_ReleaseMutex(&fidp->mx);
5817 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5818 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5819 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5822 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5823 smb_NotifyChange(FILE_ACTION_REMOVED,
5824 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5825 dscp, fullPathp, NULL, TRUE);
5828 code = cm_Unlink(dscp, fullPathp, userp, &req);
5831 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5832 smb_NotifyChange(FILE_ACTION_REMOVED,
5833 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5834 dscp, fullPathp, NULL, TRUE);
5838 lock_ObtainMutex(&fidp->mx);
5839 fidp->flags &= ~SMB_FID_DELONCLOSE;
5842 /* if this was a newly created file, then clear the creator
5843 * in the stat cache entry. */
5844 if (fidp->flags & SMB_FID_CREATED) {
5846 fidp->flags &= ~SMB_FID_CREATED;
5849 if (fidp->flags & SMB_FID_NTOPEN) {
5850 cm_ReleaseSCache(fidp->NTopen_dscp);
5851 fidp->NTopen_dscp = NULL;
5852 free(fidp->NTopen_pathp);
5853 fidp->NTopen_pathp = NULL;
5854 fidp->flags &= ~SMB_FID_NTOPEN;
5856 osi_assert(fidp->NTopen_dscp == NULL);
5857 osi_assert(fidp->NTopen_pathp == NULL);
5860 if (fidp->NTopen_wholepathp) {
5861 free(fidp->NTopen_wholepathp);
5862 fidp->NTopen_wholepathp = NULL;
5866 cm_ReleaseSCache(fidp->scp);
5869 lock_ReleaseMutex(&fidp->mx);
5872 cm_ReleaseSCache(dscp);
5875 if (deleted || nullcreator) {
5876 lock_ObtainMutex(&scp->mx);
5877 if (nullcreator && scp->creator == userp)
5878 scp->creator = NULL;
5880 scp->flags |= CM_SCACHEFLAG_DELETED;
5881 lock_ReleaseMutex(&scp->mx);
5883 lock_ObtainMutex(&scp->mx);
5884 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5885 lock_ReleaseMutex(&scp->mx);
5886 cm_ReleaseSCache(scp);
5895 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5903 fid = smb_GetSMBParm(inp, 0);
5904 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5906 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5908 fid = smb_ChainFID(fid, inp);
5909 fidp = smb_FindFID(vcp, fid, 0);
5911 return CM_ERROR_BADFD;
5914 userp = smb_GetUserFromVCP(vcp, inp);
5916 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5918 smb_ReleaseFID(fidp);
5919 cm_ReleaseUser(userp);
5924 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5926 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5927 cm_user_t *userp, long *readp)
5933 osi_hyper_t fileLength;
5935 osi_hyper_t lastByte;
5936 osi_hyper_t bufferOffset;
5937 long bufIndex, nbytes;
5939 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
5947 lock_ObtainMutex(&fidp->mx);
5950 lock_ObtainMutex(&scp->mx);
5952 if (offset.HighPart == 0) {
5953 chunk = offset.LowPart >> cm_logChunkSize;
5954 if (chunk != fidp->curr_chunk) {
5955 fidp->prev_chunk = fidp->curr_chunk;
5956 fidp->curr_chunk = chunk;
5958 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
5961 lock_ReleaseMutex(&fidp->mx);
5963 /* start by looking up the file's end */
5964 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5965 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5969 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5971 /* now we have the entry locked, look up the length */
5972 fileLength = scp->length;
5974 /* adjust count down so that it won't go past EOF */
5975 thyper.LowPart = count;
5976 thyper.HighPart = 0;
5977 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5979 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5980 /* we'd read past EOF, so just stop at fileLength bytes.
5981 * Start by computing how many bytes remain in the file.
5983 thyper = LargeIntegerSubtract(fileLength, offset);
5985 /* if we are past EOF, read 0 bytes */
5986 if (LargeIntegerLessThanZero(thyper))
5989 count = thyper.LowPart;
5994 /* now, copy the data one buffer at a time,
5995 * until we've filled the request packet
5998 /* if we've copied all the data requested, we're done */
5999 if (count <= 0) break;
6001 /* otherwise, load up a buffer of data */
6002 thyper.HighPart = offset.HighPart;
6003 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6004 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6007 buf_Release(bufferp);
6010 lock_ReleaseMutex(&scp->mx);
6012 lock_ObtainRead(&scp->bufCreateLock);
6013 code = buf_Get(scp, &thyper, &bufferp);
6014 lock_ReleaseRead(&scp->bufCreateLock);
6016 lock_ObtainMutex(&scp->mx);
6017 if (code) goto done;
6018 bufferOffset = thyper;
6020 /* now get the data in the cache */
6022 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6023 CM_SCACHESYNC_NEEDCALLBACK |
6024 CM_SCACHESYNC_READ);
6028 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6030 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6032 /* otherwise, load the buffer and try again */
6033 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6037 buf_Release(bufferp);
6041 } /* if (wrong buffer) ... */
6043 /* now we have the right buffer loaded. Copy out the
6044 * data from here to the user's buffer.
6046 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6048 /* and figure out how many bytes we want from this buffer */
6049 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6050 if (nbytes > count) nbytes = count; /* don't go past EOF */
6052 /* now copy the data */
6053 memcpy(op, bufferp->datap + bufIndex, nbytes);
6055 /* adjust counters, pointers, etc. */
6058 thyper.LowPart = nbytes;
6059 thyper.HighPart = 0;
6060 offset = LargeIntegerAdd(thyper, offset);
6064 lock_ReleaseMutex(&scp->mx);
6066 buf_Release(bufferp);
6068 if (code == 0 && sequential)
6069 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6071 cm_ReleaseSCache(scp);
6077 * smb_WriteData -- common code for Write and Raw Write
6079 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6080 cm_user_t *userp, long *writtenp)
6086 osi_hyper_t fileLength; /* file's length at start of write */
6087 osi_hyper_t minLength; /* don't read past this */
6088 long nbytes; /* # of bytes to transfer this iteration */
6090 osi_hyper_t thyper; /* hyper tmp variable */
6091 osi_hyper_t bufferOffset;
6092 long bufIndex; /* index in buffer where our data is */
6094 osi_hyper_t writeBackOffset;/* offset of region to write back when
6099 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6100 fidp->fid, offsetp->LowPart, count);
6110 lock_ObtainMutex(&fidp->mx);
6111 /* make sure we have a writable FD */
6112 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6113 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6114 fidp->fid, fidp->flags);
6115 lock_ReleaseMutex(&fidp->mx);
6116 code = CM_ERROR_BADFDOP;
6122 lock_ReleaseMutex(&fidp->mx);
6124 lock_ObtainMutex(&scp->mx);
6125 /* start by looking up the file's end */
6126 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6127 CM_SCACHESYNC_NEEDCALLBACK
6128 | CM_SCACHESYNC_SETSTATUS
6129 | CM_SCACHESYNC_GETSTATUS);
6133 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6135 /* now we have the entry locked, look up the length */
6136 fileLength = scp->length;
6137 minLength = fileLength;
6138 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6139 minLength = scp->serverLength;
6141 /* adjust file length if we extend past EOF */
6142 thyper.LowPart = count;
6143 thyper.HighPart = 0;
6144 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6145 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6146 /* we'd write past EOF, so extend the file */
6147 scp->mask |= CM_SCACHEMASK_LENGTH;
6148 scp->length = thyper;
6149 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6151 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6153 /* now, if the new position (thyper) and the old (offset) are in
6154 * different storeback windows, remember to store back the previous
6155 * storeback window when we're done with the write.
6157 if ((thyper.LowPart & (-cm_chunkSize)) !=
6158 (offset.LowPart & (-cm_chunkSize))) {
6159 /* they're different */
6161 writeBackOffset.HighPart = offset.HighPart;
6162 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6167 /* now, copy the data one buffer at a time, until we've filled the
6170 /* if we've copied all the data requested, we're done */
6174 /* handle over quota or out of space */
6175 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6176 *writtenp = written;
6177 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6181 /* otherwise, load up a buffer of data */
6182 thyper.HighPart = offset.HighPart;
6183 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6184 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6187 lock_ReleaseMutex(&bufferp->mx);
6188 buf_Release(bufferp);
6191 lock_ReleaseMutex(&scp->mx);
6193 lock_ObtainRead(&scp->bufCreateLock);
6194 code = buf_Get(scp, &thyper, &bufferp);
6195 lock_ReleaseRead(&scp->bufCreateLock);
6197 lock_ObtainMutex(&bufferp->mx);
6198 lock_ObtainMutex(&scp->mx);
6199 if (code) goto done;
6201 bufferOffset = thyper;
6203 /* now get the data in the cache */
6205 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6206 CM_SCACHESYNC_NEEDCALLBACK
6207 | CM_SCACHESYNC_WRITE
6208 | CM_SCACHESYNC_BUFLOCKED);
6212 cm_SyncOpDone(scp, bufferp,
6213 CM_SCACHESYNC_NEEDCALLBACK
6214 | CM_SCACHESYNC_WRITE
6215 | CM_SCACHESYNC_BUFLOCKED);
6217 /* If we're overwriting the entire buffer, or
6218 * if we're writing at or past EOF, mark the
6219 * buffer as current so we don't call
6220 * cm_GetBuffer. This skips the fetch from the
6221 * server in those cases where we're going to
6222 * obliterate all the data in the buffer anyway,
6223 * or in those cases where there is no useful
6224 * data at the server to start with.
6226 * Use minLength instead of scp->length, since
6227 * the latter has already been updated by this
6230 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6231 || LargeIntegerEqualTo(offset, bufferp->offset)
6232 && (count >= cm_data.buf_blockSize
6233 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6234 ConvertLongToLargeInteger(count)),
6236 if (count < cm_data.buf_blockSize
6237 && bufferp->dataVersion == -1)
6238 memset(bufferp->datap, 0,
6239 cm_data.buf_blockSize);
6240 bufferp->dataVersion = scp->dataVersion;
6243 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6245 /* otherwise, load the buffer and try again */
6246 lock_ReleaseMutex(&bufferp->mx);
6247 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6249 lock_ReleaseMutex(&scp->mx);
6250 lock_ObtainMutex(&bufferp->mx);
6251 lock_ObtainMutex(&scp->mx);
6255 lock_ReleaseMutex(&bufferp->mx);
6256 buf_Release(bufferp);
6260 } /* if (wrong buffer) ... */
6262 /* now we have the right buffer loaded. Copy out the
6263 * data from here to the user's buffer.
6265 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6267 /* and figure out how many bytes we want from this buffer */
6268 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6270 nbytes = count; /* don't go past end of request */
6272 /* now copy the data */
6273 memcpy(bufferp->datap + bufIndex, op, nbytes);
6274 buf_SetDirty(bufferp);
6276 /* and record the last writer */
6277 if (bufferp->userp != userp) {
6280 cm_ReleaseUser(bufferp->userp);
6281 bufferp->userp = userp;
6284 /* adjust counters, pointers, etc. */
6288 thyper.LowPart = nbytes;
6289 thyper.HighPart = 0;
6290 offset = LargeIntegerAdd(thyper, offset);
6294 lock_ReleaseMutex(&scp->mx);
6297 lock_ReleaseMutex(&bufferp->mx);
6298 buf_Release(bufferp);
6301 lock_ObtainMutex(&fidp->mx);
6302 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6303 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6304 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6305 fidp->NTopen_dscp, fidp->NTopen_pathp,
6308 lock_ReleaseMutex(&fidp->mx);
6310 if (code == 0 && doWriteBack) {
6312 lock_ObtainMutex(&scp->mx);
6313 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6315 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6316 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6318 lock_ReleaseMutex(&scp->mx);
6319 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6320 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6321 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6324 cm_ReleaseSCache(scp);
6326 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6327 fidp->fid, code, *writtenp);
6331 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6334 unsigned short count;
6336 unsigned short hint;
6337 long written = 0, total_written = 0;
6342 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6344 int inDataBlockCount;
6346 fd = smb_GetSMBParm(inp, 0);
6347 count = smb_GetSMBParm(inp, 1);
6348 offset.HighPart = 0; /* too bad */
6349 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6350 hint = smb_GetSMBParm(inp, 4);
6352 op = smb_GetSMBData(inp, NULL);
6353 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6355 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6356 fd, offset.LowPart, count);
6358 fd = smb_ChainFID(fd, inp);
6359 fidp = smb_FindFID(vcp, fd, 0);
6361 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6362 return CM_ERROR_BADFD;
6365 lock_ObtainMutex(&fidp->mx);
6366 if (fidp->flags & SMB_FID_IOCTL) {
6367 lock_ReleaseMutex(&fidp->mx);
6368 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6369 smb_ReleaseFID(fidp);
6370 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6373 lock_ReleaseMutex(&fidp->mx);
6374 userp = smb_GetUserFromVCP(vcp, inp);
6378 LARGE_INTEGER LOffset;
6379 LARGE_INTEGER LLength;
6381 pid = ((smb_t *) inp)->pid;
6382 key = cm_GenerateKey(vcp->vcID, pid, fd);
6384 LOffset.HighPart = offset.HighPart;
6385 LOffset.LowPart = offset.LowPart;
6386 LLength.HighPart = 0;
6387 LLength.LowPart = count;
6389 lock_ObtainMutex(&fidp->scp->mx);
6390 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6391 lock_ReleaseMutex(&fidp->scp->mx);
6394 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6399 /* special case: 0 bytes transferred means truncate to this position */
6403 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6407 truncAttr.mask = CM_ATTRMASK_LENGTH;
6408 truncAttr.length.LowPart = offset.LowPart;
6409 truncAttr.length.HighPart = 0;
6410 lock_ObtainMutex(&fidp->mx);
6411 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6412 fidp->flags |= SMB_FID_LENGTHSETDONE;
6413 lock_ReleaseMutex(&fidp->mx);
6414 smb_SetSMBParm(outp, 0, 0 /* count */);
6415 smb_SetSMBDataLength(outp, 0);
6420 * Work around bug in NT client
6422 * When copying a file, the NT client should first copy the data,
6423 * then copy the last write time. But sometimes the NT client does
6424 * these in the wrong order, so the data copies would inadvertently
6425 * cause the last write time to be overwritten. We try to detect this,
6426 * and don't set client mod time if we think that would go against the
6429 lock_ObtainMutex(&fidp->mx);
6430 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6431 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6432 fidp->scp->clientModTime = time(NULL);
6434 lock_ReleaseMutex(&fidp->mx);
6437 while ( code == 0 && count > 0 ) {
6438 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6439 if (code == 0 && written == 0)
6440 code = CM_ERROR_PARTIALWRITE;
6442 offset = LargeIntegerAdd(offset,
6443 ConvertLongToLargeInteger(written));
6445 total_written += written;
6449 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6450 total_written, code);
6452 /* set the packet data length to 3 bytes for the data block header,
6453 * plus the size of the data.
6455 smb_SetSMBParm(outp, 0, total_written);
6456 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6457 smb_SetSMBParm(outp, 3, hint);
6458 smb_SetSMBDataLength(outp, 0);
6461 smb_ReleaseFID(fidp);
6462 cm_ReleaseUser(userp);
6467 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6468 NCB *ncbp, raw_write_cont_t *rwcp)
6477 fd = smb_GetSMBParm(inp, 0);
6478 fidp = smb_FindFID(vcp, fd, 0);
6480 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6481 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6483 userp = smb_GetUserFromVCP(vcp, inp);
6486 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6488 if (rwcp->writeMode & 0x1) { /* synchronous */
6491 smb_FormatResponsePacket(vcp, inp, outp);
6492 op = (smb_t *) outp;
6493 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6494 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6495 smb_SetSMBDataLength(outp, 0);
6496 smb_SendPacket(vcp, outp);
6497 smb_FreePacket(outp);
6499 else { /* asynchronous */
6500 lock_ObtainMutex(&fidp->mx);
6501 fidp->raw_writers--;
6502 if (fidp->raw_writers == 0)
6503 thrd_SetEvent(fidp->raw_write_event);
6504 lock_ReleaseMutex(&fidp->mx);
6507 /* Give back raw buffer */
6508 lock_ObtainMutex(&smb_RawBufLock);
6509 *((char **)rawBuf) = smb_RawBufs;
6510 smb_RawBufs = rawBuf;
6511 lock_ReleaseMutex(&smb_RawBufLock);
6513 smb_ReleaseFID(fidp);
6514 cm_ReleaseUser(userp);
6517 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6522 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6525 long count, written = 0, total_written = 0;
6532 unsigned short writeMode;
6534 fd = smb_GetSMBParm(inp, 0);
6535 totalCount = smb_GetSMBParm(inp, 1);
6536 count = smb_GetSMBParm(inp, 10);
6537 writeMode = smb_GetSMBParm(inp, 7);
6539 op = (char *) inp->data;
6540 op += smb_GetSMBParm(inp, 11);
6542 offset.HighPart = 0;
6543 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6545 if (*inp->wctp == 14) {
6546 /* we received a 64-bit file offset */
6547 #ifdef AFS_LARGEFILES
6548 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6550 if (LargeIntegerLessThanZero(offset)) {
6552 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6553 offset.HighPart, offset.LowPart);
6554 return CM_ERROR_BADSMB;
6557 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6559 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6560 return CM_ERROR_BADSMB;
6563 offset.HighPart = 0;
6566 offset.HighPart = 0; /* 32-bit file offset */
6570 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6571 fd, offset.HighPart, offset.LowPart, count);
6573 " WriteRaw WriteMode 0x%x",
6576 fd = smb_ChainFID(fd, inp);
6577 fidp = smb_FindFID(vcp, fd, 0);
6579 return CM_ERROR_BADFD;
6585 LARGE_INTEGER LOffset;
6586 LARGE_INTEGER LLength;
6588 pid = ((smb_t *) inp)->pid;
6589 key = cm_GenerateKey(vcp->vcID, pid, fd);
6591 LOffset.HighPart = offset.HighPart;
6592 LOffset.LowPart = offset.LowPart;
6593 LLength.HighPart = 0;
6594 LLength.LowPart = count;
6596 lock_ObtainMutex(&fidp->scp->mx);
6597 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6598 lock_ReleaseMutex(&fidp->scp->mx);
6601 smb_ReleaseFID(fidp);
6606 userp = smb_GetUserFromVCP(vcp, inp);
6609 * Work around bug in NT client
6611 * When copying a file, the NT client should first copy the data,
6612 * then copy the last write time. But sometimes the NT client does
6613 * these in the wrong order, so the data copies would inadvertently
6614 * cause the last write time to be overwritten. We try to detect this,
6615 * and don't set client mod time if we think that would go against the
6618 lock_ObtainMutex(&fidp->mx);
6619 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6620 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6621 fidp->scp->clientModTime = time(NULL);
6623 lock_ReleaseMutex(&fidp->mx);
6626 while ( code == 0 && count > 0 ) {
6627 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6628 if (code == 0 && written == 0)
6629 code = CM_ERROR_PARTIALWRITE;
6631 offset = LargeIntegerAdd(offset,
6632 ConvertLongToLargeInteger(written));
6635 total_written += written;
6639 /* Get a raw buffer */
6642 lock_ObtainMutex(&smb_RawBufLock);
6644 /* Get a raw buf, from head of list */
6645 rawBuf = smb_RawBufs;
6646 smb_RawBufs = *(char **)smb_RawBufs;
6649 code = CM_ERROR_USESTD;
6651 lock_ReleaseMutex(&smb_RawBufLock);
6654 /* Don't allow a premature Close */
6655 if (code == 0 && (writeMode & 1) == 0) {
6656 lock_ObtainMutex(&fidp->mx);
6657 fidp->raw_writers++;
6658 thrd_ResetEvent(fidp->raw_write_event);
6659 lock_ReleaseMutex(&fidp->mx);
6662 smb_ReleaseFID(fidp);
6663 cm_ReleaseUser(userp);
6666 smb_SetSMBParm(outp, 0, total_written);
6667 smb_SetSMBDataLength(outp, 0);
6668 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6673 offset = LargeIntegerAdd(offset,
6674 ConvertLongToLargeInteger(count));
6678 rwcp->offset.HighPart = offset.HighPart;
6679 rwcp->offset.LowPart = offset.LowPart;
6680 rwcp->count = totalCount - count;
6681 rwcp->writeMode = writeMode;
6682 rwcp->alreadyWritten = total_written;
6684 /* set the packet data length to 3 bytes for the data block header,
6685 * plus the size of the data.
6687 smb_SetSMBParm(outp, 0, 0xffff);
6688 smb_SetSMBDataLength(outp, 0);
6693 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6696 long count, finalCount;
6704 fd = smb_GetSMBParm(inp, 0);
6705 count = smb_GetSMBParm(inp, 1);
6706 offset.HighPart = 0; /* too bad */
6707 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6709 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6710 fd, offset.LowPart, count);
6712 fd = smb_ChainFID(fd, inp);
6713 fidp = smb_FindFID(vcp, fd, 0);
6715 return CM_ERROR_BADFD;
6717 lock_ObtainMutex(&fidp->mx);
6718 if (fidp->flags & SMB_FID_IOCTL) {
6719 lock_ReleaseMutex(&fidp->mx);
6720 code = smb_IoctlRead(fidp, vcp, inp, outp);
6721 smb_ReleaseFID(fidp);
6724 lock_ReleaseMutex(&fidp->mx);
6727 LARGE_INTEGER LOffset, LLength;
6730 pid = ((smb_t *) inp)->pid;
6731 key = cm_GenerateKey(vcp->vcID, pid, fd);
6733 LOffset.HighPart = 0;
6734 LOffset.LowPart = offset.LowPart;
6735 LLength.HighPart = 0;
6736 LLength.LowPart = count;
6738 lock_ObtainMutex(&fidp->scp->mx);
6739 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6740 lock_ReleaseMutex(&fidp->scp->mx);
6743 smb_ReleaseFID(fidp);
6747 userp = smb_GetUserFromVCP(vcp, inp);
6749 /* remember this for final results */
6750 smb_SetSMBParm(outp, 0, count);
6751 smb_SetSMBParm(outp, 1, 0);
6752 smb_SetSMBParm(outp, 2, 0);
6753 smb_SetSMBParm(outp, 3, 0);
6754 smb_SetSMBParm(outp, 4, 0);
6756 /* set the packet data length to 3 bytes for the data block header,
6757 * plus the size of the data.
6759 smb_SetSMBDataLength(outp, count+3);
6761 /* get op ptr after putting in the parms, since otherwise we don't
6762 * know where the data really is.
6764 op = smb_GetSMBData(outp, NULL);
6766 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6767 *op++ = 1; /* data block marker */
6768 *op++ = (unsigned char) (count & 0xff);
6769 *op++ = (unsigned char) ((count >> 8) & 0xff);
6771 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6773 /* fix some things up */
6774 smb_SetSMBParm(outp, 0, finalCount);
6775 smb_SetSMBDataLength(outp, finalCount+3);
6777 smb_ReleaseFID(fidp);
6779 cm_ReleaseUser(userp);
6783 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6790 cm_scache_t *dscp; /* dir we're dealing with */
6791 cm_scache_t *scp; /* file we're creating */
6793 int initialModeBits;
6803 /* compute initial mode bits based on read-only flag in attributes */
6804 initialModeBits = 0777;
6806 tp = smb_GetSMBData(inp, NULL);
6807 pathp = smb_ParseASCIIBlock(tp, &tp);
6808 if (smb_StoreAnsiFilenames)
6809 OemToChar(pathp,pathp);
6811 if (strcmp(pathp, "\\") == 0)
6812 return CM_ERROR_EXISTS;
6814 spacep = inp->spacep;
6815 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6817 userp = smb_GetUserFromVCP(vcp, inp);
6819 caseFold = CM_FLAG_CASEFOLD;
6821 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6823 cm_ReleaseUser(userp);
6824 return CM_ERROR_NOSUCHPATH;
6827 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6828 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6829 userp, tidPathp, &req, &dscp);
6832 cm_ReleaseUser(userp);
6837 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6838 cm_ReleaseSCache(dscp);
6839 cm_ReleaseUser(userp);
6840 if ( WANTS_DFS_PATHNAMES(inp) )
6841 return CM_ERROR_PATH_NOT_COVERED;
6843 return CM_ERROR_BADSHARENAME;
6845 #endif /* DFS_SUPPORT */
6847 /* otherwise, scp points to the parent directory. Do a lookup, and
6848 * fail if we find it. Otherwise, we do the create.
6854 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6855 if (scp) cm_ReleaseSCache(scp);
6856 if (code != CM_ERROR_NOSUCHFILE) {
6857 if (code == 0) code = CM_ERROR_EXISTS;
6858 cm_ReleaseSCache(dscp);
6859 cm_ReleaseUser(userp);
6863 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6864 setAttr.clientModTime = time(NULL);
6865 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6866 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6867 smb_NotifyChange(FILE_ACTION_ADDED,
6868 FILE_NOTIFY_CHANGE_DIR_NAME,
6869 dscp, lastNamep, NULL, TRUE);
6871 /* we don't need this any longer */
6872 cm_ReleaseSCache(dscp);
6875 /* something went wrong creating or truncating the file */
6876 cm_ReleaseUser(userp);
6880 /* otherwise we succeeded */
6881 smb_SetSMBDataLength(outp, 0);
6882 cm_ReleaseUser(userp);
6887 BOOL smb_IsLegalFilename(char *filename)
6890 * Find the longest substring of filename that does not contain
6891 * any of the chars in illegalChars. If that substring is less
6892 * than the length of the whole string, then one or more of the
6893 * illegal chars is in filename.
6895 if (strcspn(filename, illegalChars) < strlen(filename))
6901 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6909 cm_scache_t *dscp; /* dir we're dealing with */
6910 cm_scache_t *scp; /* file we're creating */
6912 int initialModeBits;
6920 int created = 0; /* the file was new */
6925 excl = (inp->inCom == 0x03)? 0 : 1;
6927 attributes = smb_GetSMBParm(inp, 0);
6928 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6930 /* compute initial mode bits based on read-only flag in attributes */
6931 initialModeBits = 0666;
6932 if (attributes & SMB_ATTR_READONLY)
6933 initialModeBits &= ~0222;
6935 tp = smb_GetSMBData(inp, NULL);
6936 pathp = smb_ParseASCIIBlock(tp, &tp);
6937 if (smb_StoreAnsiFilenames)
6938 OemToChar(pathp,pathp);
6940 spacep = inp->spacep;
6941 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6943 userp = smb_GetUserFromVCP(vcp, inp);
6945 caseFold = CM_FLAG_CASEFOLD;
6947 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6949 cm_ReleaseUser(userp);
6950 return CM_ERROR_NOSUCHPATH;
6952 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6953 userp, tidPathp, &req, &dscp);
6956 cm_ReleaseUser(userp);
6961 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6962 cm_ReleaseSCache(dscp);
6963 cm_ReleaseUser(userp);
6964 if ( WANTS_DFS_PATHNAMES(inp) )
6965 return CM_ERROR_PATH_NOT_COVERED;
6967 return CM_ERROR_BADSHARENAME;
6969 #endif /* DFS_SUPPORT */
6971 /* otherwise, scp points to the parent directory. Do a lookup, and
6972 * truncate the file if we find it, otherwise we create the file.
6979 if (!smb_IsLegalFilename(lastNamep))
6980 return CM_ERROR_BADNTFILENAME;
6982 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6983 #ifdef DEBUG_VERBOSE
6986 hexp = osi_HexifyString( lastNamep );
6987 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6992 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6993 if (code && code != CM_ERROR_NOSUCHFILE) {
6994 cm_ReleaseSCache(dscp);
6995 cm_ReleaseUser(userp);
6999 /* if we get here, if code is 0, the file exists and is represented by
7000 * scp. Otherwise, we have to create it.
7004 /* oops, file shouldn't be there */
7005 cm_ReleaseSCache(dscp);
7006 cm_ReleaseSCache(scp);
7007 cm_ReleaseUser(userp);
7008 return CM_ERROR_EXISTS;
7011 setAttr.mask = CM_ATTRMASK_LENGTH;
7012 setAttr.length.LowPart = 0;
7013 setAttr.length.HighPart = 0;
7014 code = cm_SetAttr(scp, &setAttr, userp, &req);
7017 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7018 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7019 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7023 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7024 smb_NotifyChange(FILE_ACTION_ADDED,
7025 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7026 dscp, lastNamep, NULL, TRUE);
7027 } else if (!excl && code == CM_ERROR_EXISTS) {
7028 /* not an exclusive create, and someone else tried
7029 * creating it already, then we open it anyway. We
7030 * don't bother retrying after this, since if this next
7031 * fails, that means that the file was deleted after
7032 * we started this call.
7034 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7037 setAttr.mask = CM_ATTRMASK_LENGTH;
7038 setAttr.length.LowPart = 0;
7039 setAttr.length.HighPart = 0;
7040 code = cm_SetAttr(scp, &setAttr, userp, &req);
7045 /* we don't need this any longer */
7046 cm_ReleaseSCache(dscp);
7049 /* something went wrong creating or truncating the file */
7050 if (scp) cm_ReleaseSCache(scp);
7051 cm_ReleaseUser(userp);
7055 /* make sure we only open files */
7056 if (scp->fileType != CM_SCACHETYPE_FILE) {
7057 cm_ReleaseSCache(scp);
7058 cm_ReleaseUser(userp);
7059 return CM_ERROR_ISDIR;
7062 /* now all we have to do is open the file itself */
7063 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7068 lock_ObtainMutex(&fidp->mx);
7069 /* always create it open for read/write */
7070 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7072 /* remember that the file was newly created */
7074 fidp->flags |= SMB_FID_CREATED;
7076 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7078 /* save a pointer to the vnode */
7080 lock_ObtainMutex(&scp->mx);
7081 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7082 lock_ReleaseMutex(&scp->mx);
7085 fidp->userp = userp;
7086 lock_ReleaseMutex(&fidp->mx);
7088 smb_SetSMBParm(outp, 0, fidp->fid);
7089 smb_SetSMBDataLength(outp, 0);
7091 cm_Open(scp, 0, userp);
7093 smb_ReleaseFID(fidp);
7094 cm_ReleaseUser(userp);
7095 /* leave scp held since we put it in fidp->scp */
7099 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7102 osi_hyper_t new_offset;
7113 fd = smb_GetSMBParm(inp, 0);
7114 whence = smb_GetSMBParm(inp, 1);
7115 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7117 /* try to find the file descriptor */
7118 fd = smb_ChainFID(fd, inp);
7119 fidp = smb_FindFID(vcp, fd, 0);
7122 return CM_ERROR_BADFD;
7124 lock_ObtainMutex(&fidp->mx);
7125 if (fidp->flags & SMB_FID_IOCTL) {
7126 lock_ReleaseMutex(&fidp->mx);
7127 smb_ReleaseFID(fidp);
7128 return CM_ERROR_BADFD;
7130 lock_ReleaseMutex(&fidp->mx);
7132 userp = smb_GetUserFromVCP(vcp, inp);
7134 lock_ObtainMutex(&fidp->mx);
7137 lock_ReleaseMutex(&fidp->mx);
7138 lock_ObtainMutex(&scp->mx);
7139 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7140 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7142 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7144 /* offset from current offset */
7145 new_offset = LargeIntegerAdd(fidp->offset,
7146 ConvertLongToLargeInteger(offset));
7148 else if (whence == 2) {
7149 /* offset from current EOF */
7150 new_offset = LargeIntegerAdd(scp->length,
7151 ConvertLongToLargeInteger(offset));
7153 new_offset = ConvertLongToLargeInteger(offset);
7156 fidp->offset = new_offset;
7157 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7158 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7159 smb_SetSMBDataLength(outp, 0);
7161 lock_ReleaseMutex(&scp->mx);
7162 smb_ReleaseFID(fidp);
7163 cm_ReleaseSCache(scp);
7164 cm_ReleaseUser(userp);
7168 /* dispatch all of the requests received in a packet. Due to chaining, this may
7169 * be more than one request.
7171 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7172 NCB *ncbp, raw_write_cont_t *rwcp)
7176 unsigned long code = 0;
7177 unsigned char *outWctp;
7178 int nparms; /* # of bytes of parameters */
7180 int nbytes; /* bytes of data, excluding count */
7183 unsigned short errCode;
7184 unsigned long NTStatus;
7186 unsigned char errClass;
7187 unsigned int oldGen;
7188 DWORD oldTime, newTime;
7190 /* get easy pointer to the data */
7191 smbp = (smb_t *) inp->data;
7193 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7194 /* setup the basic parms for the initial request in the packet */
7195 inp->inCom = smbp->com;
7196 inp->wctp = &smbp->wct;
7198 inp->ncb_length = ncbp->ncb_length;
7203 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7204 /* log it and discard it */
7205 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7206 __FILE__, __LINE__, ncbp->ncb_length);
7207 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7211 /* We are an ongoing op */
7212 thrd_Increment(&ongoingOps);
7214 /* set up response packet for receiving output */
7215 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7216 smb_FormatResponsePacket(vcp, inp, outp);
7217 outWctp = outp->wctp;
7219 /* Remember session generation number and time */
7220 oldGen = sessionGen;
7221 oldTime = GetTickCount();
7223 while (inp->inCom != 0xff) {
7224 dp = &smb_dispatchTable[inp->inCom];
7226 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7227 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7228 code = outp->resumeCode;
7232 /* process each request in the packet; inCom, wctp and inCount
7233 * are already set up.
7235 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7238 /* now do the dispatch */
7239 /* start by formatting the response record a little, as a default */
7240 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7242 outWctp[1] = 0xff; /* no operation */
7243 outWctp[2] = 0; /* padding */
7248 /* not a chained request, this is a more reasonable default */
7249 outWctp[0] = 0; /* wct of zero */
7250 outWctp[1] = 0; /* and bcc (word) of zero */
7254 /* once set, stays set. Doesn't matter, since we never chain
7255 * "no response" calls.
7257 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7261 /* we have a recognized operation */
7263 if (inp->inCom == 0x1d)
7265 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7267 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7268 code = (*(dp->procp)) (vcp, inp, outp);
7269 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7271 if ( code == CM_ERROR_BADSMB ||
7272 code == CM_ERROR_BADOP )
7274 #endif /* LOG_PACKET */
7277 if (oldGen != sessionGen) {
7278 newTime = GetTickCount();
7279 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7280 newTime - oldTime, ncbp->ncb_length);
7281 osi_Log2(smb_logp, "Pkt straddled session startup, "
7282 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7286 /* bad opcode, fail the request, after displaying it */
7287 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7290 #endif /* LOG_PACKET */
7293 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7294 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7295 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7296 if (code == IDCANCEL)
7299 code = CM_ERROR_BADOP;
7302 /* catastrophic failure: log as much as possible */
7303 if (code == CM_ERROR_BADSMB) {
7304 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7308 #endif /* LOG_PACKET */
7309 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7312 code = CM_ERROR_INVAL;
7315 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7316 thrd_Decrement(&ongoingOps);
7321 /* now, if we failed, turn the current response into an empty
7322 * one, and fill in the response packet's error code.
7325 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7326 smb_MapNTError(code, &NTStatus);
7327 outWctp = outp->wctp;
7328 smbp = (smb_t *) &outp->data;
7329 if (code != CM_ERROR_PARTIALWRITE
7330 && code != CM_ERROR_BUFFERTOOSMALL
7331 && code != CM_ERROR_GSSCONTINUE) {
7332 /* nuke wct and bcc. For a partial
7333 * write or an in-process authentication handshake,
7334 * assume they're OK.
7340 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7341 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7342 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7343 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7344 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7348 smb_MapCoreError(code, vcp, &errCode, &errClass);
7349 outWctp = outp->wctp;
7350 smbp = (smb_t *) &outp->data;
7351 if (code != CM_ERROR_PARTIALWRITE) {
7352 /* nuke wct and bcc. For a partial
7353 * write, assume they're OK.
7359 smbp->errLow = (unsigned char) (errCode & 0xff);
7360 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7361 smbp->rcls = errClass;
7364 } /* error occurred */
7366 /* if we're here, we've finished one request. Look to see if
7367 * this is a chained opcode. If it is, setup things to process
7368 * the chained request, and setup the output buffer to hold the
7369 * chained response. Start by finding the next input record.
7371 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7372 break; /* not a chained req */
7373 tp = inp->wctp; /* points to start of last request */
7374 /* in a chained request, the first two
7375 * parm fields are required, and are
7376 * AndXCommand/AndXReserved and
7378 if (tp[0] < 2) break;
7379 if (tp[1] == 0xff) break; /* no more chained opcodes */
7381 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7384 /* and now append the next output request to the end of this
7385 * last request. Begin by finding out where the last response
7386 * ends, since that's where we'll put our new response.
7388 outWctp = outp->wctp; /* ptr to out parameters */
7389 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7390 nparms = outWctp[0] << 1;
7391 tp = outWctp + nparms + 1; /* now points to bcc field */
7392 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7393 tp += 2 /* for the count itself */ + nbytes;
7394 /* tp now points to the new output record; go back and patch the
7395 * second parameter (off2) to point to the new record.
7397 temp = (unsigned int)(tp - outp->data);
7398 outWctp[3] = (unsigned char) (temp & 0xff);
7399 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7400 outWctp[2] = 0; /* padding */
7401 outWctp[1] = inp->inCom; /* next opcode */
7403 /* finally, setup for the next iteration */
7406 } /* while loop over all requests in the packet */
7408 /* now send the output packet, and return */
7410 smb_SendPacket(vcp, outp);
7411 thrd_Decrement(&ongoingOps);
7416 /* Wait for Netbios() calls to return, and make the results available to server
7417 * threads. Note that server threads can't wait on the NCBevents array
7418 * themselves, because NCB events are manual-reset, and the servers would race
7419 * each other to reset them.
7421 void smb_ClientWaiter(void *parmp)
7426 while (smbShutdownFlag == 0) {
7427 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7429 if (code == WAIT_OBJECT_0)
7432 /* error checking */
7433 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7435 int abandonIdx = code - WAIT_ABANDONED_0;
7436 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7439 if (code == WAIT_IO_COMPLETION)
7441 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7445 if (code == WAIT_TIMEOUT)
7447 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7450 if (code == WAIT_FAILED)
7452 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7455 idx = code - WAIT_OBJECT_0;
7457 /* check idx range! */
7458 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7460 /* this is fatal - log as much as possible */
7461 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7465 thrd_ResetEvent(NCBevents[idx]);
7466 thrd_SetEvent(NCBreturns[0][idx]);
7471 * Try to have one NCBRECV request waiting for every live session. Not more
7472 * than one, because if there is more than one, it's hard to handle Write Raw.
7474 void smb_ServerWaiter(void *parmp)
7477 int idx_session, idx_NCB;
7480 while (smbShutdownFlag == 0) {
7482 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7484 if (code == WAIT_OBJECT_0)
7487 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7489 int abandonIdx = code - WAIT_ABANDONED_0;
7490 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7493 if (code == WAIT_IO_COMPLETION)
7495 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7499 if (code == WAIT_TIMEOUT)
7501 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7504 if (code == WAIT_FAILED)
7506 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7509 idx_session = code - WAIT_OBJECT_0;
7511 /* check idx range! */
7512 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7514 /* this is fatal - log as much as possible */
7515 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7521 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7523 if (code == WAIT_OBJECT_0) {
7524 if (smbShutdownFlag == 1)
7530 /* error checking */
7531 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7533 int abandonIdx = code - WAIT_ABANDONED_0;
7534 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7537 if (code == WAIT_IO_COMPLETION)
7539 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7543 if (code == WAIT_TIMEOUT)
7545 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7548 if (code == WAIT_FAILED)
7550 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7553 idx_NCB = code - WAIT_OBJECT_0;
7555 /* check idx range! */
7556 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7558 /* this is fatal - log as much as possible */
7559 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7563 /* Link them together */
7564 NCBsessions[idx_NCB] = idx_session;
7567 ncbp = NCBs[idx_NCB];
7568 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7569 ncbp->ncb_command = NCBRECV | ASYNCH;
7570 ncbp->ncb_lana_num = lanas[idx_session];
7571 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7572 ncbp->ncb_event = NCBevents[idx_NCB];
7573 ncbp->ncb_length = SMB_PACKETSIZE;
7579 * The top level loop for handling SMB request messages. Each server thread
7580 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7581 * NCB and buffer for the incoming request are loaned to us.
7583 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7584 * to immediately send a request for the rest of the data. This must come
7585 * before any other traffic for that session, so we delay setting the session
7586 * event until that data has come in.
7588 void smb_Server(VOID *parmp)
7590 INT_PTR myIdx = (INT_PTR) parmp;
7594 smb_packet_t *outbufp;
7596 int idx_NCB, idx_session;
7598 smb_vc_t *vcp = NULL;
7601 rx_StartClientThread();
7604 outbufp = GetPacket();
7605 outbufp->ncbp = outncbp;
7613 smb_ResetServerPriority();
7615 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7618 /* terminate silently if shutdown flag is set */
7619 if (code == WAIT_OBJECT_0) {
7620 if (smbShutdownFlag == 1) {
7621 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7627 /* error checking */
7628 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7630 int abandonIdx = code - WAIT_ABANDONED_0;
7631 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7634 if (code == WAIT_IO_COMPLETION)
7636 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7640 if (code == WAIT_TIMEOUT)
7642 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7645 if (code == WAIT_FAILED)
7647 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7650 idx_NCB = code - WAIT_OBJECT_0;
7652 /* check idx range! */
7653 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7655 /* this is fatal - log as much as possible */
7656 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7660 ncbp = NCBs[idx_NCB];
7661 idx_session = NCBsessions[idx_NCB];
7662 rc = ncbp->ncb_retcode;
7664 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7665 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7669 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7673 /* Can this happen? Or is it just my UNIX paranoia? */
7674 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7679 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7682 /* Client closed session */
7683 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7685 lock_ObtainMutex(&vcp->mx);
7686 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7687 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7689 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7690 lock_ReleaseMutex(&vcp->mx);
7691 lock_ObtainWrite(&smb_globalLock);
7692 dead_sessions[vcp->session] = TRUE;
7693 lock_ReleaseWrite(&smb_globalLock);
7694 smb_CleanupDeadVC(vcp);
7698 lock_ReleaseMutex(&vcp->mx);
7704 /* Treat as transient error */
7705 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7708 "dispatch smb recv failed, message incomplete, ncb_length %d",
7711 "SMB message incomplete, "
7712 "length %d", ncbp->ncb_length);
7715 * We used to discard the packet.
7716 * Instead, try handling it normally.
7720 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7724 /* A weird error code. Log it, sleep, and continue. */
7725 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7727 lock_ObtainMutex(&vcp->mx);
7728 if (vcp && vcp->errorCount++ > 3) {
7729 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7730 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7731 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7733 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7734 lock_ReleaseMutex(&vcp->mx);
7735 lock_ObtainWrite(&smb_globalLock);
7736 dead_sessions[vcp->session] = TRUE;
7737 lock_ReleaseWrite(&smb_globalLock);
7738 smb_CleanupDeadVC(vcp);
7742 lock_ReleaseMutex(&vcp->mx);
7748 lock_ReleaseMutex(&vcp->mx);
7750 thrd_SetEvent(SessionEvents[idx_session]);
7755 /* Success, so now dispatch on all the data in the packet */
7757 smb_concurrentCalls++;
7758 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7759 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7762 * If at this point vcp is NULL (implies that packet was invalid)
7763 * then we are in big trouble. This means either :
7764 * a) we have the wrong NCB.
7765 * b) Netbios screwed up the call.
7766 * c) The VC was already marked dead before we were able to
7768 * Obviously this implies that
7769 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7770 * lanas[idx_session] != ncbp->ncb_lana_num )
7771 * Either way, we can't do anything with this packet.
7772 * Log, sleep and resume.
7775 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7779 ncbp->ncb_lana_num);
7781 /* Also log in the trace log. */
7782 osi_Log4(smb_logp, "Server: VCP does not exist!"
7783 "LSNs[idx_session]=[%d],"
7784 "lanas[idx_session]=[%d],"
7785 "ncbp->ncb_lsn=[%d],"
7786 "ncbp->ncb_lana_num=[%d]",
7790 ncbp->ncb_lana_num);
7792 /* thrd_Sleep(1000); Don't bother sleeping */
7793 thrd_SetEvent(SessionEvents[idx_session]);
7794 smb_concurrentCalls--;
7798 smb_SetRequestStartTime();
7800 vcp->errorCount = 0;
7801 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7802 smbp = (smb_t *)bufp->data;
7807 if (smbp->com == 0x1d) {
7808 /* Special handling for Write Raw */
7809 raw_write_cont_t rwc;
7810 EVENT_HANDLE rwevent;
7811 char eventName[MAX_PATH];
7813 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7814 if (rwc.code == 0) {
7815 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7816 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7817 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7818 ncbp->ncb_command = NCBRECV | ASYNCH;
7819 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7820 ncbp->ncb_lana_num = vcp->lana;
7821 ncbp->ncb_buffer = rwc.buf;
7822 ncbp->ncb_length = 65535;
7823 ncbp->ncb_event = rwevent;
7825 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7826 thrd_CloseHandle(rwevent);
7828 thrd_SetEvent(SessionEvents[idx_session]);
7830 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7832 else if (smbp->com == 0xa0) {
7834 * Serialize the handling for NT Transact
7837 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7838 thrd_SetEvent(SessionEvents[idx_session]);
7840 thrd_SetEvent(SessionEvents[idx_session]);
7841 /* TODO: what else needs to be serialized? */
7842 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7845 __except( smb_ServerExceptionFilter() ) {
7848 smb_concurrentCalls--;
7851 thrd_SetEvent(NCBavails[idx_NCB]);
7858 * Exception filter for the server threads. If an exception occurs in the
7859 * dispatch routines, which is where exceptions are most common, then do a
7860 * force trace and give control to upstream exception handlers. Useful for
7863 DWORD smb_ServerExceptionFilter(void) {
7864 /* While this is not the best time to do a trace, if it succeeds, then
7865 * we have a trace (assuming tracing was enabled). Otherwise, this should
7866 * throw a second exception.
7868 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7869 afsd_ForceTrace(TRUE);
7870 buf_ForceTrace(TRUE);
7871 return EXCEPTION_CONTINUE_SEARCH;
7875 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7876 * If the number of server threads is M, and the number of live sessions is
7877 * N, then the number of NCB's in use at any time either waiting for, or
7878 * holding, received messages is M + N, so that is how many NCB's get created.
7880 void InitNCBslot(int idx)
7882 struct smb_packet *bufp;
7883 EVENT_HANDLE retHandle;
7885 char eventName[MAX_PATH];
7887 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7889 NCBs[idx] = GetNCB();
7890 sprintf(eventName,"NCBavails[%d]", idx);
7891 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7892 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7893 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7894 sprintf(eventName,"NCBevents[%d]", idx);
7895 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7896 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7897 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7898 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7899 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7900 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7901 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7902 for (i=0; i<smb_NumServerThreads; i++)
7903 NCBreturns[i][idx] = retHandle;
7905 bufp->spacep = cm_GetSpace();
7909 /* listen for new connections */
7910 void smb_Listener(void *parmp)
7916 int session, thread;
7917 smb_vc_t *vcp = NULL;
7919 char rname[NCBNAMSZ+1];
7920 char cname[MAX_COMPUTERNAME_LENGTH+1];
7921 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7922 INT_PTR lana = (INT_PTR) parmp;
7926 /* retrieve computer name */
7927 GetComputerName(cname, &cnamelen);
7930 while (smb_ListenerState == SMB_LISTENER_STARTED) {
7931 memset(ncbp, 0, sizeof(NCB));
7934 ncbp->ncb_command = NCBLISTEN;
7935 ncbp->ncb_rto = 0; /* No receive timeout */
7936 ncbp->ncb_sto = 0; /* No send timeout */
7938 /* pad out with spaces instead of null termination */
7939 len = (long)strlen(smb_localNamep);
7940 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7941 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7943 strcpy(ncbp->ncb_callname, "*");
7944 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7946 ncbp->ncb_lana_num = (UCHAR)lana;
7948 code = Netbios(ncbp);
7950 if (code == NRC_BRIDGE) {
7951 int lanaRemaining = 0;
7953 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
7958 "NCBLISTEN lana=%d failed with NRC_BRIDGE. Listener thread exiting.",
7959 ncbp->ncb_lana_num, code);
7961 for (i = 0; i < lana_list.length; i++) {
7962 if (lana_list.lana[i] == ncbp->ncb_lana_num) {
7963 smb_StopListener(ncbp, lana_list.lana[i]);
7964 lana_list.lana[i] = 255;
7966 if (lana_list.lana[i] != 255)
7970 if (lanaRemaining == 0) {
7971 smb_ListenerState = SMB_LISTENER_STOPPED;
7972 smb_LANadapter = -1;
7973 lana_list.length = 0;
7977 } else if (code != 0) {
7980 /* terminate silently if shutdown flag is set */
7981 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
7986 "NCBLISTEN lana=%d failed with code %d",
7987 ncbp->ncb_lana_num, code);
7989 "Client exiting due to network failure. Please restart client.\n");
7992 "Client exiting due to network failure. Please restart client.\n"
7993 "NCBLISTEN lana=%d failed with code %d",
7994 ncbp->ncb_lana_num, code);
7996 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7997 MB_OK|MB_SERVICE_NOTIFICATION);
7998 osi_panic(tbuffer, __FILE__, __LINE__);
8001 /* check for remote conns */
8002 /* first get remote name and insert null terminator */
8003 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8004 for (i=NCBNAMSZ; i>0; i--) {
8005 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8011 /* compare with local name */
8013 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8014 flags |= SMB_VCFLAG_REMOTECONN;
8017 lock_ObtainMutex(&smb_ListenerLock);
8019 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8020 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8022 /* now ncbp->ncb_lsn is the connection ID */
8023 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8024 if (vcp->session == 0) {
8025 /* New generation */
8026 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8029 /* Log session startup */
8031 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8032 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8033 #endif /* NOTSERVICE */
8034 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8035 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8037 if (reportSessionStartups) {
8038 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8041 lock_ObtainMutex(&vcp->mx);
8042 strcpy(vcp->rname, rname);
8043 vcp->flags |= flags;
8044 lock_ReleaseMutex(&vcp->mx);
8046 /* Allocate slot in session arrays */
8047 /* Re-use dead session if possible, otherwise add one more */
8048 /* But don't look at session[0], it is reserved */
8049 lock_ObtainWrite(&smb_globalLock);
8050 for (session = 1; session < numSessions; session++) {
8051 if (dead_sessions[session]) {
8052 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8053 dead_sessions[session] = FALSE;
8057 lock_ReleaseWrite(&smb_globalLock);
8059 /* We are re-using an existing VC because the lsn and lana
8061 session = vcp->session;
8063 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8065 /* Log session startup */
8067 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8068 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8069 #endif /* NOTSERVICE */
8070 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8071 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8073 if (reportSessionStartups) {
8074 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8078 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8079 unsigned long code = CM_ERROR_ALLBUSY;
8080 smb_packet_t * outp = GetPacket();
8081 unsigned char *outWctp;
8084 smb_FormatResponsePacket(vcp, NULL, outp);
8087 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8088 unsigned long NTStatus;
8089 smb_MapNTError(code, &NTStatus);
8090 outWctp = outp->wctp;
8091 smbp = (smb_t *) &outp->data;
8095 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8096 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8097 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8098 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8099 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8101 unsigned short errCode;
8102 unsigned char errClass;
8103 smb_MapCoreError(code, vcp, &errCode, &errClass);
8104 outWctp = outp->wctp;
8105 smbp = (smb_t *) &outp->data;
8109 smbp->errLow = (unsigned char) (errCode & 0xff);
8110 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8111 smbp->rcls = errClass;
8113 smb_SendPacket(vcp, outp);
8114 smb_FreePacket(outp);
8116 lock_ObtainMutex(&vcp->mx);
8117 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8118 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8120 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8121 lock_ReleaseMutex(&vcp->mx);
8122 lock_ObtainWrite(&smb_globalLock);
8123 dead_sessions[vcp->session] = TRUE;
8124 lock_ReleaseWrite(&smb_globalLock);
8125 smb_CleanupDeadVC(vcp);
8127 lock_ReleaseMutex(&vcp->mx);
8130 /* assert that we do not exceed the maximum number of sessions or NCBs.
8131 * we should probably want to wait for a session to be freed in case
8134 osi_assert(session < SESSION_MAX - 1);
8135 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8137 lock_ObtainMutex(&vcp->mx);
8138 vcp->session = session;
8139 lock_ReleaseMutex(&vcp->mx);
8140 lock_ObtainWrite(&smb_globalLock);
8141 LSNs[session] = ncbp->ncb_lsn;
8142 lanas[session] = ncbp->ncb_lana_num;
8143 lock_ReleaseWrite(&smb_globalLock);
8145 if (session == numSessions) {
8146 /* Add new NCB for new session */
8147 char eventName[MAX_PATH];
8149 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8151 InitNCBslot(numNCBs);
8152 lock_ObtainWrite(&smb_globalLock);
8154 lock_ReleaseWrite(&smb_globalLock);
8155 thrd_SetEvent(NCBavails[0]);
8156 thrd_SetEvent(NCBevents[0]);
8157 for (thread = 0; thread < smb_NumServerThreads; thread++)
8158 thrd_SetEvent(NCBreturns[thread][0]);
8159 /* Also add new session event */
8160 sprintf(eventName, "SessionEvents[%d]", session);
8161 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8162 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8163 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8164 lock_ObtainWrite(&smb_globalLock);
8166 lock_ReleaseWrite(&smb_globalLock);
8167 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8168 thrd_SetEvent(SessionEvents[0]);
8170 thrd_SetEvent(SessionEvents[session]);
8176 lock_ReleaseMutex(&smb_ListenerLock);
8177 } /* dispatch while loop */
8182 /* initialize Netbios */
8183 int smb_NetbiosInit(void)
8186 int i, lana, code, l;
8188 int delname_tried=0;
8191 lana_number_t lanaNum;
8193 /* setup the NCB system */
8196 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8197 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8198 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8200 if (smb_LANadapter != -1)
8201 afsi_log("LAN adapter number %d", smb_LANadapter);
8203 afsi_log("LAN adapter number not determined");
8206 afsi_log("Set for gateway service");
8208 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8210 /* something went horribly wrong. We can't proceed without a netbios name */
8212 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8213 osi_panic(buf, __FILE__, __LINE__);
8216 /* remember the name */
8217 len = (int)strlen(cm_NetbiosName);
8219 free(smb_localNamep);
8220 smb_localNamep = malloc(len+1);
8221 strcpy(smb_localNamep, cm_NetbiosName);
8222 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8225 if (smb_LANadapter == -1) {
8226 ncbp->ncb_command = NCBENUM;
8227 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8228 ncbp->ncb_length = sizeof(lana_list);
8229 code = Netbios(ncbp);
8231 afsi_log("Netbios NCBENUM error code %d", code);
8232 osi_panic(s, __FILE__, __LINE__);
8236 lana_list.length = 1;
8237 lana_list.lana[0] = smb_LANadapter;
8240 for (i = 0; i < lana_list.length; i++) {
8241 /* reset the adaptor: in Win32, this is required for every process, and
8242 * acts as an init call, not as a real hardware reset.
8244 ncbp->ncb_command = NCBRESET;
8245 ncbp->ncb_callname[0] = 100;
8246 ncbp->ncb_callname[2] = 100;
8247 ncbp->ncb_lana_num = lana_list.lana[i];
8248 code = Netbios(ncbp);
8250 code = ncbp->ncb_retcode;
8252 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8253 lana_list.lana[i] = 255; /* invalid lana */
8255 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8259 /* and declare our name so we can receive connections */
8260 memset(ncbp, 0, sizeof(*ncbp));
8261 len=lstrlen(smb_localNamep);
8262 memset(smb_sharename,' ',NCBNAMSZ);
8263 memcpy(smb_sharename,smb_localNamep,len);
8264 afsi_log("lana_list.length %d", lana_list.length);
8266 /* Keep the name so we can unregister it later */
8267 for (l = 0; l < lana_list.length; l++) {
8268 lana = lana_list.lana[l];
8270 ncbp->ncb_command = NCBADDNAME;
8271 ncbp->ncb_lana_num = lana;
8272 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8273 code = Netbios(ncbp);
8275 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8276 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8278 char name[NCBNAMSZ+1];
8280 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8281 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8285 code = ncbp->ncb_retcode;
8288 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8291 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8292 if (code == NRC_BRIDGE) { /* invalid LANA num */
8293 lana_list.lana[l] = 255;
8296 else if (code == NRC_DUPNAME) {
8297 afsi_log("Name already exists; try to delete it");
8298 memset(ncbp, 0, sizeof(*ncbp));
8299 ncbp->ncb_command = NCBDELNAME;
8300 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8301 ncbp->ncb_lana_num = lana;
8302 code = Netbios(ncbp);
8304 code = ncbp->ncb_retcode;
8306 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8308 if (code != 0 || delname_tried) {
8309 lana_list.lana[l] = 255;
8311 else if (code == 0) {
8312 if (!delname_tried) {
8320 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8321 lana_list.lana[l] = 255; /* invalid lana */
8325 lana_found = 1; /* at least one worked */
8329 osi_assert(lana_list.length >= 0);
8331 afsi_log("No valid LANA numbers found!");
8332 lana_list.length = 0;
8333 smb_LANadapter = -1;
8334 smb_ListenerState = SMB_LISTENER_STOPPED;
8337 /* we're done with the NCB now */
8340 return (lana_list.length > 0 ? 1 : 0);
8343 void smb_StartListeners()
8349 if (smb_ListenerState == SMB_LISTENER_STARTED)
8352 smb_ListenerState = SMB_LISTENER_STARTED;
8354 for (i = 0; i < lana_list.length; i++) {
8355 if (lana_list.lana[i] == 255)
8357 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8358 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8359 osi_assert(phandle != NULL);
8360 thrd_CloseHandle(phandle);
8364 void smb_RestartListeners()
8366 if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
8367 if (smb_NetbiosInit())
8368 smb_StartListeners();
8372 void smb_StopListener(NCB *ncbp, int lana)
8376 memset(ncbp, 0, sizeof(*ncbp));
8377 ncbp->ncb_command = NCBDELNAME;
8378 ncbp->ncb_lana_num = lana;
8379 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8380 code = Netbios(ncbp);
8382 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8383 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8385 /* and then reset the LANA; this will cause the listener threads to exit */
8386 ncbp->ncb_command = NCBRESET;
8387 ncbp->ncb_callname[0] = 100;
8388 ncbp->ncb_callname[2] = 100;
8389 ncbp->ncb_lana_num = lana;
8390 code = Netbios(ncbp);
8392 code = ncbp->ncb_retcode;
8394 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8396 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8400 void smb_StopListeners(void)
8405 if (smb_ListenerState == SMB_LISTENER_STOPPED)
8408 smb_ListenerState = SMB_LISTENER_STOPPED;
8412 /* Unregister the SMB name */
8413 for (l = 0; l < lana_list.length; l++) {
8414 lana = lana_list.lana[l];
8417 smb_StopListener(ncbp, lana);
8419 /* mark the adapter invalid */
8420 lana_list.lana[l] = 255; /* invalid lana */
8424 /* force a re-evaluation of the network adapters */
8425 lana_list.length = 0;
8426 smb_LANadapter = -1;
8428 Sleep(1000); /* give the listener threads a chance to exit */
8431 void smb_Init(osi_log_t *logp, int useV3,
8441 EVENT_HANDLE retHandle;
8442 char eventName[MAX_PATH];
8444 smb_TlsRequestSlot = TlsAlloc();
8446 smb_MBfunc = aMBfunc;
8450 /* Initialize smb_localZero */
8451 myTime.tm_isdst = -1; /* compute whether on DST or not */
8452 myTime.tm_year = 70;
8458 smb_localZero = mktime(&myTime);
8460 #ifndef USE_NUMERIC_TIME_CONV
8461 /* Initialize kludge-GMT */
8462 smb_CalculateNowTZ();
8463 #endif /* USE_NUMERIC_TIME_CONV */
8464 #ifdef AFS_FREELANCE_CLIENT
8465 /* Make sure the root.afs volume has the correct time */
8466 cm_noteLocalMountPointChange();
8469 /* initialize the remote debugging log */
8472 /* and the global lock */
8473 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8474 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8476 /* Raw I/O data structures */
8477 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8479 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8481 /* 4 Raw I/O buffers */
8482 smb_RawBufs = calloc(65536,1);
8483 *((char **)smb_RawBufs) = NULL;
8484 for (i=0; i<3; i++) {
8485 char *rawBuf = calloc(65536,1);
8486 *((char **)rawBuf) = smb_RawBufs;
8487 smb_RawBufs = rawBuf;
8490 /* global free lists */
8491 smb_ncbFreeListp = NULL;
8492 smb_packetFreeListp = NULL;
8496 /* Initialize listener and server structures */
8498 memset(dead_sessions, 0, sizeof(dead_sessions));
8499 sprintf(eventName, "SessionEvents[0]");
8500 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8501 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8502 afsi_log("Event Object Already Exists: %s", eventName);
8504 smb_NumServerThreads = nThreads;
8505 sprintf(eventName, "NCBavails[0]");
8506 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8507 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8508 afsi_log("Event Object Already Exists: %s", eventName);
8509 sprintf(eventName, "NCBevents[0]");
8510 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8511 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8512 afsi_log("Event Object Already Exists: %s", eventName);
8513 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8514 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8515 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8516 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8517 afsi_log("Event Object Already Exists: %s", eventName);
8518 for (i = 0; i < smb_NumServerThreads; i++) {
8519 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8520 NCBreturns[i][0] = retHandle;
8523 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8524 for (i = 0; i < smb_NumServerThreads; i++) {
8525 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8526 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8527 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8528 afsi_log("Event Object Already Exists: %s", eventName);
8529 InitNCBslot((int)(i+1));
8531 numNCBs = smb_NumServerThreads + 1;
8533 /* Initialize dispatch table */
8534 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8535 /* Prepare the table for unknown operations */
8536 for(i=0; i<= SMB_NOPCODES; i++) {
8537 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8539 /* Fill in the ones we do know */
8540 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8541 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8542 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8543 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8544 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8545 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8546 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8547 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8548 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8549 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8550 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8551 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8552 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8553 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8554 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8555 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8556 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8557 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8558 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8559 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8560 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8561 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8562 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8563 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8564 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8565 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8566 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8567 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8568 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8569 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8570 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8571 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8572 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8573 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8574 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8575 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8576 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8577 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8578 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8579 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8580 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8581 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8582 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8583 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8584 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8585 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8586 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8587 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8588 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8589 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8590 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8591 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8592 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8593 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8594 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8595 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8596 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8597 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8598 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8599 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8600 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8601 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8602 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8603 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8604 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8605 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8606 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8607 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8608 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8609 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8610 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8611 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8612 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8613 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8615 /* setup tran 2 dispatch table */
8616 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8617 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8618 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8619 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8620 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8621 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8622 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8623 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8624 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8625 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8626 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8627 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8628 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8629 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8630 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8631 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8632 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8633 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8635 /* setup the rap dispatch table */
8636 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8637 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8638 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8639 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8640 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8644 /* if we are doing SMB authentication we have register outselves as a logon process */
8645 if (smb_authType != SMB_AUTH_NONE) {
8646 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8647 LSA_STRING afsProcessName;
8648 LSA_OPERATIONAL_MODE dummy; /*junk*/
8650 afsProcessName.Buffer = "OpenAFSClientDaemon";
8651 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8652 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8654 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8656 if (nts == STATUS_SUCCESS) {
8657 LSA_STRING packageName;
8658 /* we are registered. Find out the security package id */
8659 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8660 packageName.Length = (USHORT)strlen(packageName.Buffer);
8661 packageName.MaximumLength = packageName.Length + 1;
8662 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8663 if (nts == STATUS_SUCCESS) {
8665 * This code forces Windows to authenticate against the Logon Cache
8666 * first instead of attempting to authenticate against the Domain
8667 * Controller. When the Windows logon cache is enabled this improves
8668 * performance by removing the network access and works around a bug
8669 * seen at sites which are using a MIT Kerberos principal to login
8670 * to machines joined to a non-root domain in a multi-domain forest.
8671 * MsV1_0SetProcessOption was added in Windows XP.
8673 PVOID pResponse = NULL;
8674 ULONG cbResponse = 0;
8675 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8677 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8678 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8679 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8680 OptionsRequest.DisableOptions = FALSE;
8682 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8685 sizeof(OptionsRequest),
8691 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8693 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8695 OutputDebugString(message);
8698 OutputDebugString("MsV1_0SetProcessOption success");
8699 afsi_log("MsV1_0SetProcessOption success");
8701 /* END - code from Larry */
8703 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8704 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8705 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8707 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8709 /* something went wrong. We report the error and revert back to no authentication
8710 because we can't perform any auth requests without a successful lsa handle
8711 or sec package id. */
8712 afsi_log("Reverting to NO SMB AUTH");
8713 smb_authType = SMB_AUTH_NONE;
8716 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8718 /* something went wrong. We report the error and revert back to no authentication
8719 because we can't perform any auth requests without a successful lsa handle
8720 or sec package id. */
8721 afsi_log("Reverting to NO SMB AUTH");
8722 smb_authType = SMB_AUTH_NONE;
8726 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8727 * time prevents the failure of authentication when logged into Windows with an
8728 * external Kerberos principal mapped to a local account.
8730 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8731 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8732 * then the only option is NTLMSSP anyway; so just fallback.
8737 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8738 if (secBlobLength == 0) {
8739 smb_authType = SMB_AUTH_NTLM;
8740 afsi_log("Reverting to SMB AUTH NTLM");
8749 /* Now get ourselves a domain name. */
8750 /* For now we are using the local computer name as the domain name.
8751 * It is actually the domain for local logins, and we are acting as
8752 * a local SMB server.
8754 bufsize = sizeof(smb_ServerDomainName) - 1;
8755 GetComputerName(smb_ServerDomainName, &bufsize);
8756 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8757 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8760 /* Start listeners, waiters, servers, and daemons */
8762 smb_StartListeners();
8764 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8765 NULL, 0, &lpid, "smb_ClientWaiter");
8766 osi_assert(phandle != NULL);
8767 thrd_CloseHandle(phandle);
8769 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8770 NULL, 0, &lpid, "smb_ServerWaiter");
8771 osi_assert(phandle != NULL);
8772 thrd_CloseHandle(phandle);
8774 for (i=0; i<smb_NumServerThreads; i++) {
8775 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8776 (void *) i, 0, &lpid, "smb_Server");
8777 osi_assert(phandle != NULL);
8778 thrd_CloseHandle(phandle);
8781 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8782 NULL, 0, &lpid, "smb_Daemon");
8783 osi_assert(phandle != NULL);
8784 thrd_CloseHandle(phandle);
8786 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8787 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8788 osi_assert(phandle != NULL);
8789 thrd_CloseHandle(phandle);
8794 void smb_Shutdown(void)
8801 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8803 /* setup the NCB system */
8806 /* Block new sessions by setting shutdown flag */
8807 smbShutdownFlag = 1;
8809 /* Hang up all sessions */
8810 memset((char *)ncbp, 0, sizeof(NCB));
8811 for (i = 1; i < numSessions; i++)
8813 if (dead_sessions[i])
8816 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8817 ncbp->ncb_command = NCBHANGUP;
8818 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8819 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8820 code = Netbios(ncbp);
8821 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8822 if (code == 0) code = ncbp->ncb_retcode;
8824 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8825 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8829 /* Trigger the shutdown of all SMB threads */
8830 for (i = 0; i < smb_NumServerThreads; i++)
8831 thrd_SetEvent(NCBreturns[i][0]);
8833 thrd_SetEvent(NCBevents[0]);
8834 thrd_SetEvent(SessionEvents[0]);
8835 thrd_SetEvent(NCBavails[0]);
8837 for (i = 0;i < smb_NumServerThreads; i++) {
8838 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8839 if (code == WAIT_OBJECT_0) {
8842 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8843 thrd_SetEvent(NCBreturns[i--][0]);
8847 /* Delete Netbios name */
8848 memset((char *)ncbp, 0, sizeof(NCB));
8849 for (i = 0; i < lana_list.length; i++) {
8850 if (lana_list.lana[i] == 255) continue;
8851 ncbp->ncb_command = NCBDELNAME;
8852 ncbp->ncb_lana_num = lana_list.lana[i];
8853 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8854 code = Netbios(ncbp);
8856 code = ncbp->ncb_retcode;
8858 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8859 ncbp->ncb_lana_num, code);
8864 /* Release the reference counts held by the VCs */
8865 lock_ObtainWrite(&smb_rctLock);
8866 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8871 if (vcp->magic != SMB_VC_MAGIC)
8872 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8873 __FILE__, __LINE__);
8875 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8877 if (fidp->scp != NULL) {
8880 lock_ObtainMutex(&fidp->mx);
8881 if (fidp->scp != NULL) {
8884 lock_ObtainMutex(&scp->mx);
8885 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
8886 lock_ReleaseMutex(&scp->mx);
8887 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
8888 cm_ReleaseSCache(scp);
8890 lock_ReleaseMutex(&fidp->mx);
8894 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8896 smb_ReleaseVCNoLock(tidp->vcp);
8898 cm_user_t *userp = tidp->userp;
8900 lock_ReleaseWrite(&smb_rctLock);
8901 cm_ReleaseUser(userp);
8902 lock_ObtainWrite(&smb_rctLock);
8906 lock_ReleaseWrite(&smb_rctLock);
8908 TlsFree(smb_TlsRequestSlot);
8911 /* Get the UNC \\<servername>\<sharename> prefix. */
8912 char *smb_GetSharename()
8916 /* Make sure we have been properly initialized. */
8917 if (smb_localNamep == NULL)
8920 /* Allocate space for \\<servername>\<sharename>, plus the
8923 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8924 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8930 void smb_LogPacket(smb_packet_t *packet)
8933 unsigned length, paramlen, datalen, i, j;
8935 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8937 if (!packet) return;
8939 osi_Log0(smb_logp, "*** SMB packet dump ***");
8941 vp = (BYTE *) packet->data;
8943 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8944 length = paramlen + 2 + datalen;
8947 for (i=0;i < length; i+=16)
8949 memset( buf, ' ', 80 );
8954 buf[strlen(buf)] = ' ';
8956 cp = (BYTE*) buf + 7;
8958 for (j=0;j < 16 && (i+j)<length; j++)
8960 *(cp++) = hex[vp[i+j] >> 4];
8961 *(cp++) = hex[vp[i+j] & 0xf];
8971 for (j=0;j < 16 && (i+j)<length;j++)
8973 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8984 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
8987 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8989 #endif /* LOG_PACKET */
8992 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9000 lock_ObtainRead(&smb_rctLock);
9002 sprintf(output, "begin dumping smb_vc_t\r\n");
9003 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9005 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9009 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9010 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9011 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9013 sprintf(output, "begin dumping smb_fid_t\r\n");
9014 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9016 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9018 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n",
9019 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9020 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9021 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9022 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9025 sprintf(output, "done dumping smb_fid_t\r\n");
9026 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9029 sprintf(output, "done dumping smb_vc_t\r\n");
9030 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9032 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9033 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9035 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9039 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9040 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9041 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9043 sprintf(output, "begin dumping smb_fid_t\r\n");
9044 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9046 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9048 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n",
9049 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9050 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9051 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9052 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9055 sprintf(output, "done dumping smb_fid_t\r\n");
9056 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9059 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9060 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9063 lock_ReleaseRead(&smb_rctLock);