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) + 1;
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 * 1000) {
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_MOUNTPOINT ||
4241 fileType == CM_SCACHETYPE_DFSLINK ||
4242 fileType == CM_SCACHETYPE_INVALID)
4243 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4248 memcpy(op, mask, 11); op += 11;
4249 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4250 *op++ = (char)(nextEntryCookie & 0xff);
4251 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4252 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4253 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4254 memcpy(op, &clientCookie, 4); op += 4;
4256 /* now we emit the attribute. This is sort of tricky,
4257 * since we need to really stat the file to find out
4258 * what type of entry we've got. Right now, we're
4259 * copying out data from a buffer, while holding the
4260 * scp locked, so it isn't really convenient to stat
4261 * something now. We'll put in a place holder now,
4262 * and make a second pass before returning this to get
4263 * the real attributes. So, we just skip the data for
4264 * now, and adjust it later. We allocate a patch
4265 * record to make it easy to find this point later.
4266 * The replay will happen at a time when it is safe to
4267 * unlock the directory.
4269 curPatchp = malloc(sizeof(*curPatchp));
4270 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4271 curPatchp->dptr = op;
4272 curPatchp->fid.cell = scp->fid.cell;
4273 curPatchp->fid.volume = scp->fid.volume;
4274 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4275 curPatchp->fid.unique = ntohl(dep->fid.unique);
4277 /* do hidden attribute here since name won't be around when applying
4281 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4282 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4284 curPatchp->flags = 0;
4286 op += 9; /* skip attr, time, date and size */
4288 /* zero out name area. The spec says to pad with
4289 * spaces, but Samba doesn't, and neither do we.
4293 /* finally, we get to copy out the name; we know that
4294 * it fits in 8.3 or the pattern wouldn't match, but it
4295 * never hurts to be sure.
4297 strncpy(op, actualName, 13);
4298 if (smb_StoreAnsiFilenames)
4301 /* Uppercase if requested by client */
4302 if (!KNOWS_LONG_NAMES(inp))
4307 /* now, adjust the # of entries copied */
4309 } /* if we're including this name */
4312 /* and adjust curOffset to be where the new cookie is */
4313 thyper.HighPart = 0;
4314 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4315 curOffset = LargeIntegerAdd(thyper, curOffset);
4316 } /* while copying data for dir listing */
4318 /* release the mutex */
4319 lock_ReleaseMutex(&scp->mx);
4321 buf_Release(bufferp);
4325 /* apply and free last set of patches; if not doing a star match, this
4326 * will be empty, but better safe (and freeing everything) than sorry.
4328 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4330 /* special return code for unsuccessful search */
4331 if (code == 0 && dataLength < 21 && returnedNames == 0)
4332 code = CM_ERROR_NOFILES;
4334 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4335 returnedNames, code);
4338 smb_DeleteDirSearch(dsp);
4339 smb_ReleaseDirSearch(dsp);
4340 cm_ReleaseSCache(scp);
4341 cm_ReleaseUser(userp);
4345 /* finalize the output buffer */
4346 smb_SetSMBParm(outp, 0, returnedNames);
4347 temp = (long) (op - origOp);
4348 smb_SetSMBDataLength(outp, temp);
4350 /* the data area is a variable block, which has a 5 (already there)
4351 * followed by the length of the # of data bytes. We now know this to
4352 * be "temp," although that includes the 3 bytes of vbl block header.
4353 * Deduct for them and fill in the length field.
4355 temp -= 3; /* deduct vbl block info */
4356 osi_assert(temp == (43 * returnedNames));
4357 origOp[1] = (char)(temp & 0xff);
4358 origOp[2] = (char)((temp>>8) & 0xff);
4359 if (returnedNames == 0)
4360 smb_DeleteDirSearch(dsp);
4361 smb_ReleaseDirSearch(dsp);
4362 cm_ReleaseSCache(scp);
4363 cm_ReleaseUser(userp);
4367 /* verify that this is a valid path to a directory. I don't know why they
4368 * don't use the get file attributes call.
4370 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4374 cm_scache_t *rootScp;
4375 cm_scache_t *newScp;
4384 pathp = smb_GetSMBData(inp, NULL);
4385 pathp = smb_ParseASCIIBlock(pathp, NULL);
4387 return CM_ERROR_BADFD;
4388 if (smb_StoreAnsiFilenames)
4389 OemToChar(pathp,pathp);
4390 osi_Log1(smb_logp, "SMB receive check path %s",
4391 osi_LogSaveString(smb_logp, pathp));
4393 rootScp = cm_data.rootSCachep;
4395 userp = smb_GetUserFromVCP(vcp, inp);
4397 caseFold = CM_FLAG_CASEFOLD;
4399 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4401 cm_ReleaseUser(userp);
4402 return CM_ERROR_NOSUCHPATH;
4404 code = cm_NameI(rootScp, pathp,
4405 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4406 userp, tidPathp, &req, &newScp);
4409 cm_ReleaseUser(userp);
4414 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4415 cm_ReleaseSCache(newScp);
4416 cm_ReleaseUser(userp);
4417 if ( WANTS_DFS_PATHNAMES(inp) )
4418 return CM_ERROR_PATH_NOT_COVERED;
4420 return CM_ERROR_BADSHARENAME;
4422 #endif /* DFS_SUPPORT */
4424 /* now lock the vnode with a callback; returns with newScp locked */
4425 lock_ObtainMutex(&newScp->mx);
4426 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4427 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4429 if (code != CM_ERROR_NOACCESS) {
4430 lock_ReleaseMutex(&newScp->mx);
4431 cm_ReleaseSCache(newScp);
4432 cm_ReleaseUser(userp);
4436 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4439 attrs = smb_Attributes(newScp);
4441 if (!(attrs & SMB_ATTR_DIRECTORY))
4442 code = CM_ERROR_NOTDIR;
4444 lock_ReleaseMutex(&newScp->mx);
4446 cm_ReleaseSCache(newScp);
4447 cm_ReleaseUser(userp);
4451 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4455 cm_scache_t *rootScp;
4456 unsigned short attribute;
4458 cm_scache_t *newScp;
4467 /* decode basic attributes we're passed */
4468 attribute = smb_GetSMBParm(inp, 0);
4469 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4471 pathp = smb_GetSMBData(inp, NULL);
4472 pathp = smb_ParseASCIIBlock(pathp, NULL);
4474 return CM_ERROR_BADSMB;
4475 if (smb_StoreAnsiFilenames)
4476 OemToChar(pathp,pathp);
4478 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4479 dosTime, attribute);
4481 rootScp = cm_data.rootSCachep;
4483 userp = smb_GetUserFromVCP(vcp, inp);
4485 caseFold = CM_FLAG_CASEFOLD;
4487 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4489 cm_ReleaseUser(userp);
4490 return CM_ERROR_NOSUCHFILE;
4492 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4493 tidPathp, &req, &newScp);
4496 cm_ReleaseUser(userp);
4501 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4502 cm_ReleaseSCache(newScp);
4503 cm_ReleaseUser(userp);
4504 if ( WANTS_DFS_PATHNAMES(inp) )
4505 return CM_ERROR_PATH_NOT_COVERED;
4507 return CM_ERROR_BADSHARENAME;
4509 #endif /* DFS_SUPPORT */
4511 /* now lock the vnode with a callback; returns with newScp locked; we
4512 * need the current status to determine what the new status is, in some
4515 lock_ObtainMutex(&newScp->mx);
4516 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4517 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4519 lock_ReleaseMutex(&newScp->mx);
4520 cm_ReleaseSCache(newScp);
4521 cm_ReleaseUser(userp);
4525 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4527 /* Check for RO volume */
4528 if (newScp->flags & CM_SCACHEFLAG_RO) {
4529 lock_ReleaseMutex(&newScp->mx);
4530 cm_ReleaseSCache(newScp);
4531 cm_ReleaseUser(userp);
4532 return CM_ERROR_READONLY;
4535 /* prepare for setattr call */
4538 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4539 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4541 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4542 /* we're told to make a writable file read-only */
4543 attr.unixModeBits = newScp->unixModeBits & ~0222;
4544 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4546 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4547 /* we're told to make a read-only file writable */
4548 attr.unixModeBits = newScp->unixModeBits | 0222;
4549 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4551 lock_ReleaseMutex(&newScp->mx);
4553 /* now call setattr */
4555 code = cm_SetAttr(newScp, &attr, userp, &req);
4559 cm_ReleaseSCache(newScp);
4560 cm_ReleaseUser(userp);
4565 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4569 cm_scache_t *rootScp;
4570 cm_scache_t *newScp, *dscp;
4582 pathp = smb_GetSMBData(inp, NULL);
4583 pathp = smb_ParseASCIIBlock(pathp, NULL);
4585 return CM_ERROR_BADSMB;
4587 if (*pathp == 0) /* null path */
4590 if (smb_StoreAnsiFilenames)
4591 OemToChar(pathp,pathp);
4593 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4594 osi_LogSaveString(smb_logp, pathp));
4596 rootScp = cm_data.rootSCachep;
4598 userp = smb_GetUserFromVCP(vcp, inp);
4600 /* we shouldn't need this for V3 requests, but we seem to */
4601 caseFold = CM_FLAG_CASEFOLD;
4603 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4605 cm_ReleaseUser(userp);
4606 return CM_ERROR_NOSUCHFILE;
4610 * XXX Strange hack XXX
4612 * As of Patch 5 (16 July 97), we are having the following problem:
4613 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4614 * requests to look up "desktop.ini" in all the subdirectories.
4615 * This can cause zillions of timeouts looking up non-existent cells
4616 * and volumes, especially in the top-level directory.
4618 * We have not found any way to avoid this or work around it except
4619 * to explicitly ignore the requests for mount points that haven't
4620 * yet been evaluated and for directories that haven't yet been
4623 * We should modify this hack to provide a fake desktop.ini file
4624 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4626 spacep = inp->spacep;
4627 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4628 #ifndef SPECIAL_FOLDERS
4629 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4630 code = cm_NameI(rootScp, spacep->data,
4631 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4632 userp, tidPathp, &req, &dscp);
4635 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4636 if ( WANTS_DFS_PATHNAMES(inp) )
4637 return CM_ERROR_PATH_NOT_COVERED;
4639 return CM_ERROR_BADSHARENAME;
4641 #endif /* DFS_SUPPORT */
4642 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4643 code = CM_ERROR_NOSUCHFILE;
4644 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4645 cm_buf_t *bp = buf_Find(dscp, &hzero);
4650 code = CM_ERROR_NOSUCHFILE;
4652 cm_ReleaseSCache(dscp);
4654 cm_ReleaseUser(userp);
4659 #endif /* SPECIAL_FOLDERS */
4661 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4662 tidPathp, &req, &newScp);
4664 cm_ReleaseUser(userp);
4669 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4670 cm_ReleaseSCache(newScp);
4671 cm_ReleaseUser(userp);
4672 if ( WANTS_DFS_PATHNAMES(inp) )
4673 return CM_ERROR_PATH_NOT_COVERED;
4675 return CM_ERROR_BADSHARENAME;
4677 #endif /* DFS_SUPPORT */
4679 /* now lock the vnode with a callback; returns with newScp locked */
4680 lock_ObtainMutex(&newScp->mx);
4681 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4682 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4684 lock_ReleaseMutex(&newScp->mx);
4685 cm_ReleaseSCache(newScp);
4686 cm_ReleaseUser(userp);
4690 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4693 /* use smb_Attributes instead. Also the fact that a file is
4694 * in a readonly volume doesn't mean it shojuld be marked as RO
4696 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4697 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4698 newScp->fileType == CM_SCACHETYPE_INVALID)
4699 attrs = SMB_ATTR_DIRECTORY;
4702 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4703 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4705 attrs = smb_Attributes(newScp);
4708 smb_SetSMBParm(outp, 0, attrs);
4710 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4711 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4712 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4713 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4714 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4715 smb_SetSMBParm(outp, 5, 0);
4716 smb_SetSMBParm(outp, 6, 0);
4717 smb_SetSMBParm(outp, 7, 0);
4718 smb_SetSMBParm(outp, 8, 0);
4719 smb_SetSMBParm(outp, 9, 0);
4720 smb_SetSMBDataLength(outp, 0);
4721 lock_ReleaseMutex(&newScp->mx);
4723 cm_ReleaseSCache(newScp);
4724 cm_ReleaseUser(userp);
4729 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4733 osi_Log0(smb_logp, "SMB receive tree disconnect");
4735 /* find the tree and free it */
4736 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4738 lock_ObtainWrite(&smb_rctLock);
4740 lock_ReleaseWrite(&smb_rctLock);
4741 smb_ReleaseTID(tidp);
4747 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4765 pathp = smb_GetSMBData(inp, NULL);
4766 pathp = smb_ParseASCIIBlock(pathp, NULL);
4767 if (smb_StoreAnsiFilenames)
4768 OemToChar(pathp,pathp);
4770 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4772 #ifdef DEBUG_VERBOSE
4776 hexpath = osi_HexifyString( pathp );
4777 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4782 share = smb_GetSMBParm(inp, 0);
4783 attribute = smb_GetSMBParm(inp, 1);
4785 spacep = inp->spacep;
4786 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4787 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4788 /* special case magic file name for receiving IOCTL requests
4789 * (since IOCTL calls themselves aren't getting through).
4791 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4792 smb_SetupIoctlFid(fidp, spacep);
4793 smb_SetSMBParm(outp, 0, fidp->fid);
4794 smb_SetSMBParm(outp, 1, 0); /* attrs */
4795 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4796 smb_SetSMBParm(outp, 3, 0);
4797 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4798 smb_SetSMBParm(outp, 5, 0x7fff);
4799 /* pass the open mode back */
4800 smb_SetSMBParm(outp, 6, (share & 0xf));
4801 smb_SetSMBDataLength(outp, 0);
4802 smb_ReleaseFID(fidp);
4806 userp = smb_GetUserFromVCP(vcp, inp);
4808 caseFold = CM_FLAG_CASEFOLD;
4810 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4812 cm_ReleaseUser(userp);
4813 return CM_ERROR_NOSUCHPATH;
4815 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4816 tidPathp, &req, &scp);
4819 cm_ReleaseUser(userp);
4824 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4825 cm_ReleaseSCache(scp);
4826 cm_ReleaseUser(userp);
4827 if ( WANTS_DFS_PATHNAMES(inp) )
4828 return CM_ERROR_PATH_NOT_COVERED;
4830 return CM_ERROR_BADSHARENAME;
4832 #endif /* DFS_SUPPORT */
4834 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4836 cm_ReleaseSCache(scp);
4837 cm_ReleaseUser(userp);
4841 /* don't need callback to check file type, since file types never
4842 * change, and namei and cm_Lookup all stat the object at least once on
4843 * a successful return.
4845 if (scp->fileType != CM_SCACHETYPE_FILE) {
4846 cm_ReleaseSCache(scp);
4847 cm_ReleaseUser(userp);
4848 return CM_ERROR_ISDIR;
4851 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4854 /* save a pointer to the vnode */
4856 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4857 lock_ObtainMutex(&scp->mx);
4858 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4859 lock_ReleaseMutex(&scp->mx);
4863 fidp->userp = userp;
4865 lock_ObtainMutex(&fidp->mx);
4866 if ((share & 0xf) == 0)
4867 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4868 else if ((share & 0xf) == 1)
4869 fidp->flags |= SMB_FID_OPENWRITE;
4871 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4872 lock_ReleaseMutex(&fidp->mx);
4874 lock_ObtainMutex(&scp->mx);
4875 smb_SetSMBParm(outp, 0, fidp->fid);
4876 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4877 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4878 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4879 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4880 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4881 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4882 /* pass the open mode back; XXXX add access checks */
4883 smb_SetSMBParm(outp, 6, (share & 0xf));
4884 smb_SetSMBDataLength(outp, 0);
4885 lock_ReleaseMutex(&scp->mx);
4888 cm_Open(scp, 0, userp);
4890 /* send and free packet */
4891 smb_ReleaseFID(fidp);
4892 cm_ReleaseUser(userp);
4893 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4897 typedef struct smb_unlinkRock {
4902 char *maskp; /* pointer to the star pattern */
4907 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4910 smb_unlinkRock_t *rockp;
4918 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4919 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4920 caseFold |= CM_FLAG_8DOT3;
4922 matchName = dep->name;
4923 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4925 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4926 !cm_Is8Dot3(dep->name)) {
4927 cm_Gen8Dot3Name(dep, shortName, NULL);
4928 matchName = shortName;
4929 /* 8.3 matches are always case insensitive */
4930 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4933 osi_Log1(smb_logp, "Unlinking %s",
4934 osi_LogSaveString(smb_logp, matchName));
4935 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4936 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4937 smb_NotifyChange(FILE_ACTION_REMOVED,
4938 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
4939 dscp, dep->name, NULL, TRUE);
4943 /* If we made a case sensitive exact match, we might as well quit now. */
4944 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4945 code = CM_ERROR_STOPNOW;
4953 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4962 smb_unlinkRock_t rock;
4971 attribute = smb_GetSMBParm(inp, 0);
4973 tp = smb_GetSMBData(inp, NULL);
4974 pathp = smb_ParseASCIIBlock(tp, &tp);
4975 if (smb_StoreAnsiFilenames)
4976 OemToChar(pathp,pathp);
4978 osi_Log1(smb_logp, "SMB receive unlink %s",
4979 osi_LogSaveString(smb_logp, pathp));
4981 spacep = inp->spacep;
4982 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4984 userp = smb_GetUserFromVCP(vcp, inp);
4986 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4988 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4990 cm_ReleaseUser(userp);
4991 return CM_ERROR_NOSUCHPATH;
4993 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4996 cm_ReleaseUser(userp);
5001 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5002 cm_ReleaseSCache(dscp);
5003 cm_ReleaseUser(userp);
5004 if ( WANTS_DFS_PATHNAMES(inp) )
5005 return CM_ERROR_PATH_NOT_COVERED;
5007 return CM_ERROR_BADSHARENAME;
5009 #endif /* DFS_SUPPORT */
5011 /* otherwise, scp points to the parent directory. */
5018 rock.maskp = smb_FindMask(pathp);
5019 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5022 thyper.HighPart = 0;
5028 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5029 * match. If that fails, we do a case insensitve match.
5031 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5032 !smb_IsStarMask(rock.maskp)) {
5033 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5036 thyper.HighPart = 0;
5037 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5042 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5044 if (code == CM_ERROR_STOPNOW)
5047 cm_ReleaseUser(userp);
5049 cm_ReleaseSCache(dscp);
5051 if (code == 0 && !rock.any)
5052 code = CM_ERROR_NOSUCHFILE;
5056 typedef struct smb_renameRock {
5057 cm_scache_t *odscp; /* old dir */
5058 cm_scache_t *ndscp; /* new dir */
5059 cm_user_t *userp; /* user */
5060 cm_req_t *reqp; /* request struct */
5061 smb_vc_t *vcp; /* virtual circuit */
5062 char *maskp; /* pointer to star pattern of old file name */
5063 int flags; /* tilde, casefold, etc */
5064 char *newNamep; /* ptr to the new file's name */
5068 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5071 smb_renameRock_t *rockp;
5074 char shortName[13]="";
5076 rockp = (smb_renameRock_t *) vrockp;
5078 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5079 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5080 caseFold |= CM_FLAG_8DOT3;
5082 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5084 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5085 !cm_Is8Dot3(dep->name)) {
5086 cm_Gen8Dot3Name(dep, shortName, NULL);
5087 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5092 code = cm_Rename(rockp->odscp, dep->name,
5093 rockp->ndscp, rockp->newNamep, rockp->userp,
5095 /* if the call worked, stop doing the search now, since we
5096 * really only want to rename one file.
5098 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5100 code = CM_ERROR_STOPNOW;
5110 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5113 cm_space_t *spacep = NULL;
5114 smb_renameRock_t rock;
5115 cm_scache_t *oldDscp = NULL;
5116 cm_scache_t *newDscp = NULL;
5117 cm_scache_t *tmpscp= NULL;
5118 cm_scache_t *tmpscp2 = NULL;
5128 userp = smb_GetUserFromVCP(vcp, inp);
5129 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5131 cm_ReleaseUser(userp);
5132 return CM_ERROR_NOSUCHPATH;
5136 spacep = inp->spacep;
5137 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5139 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5140 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5141 userp, tidPathp, &req, &oldDscp);
5143 cm_ReleaseUser(userp);
5148 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5149 cm_ReleaseSCache(oldDscp);
5150 cm_ReleaseUser(userp);
5151 if ( WANTS_DFS_PATHNAMES(inp) )
5152 return CM_ERROR_PATH_NOT_COVERED;
5154 return CM_ERROR_BADSHARENAME;
5156 #endif /* DFS_SUPPORT */
5158 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5159 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5160 userp, tidPathp, &req, &newDscp);
5163 cm_ReleaseSCache(oldDscp);
5164 cm_ReleaseUser(userp);
5169 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5170 cm_ReleaseSCache(oldDscp);
5171 cm_ReleaseSCache(newDscp);
5172 cm_ReleaseUser(userp);
5173 if ( WANTS_DFS_PATHNAMES(inp) )
5174 return CM_ERROR_PATH_NOT_COVERED;
5176 return CM_ERROR_BADSHARENAME;
5178 #endif /* DFS_SUPPORT */
5181 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5182 * next, get the component names, and lower case them.
5185 /* handle the old name first */
5187 oldLastNamep = oldPathp;
5191 /* and handle the new name, too */
5193 newLastNamep = newPathp;
5197 /* TODO: The old name could be a wildcard. The new name must not be */
5199 /* do the vnode call */
5200 rock.odscp = oldDscp;
5201 rock.ndscp = newDscp;
5205 rock.maskp = oldLastNamep;
5206 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5207 rock.newNamep = newLastNamep;
5210 /* Check if the file already exists; if so return error */
5211 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5212 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5213 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5214 osi_LogSaveString(smb_logp, newLastNamep));
5216 /* Check if the old and the new names differ only in case. If so return
5217 * success, else return CM_ERROR_EXISTS
5219 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5221 /* This would be a success only if the old file is *as same as* the new file */
5222 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5224 if (tmpscp == tmpscp2)
5227 code = CM_ERROR_EXISTS;
5228 cm_ReleaseSCache(tmpscp2);
5231 code = CM_ERROR_NOSUCHFILE;
5234 /* file exist, do not rename, also fixes move */
5235 osi_Log0(smb_logp, "Can't rename. Target already exists");
5236 code = CM_ERROR_EXISTS;
5240 cm_ReleaseSCache(tmpscp);
5241 cm_ReleaseSCache(newDscp);
5242 cm_ReleaseSCache(oldDscp);
5243 cm_ReleaseUser(userp);
5247 /* Now search the directory for the pattern, and do the appropriate rename when found */
5248 thyper.LowPart = 0; /* search dir from here */
5249 thyper.HighPart = 0;
5251 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5252 if (code == 0 && !rock.any) {
5254 thyper.HighPart = 0;
5255 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5256 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5258 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5260 if (code == CM_ERROR_STOPNOW)
5263 code = CM_ERROR_NOSUCHFILE;
5265 /* Handle Change Notification */
5267 * Being lazy, not distinguishing between files and dirs in this
5268 * filter, since we'd have to do a lookup.
5270 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5271 if (oldDscp == newDscp) {
5272 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5273 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5274 filter, oldDscp, oldLastNamep,
5275 newLastNamep, TRUE);
5277 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5278 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5279 filter, oldDscp, oldLastNamep,
5281 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5282 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5283 filter, newDscp, newLastNamep,
5288 cm_ReleaseSCache(tmpscp);
5289 cm_ReleaseUser(userp);
5290 cm_ReleaseSCache(oldDscp);
5291 cm_ReleaseSCache(newDscp);
5296 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5299 cm_space_t *spacep = NULL;
5300 cm_scache_t *oldDscp = NULL;
5301 cm_scache_t *newDscp = NULL;
5302 cm_scache_t *tmpscp= NULL;
5303 cm_scache_t *tmpscp2 = NULL;
5304 cm_scache_t *sscp = NULL;
5313 userp = smb_GetUserFromVCP(vcp, inp);
5315 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5317 cm_ReleaseUser(userp);
5318 return CM_ERROR_NOSUCHPATH;
5323 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5325 spacep = inp->spacep;
5326 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5328 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5329 userp, tidPathp, &req, &oldDscp);
5331 cm_ReleaseUser(userp);
5336 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5337 cm_ReleaseSCache(oldDscp);
5338 cm_ReleaseUser(userp);
5339 if ( WANTS_DFS_PATHNAMES(inp) )
5340 return CM_ERROR_PATH_NOT_COVERED;
5342 return CM_ERROR_BADSHARENAME;
5344 #endif /* DFS_SUPPORT */
5346 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5347 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5348 userp, tidPathp, &req, &newDscp);
5350 cm_ReleaseSCache(oldDscp);
5351 cm_ReleaseUser(userp);
5356 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5357 cm_ReleaseSCache(newDscp);
5358 cm_ReleaseSCache(oldDscp);
5359 cm_ReleaseUser(userp);
5360 if ( WANTS_DFS_PATHNAMES(inp) )
5361 return CM_ERROR_PATH_NOT_COVERED;
5363 return CM_ERROR_BADSHARENAME;
5365 #endif /* DFS_SUPPORT */
5367 /* Now, although we did two lookups for the two directories (because the same
5368 * directory can be referenced through different paths), we only allow hard links
5369 * within the same directory. */
5370 if (oldDscp != newDscp) {
5371 cm_ReleaseSCache(oldDscp);
5372 cm_ReleaseSCache(newDscp);
5373 cm_ReleaseUser(userp);
5374 return CM_ERROR_CROSSDEVLINK;
5377 /* handle the old name first */
5379 oldLastNamep = oldPathp;
5383 /* and handle the new name, too */
5385 newLastNamep = newPathp;
5389 /* now lookup the old name */
5390 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5391 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5393 cm_ReleaseSCache(oldDscp);
5394 cm_ReleaseSCache(newDscp);
5395 cm_ReleaseUser(userp);
5399 /* Check if the file already exists; if so return error */
5400 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5401 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5402 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5403 osi_LogSaveString(smb_logp, newLastNamep));
5405 /* if the existing link is to the same file, then we return success */
5407 if(sscp == tmpscp) {
5410 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5411 code = CM_ERROR_EXISTS;
5416 cm_ReleaseSCache(tmpscp);
5417 cm_ReleaseSCache(sscp);
5418 cm_ReleaseSCache(newDscp);
5419 cm_ReleaseSCache(oldDscp);
5420 cm_ReleaseUser(userp);
5424 /* now create the hardlink */
5425 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5426 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5427 osi_Log1(smb_logp," Link returns 0x%x", code);
5429 /* Handle Change Notification */
5431 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5432 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5433 smb_NotifyChange(FILE_ACTION_ADDED,
5434 filter, newDscp, newLastNamep,
5439 cm_ReleaseSCache(tmpscp);
5440 cm_ReleaseUser(userp);
5441 cm_ReleaseSCache(sscp);
5442 cm_ReleaseSCache(oldDscp);
5443 cm_ReleaseSCache(newDscp);
5448 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5455 tp = smb_GetSMBData(inp, NULL);
5456 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5457 if (smb_StoreAnsiFilenames)
5458 OemToChar(oldPathp,oldPathp);
5459 newPathp = smb_ParseASCIIBlock(tp, &tp);
5460 if (smb_StoreAnsiFilenames)
5461 OemToChar(newPathp,newPathp);
5463 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5464 osi_LogSaveString(smb_logp, oldPathp),
5465 osi_LogSaveString(smb_logp, newPathp));
5467 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5469 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5475 typedef struct smb_rmdirRock {
5479 char *maskp; /* pointer to the star pattern */
5484 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5487 smb_rmdirRock_t *rockp;
5492 rockp = (smb_rmdirRock_t *) vrockp;
5494 matchName = dep->name;
5495 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5496 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5498 match = (strcmp(matchName, rockp->maskp) == 0);
5500 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5501 !cm_Is8Dot3(dep->name)) {
5502 cm_Gen8Dot3Name(dep, shortName, NULL);
5503 matchName = shortName;
5504 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5507 osi_Log1(smb_logp, "Removing directory %s",
5508 osi_LogSaveString(smb_logp, matchName));
5509 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5510 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5511 smb_NotifyChange(FILE_ACTION_REMOVED,
5512 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5513 dscp, dep->name, NULL, TRUE);
5522 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5530 smb_rmdirRock_t rock;
5539 tp = smb_GetSMBData(inp, NULL);
5540 pathp = smb_ParseASCIIBlock(tp, &tp);
5541 if (smb_StoreAnsiFilenames)
5542 OemToChar(pathp,pathp);
5544 spacep = inp->spacep;
5545 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5547 userp = smb_GetUserFromVCP(vcp, inp);
5549 caseFold = CM_FLAG_CASEFOLD;
5551 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5553 cm_ReleaseUser(userp);
5554 return CM_ERROR_NOSUCHPATH;
5556 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5557 userp, tidPathp, &req, &dscp);
5560 cm_ReleaseUser(userp);
5565 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5566 cm_ReleaseSCache(dscp);
5567 cm_ReleaseUser(userp);
5568 if ( WANTS_DFS_PATHNAMES(inp) )
5569 return CM_ERROR_PATH_NOT_COVERED;
5571 return CM_ERROR_BADSHARENAME;
5573 #endif /* DFS_SUPPORT */
5575 /* otherwise, scp points to the parent directory. */
5582 rock.maskp = lastNamep;
5583 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5586 thyper.HighPart = 0;
5591 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5592 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5593 if (code == 0 && !rock.any) {
5595 thyper.HighPart = 0;
5596 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5597 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5600 cm_ReleaseUser(userp);
5602 cm_ReleaseSCache(dscp);
5604 if (code == 0 && !rock.any)
5605 code = CM_ERROR_NOSUCHFILE;
5609 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5619 fid = smb_GetSMBParm(inp, 0);
5621 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5623 fid = smb_ChainFID(fid, inp);
5624 fidp = smb_FindFID(vcp, fid, 0);
5626 return CM_ERROR_BADFD;
5628 lock_ObtainMutex(&fidp->mx);
5629 if (fidp->flags & SMB_FID_IOCTL) {
5630 lock_ReleaseMutex(&fidp->mx);
5631 smb_ReleaseFID(fidp);
5632 return CM_ERROR_BADFD;
5634 lock_ReleaseMutex(&fidp->mx);
5636 userp = smb_GetUserFromVCP(vcp, inp);
5638 lock_ObtainMutex(&fidp->mx);
5639 if (fidp->flags & SMB_FID_OPENWRITE) {
5640 cm_scache_t * scp = fidp->scp;
5642 lock_ReleaseMutex(&fidp->mx);
5643 code = cm_FSync(scp, userp, &req);
5644 cm_ReleaseSCache(scp);
5647 lock_ReleaseMutex(&fidp->mx);
5650 smb_ReleaseFID(fidp);
5652 cm_ReleaseUser(userp);
5657 struct smb_FullNameRock {
5663 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5667 struct smb_FullNameRock *vrockp;
5669 vrockp = (struct smb_FullNameRock *)rockp;
5671 if (!cm_Is8Dot3(dep->name)) {
5672 cm_Gen8Dot3Name(dep, shortName, NULL);
5674 if (cm_stricmp(shortName, vrockp->name) == 0) {
5675 vrockp->fullName = strdup(dep->name);
5676 return CM_ERROR_STOPNOW;
5679 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5680 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5681 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5682 vrockp->fullName = strdup(dep->name);
5683 return CM_ERROR_STOPNOW;
5688 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5689 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5691 struct smb_FullNameRock rock;
5697 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5698 if (code == CM_ERROR_STOPNOW)
5699 *newPathp = rock.fullName;
5701 *newPathp = strdup(pathp);
5704 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5705 afs_uint32 dosTime) {
5708 cm_scache_t *dscp = NULL;
5710 cm_scache_t * scp = NULL;
5712 int nullcreator = 0;
5714 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5715 fidp, fidp->fid, scp, vcp);
5718 lock_ObtainMutex(&fidp->mx);
5719 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5720 lock_ReleaseMutex(&fidp->mx);
5721 osi_Log0(smb_logp, " No user specified. Not closing fid");
5722 return CM_ERROR_BADFD;
5725 userp = fidp->userp; /* no hold required since fidp is held
5726 throughout the function */
5727 lock_ReleaseMutex(&fidp->mx);
5732 lock_ObtainWrite(&smb_rctLock);
5734 osi_Log0(smb_logp, " Fid already closed.");
5735 lock_ReleaseWrite(&smb_rctLock);
5736 return CM_ERROR_BADFD;
5739 lock_ReleaseWrite(&smb_rctLock);
5741 lock_ObtainMutex(&fidp->mx);
5742 if (fidp->NTopen_dscp) {
5743 dscp = fidp->NTopen_dscp;
5744 cm_HoldSCache(dscp);
5747 if (fidp->NTopen_pathp) {
5748 pathp = strdup(fidp->NTopen_pathp);
5756 /* Don't jump the gun on an async raw write */
5757 while (fidp->raw_writers) {
5758 lock_ReleaseMutex(&fidp->mx);
5759 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5760 lock_ObtainMutex(&fidp->mx);
5763 /* watch for ioctl closes, and read-only opens */
5765 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5766 == SMB_FID_OPENWRITE) {
5767 if (dosTime != 0 && dosTime != -1) {
5768 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5769 /* This fixes defect 10958 */
5770 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5771 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5773 lock_ReleaseMutex(&fidp->mx);
5774 code = cm_FSync(scp, userp, &req);
5775 lock_ObtainMutex(&fidp->mx);
5780 /* unlock any pending locks */
5781 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5782 scp->fileType == CM_SCACHETYPE_FILE) {
5786 lock_ReleaseMutex(&fidp->mx);
5788 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5790 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5791 lock_ObtainMutex(&scp->mx);
5793 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5794 CM_SCACHESYNC_NEEDCALLBACK
5795 | CM_SCACHESYNC_GETSTATUS
5796 | CM_SCACHESYNC_LOCK);
5800 "smb CoreClose SyncOp failure code 0x%x", tcode);
5801 goto post_syncopdone;
5804 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5806 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5810 lock_ReleaseMutex(&scp->mx);
5811 lock_ObtainMutex(&fidp->mx);
5814 if (fidp->flags & SMB_FID_DELONCLOSE) {
5817 lock_ReleaseMutex(&fidp->mx);
5818 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5819 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5820 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5823 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5824 smb_NotifyChange(FILE_ACTION_REMOVED,
5825 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5826 dscp, fullPathp, NULL, TRUE);
5829 code = cm_Unlink(dscp, fullPathp, userp, &req);
5832 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5833 smb_NotifyChange(FILE_ACTION_REMOVED,
5834 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5835 dscp, fullPathp, NULL, TRUE);
5839 lock_ObtainMutex(&fidp->mx);
5840 fidp->flags &= ~SMB_FID_DELONCLOSE;
5843 /* if this was a newly created file, then clear the creator
5844 * in the stat cache entry. */
5845 if (fidp->flags & SMB_FID_CREATED) {
5847 fidp->flags &= ~SMB_FID_CREATED;
5850 if (fidp->flags & SMB_FID_NTOPEN) {
5851 cm_ReleaseSCache(fidp->NTopen_dscp);
5852 fidp->NTopen_dscp = NULL;
5853 free(fidp->NTopen_pathp);
5854 fidp->NTopen_pathp = NULL;
5855 fidp->flags &= ~SMB_FID_NTOPEN;
5857 osi_assert(fidp->NTopen_dscp == NULL);
5858 osi_assert(fidp->NTopen_pathp == NULL);
5861 if (fidp->NTopen_wholepathp) {
5862 free(fidp->NTopen_wholepathp);
5863 fidp->NTopen_wholepathp = NULL;
5867 cm_ReleaseSCache(fidp->scp);
5870 lock_ReleaseMutex(&fidp->mx);
5873 cm_ReleaseSCache(dscp);
5876 if (deleted || nullcreator) {
5877 lock_ObtainMutex(&scp->mx);
5878 if (nullcreator && scp->creator == userp)
5879 scp->creator = NULL;
5881 scp->flags |= CM_SCACHEFLAG_DELETED;
5882 lock_ReleaseMutex(&scp->mx);
5884 lock_ObtainMutex(&scp->mx);
5885 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5886 lock_ReleaseMutex(&scp->mx);
5887 cm_ReleaseSCache(scp);
5896 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5904 fid = smb_GetSMBParm(inp, 0);
5905 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5907 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5909 fid = smb_ChainFID(fid, inp);
5910 fidp = smb_FindFID(vcp, fid, 0);
5912 return CM_ERROR_BADFD;
5915 userp = smb_GetUserFromVCP(vcp, inp);
5917 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5919 smb_ReleaseFID(fidp);
5920 cm_ReleaseUser(userp);
5925 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5927 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5928 cm_user_t *userp, long *readp)
5934 osi_hyper_t fileLength;
5936 osi_hyper_t lastByte;
5937 osi_hyper_t bufferOffset;
5938 long bufIndex, nbytes;
5940 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
5948 lock_ObtainMutex(&fidp->mx);
5951 lock_ObtainMutex(&scp->mx);
5953 if (offset.HighPart == 0) {
5954 chunk = offset.LowPart >> cm_logChunkSize;
5955 if (chunk != fidp->curr_chunk) {
5956 fidp->prev_chunk = fidp->curr_chunk;
5957 fidp->curr_chunk = chunk;
5959 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
5962 lock_ReleaseMutex(&fidp->mx);
5964 /* start by looking up the file's end */
5965 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5966 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5970 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5972 /* now we have the entry locked, look up the length */
5973 fileLength = scp->length;
5975 /* adjust count down so that it won't go past EOF */
5976 thyper.LowPart = count;
5977 thyper.HighPart = 0;
5978 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5980 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5981 /* we'd read past EOF, so just stop at fileLength bytes.
5982 * Start by computing how many bytes remain in the file.
5984 thyper = LargeIntegerSubtract(fileLength, offset);
5986 /* if we are past EOF, read 0 bytes */
5987 if (LargeIntegerLessThanZero(thyper))
5990 count = thyper.LowPart;
5995 /* now, copy the data one buffer at a time,
5996 * until we've filled the request packet
5999 /* if we've copied all the data requested, we're done */
6000 if (count <= 0) break;
6002 /* otherwise, load up a buffer of data */
6003 thyper.HighPart = offset.HighPart;
6004 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6005 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6008 buf_Release(bufferp);
6011 lock_ReleaseMutex(&scp->mx);
6013 lock_ObtainRead(&scp->bufCreateLock);
6014 code = buf_Get(scp, &thyper, &bufferp);
6015 lock_ReleaseRead(&scp->bufCreateLock);
6017 lock_ObtainMutex(&scp->mx);
6018 if (code) goto done;
6019 bufferOffset = thyper;
6021 /* now get the data in the cache */
6023 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6024 CM_SCACHESYNC_NEEDCALLBACK |
6025 CM_SCACHESYNC_READ);
6029 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6031 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6033 /* otherwise, load the buffer and try again */
6034 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6038 buf_Release(bufferp);
6042 } /* if (wrong buffer) ... */
6044 /* now we have the right buffer loaded. Copy out the
6045 * data from here to the user's buffer.
6047 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6049 /* and figure out how many bytes we want from this buffer */
6050 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6051 if (nbytes > count) nbytes = count; /* don't go past EOF */
6053 /* now copy the data */
6054 memcpy(op, bufferp->datap + bufIndex, nbytes);
6056 /* adjust counters, pointers, etc. */
6059 thyper.LowPart = nbytes;
6060 thyper.HighPart = 0;
6061 offset = LargeIntegerAdd(thyper, offset);
6065 lock_ReleaseMutex(&scp->mx);
6067 buf_Release(bufferp);
6069 if (code == 0 && sequential)
6070 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6072 cm_ReleaseSCache(scp);
6078 * smb_WriteData -- common code for Write and Raw Write
6080 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6081 cm_user_t *userp, long *writtenp)
6087 osi_hyper_t fileLength; /* file's length at start of write */
6088 osi_hyper_t minLength; /* don't read past this */
6089 long nbytes; /* # of bytes to transfer this iteration */
6091 osi_hyper_t thyper; /* hyper tmp variable */
6092 osi_hyper_t bufferOffset;
6093 long bufIndex; /* index in buffer where our data is */
6095 osi_hyper_t writeBackOffset;/* offset of region to write back when
6100 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6101 fidp->fid, offsetp->LowPart, count);
6111 lock_ObtainMutex(&fidp->mx);
6112 /* make sure we have a writable FD */
6113 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6114 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6115 fidp->fid, fidp->flags);
6116 lock_ReleaseMutex(&fidp->mx);
6117 code = CM_ERROR_BADFDOP;
6123 lock_ReleaseMutex(&fidp->mx);
6125 lock_ObtainMutex(&scp->mx);
6126 /* start by looking up the file's end */
6127 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6128 CM_SCACHESYNC_NEEDCALLBACK
6129 | CM_SCACHESYNC_SETSTATUS
6130 | CM_SCACHESYNC_GETSTATUS);
6134 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6136 /* now we have the entry locked, look up the length */
6137 fileLength = scp->length;
6138 minLength = fileLength;
6139 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6140 minLength = scp->serverLength;
6142 /* adjust file length if we extend past EOF */
6143 thyper.LowPart = count;
6144 thyper.HighPart = 0;
6145 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6146 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6147 /* we'd write past EOF, so extend the file */
6148 scp->mask |= CM_SCACHEMASK_LENGTH;
6149 scp->length = thyper;
6150 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6152 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6154 /* now, if the new position (thyper) and the old (offset) are in
6155 * different storeback windows, remember to store back the previous
6156 * storeback window when we're done with the write.
6158 if ((thyper.LowPart & (-cm_chunkSize)) !=
6159 (offset.LowPart & (-cm_chunkSize))) {
6160 /* they're different */
6162 writeBackOffset.HighPart = offset.HighPart;
6163 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6168 /* now, copy the data one buffer at a time, until we've filled the
6171 /* if we've copied all the data requested, we're done */
6175 /* handle over quota or out of space */
6176 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6177 *writtenp = written;
6178 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6182 /* otherwise, load up a buffer of data */
6183 thyper.HighPart = offset.HighPart;
6184 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6185 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6188 lock_ReleaseMutex(&bufferp->mx);
6189 buf_Release(bufferp);
6192 lock_ReleaseMutex(&scp->mx);
6194 lock_ObtainRead(&scp->bufCreateLock);
6195 code = buf_Get(scp, &thyper, &bufferp);
6196 lock_ReleaseRead(&scp->bufCreateLock);
6198 lock_ObtainMutex(&bufferp->mx);
6199 lock_ObtainMutex(&scp->mx);
6200 if (code) goto done;
6202 bufferOffset = thyper;
6204 /* now get the data in the cache */
6206 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6207 CM_SCACHESYNC_NEEDCALLBACK
6208 | CM_SCACHESYNC_WRITE
6209 | CM_SCACHESYNC_BUFLOCKED);
6213 cm_SyncOpDone(scp, bufferp,
6214 CM_SCACHESYNC_NEEDCALLBACK
6215 | CM_SCACHESYNC_WRITE
6216 | CM_SCACHESYNC_BUFLOCKED);
6218 /* If we're overwriting the entire buffer, or
6219 * if we're writing at or past EOF, mark the
6220 * buffer as current so we don't call
6221 * cm_GetBuffer. This skips the fetch from the
6222 * server in those cases where we're going to
6223 * obliterate all the data in the buffer anyway,
6224 * or in those cases where there is no useful
6225 * data at the server to start with.
6227 * Use minLength instead of scp->length, since
6228 * the latter has already been updated by this
6231 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6232 || LargeIntegerEqualTo(offset, bufferp->offset)
6233 && (count >= cm_data.buf_blockSize
6234 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6235 ConvertLongToLargeInteger(count)),
6237 if (count < cm_data.buf_blockSize
6238 && bufferp->dataVersion == -1)
6239 memset(bufferp->datap, 0,
6240 cm_data.buf_blockSize);
6241 bufferp->dataVersion = scp->dataVersion;
6244 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6246 /* otherwise, load the buffer and try again */
6247 lock_ReleaseMutex(&bufferp->mx);
6248 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6250 lock_ReleaseMutex(&scp->mx);
6251 lock_ObtainMutex(&bufferp->mx);
6252 lock_ObtainMutex(&scp->mx);
6256 lock_ReleaseMutex(&bufferp->mx);
6257 buf_Release(bufferp);
6261 } /* if (wrong buffer) ... */
6263 /* now we have the right buffer loaded. Copy out the
6264 * data from here to the user's buffer.
6266 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6268 /* and figure out how many bytes we want from this buffer */
6269 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6271 nbytes = count; /* don't go past end of request */
6273 /* now copy the data */
6274 memcpy(bufferp->datap + bufIndex, op, nbytes);
6275 buf_SetDirty(bufferp);
6277 /* and record the last writer */
6278 if (bufferp->userp != userp) {
6281 cm_ReleaseUser(bufferp->userp);
6282 bufferp->userp = userp;
6285 /* adjust counters, pointers, etc. */
6289 thyper.LowPart = nbytes;
6290 thyper.HighPart = 0;
6291 offset = LargeIntegerAdd(thyper, offset);
6295 lock_ReleaseMutex(&scp->mx);
6298 lock_ReleaseMutex(&bufferp->mx);
6299 buf_Release(bufferp);
6302 lock_ObtainMutex(&fidp->mx);
6303 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6304 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6305 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6306 fidp->NTopen_dscp, fidp->NTopen_pathp,
6309 lock_ReleaseMutex(&fidp->mx);
6311 if (code == 0 && doWriteBack) {
6313 lock_ObtainMutex(&scp->mx);
6314 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6316 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6317 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6319 lock_ReleaseMutex(&scp->mx);
6320 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6321 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6322 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6325 cm_ReleaseSCache(scp);
6327 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6328 fidp->fid, code, *writtenp);
6332 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6335 unsigned short count;
6337 unsigned short hint;
6338 long written = 0, total_written = 0;
6343 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6345 int inDataBlockCount;
6347 fd = smb_GetSMBParm(inp, 0);
6348 count = smb_GetSMBParm(inp, 1);
6349 offset.HighPart = 0; /* too bad */
6350 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6351 hint = smb_GetSMBParm(inp, 4);
6353 op = smb_GetSMBData(inp, NULL);
6354 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6356 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6357 fd, offset.LowPart, count);
6359 fd = smb_ChainFID(fd, inp);
6360 fidp = smb_FindFID(vcp, fd, 0);
6362 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6363 return CM_ERROR_BADFD;
6366 lock_ObtainMutex(&fidp->mx);
6367 if (fidp->flags & SMB_FID_IOCTL) {
6368 lock_ReleaseMutex(&fidp->mx);
6369 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6370 smb_ReleaseFID(fidp);
6371 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6374 lock_ReleaseMutex(&fidp->mx);
6375 userp = smb_GetUserFromVCP(vcp, inp);
6379 LARGE_INTEGER LOffset;
6380 LARGE_INTEGER LLength;
6382 pid = ((smb_t *) inp)->pid;
6383 key = cm_GenerateKey(vcp->vcID, pid, fd);
6385 LOffset.HighPart = offset.HighPart;
6386 LOffset.LowPart = offset.LowPart;
6387 LLength.HighPart = 0;
6388 LLength.LowPart = count;
6390 lock_ObtainMutex(&fidp->scp->mx);
6391 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6392 lock_ReleaseMutex(&fidp->scp->mx);
6395 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6400 /* special case: 0 bytes transferred means truncate to this position */
6404 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6408 truncAttr.mask = CM_ATTRMASK_LENGTH;
6409 truncAttr.length.LowPart = offset.LowPart;
6410 truncAttr.length.HighPart = 0;
6411 lock_ObtainMutex(&fidp->mx);
6412 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6413 fidp->flags |= SMB_FID_LENGTHSETDONE;
6414 lock_ReleaseMutex(&fidp->mx);
6415 smb_SetSMBParm(outp, 0, 0 /* count */);
6416 smb_SetSMBDataLength(outp, 0);
6421 * Work around bug in NT client
6423 * When copying a file, the NT client should first copy the data,
6424 * then copy the last write time. But sometimes the NT client does
6425 * these in the wrong order, so the data copies would inadvertently
6426 * cause the last write time to be overwritten. We try to detect this,
6427 * and don't set client mod time if we think that would go against the
6430 lock_ObtainMutex(&fidp->mx);
6431 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6432 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6433 fidp->scp->clientModTime = time(NULL);
6435 lock_ReleaseMutex(&fidp->mx);
6438 while ( code == 0 && count > 0 ) {
6439 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6440 if (code == 0 && written == 0)
6441 code = CM_ERROR_PARTIALWRITE;
6443 offset = LargeIntegerAdd(offset,
6444 ConvertLongToLargeInteger(written));
6445 count -= (unsigned short)written;
6446 total_written += written;
6450 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6451 total_written, code);
6453 /* set the packet data length to 3 bytes for the data block header,
6454 * plus the size of the data.
6456 smb_SetSMBParm(outp, 0, total_written);
6457 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6458 smb_SetSMBParm(outp, 3, hint);
6459 smb_SetSMBDataLength(outp, 0);
6462 smb_ReleaseFID(fidp);
6463 cm_ReleaseUser(userp);
6468 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6469 NCB *ncbp, raw_write_cont_t *rwcp)
6478 fd = smb_GetSMBParm(inp, 0);
6479 fidp = smb_FindFID(vcp, fd, 0);
6481 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6482 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6484 userp = smb_GetUserFromVCP(vcp, inp);
6487 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6489 if (rwcp->writeMode & 0x1) { /* synchronous */
6492 smb_FormatResponsePacket(vcp, inp, outp);
6493 op = (smb_t *) outp;
6494 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6495 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6496 smb_SetSMBDataLength(outp, 0);
6497 smb_SendPacket(vcp, outp);
6498 smb_FreePacket(outp);
6500 else { /* asynchronous */
6501 lock_ObtainMutex(&fidp->mx);
6502 fidp->raw_writers--;
6503 if (fidp->raw_writers == 0)
6504 thrd_SetEvent(fidp->raw_write_event);
6505 lock_ReleaseMutex(&fidp->mx);
6508 /* Give back raw buffer */
6509 lock_ObtainMutex(&smb_RawBufLock);
6510 *((char **)rawBuf) = smb_RawBufs;
6511 smb_RawBufs = rawBuf;
6512 lock_ReleaseMutex(&smb_RawBufLock);
6514 smb_ReleaseFID(fidp);
6515 cm_ReleaseUser(userp);
6518 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6523 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6526 long count, written = 0, total_written = 0;
6533 unsigned short writeMode;
6535 fd = smb_GetSMBParm(inp, 0);
6536 totalCount = smb_GetSMBParm(inp, 1);
6537 count = smb_GetSMBParm(inp, 10);
6538 writeMode = smb_GetSMBParm(inp, 7);
6540 op = (char *) inp->data;
6541 op += smb_GetSMBParm(inp, 11);
6543 offset.HighPart = 0;
6544 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6546 if (*inp->wctp == 14) {
6547 /* we received a 64-bit file offset */
6548 #ifdef AFS_LARGEFILES
6549 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6551 if (LargeIntegerLessThanZero(offset)) {
6553 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6554 offset.HighPart, offset.LowPart);
6555 return CM_ERROR_BADSMB;
6558 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6560 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6561 return CM_ERROR_BADSMB;
6564 offset.HighPart = 0;
6567 offset.HighPart = 0; /* 32-bit file offset */
6571 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6572 fd, offset.HighPart, offset.LowPart, count);
6574 " WriteRaw WriteMode 0x%x",
6577 fd = smb_ChainFID(fd, inp);
6578 fidp = smb_FindFID(vcp, fd, 0);
6580 return CM_ERROR_BADFD;
6586 LARGE_INTEGER LOffset;
6587 LARGE_INTEGER LLength;
6589 pid = ((smb_t *) inp)->pid;
6590 key = cm_GenerateKey(vcp->vcID, pid, fd);
6592 LOffset.HighPart = offset.HighPart;
6593 LOffset.LowPart = offset.LowPart;
6594 LLength.HighPart = 0;
6595 LLength.LowPart = count;
6597 lock_ObtainMutex(&fidp->scp->mx);
6598 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6599 lock_ReleaseMutex(&fidp->scp->mx);
6602 smb_ReleaseFID(fidp);
6607 userp = smb_GetUserFromVCP(vcp, inp);
6610 * Work around bug in NT client
6612 * When copying a file, the NT client should first copy the data,
6613 * then copy the last write time. But sometimes the NT client does
6614 * these in the wrong order, so the data copies would inadvertently
6615 * cause the last write time to be overwritten. We try to detect this,
6616 * and don't set client mod time if we think that would go against the
6619 lock_ObtainMutex(&fidp->mx);
6620 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6621 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6622 fidp->scp->clientModTime = time(NULL);
6624 lock_ReleaseMutex(&fidp->mx);
6627 while ( code == 0 && count > 0 ) {
6628 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6629 if (code == 0 && written == 0)
6630 code = CM_ERROR_PARTIALWRITE;
6632 offset = LargeIntegerAdd(offset,
6633 ConvertLongToLargeInteger(written));
6636 total_written += written;
6640 /* Get a raw buffer */
6643 lock_ObtainMutex(&smb_RawBufLock);
6645 /* Get a raw buf, from head of list */
6646 rawBuf = smb_RawBufs;
6647 smb_RawBufs = *(char **)smb_RawBufs;
6650 code = CM_ERROR_USESTD;
6652 lock_ReleaseMutex(&smb_RawBufLock);
6655 /* Don't allow a premature Close */
6656 if (code == 0 && (writeMode & 1) == 0) {
6657 lock_ObtainMutex(&fidp->mx);
6658 fidp->raw_writers++;
6659 thrd_ResetEvent(fidp->raw_write_event);
6660 lock_ReleaseMutex(&fidp->mx);
6663 smb_ReleaseFID(fidp);
6664 cm_ReleaseUser(userp);
6667 smb_SetSMBParm(outp, 0, total_written);
6668 smb_SetSMBDataLength(outp, 0);
6669 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6674 offset = LargeIntegerAdd(offset,
6675 ConvertLongToLargeInteger(count));
6679 rwcp->offset.HighPart = offset.HighPart;
6680 rwcp->offset.LowPart = offset.LowPart;
6681 rwcp->count = totalCount - count;
6682 rwcp->writeMode = writeMode;
6683 rwcp->alreadyWritten = total_written;
6685 /* set the packet data length to 3 bytes for the data block header,
6686 * plus the size of the data.
6688 smb_SetSMBParm(outp, 0, 0xffff);
6689 smb_SetSMBDataLength(outp, 0);
6694 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6697 long count, finalCount;
6705 fd = smb_GetSMBParm(inp, 0);
6706 count = smb_GetSMBParm(inp, 1);
6707 offset.HighPart = 0; /* too bad */
6708 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6710 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6711 fd, offset.LowPart, count);
6713 fd = smb_ChainFID(fd, inp);
6714 fidp = smb_FindFID(vcp, fd, 0);
6716 return CM_ERROR_BADFD;
6718 lock_ObtainMutex(&fidp->mx);
6719 if (fidp->flags & SMB_FID_IOCTL) {
6720 lock_ReleaseMutex(&fidp->mx);
6721 code = smb_IoctlRead(fidp, vcp, inp, outp);
6722 smb_ReleaseFID(fidp);
6725 lock_ReleaseMutex(&fidp->mx);
6728 LARGE_INTEGER LOffset, LLength;
6731 pid = ((smb_t *) inp)->pid;
6732 key = cm_GenerateKey(vcp->vcID, pid, fd);
6734 LOffset.HighPart = 0;
6735 LOffset.LowPart = offset.LowPart;
6736 LLength.HighPart = 0;
6737 LLength.LowPart = count;
6739 lock_ObtainMutex(&fidp->scp->mx);
6740 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6741 lock_ReleaseMutex(&fidp->scp->mx);
6744 smb_ReleaseFID(fidp);
6748 userp = smb_GetUserFromVCP(vcp, inp);
6750 /* remember this for final results */
6751 smb_SetSMBParm(outp, 0, count);
6752 smb_SetSMBParm(outp, 1, 0);
6753 smb_SetSMBParm(outp, 2, 0);
6754 smb_SetSMBParm(outp, 3, 0);
6755 smb_SetSMBParm(outp, 4, 0);
6757 /* set the packet data length to 3 bytes for the data block header,
6758 * plus the size of the data.
6760 smb_SetSMBDataLength(outp, count+3);
6762 /* get op ptr after putting in the parms, since otherwise we don't
6763 * know where the data really is.
6765 op = smb_GetSMBData(outp, NULL);
6767 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6768 *op++ = 1; /* data block marker */
6769 *op++ = (unsigned char) (count & 0xff);
6770 *op++ = (unsigned char) ((count >> 8) & 0xff);
6772 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6774 /* fix some things up */
6775 smb_SetSMBParm(outp, 0, finalCount);
6776 smb_SetSMBDataLength(outp, finalCount+3);
6778 smb_ReleaseFID(fidp);
6780 cm_ReleaseUser(userp);
6784 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6791 cm_scache_t *dscp; /* dir we're dealing with */
6792 cm_scache_t *scp; /* file we're creating */
6794 int initialModeBits;
6804 /* compute initial mode bits based on read-only flag in attributes */
6805 initialModeBits = 0777;
6807 tp = smb_GetSMBData(inp, NULL);
6808 pathp = smb_ParseASCIIBlock(tp, &tp);
6809 if (smb_StoreAnsiFilenames)
6810 OemToChar(pathp,pathp);
6812 if (strcmp(pathp, "\\") == 0)
6813 return CM_ERROR_EXISTS;
6815 spacep = inp->spacep;
6816 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6818 userp = smb_GetUserFromVCP(vcp, inp);
6820 caseFold = CM_FLAG_CASEFOLD;
6822 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6824 cm_ReleaseUser(userp);
6825 return CM_ERROR_NOSUCHPATH;
6828 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6829 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6830 userp, tidPathp, &req, &dscp);
6833 cm_ReleaseUser(userp);
6838 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6839 cm_ReleaseSCache(dscp);
6840 cm_ReleaseUser(userp);
6841 if ( WANTS_DFS_PATHNAMES(inp) )
6842 return CM_ERROR_PATH_NOT_COVERED;
6844 return CM_ERROR_BADSHARENAME;
6846 #endif /* DFS_SUPPORT */
6848 /* otherwise, scp points to the parent directory. Do a lookup, and
6849 * fail if we find it. Otherwise, we do the create.
6855 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6856 if (scp) cm_ReleaseSCache(scp);
6857 if (code != CM_ERROR_NOSUCHFILE) {
6858 if (code == 0) code = CM_ERROR_EXISTS;
6859 cm_ReleaseSCache(dscp);
6860 cm_ReleaseUser(userp);
6864 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6865 setAttr.clientModTime = time(NULL);
6866 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6867 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6868 smb_NotifyChange(FILE_ACTION_ADDED,
6869 FILE_NOTIFY_CHANGE_DIR_NAME,
6870 dscp, lastNamep, NULL, TRUE);
6872 /* we don't need this any longer */
6873 cm_ReleaseSCache(dscp);
6876 /* something went wrong creating or truncating the file */
6877 cm_ReleaseUser(userp);
6881 /* otherwise we succeeded */
6882 smb_SetSMBDataLength(outp, 0);
6883 cm_ReleaseUser(userp);
6888 BOOL smb_IsLegalFilename(char *filename)
6891 * Find the longest substring of filename that does not contain
6892 * any of the chars in illegalChars. If that substring is less
6893 * than the length of the whole string, then one or more of the
6894 * illegal chars is in filename.
6896 if (strcspn(filename, illegalChars) < strlen(filename))
6902 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6910 cm_scache_t *dscp; /* dir we're dealing with */
6911 cm_scache_t *scp; /* file we're creating */
6913 int initialModeBits;
6921 int created = 0; /* the file was new */
6926 excl = (inp->inCom == 0x03)? 0 : 1;
6928 attributes = smb_GetSMBParm(inp, 0);
6929 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6931 /* compute initial mode bits based on read-only flag in attributes */
6932 initialModeBits = 0666;
6933 if (attributes & SMB_ATTR_READONLY)
6934 initialModeBits &= ~0222;
6936 tp = smb_GetSMBData(inp, NULL);
6937 pathp = smb_ParseASCIIBlock(tp, &tp);
6938 if (smb_StoreAnsiFilenames)
6939 OemToChar(pathp,pathp);
6941 spacep = inp->spacep;
6942 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6944 userp = smb_GetUserFromVCP(vcp, inp);
6946 caseFold = CM_FLAG_CASEFOLD;
6948 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6950 cm_ReleaseUser(userp);
6951 return CM_ERROR_NOSUCHPATH;
6953 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6954 userp, tidPathp, &req, &dscp);
6957 cm_ReleaseUser(userp);
6962 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6963 cm_ReleaseSCache(dscp);
6964 cm_ReleaseUser(userp);
6965 if ( WANTS_DFS_PATHNAMES(inp) )
6966 return CM_ERROR_PATH_NOT_COVERED;
6968 return CM_ERROR_BADSHARENAME;
6970 #endif /* DFS_SUPPORT */
6972 /* otherwise, scp points to the parent directory. Do a lookup, and
6973 * truncate the file if we find it, otherwise we create the file.
6980 if (!smb_IsLegalFilename(lastNamep))
6981 return CM_ERROR_BADNTFILENAME;
6983 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6984 #ifdef DEBUG_VERBOSE
6987 hexp = osi_HexifyString( lastNamep );
6988 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6993 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6994 if (code && code != CM_ERROR_NOSUCHFILE) {
6995 cm_ReleaseSCache(dscp);
6996 cm_ReleaseUser(userp);
7000 /* if we get here, if code is 0, the file exists and is represented by
7001 * scp. Otherwise, we have to create it.
7005 /* oops, file shouldn't be there */
7006 cm_ReleaseSCache(dscp);
7007 cm_ReleaseSCache(scp);
7008 cm_ReleaseUser(userp);
7009 return CM_ERROR_EXISTS;
7012 setAttr.mask = CM_ATTRMASK_LENGTH;
7013 setAttr.length.LowPart = 0;
7014 setAttr.length.HighPart = 0;
7015 code = cm_SetAttr(scp, &setAttr, userp, &req);
7018 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7019 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7020 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7024 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7025 smb_NotifyChange(FILE_ACTION_ADDED,
7026 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7027 dscp, lastNamep, NULL, TRUE);
7028 } else if (!excl && code == CM_ERROR_EXISTS) {
7029 /* not an exclusive create, and someone else tried
7030 * creating it already, then we open it anyway. We
7031 * don't bother retrying after this, since if this next
7032 * fails, that means that the file was deleted after
7033 * we started this call.
7035 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7038 setAttr.mask = CM_ATTRMASK_LENGTH;
7039 setAttr.length.LowPart = 0;
7040 setAttr.length.HighPart = 0;
7041 code = cm_SetAttr(scp, &setAttr, userp, &req);
7046 /* we don't need this any longer */
7047 cm_ReleaseSCache(dscp);
7050 /* something went wrong creating or truncating the file */
7051 if (scp) cm_ReleaseSCache(scp);
7052 cm_ReleaseUser(userp);
7056 /* make sure we only open files */
7057 if (scp->fileType != CM_SCACHETYPE_FILE) {
7058 cm_ReleaseSCache(scp);
7059 cm_ReleaseUser(userp);
7060 return CM_ERROR_ISDIR;
7063 /* now all we have to do is open the file itself */
7064 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7069 lock_ObtainMutex(&fidp->mx);
7070 /* always create it open for read/write */
7071 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7073 /* remember that the file was newly created */
7075 fidp->flags |= SMB_FID_CREATED;
7077 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7079 /* save a pointer to the vnode */
7081 lock_ObtainMutex(&scp->mx);
7082 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7083 lock_ReleaseMutex(&scp->mx);
7086 fidp->userp = userp;
7087 lock_ReleaseMutex(&fidp->mx);
7089 smb_SetSMBParm(outp, 0, fidp->fid);
7090 smb_SetSMBDataLength(outp, 0);
7092 cm_Open(scp, 0, userp);
7094 smb_ReleaseFID(fidp);
7095 cm_ReleaseUser(userp);
7096 /* leave scp held since we put it in fidp->scp */
7100 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7103 osi_hyper_t new_offset;
7114 fd = smb_GetSMBParm(inp, 0);
7115 whence = smb_GetSMBParm(inp, 1);
7116 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7118 /* try to find the file descriptor */
7119 fd = smb_ChainFID(fd, inp);
7120 fidp = smb_FindFID(vcp, fd, 0);
7123 return CM_ERROR_BADFD;
7125 lock_ObtainMutex(&fidp->mx);
7126 if (fidp->flags & SMB_FID_IOCTL) {
7127 lock_ReleaseMutex(&fidp->mx);
7128 smb_ReleaseFID(fidp);
7129 return CM_ERROR_BADFD;
7131 lock_ReleaseMutex(&fidp->mx);
7133 userp = smb_GetUserFromVCP(vcp, inp);
7135 lock_ObtainMutex(&fidp->mx);
7138 lock_ReleaseMutex(&fidp->mx);
7139 lock_ObtainMutex(&scp->mx);
7140 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7141 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7143 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7145 /* offset from current offset */
7146 new_offset = LargeIntegerAdd(fidp->offset,
7147 ConvertLongToLargeInteger(offset));
7149 else if (whence == 2) {
7150 /* offset from current EOF */
7151 new_offset = LargeIntegerAdd(scp->length,
7152 ConvertLongToLargeInteger(offset));
7154 new_offset = ConvertLongToLargeInteger(offset);
7157 fidp->offset = new_offset;
7158 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7159 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7160 smb_SetSMBDataLength(outp, 0);
7162 lock_ReleaseMutex(&scp->mx);
7163 smb_ReleaseFID(fidp);
7164 cm_ReleaseSCache(scp);
7165 cm_ReleaseUser(userp);
7169 /* dispatch all of the requests received in a packet. Due to chaining, this may
7170 * be more than one request.
7172 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7173 NCB *ncbp, raw_write_cont_t *rwcp)
7177 unsigned long code = 0;
7178 unsigned char *outWctp;
7179 int nparms; /* # of bytes of parameters */
7181 int nbytes; /* bytes of data, excluding count */
7184 unsigned short errCode;
7185 unsigned long NTStatus;
7187 unsigned char errClass;
7188 unsigned int oldGen;
7189 DWORD oldTime, newTime;
7191 /* get easy pointer to the data */
7192 smbp = (smb_t *) inp->data;
7194 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7195 /* setup the basic parms for the initial request in the packet */
7196 inp->inCom = smbp->com;
7197 inp->wctp = &smbp->wct;
7199 inp->ncb_length = ncbp->ncb_length;
7204 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7205 /* log it and discard it */
7206 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7207 __FILE__, __LINE__, ncbp->ncb_length);
7208 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7212 /* We are an ongoing op */
7213 thrd_Increment(&ongoingOps);
7215 /* set up response packet for receiving output */
7216 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7217 smb_FormatResponsePacket(vcp, inp, outp);
7218 outWctp = outp->wctp;
7220 /* Remember session generation number and time */
7221 oldGen = sessionGen;
7222 oldTime = GetTickCount();
7224 while (inp->inCom != 0xff) {
7225 dp = &smb_dispatchTable[inp->inCom];
7227 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7228 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7229 code = outp->resumeCode;
7233 /* process each request in the packet; inCom, wctp and inCount
7234 * are already set up.
7236 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7239 /* now do the dispatch */
7240 /* start by formatting the response record a little, as a default */
7241 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7243 outWctp[1] = 0xff; /* no operation */
7244 outWctp[2] = 0; /* padding */
7249 /* not a chained request, this is a more reasonable default */
7250 outWctp[0] = 0; /* wct of zero */
7251 outWctp[1] = 0; /* and bcc (word) of zero */
7255 /* once set, stays set. Doesn't matter, since we never chain
7256 * "no response" calls.
7258 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7262 /* we have a recognized operation */
7264 if (inp->inCom == 0x1d)
7266 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7268 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7269 code = (*(dp->procp)) (vcp, inp, outp);
7270 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7272 if ( code == CM_ERROR_BADSMB ||
7273 code == CM_ERROR_BADOP )
7275 #endif /* LOG_PACKET */
7278 if (oldGen != sessionGen) {
7279 newTime = GetTickCount();
7280 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7281 newTime - oldTime, ncbp->ncb_length);
7282 osi_Log2(smb_logp, "Pkt straddled session startup, "
7283 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7287 /* bad opcode, fail the request, after displaying it */
7288 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7291 #endif /* LOG_PACKET */
7294 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7295 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7296 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7297 if (code == IDCANCEL)
7300 code = CM_ERROR_BADOP;
7303 /* catastrophic failure: log as much as possible */
7304 if (code == CM_ERROR_BADSMB) {
7305 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7309 #endif /* LOG_PACKET */
7310 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7313 code = CM_ERROR_INVAL;
7316 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7317 thrd_Decrement(&ongoingOps);
7322 /* now, if we failed, turn the current response into an empty
7323 * one, and fill in the response packet's error code.
7326 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7327 smb_MapNTError(code, &NTStatus);
7328 outWctp = outp->wctp;
7329 smbp = (smb_t *) &outp->data;
7330 if (code != CM_ERROR_PARTIALWRITE
7331 && code != CM_ERROR_BUFFERTOOSMALL
7332 && code != CM_ERROR_GSSCONTINUE) {
7333 /* nuke wct and bcc. For a partial
7334 * write or an in-process authentication handshake,
7335 * assume they're OK.
7341 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7342 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7343 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7344 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7345 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7349 smb_MapCoreError(code, vcp, &errCode, &errClass);
7350 outWctp = outp->wctp;
7351 smbp = (smb_t *) &outp->data;
7352 if (code != CM_ERROR_PARTIALWRITE) {
7353 /* nuke wct and bcc. For a partial
7354 * write, assume they're OK.
7360 smbp->errLow = (unsigned char) (errCode & 0xff);
7361 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7362 smbp->rcls = errClass;
7365 } /* error occurred */
7367 /* if we're here, we've finished one request. Look to see if
7368 * this is a chained opcode. If it is, setup things to process
7369 * the chained request, and setup the output buffer to hold the
7370 * chained response. Start by finding the next input record.
7372 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7373 break; /* not a chained req */
7374 tp = inp->wctp; /* points to start of last request */
7375 /* in a chained request, the first two
7376 * parm fields are required, and are
7377 * AndXCommand/AndXReserved and
7379 if (tp[0] < 2) break;
7380 if (tp[1] == 0xff) break; /* no more chained opcodes */
7382 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7385 /* and now append the next output request to the end of this
7386 * last request. Begin by finding out where the last response
7387 * ends, since that's where we'll put our new response.
7389 outWctp = outp->wctp; /* ptr to out parameters */
7390 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7391 nparms = outWctp[0] << 1;
7392 tp = outWctp + nparms + 1; /* now points to bcc field */
7393 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7394 tp += 2 /* for the count itself */ + nbytes;
7395 /* tp now points to the new output record; go back and patch the
7396 * second parameter (off2) to point to the new record.
7398 temp = (unsigned int)(tp - outp->data);
7399 outWctp[3] = (unsigned char) (temp & 0xff);
7400 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7401 outWctp[2] = 0; /* padding */
7402 outWctp[1] = inp->inCom; /* next opcode */
7404 /* finally, setup for the next iteration */
7407 } /* while loop over all requests in the packet */
7409 /* now send the output packet, and return */
7411 smb_SendPacket(vcp, outp);
7412 thrd_Decrement(&ongoingOps);
7417 /* Wait for Netbios() calls to return, and make the results available to server
7418 * threads. Note that server threads can't wait on the NCBevents array
7419 * themselves, because NCB events are manual-reset, and the servers would race
7420 * each other to reset them.
7422 void smb_ClientWaiter(void *parmp)
7427 while (smbShutdownFlag == 0) {
7428 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7430 if (code == WAIT_OBJECT_0)
7433 /* error checking */
7434 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7436 int abandonIdx = code - WAIT_ABANDONED_0;
7437 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7440 if (code == WAIT_IO_COMPLETION)
7442 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7446 if (code == WAIT_TIMEOUT)
7448 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7451 if (code == WAIT_FAILED)
7453 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7456 idx = code - WAIT_OBJECT_0;
7458 /* check idx range! */
7459 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7461 /* this is fatal - log as much as possible */
7462 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7466 thrd_ResetEvent(NCBevents[idx]);
7467 thrd_SetEvent(NCBreturns[0][idx]);
7472 * Try to have one NCBRECV request waiting for every live session. Not more
7473 * than one, because if there is more than one, it's hard to handle Write Raw.
7475 void smb_ServerWaiter(void *parmp)
7478 int idx_session, idx_NCB;
7481 while (smbShutdownFlag == 0) {
7483 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7485 if (code == WAIT_OBJECT_0)
7488 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7490 int abandonIdx = code - WAIT_ABANDONED_0;
7491 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7494 if (code == WAIT_IO_COMPLETION)
7496 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7500 if (code == WAIT_TIMEOUT)
7502 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7505 if (code == WAIT_FAILED)
7507 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7510 idx_session = code - WAIT_OBJECT_0;
7512 /* check idx range! */
7513 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7515 /* this is fatal - log as much as possible */
7516 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7522 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7524 if (code == WAIT_OBJECT_0) {
7525 if (smbShutdownFlag == 1)
7531 /* error checking */
7532 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7534 int abandonIdx = code - WAIT_ABANDONED_0;
7535 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7538 if (code == WAIT_IO_COMPLETION)
7540 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7544 if (code == WAIT_TIMEOUT)
7546 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7549 if (code == WAIT_FAILED)
7551 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7554 idx_NCB = code - WAIT_OBJECT_0;
7556 /* check idx range! */
7557 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7559 /* this is fatal - log as much as possible */
7560 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7564 /* Link them together */
7565 NCBsessions[idx_NCB] = idx_session;
7568 ncbp = NCBs[idx_NCB];
7569 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7570 ncbp->ncb_command = NCBRECV | ASYNCH;
7571 ncbp->ncb_lana_num = lanas[idx_session];
7572 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7573 ncbp->ncb_event = NCBevents[idx_NCB];
7574 ncbp->ncb_length = SMB_PACKETSIZE;
7580 * The top level loop for handling SMB request messages. Each server thread
7581 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7582 * NCB and buffer for the incoming request are loaned to us.
7584 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7585 * to immediately send a request for the rest of the data. This must come
7586 * before any other traffic for that session, so we delay setting the session
7587 * event until that data has come in.
7589 void smb_Server(VOID *parmp)
7591 INT_PTR myIdx = (INT_PTR) parmp;
7595 smb_packet_t *outbufp;
7597 int idx_NCB, idx_session;
7599 smb_vc_t *vcp = NULL;
7602 rx_StartClientThread();
7605 outbufp = GetPacket();
7606 outbufp->ncbp = outncbp;
7614 smb_ResetServerPriority();
7616 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7619 /* terminate silently if shutdown flag is set */
7620 if (code == WAIT_OBJECT_0) {
7621 if (smbShutdownFlag == 1) {
7622 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7628 /* error checking */
7629 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7631 int abandonIdx = code - WAIT_ABANDONED_0;
7632 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7635 if (code == WAIT_IO_COMPLETION)
7637 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7641 if (code == WAIT_TIMEOUT)
7643 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7646 if (code == WAIT_FAILED)
7648 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7651 idx_NCB = code - WAIT_OBJECT_0;
7653 /* check idx range! */
7654 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7656 /* this is fatal - log as much as possible */
7657 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7661 ncbp = NCBs[idx_NCB];
7662 idx_session = NCBsessions[idx_NCB];
7663 rc = ncbp->ncb_retcode;
7665 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7666 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7670 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7674 /* Can this happen? Or is it just my UNIX paranoia? */
7675 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7680 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7683 /* Client closed session */
7684 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7686 lock_ObtainMutex(&vcp->mx);
7687 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7688 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7690 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7691 lock_ReleaseMutex(&vcp->mx);
7692 lock_ObtainWrite(&smb_globalLock);
7693 dead_sessions[vcp->session] = TRUE;
7694 lock_ReleaseWrite(&smb_globalLock);
7695 smb_CleanupDeadVC(vcp);
7699 lock_ReleaseMutex(&vcp->mx);
7705 /* Treat as transient error */
7706 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7709 "dispatch smb recv failed, message incomplete, ncb_length %d",
7712 "SMB message incomplete, "
7713 "length %d", ncbp->ncb_length);
7716 * We used to discard the packet.
7717 * Instead, try handling it normally.
7721 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7725 /* A weird error code. Log it, sleep, and continue. */
7726 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7728 lock_ObtainMutex(&vcp->mx);
7729 if (vcp && vcp->errorCount++ > 3) {
7730 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7731 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7732 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7734 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7735 lock_ReleaseMutex(&vcp->mx);
7736 lock_ObtainWrite(&smb_globalLock);
7737 dead_sessions[vcp->session] = TRUE;
7738 lock_ReleaseWrite(&smb_globalLock);
7739 smb_CleanupDeadVC(vcp);
7743 lock_ReleaseMutex(&vcp->mx);
7749 lock_ReleaseMutex(&vcp->mx);
7751 thrd_SetEvent(SessionEvents[idx_session]);
7756 /* Success, so now dispatch on all the data in the packet */
7758 smb_concurrentCalls++;
7759 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7760 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7763 * If at this point vcp is NULL (implies that packet was invalid)
7764 * then we are in big trouble. This means either :
7765 * a) we have the wrong NCB.
7766 * b) Netbios screwed up the call.
7767 * c) The VC was already marked dead before we were able to
7769 * Obviously this implies that
7770 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7771 * lanas[idx_session] != ncbp->ncb_lana_num )
7772 * Either way, we can't do anything with this packet.
7773 * Log, sleep and resume.
7776 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7780 ncbp->ncb_lana_num);
7782 /* Also log in the trace log. */
7783 osi_Log4(smb_logp, "Server: VCP does not exist!"
7784 "LSNs[idx_session]=[%d],"
7785 "lanas[idx_session]=[%d],"
7786 "ncbp->ncb_lsn=[%d],"
7787 "ncbp->ncb_lana_num=[%d]",
7791 ncbp->ncb_lana_num);
7793 /* thrd_Sleep(1000); Don't bother sleeping */
7794 thrd_SetEvent(SessionEvents[idx_session]);
7795 smb_concurrentCalls--;
7799 smb_SetRequestStartTime();
7801 vcp->errorCount = 0;
7802 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7803 smbp = (smb_t *)bufp->data;
7808 if (smbp->com == 0x1d) {
7809 /* Special handling for Write Raw */
7810 raw_write_cont_t rwc;
7811 EVENT_HANDLE rwevent;
7812 char eventName[MAX_PATH];
7814 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7815 if (rwc.code == 0) {
7816 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7817 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7818 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7819 ncbp->ncb_command = NCBRECV | ASYNCH;
7820 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7821 ncbp->ncb_lana_num = vcp->lana;
7822 ncbp->ncb_buffer = rwc.buf;
7823 ncbp->ncb_length = 65535;
7824 ncbp->ncb_event = rwevent;
7826 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7827 thrd_CloseHandle(rwevent);
7829 thrd_SetEvent(SessionEvents[idx_session]);
7831 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7833 else if (smbp->com == 0xa0) {
7835 * Serialize the handling for NT Transact
7838 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7839 thrd_SetEvent(SessionEvents[idx_session]);
7841 thrd_SetEvent(SessionEvents[idx_session]);
7842 /* TODO: what else needs to be serialized? */
7843 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7846 __except( smb_ServerExceptionFilter() ) {
7849 smb_concurrentCalls--;
7852 thrd_SetEvent(NCBavails[idx_NCB]);
7859 * Exception filter for the server threads. If an exception occurs in the
7860 * dispatch routines, which is where exceptions are most common, then do a
7861 * force trace and give control to upstream exception handlers. Useful for
7864 DWORD smb_ServerExceptionFilter(void) {
7865 /* While this is not the best time to do a trace, if it succeeds, then
7866 * we have a trace (assuming tracing was enabled). Otherwise, this should
7867 * throw a second exception.
7869 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7870 afsd_ForceTrace(TRUE);
7871 buf_ForceTrace(TRUE);
7872 return EXCEPTION_CONTINUE_SEARCH;
7876 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7877 * If the number of server threads is M, and the number of live sessions is
7878 * N, then the number of NCB's in use at any time either waiting for, or
7879 * holding, received messages is M + N, so that is how many NCB's get created.
7881 void InitNCBslot(int idx)
7883 struct smb_packet *bufp;
7884 EVENT_HANDLE retHandle;
7886 char eventName[MAX_PATH];
7888 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7890 NCBs[idx] = GetNCB();
7891 sprintf(eventName,"NCBavails[%d]", idx);
7892 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7893 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7894 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7895 sprintf(eventName,"NCBevents[%d]", idx);
7896 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7897 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7898 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7899 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7900 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7901 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7902 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7903 for (i=0; i<smb_NumServerThreads; i++)
7904 NCBreturns[i][idx] = retHandle;
7906 bufp->spacep = cm_GetSpace();
7910 /* listen for new connections */
7911 void smb_Listener(void *parmp)
7917 int session, thread;
7918 smb_vc_t *vcp = NULL;
7920 char rname[NCBNAMSZ+1];
7921 char cname[MAX_COMPUTERNAME_LENGTH+1];
7922 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7923 INT_PTR lana = (INT_PTR) parmp;
7927 /* retrieve computer name */
7928 GetComputerName(cname, &cnamelen);
7931 while (smb_ListenerState == SMB_LISTENER_STARTED) {
7932 memset(ncbp, 0, sizeof(NCB));
7935 ncbp->ncb_command = NCBLISTEN;
7936 ncbp->ncb_rto = 0; /* No receive timeout */
7937 ncbp->ncb_sto = 0; /* No send timeout */
7939 /* pad out with spaces instead of null termination */
7940 len = (long)strlen(smb_localNamep);
7941 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7942 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7944 strcpy(ncbp->ncb_callname, "*");
7945 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7947 ncbp->ncb_lana_num = (UCHAR)lana;
7949 code = Netbios(ncbp);
7951 if (code == NRC_BRIDGE) {
7952 int lanaRemaining = 0;
7954 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
7959 "NCBLISTEN lana=%d failed with NRC_BRIDGE. Listener thread exiting.",
7960 ncbp->ncb_lana_num, code);
7962 for (i = 0; i < lana_list.length; i++) {
7963 if (lana_list.lana[i] == ncbp->ncb_lana_num) {
7964 smb_StopListener(ncbp, lana_list.lana[i]);
7965 lana_list.lana[i] = 255;
7967 if (lana_list.lana[i] != 255)
7971 if (lanaRemaining == 0) {
7972 cm_VolStatus_Network_Stopped(cm_NetbiosName
7977 smb_ListenerState = SMB_LISTENER_STOPPED;
7978 smb_LANadapter = -1;
7979 lana_list.length = 0;
7983 } else if (code != 0) {
7986 /* terminate silently if shutdown flag is set */
7987 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
7992 "NCBLISTEN lana=%d failed with code %d",
7993 ncbp->ncb_lana_num, code);
7995 "Client exiting due to network failure. Please restart client.\n");
7998 "Client exiting due to network failure. Please restart client.\n"
7999 "NCBLISTEN lana=%d failed with code %d",
8000 ncbp->ncb_lana_num, code);
8002 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8003 MB_OK|MB_SERVICE_NOTIFICATION);
8004 osi_panic(tbuffer, __FILE__, __LINE__);
8007 /* check for remote conns */
8008 /* first get remote name and insert null terminator */
8009 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8010 for (i=NCBNAMSZ; i>0; i--) {
8011 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8017 /* compare with local name */
8019 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8020 flags |= SMB_VCFLAG_REMOTECONN;
8023 lock_ObtainMutex(&smb_ListenerLock);
8025 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8026 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8028 /* now ncbp->ncb_lsn is the connection ID */
8029 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8030 if (vcp->session == 0) {
8031 /* New generation */
8032 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8035 /* Log session startup */
8037 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8038 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8039 #endif /* NOTSERVICE */
8040 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8041 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8043 if (reportSessionStartups) {
8044 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8047 lock_ObtainMutex(&vcp->mx);
8048 strcpy(vcp->rname, rname);
8049 vcp->flags |= flags;
8050 lock_ReleaseMutex(&vcp->mx);
8052 /* Allocate slot in session arrays */
8053 /* Re-use dead session if possible, otherwise add one more */
8054 /* But don't look at session[0], it is reserved */
8055 lock_ObtainWrite(&smb_globalLock);
8056 for (session = 1; session < numSessions; session++) {
8057 if (dead_sessions[session]) {
8058 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8059 dead_sessions[session] = FALSE;
8063 lock_ReleaseWrite(&smb_globalLock);
8065 /* We are re-using an existing VC because the lsn and lana
8067 session = vcp->session;
8069 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8071 /* Log session startup */
8073 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8074 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8075 #endif /* NOTSERVICE */
8076 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8077 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8079 if (reportSessionStartups) {
8080 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8084 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8085 unsigned long code = CM_ERROR_ALLBUSY;
8086 smb_packet_t * outp = GetPacket();
8087 unsigned char *outWctp;
8090 smb_FormatResponsePacket(vcp, NULL, outp);
8093 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8094 unsigned long NTStatus;
8095 smb_MapNTError(code, &NTStatus);
8096 outWctp = outp->wctp;
8097 smbp = (smb_t *) &outp->data;
8101 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8102 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8103 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8104 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8105 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8107 unsigned short errCode;
8108 unsigned char errClass;
8109 smb_MapCoreError(code, vcp, &errCode, &errClass);
8110 outWctp = outp->wctp;
8111 smbp = (smb_t *) &outp->data;
8115 smbp->errLow = (unsigned char) (errCode & 0xff);
8116 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8117 smbp->rcls = errClass;
8119 smb_SendPacket(vcp, outp);
8120 smb_FreePacket(outp);
8122 lock_ObtainMutex(&vcp->mx);
8123 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8124 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8126 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8127 lock_ReleaseMutex(&vcp->mx);
8128 lock_ObtainWrite(&smb_globalLock);
8129 dead_sessions[vcp->session] = TRUE;
8130 lock_ReleaseWrite(&smb_globalLock);
8131 smb_CleanupDeadVC(vcp);
8133 lock_ReleaseMutex(&vcp->mx);
8136 /* assert that we do not exceed the maximum number of sessions or NCBs.
8137 * we should probably want to wait for a session to be freed in case
8140 osi_assert(session < SESSION_MAX - 1);
8141 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8143 lock_ObtainMutex(&vcp->mx);
8144 vcp->session = session;
8145 lock_ReleaseMutex(&vcp->mx);
8146 lock_ObtainWrite(&smb_globalLock);
8147 LSNs[session] = ncbp->ncb_lsn;
8148 lanas[session] = ncbp->ncb_lana_num;
8149 lock_ReleaseWrite(&smb_globalLock);
8151 if (session == numSessions) {
8152 /* Add new NCB for new session */
8153 char eventName[MAX_PATH];
8155 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8157 InitNCBslot(numNCBs);
8158 lock_ObtainWrite(&smb_globalLock);
8160 lock_ReleaseWrite(&smb_globalLock);
8161 thrd_SetEvent(NCBavails[0]);
8162 thrd_SetEvent(NCBevents[0]);
8163 for (thread = 0; thread < smb_NumServerThreads; thread++)
8164 thrd_SetEvent(NCBreturns[thread][0]);
8165 /* Also add new session event */
8166 sprintf(eventName, "SessionEvents[%d]", session);
8167 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8168 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8169 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8170 lock_ObtainWrite(&smb_globalLock);
8172 lock_ReleaseWrite(&smb_globalLock);
8173 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8174 thrd_SetEvent(SessionEvents[0]);
8176 thrd_SetEvent(SessionEvents[session]);
8182 lock_ReleaseMutex(&smb_ListenerLock);
8183 } /* dispatch while loop */
8188 /* initialize Netbios */
8189 int smb_NetbiosInit(void)
8192 int i, lana, code, l;
8194 int delname_tried=0;
8197 lana_number_t lanaNum;
8199 /* setup the NCB system */
8202 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8203 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8204 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8206 if (smb_LANadapter != -1)
8207 afsi_log("LAN adapter number %d", smb_LANadapter);
8209 afsi_log("LAN adapter number not determined");
8212 afsi_log("Set for gateway service");
8214 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8216 /* something went horribly wrong. We can't proceed without a netbios name */
8218 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8219 osi_panic(buf, __FILE__, __LINE__);
8222 /* remember the name */
8223 len = (int)strlen(cm_NetbiosName);
8225 free(smb_localNamep);
8226 smb_localNamep = malloc(len+1);
8227 strcpy(smb_localNamep, cm_NetbiosName);
8228 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8231 if (smb_LANadapter == -1) {
8232 ncbp->ncb_command = NCBENUM;
8233 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8234 ncbp->ncb_length = sizeof(lana_list);
8235 code = Netbios(ncbp);
8237 afsi_log("Netbios NCBENUM error code %d", code);
8238 osi_panic(s, __FILE__, __LINE__);
8242 lana_list.length = 1;
8243 lana_list.lana[0] = smb_LANadapter;
8246 for (i = 0; i < lana_list.length; i++) {
8247 /* reset the adaptor: in Win32, this is required for every process, and
8248 * acts as an init call, not as a real hardware reset.
8250 ncbp->ncb_command = NCBRESET;
8251 ncbp->ncb_callname[0] = 100;
8252 ncbp->ncb_callname[2] = 100;
8253 ncbp->ncb_lana_num = lana_list.lana[i];
8254 code = Netbios(ncbp);
8256 code = ncbp->ncb_retcode;
8258 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8259 lana_list.lana[i] = 255; /* invalid lana */
8261 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8265 /* and declare our name so we can receive connections */
8266 memset(ncbp, 0, sizeof(*ncbp));
8267 len=lstrlen(smb_localNamep);
8268 memset(smb_sharename,' ',NCBNAMSZ);
8269 memcpy(smb_sharename,smb_localNamep,len);
8270 afsi_log("lana_list.length %d", lana_list.length);
8272 /* Keep the name so we can unregister it later */
8273 for (l = 0; l < lana_list.length; l++) {
8274 lana = lana_list.lana[l];
8276 ncbp->ncb_command = NCBADDNAME;
8277 ncbp->ncb_lana_num = lana;
8278 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8279 code = Netbios(ncbp);
8281 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8282 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8284 char name[NCBNAMSZ+1];
8286 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8287 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8291 code = ncbp->ncb_retcode;
8294 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8297 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8298 if (code == NRC_BRIDGE) { /* invalid LANA num */
8299 lana_list.lana[l] = 255;
8302 else if (code == NRC_DUPNAME) {
8303 afsi_log("Name already exists; try to delete it");
8304 memset(ncbp, 0, sizeof(*ncbp));
8305 ncbp->ncb_command = NCBDELNAME;
8306 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8307 ncbp->ncb_lana_num = lana;
8308 code = Netbios(ncbp);
8310 code = ncbp->ncb_retcode;
8312 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8314 if (code != 0 || delname_tried) {
8315 lana_list.lana[l] = 255;
8317 else if (code == 0) {
8318 if (!delname_tried) {
8326 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8327 lana_list.lana[l] = 255; /* invalid lana */
8331 lana_found = 1; /* at least one worked */
8335 osi_assert(lana_list.length >= 0);
8337 afsi_log("No valid LANA numbers found!");
8338 lana_list.length = 0;
8339 smb_LANadapter = -1;
8340 smb_ListenerState = SMB_LISTENER_STOPPED;
8341 cm_VolStatus_Network_Stopped(cm_NetbiosName
8348 /* we're done with the NCB now */
8351 return (lana_list.length > 0 ? 1 : 0);
8354 void smb_StartListeners()
8360 if (smb_ListenerState == SMB_LISTENER_STARTED)
8363 smb_ListenerState = SMB_LISTENER_STARTED;
8364 cm_VolStatus_Network_Started(cm_NetbiosName
8370 for (i = 0; i < lana_list.length; i++) {
8371 if (lana_list.lana[i] == 255)
8373 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8374 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8375 osi_assert(phandle != NULL);
8376 thrd_CloseHandle(phandle);
8380 void smb_RestartListeners()
8382 if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
8383 if (smb_NetbiosInit())
8384 smb_StartListeners();
8388 void smb_StopListener(NCB *ncbp, int lana)
8392 memset(ncbp, 0, sizeof(*ncbp));
8393 ncbp->ncb_command = NCBDELNAME;
8394 ncbp->ncb_lana_num = lana;
8395 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8396 code = Netbios(ncbp);
8398 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8399 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8401 /* and then reset the LANA; this will cause the listener threads to exit */
8402 ncbp->ncb_command = NCBRESET;
8403 ncbp->ncb_callname[0] = 100;
8404 ncbp->ncb_callname[2] = 100;
8405 ncbp->ncb_lana_num = lana;
8406 code = Netbios(ncbp);
8408 code = ncbp->ncb_retcode;
8410 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8412 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8416 void smb_StopListeners(void)
8421 if (smb_ListenerState == SMB_LISTENER_STOPPED)
8424 smb_ListenerState = SMB_LISTENER_STOPPED;
8425 cm_VolStatus_Network_Stopped(cm_NetbiosName
8433 /* Unregister the SMB name */
8434 for (l = 0; l < lana_list.length; l++) {
8435 lana = lana_list.lana[l];
8438 smb_StopListener(ncbp, lana);
8440 /* mark the adapter invalid */
8441 lana_list.lana[l] = 255; /* invalid lana */
8445 /* force a re-evaluation of the network adapters */
8446 lana_list.length = 0;
8447 smb_LANadapter = -1;
8449 Sleep(1000); /* give the listener threads a chance to exit */
8452 void smb_Init(osi_log_t *logp, int useV3,
8462 EVENT_HANDLE retHandle;
8463 char eventName[MAX_PATH];
8465 smb_TlsRequestSlot = TlsAlloc();
8467 smb_MBfunc = aMBfunc;
8471 /* Initialize smb_localZero */
8472 myTime.tm_isdst = -1; /* compute whether on DST or not */
8473 myTime.tm_year = 70;
8479 smb_localZero = mktime(&myTime);
8481 #ifndef USE_NUMERIC_TIME_CONV
8482 /* Initialize kludge-GMT */
8483 smb_CalculateNowTZ();
8484 #endif /* USE_NUMERIC_TIME_CONV */
8485 #ifdef AFS_FREELANCE_CLIENT
8486 /* Make sure the root.afs volume has the correct time */
8487 cm_noteLocalMountPointChange();
8490 /* initialize the remote debugging log */
8493 /* and the global lock */
8494 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8495 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8497 /* Raw I/O data structures */
8498 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8500 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8502 /* 4 Raw I/O buffers */
8503 smb_RawBufs = calloc(65536,1);
8504 *((char **)smb_RawBufs) = NULL;
8505 for (i=0; i<3; i++) {
8506 char *rawBuf = calloc(65536,1);
8507 *((char **)rawBuf) = smb_RawBufs;
8508 smb_RawBufs = rawBuf;
8511 /* global free lists */
8512 smb_ncbFreeListp = NULL;
8513 smb_packetFreeListp = NULL;
8517 /* Initialize listener and server structures */
8519 memset(dead_sessions, 0, sizeof(dead_sessions));
8520 sprintf(eventName, "SessionEvents[0]");
8521 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8522 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8523 afsi_log("Event Object Already Exists: %s", eventName);
8525 smb_NumServerThreads = nThreads;
8526 sprintf(eventName, "NCBavails[0]");
8527 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8528 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8529 afsi_log("Event Object Already Exists: %s", eventName);
8530 sprintf(eventName, "NCBevents[0]");
8531 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8532 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8533 afsi_log("Event Object Already Exists: %s", eventName);
8534 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8535 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8536 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8537 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8538 afsi_log("Event Object Already Exists: %s", eventName);
8539 for (i = 0; i < smb_NumServerThreads; i++) {
8540 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8541 NCBreturns[i][0] = retHandle;
8544 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8545 for (i = 0; i < smb_NumServerThreads; i++) {
8546 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8547 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8548 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8549 afsi_log("Event Object Already Exists: %s", eventName);
8550 InitNCBslot((int)(i+1));
8552 numNCBs = smb_NumServerThreads + 1;
8554 /* Initialize dispatch table */
8555 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8556 /* Prepare the table for unknown operations */
8557 for(i=0; i<= SMB_NOPCODES; i++) {
8558 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8560 /* Fill in the ones we do know */
8561 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8562 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8563 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8564 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8565 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8566 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8567 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8568 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8569 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8570 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8571 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8572 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8573 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8574 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8575 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8576 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8577 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8578 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8579 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8580 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8581 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8582 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8583 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8584 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8585 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8586 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8587 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8588 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8589 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8590 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8591 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8592 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8593 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8594 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8595 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8596 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8597 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8598 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8599 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8600 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8601 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8602 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8603 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8604 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8605 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8606 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8607 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8608 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8609 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8610 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8611 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8612 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8613 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8614 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8615 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8616 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8617 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8618 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8619 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8620 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8621 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8622 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8623 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8624 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8625 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8626 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8627 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8628 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8629 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8630 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8631 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8632 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8633 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8634 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8636 /* setup tran 2 dispatch table */
8637 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8638 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8639 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8640 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8641 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8642 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8643 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8644 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8645 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8646 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8647 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8648 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8649 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8650 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8651 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8652 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8653 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8654 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8656 /* setup the rap dispatch table */
8657 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8658 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8659 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8660 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8661 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8665 /* if we are doing SMB authentication we have register outselves as a logon process */
8666 if (smb_authType != SMB_AUTH_NONE) {
8667 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8668 LSA_STRING afsProcessName;
8669 LSA_OPERATIONAL_MODE dummy; /*junk*/
8671 afsProcessName.Buffer = "OpenAFSClientDaemon";
8672 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8673 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8675 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8677 if (nts == STATUS_SUCCESS) {
8678 LSA_STRING packageName;
8679 /* we are registered. Find out the security package id */
8680 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8681 packageName.Length = (USHORT)strlen(packageName.Buffer);
8682 packageName.MaximumLength = packageName.Length + 1;
8683 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8684 if (nts == STATUS_SUCCESS) {
8686 * This code forces Windows to authenticate against the Logon Cache
8687 * first instead of attempting to authenticate against the Domain
8688 * Controller. When the Windows logon cache is enabled this improves
8689 * performance by removing the network access and works around a bug
8690 * seen at sites which are using a MIT Kerberos principal to login
8691 * to machines joined to a non-root domain in a multi-domain forest.
8692 * MsV1_0SetProcessOption was added in Windows XP.
8694 PVOID pResponse = NULL;
8695 ULONG cbResponse = 0;
8696 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8698 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8699 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8700 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8701 OptionsRequest.DisableOptions = FALSE;
8703 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8706 sizeof(OptionsRequest),
8712 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8714 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8716 OutputDebugString(message);
8719 OutputDebugString("MsV1_0SetProcessOption success");
8720 afsi_log("MsV1_0SetProcessOption success");
8722 /* END - code from Larry */
8724 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8725 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8726 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8728 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8730 /* something went wrong. We report the error and revert back to no authentication
8731 because we can't perform any auth requests without a successful lsa handle
8732 or sec package id. */
8733 afsi_log("Reverting to NO SMB AUTH");
8734 smb_authType = SMB_AUTH_NONE;
8737 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8739 /* something went wrong. We report the error and revert back to no authentication
8740 because we can't perform any auth requests without a successful lsa handle
8741 or sec package id. */
8742 afsi_log("Reverting to NO SMB AUTH");
8743 smb_authType = SMB_AUTH_NONE;
8747 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8748 * time prevents the failure of authentication when logged into Windows with an
8749 * external Kerberos principal mapped to a local account.
8751 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8752 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8753 * then the only option is NTLMSSP anyway; so just fallback.
8758 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8759 if (secBlobLength == 0) {
8760 smb_authType = SMB_AUTH_NTLM;
8761 afsi_log("Reverting to SMB AUTH NTLM");
8770 /* Now get ourselves a domain name. */
8771 /* For now we are using the local computer name as the domain name.
8772 * It is actually the domain for local logins, and we are acting as
8773 * a local SMB server.
8775 bufsize = sizeof(smb_ServerDomainName) - 1;
8776 GetComputerName(smb_ServerDomainName, &bufsize);
8777 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8778 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8781 /* Start listeners, waiters, servers, and daemons */
8783 smb_StartListeners();
8785 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8786 NULL, 0, &lpid, "smb_ClientWaiter");
8787 osi_assert(phandle != NULL);
8788 thrd_CloseHandle(phandle);
8790 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8791 NULL, 0, &lpid, "smb_ServerWaiter");
8792 osi_assert(phandle != NULL);
8793 thrd_CloseHandle(phandle);
8795 for (i=0; i<smb_NumServerThreads; i++) {
8796 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8797 (void *) i, 0, &lpid, "smb_Server");
8798 osi_assert(phandle != NULL);
8799 thrd_CloseHandle(phandle);
8802 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8803 NULL, 0, &lpid, "smb_Daemon");
8804 osi_assert(phandle != NULL);
8805 thrd_CloseHandle(phandle);
8807 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8808 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8809 osi_assert(phandle != NULL);
8810 thrd_CloseHandle(phandle);
8815 void smb_Shutdown(void)
8822 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8824 /* setup the NCB system */
8827 /* Block new sessions by setting shutdown flag */
8828 smbShutdownFlag = 1;
8830 /* Hang up all sessions */
8831 memset((char *)ncbp, 0, sizeof(NCB));
8832 for (i = 1; i < numSessions; i++)
8834 if (dead_sessions[i])
8837 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8838 ncbp->ncb_command = NCBHANGUP;
8839 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8840 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8841 code = Netbios(ncbp);
8842 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8843 if (code == 0) code = ncbp->ncb_retcode;
8845 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8846 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8850 /* Trigger the shutdown of all SMB threads */
8851 for (i = 0; i < smb_NumServerThreads; i++)
8852 thrd_SetEvent(NCBreturns[i][0]);
8854 thrd_SetEvent(NCBevents[0]);
8855 thrd_SetEvent(SessionEvents[0]);
8856 thrd_SetEvent(NCBavails[0]);
8858 for (i = 0;i < smb_NumServerThreads; i++) {
8859 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8860 if (code == WAIT_OBJECT_0) {
8863 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8864 thrd_SetEvent(NCBreturns[i--][0]);
8868 /* Delete Netbios name */
8869 memset((char *)ncbp, 0, sizeof(NCB));
8870 for (i = 0; i < lana_list.length; i++) {
8871 if (lana_list.lana[i] == 255) continue;
8872 ncbp->ncb_command = NCBDELNAME;
8873 ncbp->ncb_lana_num = lana_list.lana[i];
8874 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8875 code = Netbios(ncbp);
8877 code = ncbp->ncb_retcode;
8879 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8880 ncbp->ncb_lana_num, code);
8885 /* Release the reference counts held by the VCs */
8886 lock_ObtainWrite(&smb_rctLock);
8887 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8892 if (vcp->magic != SMB_VC_MAGIC)
8893 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8894 __FILE__, __LINE__);
8896 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8898 if (fidp->scp != NULL) {
8901 lock_ObtainMutex(&fidp->mx);
8902 if (fidp->scp != NULL) {
8905 lock_ObtainMutex(&scp->mx);
8906 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
8907 lock_ReleaseMutex(&scp->mx);
8908 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
8909 cm_ReleaseSCache(scp);
8911 lock_ReleaseMutex(&fidp->mx);
8915 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8917 smb_ReleaseVCNoLock(tidp->vcp);
8919 cm_user_t *userp = tidp->userp;
8921 lock_ReleaseWrite(&smb_rctLock);
8922 cm_ReleaseUser(userp);
8923 lock_ObtainWrite(&smb_rctLock);
8927 lock_ReleaseWrite(&smb_rctLock);
8929 TlsFree(smb_TlsRequestSlot);
8932 /* Get the UNC \\<servername>\<sharename> prefix. */
8933 char *smb_GetSharename()
8937 /* Make sure we have been properly initialized. */
8938 if (smb_localNamep == NULL)
8941 /* Allocate space for \\<servername>\<sharename>, plus the
8944 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8945 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8951 void smb_LogPacket(smb_packet_t *packet)
8954 unsigned length, paramlen, datalen, i, j;
8956 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8958 if (!packet) return;
8960 osi_Log0(smb_logp, "*** SMB packet dump ***");
8962 vp = (BYTE *) packet->data;
8964 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8965 length = paramlen + 2 + datalen;
8968 for (i=0;i < length; i+=16)
8970 memset( buf, ' ', 80 );
8975 buf[strlen(buf)] = ' ';
8977 cp = (BYTE*) buf + 7;
8979 for (j=0;j < 16 && (i+j)<length; j++)
8981 *(cp++) = hex[vp[i+j] >> 4];
8982 *(cp++) = hex[vp[i+j] & 0xf];
8992 for (j=0;j < 16 && (i+j)<length;j++)
8994 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9005 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9008 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9010 #endif /* LOG_PACKET */
9013 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9021 lock_ObtainRead(&smb_rctLock);
9023 sprintf(output, "begin dumping smb_vc_t\r\n");
9024 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9026 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9030 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9031 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9032 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9034 sprintf(output, "begin dumping smb_fid_t\r\n");
9035 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9037 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9039 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",
9040 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9041 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9042 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9043 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9046 sprintf(output, "done dumping smb_fid_t\r\n");
9047 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9050 sprintf(output, "done dumping smb_vc_t\r\n");
9051 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9053 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9054 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9056 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9060 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9061 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9062 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9064 sprintf(output, "begin dumping smb_fid_t\r\n");
9065 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9067 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9069 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",
9070 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9071 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9072 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9073 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9076 sprintf(output, "done dumping smb_fid_t\r\n");
9077 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9080 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9081 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9084 lock_ReleaseRead(&smb_rctLock);
9088 long smb_IsNetworkStarted(void)
9090 return (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);