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 */
4905 cm_dirEntryList_t * matches;
4908 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4911 smb_unlinkRock_t *rockp;
4919 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4920 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4921 caseFold |= CM_FLAG_8DOT3;
4923 matchName = dep->name;
4924 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4926 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4927 !cm_Is8Dot3(dep->name)) {
4928 cm_Gen8Dot3Name(dep, shortName, NULL);
4929 matchName = shortName;
4930 /* 8.3 matches are always case insensitive */
4931 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4934 osi_Log1(smb_logp, "Found match %s",
4935 osi_LogSaveString(smb_logp, matchName));
4937 cm_DirEntryListAdd(dep->name, &rockp->matches);
4941 /* If we made a case sensitive exact match, we might as well quit now. */
4942 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4943 code = CM_ERROR_STOPNOW;
4952 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4961 smb_unlinkRock_t rock;
4970 attribute = smb_GetSMBParm(inp, 0);
4972 tp = smb_GetSMBData(inp, NULL);
4973 pathp = smb_ParseASCIIBlock(tp, &tp);
4974 if (smb_StoreAnsiFilenames)
4975 OemToChar(pathp,pathp);
4977 osi_Log1(smb_logp, "SMB receive unlink %s",
4978 osi_LogSaveString(smb_logp, pathp));
4980 spacep = inp->spacep;
4981 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4983 userp = smb_GetUserFromVCP(vcp, inp);
4985 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4987 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4989 cm_ReleaseUser(userp);
4990 return CM_ERROR_NOSUCHPATH;
4992 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4995 cm_ReleaseUser(userp);
5000 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5001 cm_ReleaseSCache(dscp);
5002 cm_ReleaseUser(userp);
5003 if ( WANTS_DFS_PATHNAMES(inp) )
5004 return CM_ERROR_PATH_NOT_COVERED;
5006 return CM_ERROR_BADSHARENAME;
5008 #endif /* DFS_SUPPORT */
5010 /* otherwise, scp points to the parent directory. */
5017 rock.maskp = smb_FindMask(pathp);
5018 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5021 thyper.HighPart = 0;
5026 rock.matches = NULL;
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 if (code == 0 && rock.matches) {
5048 cm_dirEntryList_t * entry;
5050 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5052 osi_Log1(smb_logp, "Unlinking %s",
5053 osi_LogSaveString(smb_logp, entry->name));
5054 code = cm_Unlink(dscp, entry->name, userp, &req);
5056 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5057 smb_NotifyChange(FILE_ACTION_REMOVED,
5058 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5059 dscp, entry->name, NULL, TRUE);
5063 cm_DirEntryListFree(&rock.matches);
5065 cm_ReleaseUser(userp);
5067 cm_ReleaseSCache(dscp);
5069 if (code == 0 && !rock.any)
5070 code = CM_ERROR_NOSUCHFILE;
5074 typedef struct smb_renameRock {
5075 cm_scache_t *odscp; /* old dir */
5076 cm_scache_t *ndscp; /* new dir */
5077 cm_user_t *userp; /* user */
5078 cm_req_t *reqp; /* request struct */
5079 smb_vc_t *vcp; /* virtual circuit */
5080 char *maskp; /* pointer to star pattern of old file name */
5081 int flags; /* tilde, casefold, etc */
5082 char *newNamep; /* ptr to the new file's name */
5083 char oldName[MAX_PATH];
5087 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5090 smb_renameRock_t *rockp;
5093 char shortName[13]="";
5095 rockp = (smb_renameRock_t *) vrockp;
5097 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5098 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5099 caseFold |= CM_FLAG_8DOT3;
5101 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5103 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5104 !cm_Is8Dot3(dep->name)) {
5105 cm_Gen8Dot3Name(dep, shortName, NULL);
5106 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5111 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5112 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5113 code = CM_ERROR_STOPNOW;
5123 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5126 cm_space_t *spacep = NULL;
5127 smb_renameRock_t rock;
5128 cm_scache_t *oldDscp = NULL;
5129 cm_scache_t *newDscp = NULL;
5130 cm_scache_t *tmpscp= NULL;
5131 cm_scache_t *tmpscp2 = NULL;
5141 userp = smb_GetUserFromVCP(vcp, inp);
5142 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5144 cm_ReleaseUser(userp);
5145 return CM_ERROR_NOSUCHPATH;
5149 spacep = inp->spacep;
5150 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5152 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5153 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5154 userp, tidPathp, &req, &oldDscp);
5156 cm_ReleaseUser(userp);
5161 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5162 cm_ReleaseSCache(oldDscp);
5163 cm_ReleaseUser(userp);
5164 if ( WANTS_DFS_PATHNAMES(inp) )
5165 return CM_ERROR_PATH_NOT_COVERED;
5167 return CM_ERROR_BADSHARENAME;
5169 #endif /* DFS_SUPPORT */
5171 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5172 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5173 userp, tidPathp, &req, &newDscp);
5176 cm_ReleaseSCache(oldDscp);
5177 cm_ReleaseUser(userp);
5182 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5183 cm_ReleaseSCache(oldDscp);
5184 cm_ReleaseSCache(newDscp);
5185 cm_ReleaseUser(userp);
5186 if ( WANTS_DFS_PATHNAMES(inp) )
5187 return CM_ERROR_PATH_NOT_COVERED;
5189 return CM_ERROR_BADSHARENAME;
5191 #endif /* DFS_SUPPORT */
5194 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5195 * next, get the component names, and lower case them.
5198 /* handle the old name first */
5200 oldLastNamep = oldPathp;
5204 /* and handle the new name, too */
5206 newLastNamep = newPathp;
5210 /* TODO: The old name could be a wildcard. The new name must not be */
5212 /* do the vnode call */
5213 rock.odscp = oldDscp;
5214 rock.ndscp = newDscp;
5218 rock.maskp = oldLastNamep;
5219 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5220 rock.newNamep = newLastNamep;
5221 rock.oldName[0] = '\0';
5224 /* Check if the file already exists; if so return error */
5225 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5226 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5227 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5228 osi_LogSaveString(smb_logp, newLastNamep));
5230 /* Check if the old and the new names differ only in case. If so return
5231 * success, else return CM_ERROR_EXISTS
5233 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5235 /* This would be a success only if the old file is *as same as* the new file */
5236 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5238 if (tmpscp == tmpscp2)
5241 code = CM_ERROR_EXISTS;
5242 cm_ReleaseSCache(tmpscp2);
5245 code = CM_ERROR_NOSUCHFILE;
5248 /* file exist, do not rename, also fixes move */
5249 osi_Log0(smb_logp, "Can't rename. Target already exists");
5250 code = CM_ERROR_EXISTS;
5254 cm_ReleaseSCache(tmpscp);
5255 cm_ReleaseSCache(newDscp);
5256 cm_ReleaseSCache(oldDscp);
5257 cm_ReleaseUser(userp);
5261 /* Now search the directory for the pattern, and do the appropriate rename when found */
5262 thyper.LowPart = 0; /* search dir from here */
5263 thyper.HighPart = 0;
5265 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5266 if (code == 0 && !rock.any) {
5268 thyper.HighPart = 0;
5269 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5270 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5272 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5274 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5275 code = cm_Rename(rock.odscp, rock.oldName,
5276 rock.ndscp, rock.newNamep, rock.userp,
5278 /* if the call worked, stop doing the search now, since we
5279 * really only want to rename one file.
5281 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5282 } else if (code == 0) {
5283 code = CM_ERROR_NOSUCHFILE;
5286 /* Handle Change Notification */
5288 * Being lazy, not distinguishing between files and dirs in this
5289 * filter, since we'd have to do a lookup.
5292 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5293 if (oldDscp == newDscp) {
5294 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5295 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5296 filter, oldDscp, oldLastNamep,
5297 newLastNamep, TRUE);
5299 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5300 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5301 filter, oldDscp, oldLastNamep,
5303 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5304 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5305 filter, newDscp, newLastNamep,
5310 cm_ReleaseSCache(tmpscp);
5311 cm_ReleaseUser(userp);
5312 cm_ReleaseSCache(oldDscp);
5313 cm_ReleaseSCache(newDscp);
5318 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5321 cm_space_t *spacep = NULL;
5322 cm_scache_t *oldDscp = NULL;
5323 cm_scache_t *newDscp = NULL;
5324 cm_scache_t *tmpscp= NULL;
5325 cm_scache_t *tmpscp2 = NULL;
5326 cm_scache_t *sscp = NULL;
5335 userp = smb_GetUserFromVCP(vcp, inp);
5337 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5339 cm_ReleaseUser(userp);
5340 return CM_ERROR_NOSUCHPATH;
5345 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5347 spacep = inp->spacep;
5348 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5350 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5351 userp, tidPathp, &req, &oldDscp);
5353 cm_ReleaseUser(userp);
5358 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5359 cm_ReleaseSCache(oldDscp);
5360 cm_ReleaseUser(userp);
5361 if ( WANTS_DFS_PATHNAMES(inp) )
5362 return CM_ERROR_PATH_NOT_COVERED;
5364 return CM_ERROR_BADSHARENAME;
5366 #endif /* DFS_SUPPORT */
5368 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5369 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5370 userp, tidPathp, &req, &newDscp);
5372 cm_ReleaseSCache(oldDscp);
5373 cm_ReleaseUser(userp);
5378 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5379 cm_ReleaseSCache(newDscp);
5380 cm_ReleaseSCache(oldDscp);
5381 cm_ReleaseUser(userp);
5382 if ( WANTS_DFS_PATHNAMES(inp) )
5383 return CM_ERROR_PATH_NOT_COVERED;
5385 return CM_ERROR_BADSHARENAME;
5387 #endif /* DFS_SUPPORT */
5389 /* Now, although we did two lookups for the two directories (because the same
5390 * directory can be referenced through different paths), we only allow hard links
5391 * within the same directory. */
5392 if (oldDscp != newDscp) {
5393 cm_ReleaseSCache(oldDscp);
5394 cm_ReleaseSCache(newDscp);
5395 cm_ReleaseUser(userp);
5396 return CM_ERROR_CROSSDEVLINK;
5399 /* handle the old name first */
5401 oldLastNamep = oldPathp;
5405 /* and handle the new name, too */
5407 newLastNamep = newPathp;
5411 /* now lookup the old name */
5412 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5413 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5415 cm_ReleaseSCache(oldDscp);
5416 cm_ReleaseSCache(newDscp);
5417 cm_ReleaseUser(userp);
5421 /* Check if the file already exists; if so return error */
5422 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5423 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
5424 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5425 osi_LogSaveString(smb_logp, newLastNamep));
5427 /* if the existing link is to the same file, then we return success */
5429 if(sscp == tmpscp) {
5432 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5433 code = CM_ERROR_EXISTS;
5438 cm_ReleaseSCache(tmpscp);
5439 cm_ReleaseSCache(sscp);
5440 cm_ReleaseSCache(newDscp);
5441 cm_ReleaseSCache(oldDscp);
5442 cm_ReleaseUser(userp);
5446 /* now create the hardlink */
5447 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5448 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5449 osi_Log1(smb_logp," Link returns 0x%x", code);
5451 /* Handle Change Notification */
5453 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5454 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5455 smb_NotifyChange(FILE_ACTION_ADDED,
5456 filter, newDscp, newLastNamep,
5462 cm_ReleaseSCache(tmpscp);
5463 cm_ReleaseUser(userp);
5464 cm_ReleaseSCache(sscp);
5465 cm_ReleaseSCache(oldDscp);
5466 cm_ReleaseSCache(newDscp);
5471 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5478 tp = smb_GetSMBData(inp, NULL);
5479 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5480 if (smb_StoreAnsiFilenames)
5481 OemToChar(oldPathp,oldPathp);
5482 newPathp = smb_ParseASCIIBlock(tp, &tp);
5483 if (smb_StoreAnsiFilenames)
5484 OemToChar(newPathp,newPathp);
5486 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5487 osi_LogSaveString(smb_logp, oldPathp),
5488 osi_LogSaveString(smb_logp, newPathp));
5490 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5492 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5498 typedef struct smb_rmdirRock {
5502 char *maskp; /* pointer to the star pattern */
5505 cm_dirEntryList_t * matches;
5508 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5511 smb_rmdirRock_t *rockp;
5516 rockp = (smb_rmdirRock_t *) vrockp;
5518 matchName = dep->name;
5519 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5520 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5522 match = (strcmp(matchName, rockp->maskp) == 0);
5524 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5525 !cm_Is8Dot3(dep->name)) {
5526 cm_Gen8Dot3Name(dep, shortName, NULL);
5527 matchName = shortName;
5528 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5533 cm_DirEntryListAdd(dep->name, &rockp->matches);
5539 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5547 smb_rmdirRock_t rock;
5556 tp = smb_GetSMBData(inp, NULL);
5557 pathp = smb_ParseASCIIBlock(tp, &tp);
5558 if (smb_StoreAnsiFilenames)
5559 OemToChar(pathp,pathp);
5561 spacep = inp->spacep;
5562 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5564 userp = smb_GetUserFromVCP(vcp, inp);
5566 caseFold = CM_FLAG_CASEFOLD;
5568 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5570 cm_ReleaseUser(userp);
5571 return CM_ERROR_NOSUCHPATH;
5573 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5574 userp, tidPathp, &req, &dscp);
5577 cm_ReleaseUser(userp);
5582 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5583 cm_ReleaseSCache(dscp);
5584 cm_ReleaseUser(userp);
5585 if ( WANTS_DFS_PATHNAMES(inp) )
5586 return CM_ERROR_PATH_NOT_COVERED;
5588 return CM_ERROR_BADSHARENAME;
5590 #endif /* DFS_SUPPORT */
5592 /* otherwise, scp points to the parent directory. */
5599 rock.maskp = lastNamep;
5600 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5603 thyper.HighPart = 0;
5607 rock.matches = NULL;
5609 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5610 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5611 if (code == 0 && !rock.any) {
5613 thyper.HighPart = 0;
5614 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5615 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5618 if (code == 0 && rock.matches) {
5619 cm_dirEntryList_t * entry;
5621 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5622 osi_Log1(smb_logp, "Removing directory %s",
5623 osi_LogSaveString(smb_logp, entry->name));
5625 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5627 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5628 smb_NotifyChange(FILE_ACTION_REMOVED,
5629 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5630 dscp, entry->name, NULL, TRUE);
5634 cm_DirEntryListFree(&rock.matches);
5636 cm_ReleaseUser(userp);
5638 cm_ReleaseSCache(dscp);
5640 if (code == 0 && !rock.any)
5641 code = CM_ERROR_NOSUCHFILE;
5645 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5655 fid = smb_GetSMBParm(inp, 0);
5657 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5659 fid = smb_ChainFID(fid, inp);
5660 fidp = smb_FindFID(vcp, fid, 0);
5662 return CM_ERROR_BADFD;
5664 lock_ObtainMutex(&fidp->mx);
5665 if (fidp->flags & SMB_FID_IOCTL) {
5666 lock_ReleaseMutex(&fidp->mx);
5667 smb_ReleaseFID(fidp);
5668 return CM_ERROR_BADFD;
5670 lock_ReleaseMutex(&fidp->mx);
5672 userp = smb_GetUserFromVCP(vcp, inp);
5674 lock_ObtainMutex(&fidp->mx);
5675 if (fidp->flags & SMB_FID_OPENWRITE) {
5676 cm_scache_t * scp = fidp->scp;
5678 lock_ReleaseMutex(&fidp->mx);
5679 code = cm_FSync(scp, userp, &req);
5680 cm_ReleaseSCache(scp);
5683 lock_ReleaseMutex(&fidp->mx);
5686 smb_ReleaseFID(fidp);
5688 cm_ReleaseUser(userp);
5693 struct smb_FullNameRock {
5699 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5703 struct smb_FullNameRock *vrockp;
5705 vrockp = (struct smb_FullNameRock *)rockp;
5707 if (!cm_Is8Dot3(dep->name)) {
5708 cm_Gen8Dot3Name(dep, shortName, NULL);
5710 if (cm_stricmp(shortName, vrockp->name) == 0) {
5711 vrockp->fullName = strdup(dep->name);
5712 return CM_ERROR_STOPNOW;
5715 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5716 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5717 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5718 vrockp->fullName = strdup(dep->name);
5719 return CM_ERROR_STOPNOW;
5724 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5725 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5727 struct smb_FullNameRock rock;
5733 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5734 if (code == CM_ERROR_STOPNOW)
5735 *newPathp = rock.fullName;
5737 *newPathp = strdup(pathp);
5740 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5741 afs_uint32 dosTime) {
5744 cm_scache_t *dscp = NULL;
5746 cm_scache_t * scp = NULL;
5748 int nullcreator = 0;
5750 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5751 fidp, fidp->fid, scp, vcp);
5754 lock_ObtainMutex(&fidp->mx);
5755 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5756 lock_ReleaseMutex(&fidp->mx);
5757 osi_Log0(smb_logp, " No user specified. Not closing fid");
5758 return CM_ERROR_BADFD;
5761 userp = fidp->userp; /* no hold required since fidp is held
5762 throughout the function */
5763 lock_ReleaseMutex(&fidp->mx);
5768 lock_ObtainWrite(&smb_rctLock);
5770 osi_Log0(smb_logp, " Fid already closed.");
5771 lock_ReleaseWrite(&smb_rctLock);
5772 return CM_ERROR_BADFD;
5775 lock_ReleaseWrite(&smb_rctLock);
5777 lock_ObtainMutex(&fidp->mx);
5778 if (fidp->NTopen_dscp) {
5779 dscp = fidp->NTopen_dscp;
5780 cm_HoldSCache(dscp);
5783 if (fidp->NTopen_pathp) {
5784 pathp = strdup(fidp->NTopen_pathp);
5792 /* Don't jump the gun on an async raw write */
5793 while (fidp->raw_writers) {
5794 lock_ReleaseMutex(&fidp->mx);
5795 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5796 lock_ObtainMutex(&fidp->mx);
5799 /* watch for ioctl closes, and read-only opens */
5801 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5802 == SMB_FID_OPENWRITE) {
5803 if (dosTime != 0 && dosTime != -1) {
5804 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5805 /* This fixes defect 10958 */
5806 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5807 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5809 lock_ReleaseMutex(&fidp->mx);
5810 code = cm_FSync(scp, userp, &req);
5811 lock_ObtainMutex(&fidp->mx);
5816 /* unlock any pending locks */
5817 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5818 scp->fileType == CM_SCACHETYPE_FILE) {
5822 lock_ReleaseMutex(&fidp->mx);
5824 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5826 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5827 lock_ObtainMutex(&scp->mx);
5829 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5830 CM_SCACHESYNC_NEEDCALLBACK
5831 | CM_SCACHESYNC_GETSTATUS
5832 | CM_SCACHESYNC_LOCK);
5836 "smb CoreClose SyncOp failure code 0x%x", tcode);
5837 goto post_syncopdone;
5840 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5842 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5846 lock_ReleaseMutex(&scp->mx);
5847 lock_ObtainMutex(&fidp->mx);
5850 if (fidp->flags & SMB_FID_DELONCLOSE) {
5853 lock_ReleaseMutex(&fidp->mx);
5854 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5855 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5856 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5859 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5860 smb_NotifyChange(FILE_ACTION_REMOVED,
5861 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5862 dscp, fullPathp, NULL, TRUE);
5865 code = cm_Unlink(dscp, fullPathp, userp, &req);
5868 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5869 smb_NotifyChange(FILE_ACTION_REMOVED,
5870 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5871 dscp, fullPathp, NULL, TRUE);
5875 lock_ObtainMutex(&fidp->mx);
5876 fidp->flags &= ~SMB_FID_DELONCLOSE;
5879 /* if this was a newly created file, then clear the creator
5880 * in the stat cache entry. */
5881 if (fidp->flags & SMB_FID_CREATED) {
5883 fidp->flags &= ~SMB_FID_CREATED;
5886 if (fidp->flags & SMB_FID_NTOPEN) {
5887 cm_ReleaseSCache(fidp->NTopen_dscp);
5888 fidp->NTopen_dscp = NULL;
5889 free(fidp->NTopen_pathp);
5890 fidp->NTopen_pathp = NULL;
5891 fidp->flags &= ~SMB_FID_NTOPEN;
5893 osi_assert(fidp->NTopen_dscp == NULL);
5894 osi_assert(fidp->NTopen_pathp == NULL);
5897 if (fidp->NTopen_wholepathp) {
5898 free(fidp->NTopen_wholepathp);
5899 fidp->NTopen_wholepathp = NULL;
5903 cm_ReleaseSCache(fidp->scp);
5906 lock_ReleaseMutex(&fidp->mx);
5909 cm_ReleaseSCache(dscp);
5912 if (deleted || nullcreator) {
5913 lock_ObtainMutex(&scp->mx);
5914 if (nullcreator && scp->creator == userp)
5915 scp->creator = NULL;
5917 scp->flags |= CM_SCACHEFLAG_DELETED;
5918 lock_ReleaseMutex(&scp->mx);
5920 lock_ObtainMutex(&scp->mx);
5921 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5922 lock_ReleaseMutex(&scp->mx);
5923 cm_ReleaseSCache(scp);
5932 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5940 fid = smb_GetSMBParm(inp, 0);
5941 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5943 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5945 fid = smb_ChainFID(fid, inp);
5946 fidp = smb_FindFID(vcp, fid, 0);
5948 return CM_ERROR_BADFD;
5951 userp = smb_GetUserFromVCP(vcp, inp);
5953 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5955 smb_ReleaseFID(fidp);
5956 cm_ReleaseUser(userp);
5961 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5963 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5964 cm_user_t *userp, long *readp)
5970 osi_hyper_t fileLength;
5972 osi_hyper_t lastByte;
5973 osi_hyper_t bufferOffset;
5974 long bufIndex, nbytes;
5976 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
5984 lock_ObtainMutex(&fidp->mx);
5987 lock_ObtainMutex(&scp->mx);
5989 if (offset.HighPart == 0) {
5990 chunk = offset.LowPart >> cm_logChunkSize;
5991 if (chunk != fidp->curr_chunk) {
5992 fidp->prev_chunk = fidp->curr_chunk;
5993 fidp->curr_chunk = chunk;
5995 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
5998 lock_ReleaseMutex(&fidp->mx);
6000 /* start by looking up the file's end */
6001 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6002 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6006 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6008 /* now we have the entry locked, look up the length */
6009 fileLength = scp->length;
6011 /* adjust count down so that it won't go past EOF */
6012 thyper.LowPart = count;
6013 thyper.HighPart = 0;
6014 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6016 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6017 /* we'd read past EOF, so just stop at fileLength bytes.
6018 * Start by computing how many bytes remain in the file.
6020 thyper = LargeIntegerSubtract(fileLength, offset);
6022 /* if we are past EOF, read 0 bytes */
6023 if (LargeIntegerLessThanZero(thyper))
6026 count = thyper.LowPart;
6031 /* now, copy the data one buffer at a time,
6032 * until we've filled the request packet
6035 /* if we've copied all the data requested, we're done */
6036 if (count <= 0) break;
6038 /* otherwise, load up a buffer of data */
6039 thyper.HighPart = offset.HighPart;
6040 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6041 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6044 buf_Release(bufferp);
6047 lock_ReleaseMutex(&scp->mx);
6049 lock_ObtainRead(&scp->bufCreateLock);
6050 code = buf_Get(scp, &thyper, &bufferp);
6051 lock_ReleaseRead(&scp->bufCreateLock);
6053 lock_ObtainMutex(&scp->mx);
6054 if (code) goto done;
6055 bufferOffset = thyper;
6057 /* now get the data in the cache */
6059 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6060 CM_SCACHESYNC_NEEDCALLBACK |
6061 CM_SCACHESYNC_READ);
6065 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6067 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6069 /* otherwise, load the buffer and try again */
6070 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6074 buf_Release(bufferp);
6078 } /* if (wrong buffer) ... */
6080 /* now we have the right buffer loaded. Copy out the
6081 * data from here to the user's buffer.
6083 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6085 /* and figure out how many bytes we want from this buffer */
6086 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6087 if (nbytes > count) nbytes = count; /* don't go past EOF */
6089 /* now copy the data */
6090 memcpy(op, bufferp->datap + bufIndex, nbytes);
6092 /* adjust counters, pointers, etc. */
6095 thyper.LowPart = nbytes;
6096 thyper.HighPart = 0;
6097 offset = LargeIntegerAdd(thyper, offset);
6101 lock_ReleaseMutex(&scp->mx);
6103 buf_Release(bufferp);
6105 if (code == 0 && sequential)
6106 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6108 cm_ReleaseSCache(scp);
6114 * smb_WriteData -- common code for Write and Raw Write
6116 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6117 cm_user_t *userp, long *writtenp)
6123 osi_hyper_t fileLength; /* file's length at start of write */
6124 osi_hyper_t minLength; /* don't read past this */
6125 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6127 osi_hyper_t thyper; /* hyper tmp variable */
6128 osi_hyper_t bufferOffset;
6129 afs_uint32 bufIndex; /* index in buffer where our data is */
6131 osi_hyper_t writeBackOffset;/* offset of region to write back when
6136 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6137 fidp->fid, offsetp->LowPart, count);
6147 lock_ObtainMutex(&fidp->mx);
6148 /* make sure we have a writable FD */
6149 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6150 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6151 fidp->fid, fidp->flags);
6152 lock_ReleaseMutex(&fidp->mx);
6153 code = CM_ERROR_BADFDOP;
6159 lock_ReleaseMutex(&fidp->mx);
6161 lock_ObtainMutex(&scp->mx);
6162 /* start by looking up the file's end */
6163 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6164 CM_SCACHESYNC_NEEDCALLBACK
6165 | CM_SCACHESYNC_SETSTATUS
6166 | CM_SCACHESYNC_GETSTATUS);
6170 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6172 /* now we have the entry locked, look up the length */
6173 fileLength = scp->length;
6174 minLength = fileLength;
6175 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6176 minLength = scp->serverLength;
6178 /* adjust file length if we extend past EOF */
6179 thyper.LowPart = count;
6180 thyper.HighPart = 0;
6181 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6182 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6183 /* we'd write past EOF, so extend the file */
6184 scp->mask |= CM_SCACHEMASK_LENGTH;
6185 scp->length = thyper;
6186 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6188 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6190 /* now, if the new position (thyper) and the old (offset) are in
6191 * different storeback windows, remember to store back the previous
6192 * storeback window when we're done with the write.
6194 if ((thyper.LowPart & (-cm_chunkSize)) !=
6195 (offset.LowPart & (-cm_chunkSize))) {
6196 /* they're different */
6198 writeBackOffset.HighPart = offset.HighPart;
6199 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6204 /* now, copy the data one buffer at a time, until we've filled the
6207 /* if we've copied all the data requested, we're done */
6211 /* handle over quota or out of space */
6212 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6213 *writtenp = written;
6214 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6218 /* otherwise, load up a buffer of data */
6219 thyper.HighPart = offset.HighPart;
6220 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6221 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6224 lock_ReleaseMutex(&bufferp->mx);
6225 buf_Release(bufferp);
6228 lock_ReleaseMutex(&scp->mx);
6230 lock_ObtainRead(&scp->bufCreateLock);
6231 code = buf_Get(scp, &thyper, &bufferp);
6232 lock_ReleaseRead(&scp->bufCreateLock);
6234 lock_ObtainMutex(&bufferp->mx);
6235 lock_ObtainMutex(&scp->mx);
6236 if (code) goto done;
6238 bufferOffset = thyper;
6240 /* now get the data in the cache */
6242 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6243 CM_SCACHESYNC_NEEDCALLBACK
6244 | CM_SCACHESYNC_WRITE
6245 | CM_SCACHESYNC_BUFLOCKED);
6249 cm_SyncOpDone(scp, bufferp,
6250 CM_SCACHESYNC_NEEDCALLBACK
6251 | CM_SCACHESYNC_WRITE
6252 | CM_SCACHESYNC_BUFLOCKED);
6254 /* If we're overwriting the entire buffer, or
6255 * if we're writing at or past EOF, mark the
6256 * buffer as current so we don't call
6257 * cm_GetBuffer. This skips the fetch from the
6258 * server in those cases where we're going to
6259 * obliterate all the data in the buffer anyway,
6260 * or in those cases where there is no useful
6261 * data at the server to start with.
6263 * Use minLength instead of scp->length, since
6264 * the latter has already been updated by this
6267 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6268 || LargeIntegerEqualTo(offset, bufferp->offset)
6269 && (count >= cm_data.buf_blockSize
6270 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6271 ConvertLongToLargeInteger(count)),
6273 if (count < cm_data.buf_blockSize
6274 && bufferp->dataVersion == -1)
6275 memset(bufferp->datap, 0,
6276 cm_data.buf_blockSize);
6277 bufferp->dataVersion = scp->dataVersion;
6280 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6282 /* otherwise, load the buffer and try again */
6283 lock_ReleaseMutex(&bufferp->mx);
6284 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6286 lock_ReleaseMutex(&scp->mx);
6287 lock_ObtainMutex(&bufferp->mx);
6288 lock_ObtainMutex(&scp->mx);
6292 lock_ReleaseMutex(&bufferp->mx);
6293 buf_Release(bufferp);
6297 } /* if (wrong buffer) ... */
6299 /* now we have the right buffer loaded. Copy out the
6300 * data from here to the user's buffer.
6302 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6304 /* and figure out how many bytes we want from this buffer */
6305 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6307 nbytes = count; /* don't go past end of request */
6309 /* now copy the data */
6310 memcpy(bufferp->datap + bufIndex, op, nbytes);
6311 buf_SetDirty(bufferp, bufIndex, nbytes);
6313 /* and record the last writer */
6314 if (bufferp->userp != userp) {
6317 cm_ReleaseUser(bufferp->userp);
6318 bufferp->userp = userp;
6321 /* adjust counters, pointers, etc. */
6325 thyper.LowPart = nbytes;
6326 thyper.HighPart = 0;
6327 offset = LargeIntegerAdd(thyper, offset);
6331 lock_ReleaseMutex(&scp->mx);
6334 lock_ReleaseMutex(&bufferp->mx);
6335 buf_Release(bufferp);
6338 lock_ObtainMutex(&fidp->mx);
6339 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6340 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6341 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6342 fidp->NTopen_dscp, fidp->NTopen_pathp,
6345 lock_ReleaseMutex(&fidp->mx);
6347 if (code == 0 && doWriteBack) {
6349 lock_ObtainMutex(&scp->mx);
6350 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6352 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6353 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6355 lock_ReleaseMutex(&scp->mx);
6356 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6357 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6358 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6361 cm_ReleaseSCache(scp);
6363 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6364 fidp->fid, code, *writtenp);
6368 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6371 unsigned short count;
6373 unsigned short hint;
6374 long written = 0, total_written = 0;
6379 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6381 int inDataBlockCount;
6383 fd = smb_GetSMBParm(inp, 0);
6384 count = smb_GetSMBParm(inp, 1);
6385 offset.HighPart = 0; /* too bad */
6386 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6387 hint = smb_GetSMBParm(inp, 4);
6389 op = smb_GetSMBData(inp, NULL);
6390 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6392 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6393 fd, offset.LowPart, count);
6395 fd = smb_ChainFID(fd, inp);
6396 fidp = smb_FindFID(vcp, fd, 0);
6398 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6399 return CM_ERROR_BADFD;
6402 lock_ObtainMutex(&fidp->mx);
6403 if (fidp->flags & SMB_FID_IOCTL) {
6404 lock_ReleaseMutex(&fidp->mx);
6405 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6406 smb_ReleaseFID(fidp);
6407 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6410 lock_ReleaseMutex(&fidp->mx);
6411 userp = smb_GetUserFromVCP(vcp, inp);
6415 LARGE_INTEGER LOffset;
6416 LARGE_INTEGER LLength;
6418 pid = ((smb_t *) inp)->pid;
6419 key = cm_GenerateKey(vcp->vcID, pid, fd);
6421 LOffset.HighPart = offset.HighPart;
6422 LOffset.LowPart = offset.LowPart;
6423 LLength.HighPart = 0;
6424 LLength.LowPart = count;
6426 lock_ObtainMutex(&fidp->scp->mx);
6427 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6428 lock_ReleaseMutex(&fidp->scp->mx);
6431 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6436 /* special case: 0 bytes transferred means truncate to this position */
6440 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6444 truncAttr.mask = CM_ATTRMASK_LENGTH;
6445 truncAttr.length.LowPart = offset.LowPart;
6446 truncAttr.length.HighPart = 0;
6447 lock_ObtainMutex(&fidp->mx);
6448 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6449 fidp->flags |= SMB_FID_LENGTHSETDONE;
6450 lock_ReleaseMutex(&fidp->mx);
6451 smb_SetSMBParm(outp, 0, 0 /* count */);
6452 smb_SetSMBDataLength(outp, 0);
6457 * Work around bug in NT client
6459 * When copying a file, the NT client should first copy the data,
6460 * then copy the last write time. But sometimes the NT client does
6461 * these in the wrong order, so the data copies would inadvertently
6462 * cause the last write time to be overwritten. We try to detect this,
6463 * and don't set client mod time if we think that would go against the
6466 lock_ObtainMutex(&fidp->mx);
6467 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6468 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6469 fidp->scp->clientModTime = time(NULL);
6471 lock_ReleaseMutex(&fidp->mx);
6474 while ( code == 0 && count > 0 ) {
6475 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6476 if (code == 0 && written == 0)
6477 code = CM_ERROR_PARTIALWRITE;
6479 offset = LargeIntegerAdd(offset,
6480 ConvertLongToLargeInteger(written));
6481 count -= (unsigned short)written;
6482 total_written += written;
6486 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6487 total_written, code);
6489 /* set the packet data length to 3 bytes for the data block header,
6490 * plus the size of the data.
6492 smb_SetSMBParm(outp, 0, total_written);
6493 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6494 smb_SetSMBParm(outp, 3, hint);
6495 smb_SetSMBDataLength(outp, 0);
6498 smb_ReleaseFID(fidp);
6499 cm_ReleaseUser(userp);
6504 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6505 NCB *ncbp, raw_write_cont_t *rwcp)
6514 fd = smb_GetSMBParm(inp, 0);
6515 fidp = smb_FindFID(vcp, fd, 0);
6517 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6518 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6520 userp = smb_GetUserFromVCP(vcp, inp);
6523 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6525 if (rwcp->writeMode & 0x1) { /* synchronous */
6528 smb_FormatResponsePacket(vcp, inp, outp);
6529 op = (smb_t *) outp;
6530 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6531 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6532 smb_SetSMBDataLength(outp, 0);
6533 smb_SendPacket(vcp, outp);
6534 smb_FreePacket(outp);
6536 else { /* asynchronous */
6537 lock_ObtainMutex(&fidp->mx);
6538 fidp->raw_writers--;
6539 if (fidp->raw_writers == 0)
6540 thrd_SetEvent(fidp->raw_write_event);
6541 lock_ReleaseMutex(&fidp->mx);
6544 /* Give back raw buffer */
6545 lock_ObtainMutex(&smb_RawBufLock);
6546 *((char **)rawBuf) = smb_RawBufs;
6547 smb_RawBufs = rawBuf;
6548 lock_ReleaseMutex(&smb_RawBufLock);
6550 smb_ReleaseFID(fidp);
6551 cm_ReleaseUser(userp);
6554 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6559 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6562 long count, written = 0, total_written = 0;
6569 unsigned short writeMode;
6571 fd = smb_GetSMBParm(inp, 0);
6572 totalCount = smb_GetSMBParm(inp, 1);
6573 count = smb_GetSMBParm(inp, 10);
6574 writeMode = smb_GetSMBParm(inp, 7);
6576 op = (char *) inp->data;
6577 op += smb_GetSMBParm(inp, 11);
6579 offset.HighPart = 0;
6580 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6582 if (*inp->wctp == 14) {
6583 /* we received a 64-bit file offset */
6584 #ifdef AFS_LARGEFILES
6585 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6587 if (LargeIntegerLessThanZero(offset)) {
6589 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6590 offset.HighPart, offset.LowPart);
6591 return CM_ERROR_BADSMB;
6594 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6596 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6597 return CM_ERROR_BADSMB;
6600 offset.HighPart = 0;
6603 offset.HighPart = 0; /* 32-bit file offset */
6607 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6608 fd, offset.HighPart, offset.LowPart, count);
6610 " WriteRaw WriteMode 0x%x",
6613 fd = smb_ChainFID(fd, inp);
6614 fidp = smb_FindFID(vcp, fd, 0);
6616 return CM_ERROR_BADFD;
6622 LARGE_INTEGER LOffset;
6623 LARGE_INTEGER LLength;
6625 pid = ((smb_t *) inp)->pid;
6626 key = cm_GenerateKey(vcp->vcID, pid, fd);
6628 LOffset.HighPart = offset.HighPart;
6629 LOffset.LowPart = offset.LowPart;
6630 LLength.HighPart = 0;
6631 LLength.LowPart = count;
6633 lock_ObtainMutex(&fidp->scp->mx);
6634 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6635 lock_ReleaseMutex(&fidp->scp->mx);
6638 smb_ReleaseFID(fidp);
6643 userp = smb_GetUserFromVCP(vcp, inp);
6646 * Work around bug in NT client
6648 * When copying a file, the NT client should first copy the data,
6649 * then copy the last write time. But sometimes the NT client does
6650 * these in the wrong order, so the data copies would inadvertently
6651 * cause the last write time to be overwritten. We try to detect this,
6652 * and don't set client mod time if we think that would go against the
6655 lock_ObtainMutex(&fidp->mx);
6656 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6657 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6658 fidp->scp->clientModTime = time(NULL);
6660 lock_ReleaseMutex(&fidp->mx);
6663 while ( code == 0 && count > 0 ) {
6664 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6665 if (code == 0 && written == 0)
6666 code = CM_ERROR_PARTIALWRITE;
6668 offset = LargeIntegerAdd(offset,
6669 ConvertLongToLargeInteger(written));
6672 total_written += written;
6676 /* Get a raw buffer */
6679 lock_ObtainMutex(&smb_RawBufLock);
6681 /* Get a raw buf, from head of list */
6682 rawBuf = smb_RawBufs;
6683 smb_RawBufs = *(char **)smb_RawBufs;
6686 code = CM_ERROR_USESTD;
6688 lock_ReleaseMutex(&smb_RawBufLock);
6691 /* Don't allow a premature Close */
6692 if (code == 0 && (writeMode & 1) == 0) {
6693 lock_ObtainMutex(&fidp->mx);
6694 fidp->raw_writers++;
6695 thrd_ResetEvent(fidp->raw_write_event);
6696 lock_ReleaseMutex(&fidp->mx);
6699 smb_ReleaseFID(fidp);
6700 cm_ReleaseUser(userp);
6703 smb_SetSMBParm(outp, 0, total_written);
6704 smb_SetSMBDataLength(outp, 0);
6705 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6710 offset = LargeIntegerAdd(offset,
6711 ConvertLongToLargeInteger(count));
6715 rwcp->offset.HighPart = offset.HighPart;
6716 rwcp->offset.LowPart = offset.LowPart;
6717 rwcp->count = totalCount - count;
6718 rwcp->writeMode = writeMode;
6719 rwcp->alreadyWritten = total_written;
6721 /* set the packet data length to 3 bytes for the data block header,
6722 * plus the size of the data.
6724 smb_SetSMBParm(outp, 0, 0xffff);
6725 smb_SetSMBDataLength(outp, 0);
6730 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6733 long count, finalCount;
6741 fd = smb_GetSMBParm(inp, 0);
6742 count = smb_GetSMBParm(inp, 1);
6743 offset.HighPart = 0; /* too bad */
6744 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6746 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6747 fd, offset.LowPart, count);
6749 fd = smb_ChainFID(fd, inp);
6750 fidp = smb_FindFID(vcp, fd, 0);
6752 return CM_ERROR_BADFD;
6754 lock_ObtainMutex(&fidp->mx);
6755 if (fidp->flags & SMB_FID_IOCTL) {
6756 lock_ReleaseMutex(&fidp->mx);
6757 code = smb_IoctlRead(fidp, vcp, inp, outp);
6758 smb_ReleaseFID(fidp);
6761 lock_ReleaseMutex(&fidp->mx);
6764 LARGE_INTEGER LOffset, LLength;
6767 pid = ((smb_t *) inp)->pid;
6768 key = cm_GenerateKey(vcp->vcID, pid, fd);
6770 LOffset.HighPart = 0;
6771 LOffset.LowPart = offset.LowPart;
6772 LLength.HighPart = 0;
6773 LLength.LowPart = count;
6775 lock_ObtainMutex(&fidp->scp->mx);
6776 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6777 lock_ReleaseMutex(&fidp->scp->mx);
6780 smb_ReleaseFID(fidp);
6784 userp = smb_GetUserFromVCP(vcp, inp);
6786 /* remember this for final results */
6787 smb_SetSMBParm(outp, 0, count);
6788 smb_SetSMBParm(outp, 1, 0);
6789 smb_SetSMBParm(outp, 2, 0);
6790 smb_SetSMBParm(outp, 3, 0);
6791 smb_SetSMBParm(outp, 4, 0);
6793 /* set the packet data length to 3 bytes for the data block header,
6794 * plus the size of the data.
6796 smb_SetSMBDataLength(outp, count+3);
6798 /* get op ptr after putting in the parms, since otherwise we don't
6799 * know where the data really is.
6801 op = smb_GetSMBData(outp, NULL);
6803 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6804 *op++ = 1; /* data block marker */
6805 *op++ = (unsigned char) (count & 0xff);
6806 *op++ = (unsigned char) ((count >> 8) & 0xff);
6808 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6810 /* fix some things up */
6811 smb_SetSMBParm(outp, 0, finalCount);
6812 smb_SetSMBDataLength(outp, finalCount+3);
6814 smb_ReleaseFID(fidp);
6816 cm_ReleaseUser(userp);
6820 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6827 cm_scache_t *dscp; /* dir we're dealing with */
6828 cm_scache_t *scp; /* file we're creating */
6830 int initialModeBits;
6840 /* compute initial mode bits based on read-only flag in attributes */
6841 initialModeBits = 0777;
6843 tp = smb_GetSMBData(inp, NULL);
6844 pathp = smb_ParseASCIIBlock(tp, &tp);
6845 if (smb_StoreAnsiFilenames)
6846 OemToChar(pathp,pathp);
6848 if (strcmp(pathp, "\\") == 0)
6849 return CM_ERROR_EXISTS;
6851 spacep = inp->spacep;
6852 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6854 userp = smb_GetUserFromVCP(vcp, inp);
6856 caseFold = CM_FLAG_CASEFOLD;
6858 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6860 cm_ReleaseUser(userp);
6861 return CM_ERROR_NOSUCHPATH;
6864 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6865 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6866 userp, tidPathp, &req, &dscp);
6869 cm_ReleaseUser(userp);
6874 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6875 cm_ReleaseSCache(dscp);
6876 cm_ReleaseUser(userp);
6877 if ( WANTS_DFS_PATHNAMES(inp) )
6878 return CM_ERROR_PATH_NOT_COVERED;
6880 return CM_ERROR_BADSHARENAME;
6882 #endif /* DFS_SUPPORT */
6884 /* otherwise, scp points to the parent directory. Do a lookup, and
6885 * fail if we find it. Otherwise, we do the create.
6891 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6892 if (scp) cm_ReleaseSCache(scp);
6893 if (code != CM_ERROR_NOSUCHFILE) {
6894 if (code == 0) code = CM_ERROR_EXISTS;
6895 cm_ReleaseSCache(dscp);
6896 cm_ReleaseUser(userp);
6900 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6901 setAttr.clientModTime = time(NULL);
6902 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6903 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6904 smb_NotifyChange(FILE_ACTION_ADDED,
6905 FILE_NOTIFY_CHANGE_DIR_NAME,
6906 dscp, lastNamep, NULL, TRUE);
6908 /* we don't need this any longer */
6909 cm_ReleaseSCache(dscp);
6912 /* something went wrong creating or truncating the file */
6913 cm_ReleaseUser(userp);
6917 /* otherwise we succeeded */
6918 smb_SetSMBDataLength(outp, 0);
6919 cm_ReleaseUser(userp);
6924 BOOL smb_IsLegalFilename(char *filename)
6927 * Find the longest substring of filename that does not contain
6928 * any of the chars in illegalChars. If that substring is less
6929 * than the length of the whole string, then one or more of the
6930 * illegal chars is in filename.
6932 if (strcspn(filename, illegalChars) < strlen(filename))
6938 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6946 cm_scache_t *dscp; /* dir we're dealing with */
6947 cm_scache_t *scp; /* file we're creating */
6949 int initialModeBits;
6957 int created = 0; /* the file was new */
6962 excl = (inp->inCom == 0x03)? 0 : 1;
6964 attributes = smb_GetSMBParm(inp, 0);
6965 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6967 /* compute initial mode bits based on read-only flag in attributes */
6968 initialModeBits = 0666;
6969 if (attributes & SMB_ATTR_READONLY)
6970 initialModeBits &= ~0222;
6972 tp = smb_GetSMBData(inp, NULL);
6973 pathp = smb_ParseASCIIBlock(tp, &tp);
6974 if (smb_StoreAnsiFilenames)
6975 OemToChar(pathp,pathp);
6977 spacep = inp->spacep;
6978 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6980 userp = smb_GetUserFromVCP(vcp, inp);
6982 caseFold = CM_FLAG_CASEFOLD;
6984 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6986 cm_ReleaseUser(userp);
6987 return CM_ERROR_NOSUCHPATH;
6989 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6990 userp, tidPathp, &req, &dscp);
6993 cm_ReleaseUser(userp);
6998 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6999 cm_ReleaseSCache(dscp);
7000 cm_ReleaseUser(userp);
7001 if ( WANTS_DFS_PATHNAMES(inp) )
7002 return CM_ERROR_PATH_NOT_COVERED;
7004 return CM_ERROR_BADSHARENAME;
7006 #endif /* DFS_SUPPORT */
7008 /* otherwise, scp points to the parent directory. Do a lookup, and
7009 * truncate the file if we find it, otherwise we create the file.
7016 if (!smb_IsLegalFilename(lastNamep))
7017 return CM_ERROR_BADNTFILENAME;
7019 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7020 #ifdef DEBUG_VERBOSE
7023 hexp = osi_HexifyString( lastNamep );
7024 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7029 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7030 if (code && code != CM_ERROR_NOSUCHFILE) {
7031 cm_ReleaseSCache(dscp);
7032 cm_ReleaseUser(userp);
7036 /* if we get here, if code is 0, the file exists and is represented by
7037 * scp. Otherwise, we have to create it.
7041 /* oops, file shouldn't be there */
7042 cm_ReleaseSCache(dscp);
7043 cm_ReleaseSCache(scp);
7044 cm_ReleaseUser(userp);
7045 return CM_ERROR_EXISTS;
7048 setAttr.mask = CM_ATTRMASK_LENGTH;
7049 setAttr.length.LowPart = 0;
7050 setAttr.length.HighPart = 0;
7051 code = cm_SetAttr(scp, &setAttr, userp, &req);
7054 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7055 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7056 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7060 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7061 smb_NotifyChange(FILE_ACTION_ADDED,
7062 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7063 dscp, lastNamep, NULL, TRUE);
7064 } else if (!excl && code == CM_ERROR_EXISTS) {
7065 /* not an exclusive create, and someone else tried
7066 * creating it already, then we open it anyway. We
7067 * don't bother retrying after this, since if this next
7068 * fails, that means that the file was deleted after
7069 * we started this call.
7071 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7074 setAttr.mask = CM_ATTRMASK_LENGTH;
7075 setAttr.length.LowPart = 0;
7076 setAttr.length.HighPart = 0;
7077 code = cm_SetAttr(scp, &setAttr, userp, &req);
7082 /* we don't need this any longer */
7083 cm_ReleaseSCache(dscp);
7086 /* something went wrong creating or truncating the file */
7087 if (scp) cm_ReleaseSCache(scp);
7088 cm_ReleaseUser(userp);
7092 /* make sure we only open files */
7093 if (scp->fileType != CM_SCACHETYPE_FILE) {
7094 cm_ReleaseSCache(scp);
7095 cm_ReleaseUser(userp);
7096 return CM_ERROR_ISDIR;
7099 /* now all we have to do is open the file itself */
7100 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7105 lock_ObtainMutex(&fidp->mx);
7106 /* always create it open for read/write */
7107 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7109 /* remember that the file was newly created */
7111 fidp->flags |= SMB_FID_CREATED;
7113 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7115 /* save a pointer to the vnode */
7117 lock_ObtainMutex(&scp->mx);
7118 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7119 lock_ReleaseMutex(&scp->mx);
7122 fidp->userp = userp;
7123 lock_ReleaseMutex(&fidp->mx);
7125 smb_SetSMBParm(outp, 0, fidp->fid);
7126 smb_SetSMBDataLength(outp, 0);
7128 cm_Open(scp, 0, userp);
7130 smb_ReleaseFID(fidp);
7131 cm_ReleaseUser(userp);
7132 /* leave scp held since we put it in fidp->scp */
7136 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7139 osi_hyper_t new_offset;
7150 fd = smb_GetSMBParm(inp, 0);
7151 whence = smb_GetSMBParm(inp, 1);
7152 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7154 /* try to find the file descriptor */
7155 fd = smb_ChainFID(fd, inp);
7156 fidp = smb_FindFID(vcp, fd, 0);
7159 return CM_ERROR_BADFD;
7161 lock_ObtainMutex(&fidp->mx);
7162 if (fidp->flags & SMB_FID_IOCTL) {
7163 lock_ReleaseMutex(&fidp->mx);
7164 smb_ReleaseFID(fidp);
7165 return CM_ERROR_BADFD;
7167 lock_ReleaseMutex(&fidp->mx);
7169 userp = smb_GetUserFromVCP(vcp, inp);
7171 lock_ObtainMutex(&fidp->mx);
7174 lock_ReleaseMutex(&fidp->mx);
7175 lock_ObtainMutex(&scp->mx);
7176 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7177 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7179 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7181 /* offset from current offset */
7182 new_offset = LargeIntegerAdd(fidp->offset,
7183 ConvertLongToLargeInteger(offset));
7185 else if (whence == 2) {
7186 /* offset from current EOF */
7187 new_offset = LargeIntegerAdd(scp->length,
7188 ConvertLongToLargeInteger(offset));
7190 new_offset = ConvertLongToLargeInteger(offset);
7193 fidp->offset = new_offset;
7194 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7195 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7196 smb_SetSMBDataLength(outp, 0);
7198 lock_ReleaseMutex(&scp->mx);
7199 smb_ReleaseFID(fidp);
7200 cm_ReleaseSCache(scp);
7201 cm_ReleaseUser(userp);
7205 /* dispatch all of the requests received in a packet. Due to chaining, this may
7206 * be more than one request.
7208 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7209 NCB *ncbp, raw_write_cont_t *rwcp)
7213 unsigned long code = 0;
7214 unsigned char *outWctp;
7215 int nparms; /* # of bytes of parameters */
7217 int nbytes; /* bytes of data, excluding count */
7220 unsigned short errCode;
7221 unsigned long NTStatus;
7223 unsigned char errClass;
7224 unsigned int oldGen;
7225 DWORD oldTime, newTime;
7227 /* get easy pointer to the data */
7228 smbp = (smb_t *) inp->data;
7230 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7231 /* setup the basic parms for the initial request in the packet */
7232 inp->inCom = smbp->com;
7233 inp->wctp = &smbp->wct;
7235 inp->ncb_length = ncbp->ncb_length;
7240 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7241 /* log it and discard it */
7242 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7243 __FILE__, __LINE__, ncbp->ncb_length);
7244 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7248 /* We are an ongoing op */
7249 thrd_Increment(&ongoingOps);
7251 /* set up response packet for receiving output */
7252 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7253 smb_FormatResponsePacket(vcp, inp, outp);
7254 outWctp = outp->wctp;
7256 /* Remember session generation number and time */
7257 oldGen = sessionGen;
7258 oldTime = GetTickCount();
7260 while (inp->inCom != 0xff) {
7261 dp = &smb_dispatchTable[inp->inCom];
7263 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7264 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7265 code = outp->resumeCode;
7269 /* process each request in the packet; inCom, wctp and inCount
7270 * are already set up.
7272 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7275 /* now do the dispatch */
7276 /* start by formatting the response record a little, as a default */
7277 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7279 outWctp[1] = 0xff; /* no operation */
7280 outWctp[2] = 0; /* padding */
7285 /* not a chained request, this is a more reasonable default */
7286 outWctp[0] = 0; /* wct of zero */
7287 outWctp[1] = 0; /* and bcc (word) of zero */
7291 /* once set, stays set. Doesn't matter, since we never chain
7292 * "no response" calls.
7294 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7298 /* we have a recognized operation */
7300 if (inp->inCom == 0x1d)
7302 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7304 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7305 code = (*(dp->procp)) (vcp, inp, outp);
7306 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7308 if ( code == CM_ERROR_BADSMB ||
7309 code == CM_ERROR_BADOP )
7311 #endif /* LOG_PACKET */
7314 if (oldGen != sessionGen) {
7315 newTime = GetTickCount();
7316 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7317 newTime - oldTime, ncbp->ncb_length);
7318 osi_Log2(smb_logp, "Pkt straddled session startup, "
7319 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7323 /* bad opcode, fail the request, after displaying it */
7324 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7327 #endif /* LOG_PACKET */
7330 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7331 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7332 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7333 if (code == IDCANCEL)
7336 code = CM_ERROR_BADOP;
7339 /* catastrophic failure: log as much as possible */
7340 if (code == CM_ERROR_BADSMB) {
7341 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7345 #endif /* LOG_PACKET */
7346 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7349 code = CM_ERROR_INVAL;
7352 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7353 thrd_Decrement(&ongoingOps);
7358 /* now, if we failed, turn the current response into an empty
7359 * one, and fill in the response packet's error code.
7362 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7363 smb_MapNTError(code, &NTStatus);
7364 outWctp = outp->wctp;
7365 smbp = (smb_t *) &outp->data;
7366 if (code != CM_ERROR_PARTIALWRITE
7367 && code != CM_ERROR_BUFFERTOOSMALL
7368 && code != CM_ERROR_GSSCONTINUE) {
7369 /* nuke wct and bcc. For a partial
7370 * write or an in-process authentication handshake,
7371 * assume they're OK.
7377 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7378 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7379 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7380 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7381 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7385 smb_MapCoreError(code, vcp, &errCode, &errClass);
7386 outWctp = outp->wctp;
7387 smbp = (smb_t *) &outp->data;
7388 if (code != CM_ERROR_PARTIALWRITE) {
7389 /* nuke wct and bcc. For a partial
7390 * write, assume they're OK.
7396 smbp->errLow = (unsigned char) (errCode & 0xff);
7397 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7398 smbp->rcls = errClass;
7401 } /* error occurred */
7403 /* if we're here, we've finished one request. Look to see if
7404 * this is a chained opcode. If it is, setup things to process
7405 * the chained request, and setup the output buffer to hold the
7406 * chained response. Start by finding the next input record.
7408 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7409 break; /* not a chained req */
7410 tp = inp->wctp; /* points to start of last request */
7411 /* in a chained request, the first two
7412 * parm fields are required, and are
7413 * AndXCommand/AndXReserved and
7415 if (tp[0] < 2) break;
7416 if (tp[1] == 0xff) break; /* no more chained opcodes */
7418 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7421 /* and now append the next output request to the end of this
7422 * last request. Begin by finding out where the last response
7423 * ends, since that's where we'll put our new response.
7425 outWctp = outp->wctp; /* ptr to out parameters */
7426 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7427 nparms = outWctp[0] << 1;
7428 tp = outWctp + nparms + 1; /* now points to bcc field */
7429 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7430 tp += 2 /* for the count itself */ + nbytes;
7431 /* tp now points to the new output record; go back and patch the
7432 * second parameter (off2) to point to the new record.
7434 temp = (unsigned int)(tp - outp->data);
7435 outWctp[3] = (unsigned char) (temp & 0xff);
7436 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7437 outWctp[2] = 0; /* padding */
7438 outWctp[1] = inp->inCom; /* next opcode */
7440 /* finally, setup for the next iteration */
7443 } /* while loop over all requests in the packet */
7445 /* now send the output packet, and return */
7447 smb_SendPacket(vcp, outp);
7448 thrd_Decrement(&ongoingOps);
7453 /* Wait for Netbios() calls to return, and make the results available to server
7454 * threads. Note that server threads can't wait on the NCBevents array
7455 * themselves, because NCB events are manual-reset, and the servers would race
7456 * each other to reset them.
7458 void smb_ClientWaiter(void *parmp)
7463 while (smbShutdownFlag == 0) {
7464 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7466 if (code == WAIT_OBJECT_0)
7469 /* error checking */
7470 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7472 int abandonIdx = code - WAIT_ABANDONED_0;
7473 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7476 if (code == WAIT_IO_COMPLETION)
7478 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7482 if (code == WAIT_TIMEOUT)
7484 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7487 if (code == WAIT_FAILED)
7489 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7492 idx = code - WAIT_OBJECT_0;
7494 /* check idx range! */
7495 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7497 /* this is fatal - log as much as possible */
7498 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7502 thrd_ResetEvent(NCBevents[idx]);
7503 thrd_SetEvent(NCBreturns[0][idx]);
7508 * Try to have one NCBRECV request waiting for every live session. Not more
7509 * than one, because if there is more than one, it's hard to handle Write Raw.
7511 void smb_ServerWaiter(void *parmp)
7514 int idx_session, idx_NCB;
7517 while (smbShutdownFlag == 0) {
7519 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7521 if (code == WAIT_OBJECT_0)
7524 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7526 int abandonIdx = code - WAIT_ABANDONED_0;
7527 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7530 if (code == WAIT_IO_COMPLETION)
7532 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7536 if (code == WAIT_TIMEOUT)
7538 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7541 if (code == WAIT_FAILED)
7543 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7546 idx_session = code - WAIT_OBJECT_0;
7548 /* check idx range! */
7549 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7551 /* this is fatal - log as much as possible */
7552 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7558 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7560 if (code == WAIT_OBJECT_0) {
7561 if (smbShutdownFlag == 1)
7567 /* error checking */
7568 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7570 int abandonIdx = code - WAIT_ABANDONED_0;
7571 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7574 if (code == WAIT_IO_COMPLETION)
7576 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7580 if (code == WAIT_TIMEOUT)
7582 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7585 if (code == WAIT_FAILED)
7587 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7590 idx_NCB = code - WAIT_OBJECT_0;
7592 /* check idx range! */
7593 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7595 /* this is fatal - log as much as possible */
7596 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7600 /* Link them together */
7601 NCBsessions[idx_NCB] = idx_session;
7604 ncbp = NCBs[idx_NCB];
7605 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7606 ncbp->ncb_command = NCBRECV | ASYNCH;
7607 ncbp->ncb_lana_num = lanas[idx_session];
7608 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7609 ncbp->ncb_event = NCBevents[idx_NCB];
7610 ncbp->ncb_length = SMB_PACKETSIZE;
7616 * The top level loop for handling SMB request messages. Each server thread
7617 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7618 * NCB and buffer for the incoming request are loaned to us.
7620 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7621 * to immediately send a request for the rest of the data. This must come
7622 * before any other traffic for that session, so we delay setting the session
7623 * event until that data has come in.
7625 void smb_Server(VOID *parmp)
7627 INT_PTR myIdx = (INT_PTR) parmp;
7631 smb_packet_t *outbufp;
7633 int idx_NCB, idx_session;
7635 smb_vc_t *vcp = NULL;
7638 rx_StartClientThread();
7641 outbufp = GetPacket();
7642 outbufp->ncbp = outncbp;
7650 smb_ResetServerPriority();
7652 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7655 /* terminate silently if shutdown flag is set */
7656 if (code == WAIT_OBJECT_0) {
7657 if (smbShutdownFlag == 1) {
7658 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7664 /* error checking */
7665 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7667 int abandonIdx = code - WAIT_ABANDONED_0;
7668 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7671 if (code == WAIT_IO_COMPLETION)
7673 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7677 if (code == WAIT_TIMEOUT)
7679 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7682 if (code == WAIT_FAILED)
7684 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7687 idx_NCB = code - WAIT_OBJECT_0;
7689 /* check idx range! */
7690 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7692 /* this is fatal - log as much as possible */
7693 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7697 ncbp = NCBs[idx_NCB];
7698 idx_session = NCBsessions[idx_NCB];
7699 rc = ncbp->ncb_retcode;
7701 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7702 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7706 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7710 /* Can this happen? Or is it just my UNIX paranoia? */
7711 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7716 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7719 /* Client closed session */
7720 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7722 lock_ObtainMutex(&vcp->mx);
7723 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7724 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7726 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7727 lock_ReleaseMutex(&vcp->mx);
7728 lock_ObtainWrite(&smb_globalLock);
7729 dead_sessions[vcp->session] = TRUE;
7730 lock_ReleaseWrite(&smb_globalLock);
7731 smb_CleanupDeadVC(vcp);
7735 lock_ReleaseMutex(&vcp->mx);
7741 /* Treat as transient error */
7742 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7745 "dispatch smb recv failed, message incomplete, ncb_length %d",
7748 "SMB message incomplete, "
7749 "length %d", ncbp->ncb_length);
7752 * We used to discard the packet.
7753 * Instead, try handling it normally.
7757 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7761 /* A weird error code. Log it, sleep, and continue. */
7762 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7764 lock_ObtainMutex(&vcp->mx);
7765 if (vcp && vcp->errorCount++ > 3) {
7766 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7767 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7768 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7770 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7771 lock_ReleaseMutex(&vcp->mx);
7772 lock_ObtainWrite(&smb_globalLock);
7773 dead_sessions[vcp->session] = TRUE;
7774 lock_ReleaseWrite(&smb_globalLock);
7775 smb_CleanupDeadVC(vcp);
7779 lock_ReleaseMutex(&vcp->mx);
7785 lock_ReleaseMutex(&vcp->mx);
7787 thrd_SetEvent(SessionEvents[idx_session]);
7792 /* Success, so now dispatch on all the data in the packet */
7794 smb_concurrentCalls++;
7795 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7796 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7799 * If at this point vcp is NULL (implies that packet was invalid)
7800 * then we are in big trouble. This means either :
7801 * a) we have the wrong NCB.
7802 * b) Netbios screwed up the call.
7803 * c) The VC was already marked dead before we were able to
7805 * Obviously this implies that
7806 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7807 * lanas[idx_session] != ncbp->ncb_lana_num )
7808 * Either way, we can't do anything with this packet.
7809 * Log, sleep and resume.
7812 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7816 ncbp->ncb_lana_num);
7818 /* Also log in the trace log. */
7819 osi_Log4(smb_logp, "Server: VCP does not exist!"
7820 "LSNs[idx_session]=[%d],"
7821 "lanas[idx_session]=[%d],"
7822 "ncbp->ncb_lsn=[%d],"
7823 "ncbp->ncb_lana_num=[%d]",
7827 ncbp->ncb_lana_num);
7829 /* thrd_Sleep(1000); Don't bother sleeping */
7830 thrd_SetEvent(SessionEvents[idx_session]);
7831 smb_concurrentCalls--;
7835 smb_SetRequestStartTime();
7837 vcp->errorCount = 0;
7838 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7839 smbp = (smb_t *)bufp->data;
7844 if (smbp->com == 0x1d) {
7845 /* Special handling for Write Raw */
7846 raw_write_cont_t rwc;
7847 EVENT_HANDLE rwevent;
7848 char eventName[MAX_PATH];
7850 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7851 if (rwc.code == 0) {
7852 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7853 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7854 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7855 ncbp->ncb_command = NCBRECV | ASYNCH;
7856 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7857 ncbp->ncb_lana_num = vcp->lana;
7858 ncbp->ncb_buffer = rwc.buf;
7859 ncbp->ncb_length = 65535;
7860 ncbp->ncb_event = rwevent;
7862 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7863 thrd_CloseHandle(rwevent);
7865 thrd_SetEvent(SessionEvents[idx_session]);
7867 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7869 else if (smbp->com == 0xa0) {
7871 * Serialize the handling for NT Transact
7874 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7875 thrd_SetEvent(SessionEvents[idx_session]);
7877 thrd_SetEvent(SessionEvents[idx_session]);
7878 /* TODO: what else needs to be serialized? */
7879 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7882 __except( smb_ServerExceptionFilter() ) {
7885 smb_concurrentCalls--;
7888 thrd_SetEvent(NCBavails[idx_NCB]);
7895 * Exception filter for the server threads. If an exception occurs in the
7896 * dispatch routines, which is where exceptions are most common, then do a
7897 * force trace and give control to upstream exception handlers. Useful for
7900 DWORD smb_ServerExceptionFilter(void) {
7901 /* While this is not the best time to do a trace, if it succeeds, then
7902 * we have a trace (assuming tracing was enabled). Otherwise, this should
7903 * throw a second exception.
7905 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7906 afsd_ForceTrace(TRUE);
7907 buf_ForceTrace(TRUE);
7908 return EXCEPTION_CONTINUE_SEARCH;
7912 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7913 * If the number of server threads is M, and the number of live sessions is
7914 * N, then the number of NCB's in use at any time either waiting for, or
7915 * holding, received messages is M + N, so that is how many NCB's get created.
7917 void InitNCBslot(int idx)
7919 struct smb_packet *bufp;
7920 EVENT_HANDLE retHandle;
7922 char eventName[MAX_PATH];
7924 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7926 NCBs[idx] = GetNCB();
7927 sprintf(eventName,"NCBavails[%d]", idx);
7928 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7929 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7930 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7931 sprintf(eventName,"NCBevents[%d]", idx);
7932 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7933 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7934 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7935 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7936 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7937 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7938 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7939 for (i=0; i<smb_NumServerThreads; i++)
7940 NCBreturns[i][idx] = retHandle;
7942 bufp->spacep = cm_GetSpace();
7946 /* listen for new connections */
7947 void smb_Listener(void *parmp)
7953 int session, thread;
7954 smb_vc_t *vcp = NULL;
7956 char rname[NCBNAMSZ+1];
7957 char cname[MAX_COMPUTERNAME_LENGTH+1];
7958 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7959 INT_PTR lana = (INT_PTR) parmp;
7963 /* retrieve computer name */
7964 GetComputerName(cname, &cnamelen);
7967 while (smb_ListenerState == SMB_LISTENER_STARTED) {
7968 memset(ncbp, 0, sizeof(NCB));
7971 ncbp->ncb_command = NCBLISTEN;
7972 ncbp->ncb_rto = 0; /* No receive timeout */
7973 ncbp->ncb_sto = 0; /* No send timeout */
7975 /* pad out with spaces instead of null termination */
7976 len = (long)strlen(smb_localNamep);
7977 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7978 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7980 strcpy(ncbp->ncb_callname, "*");
7981 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7983 ncbp->ncb_lana_num = (UCHAR)lana;
7985 code = Netbios(ncbp);
7987 if (code == NRC_BRIDGE) {
7988 int lanaRemaining = 0;
7990 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
7995 "NCBLISTEN lana=%d failed with NRC_BRIDGE. Listener thread exiting.",
7996 ncbp->ncb_lana_num, code);
7998 for (i = 0; i < lana_list.length; i++) {
7999 if (lana_list.lana[i] == ncbp->ncb_lana_num) {
8000 smb_StopListener(ncbp, lana_list.lana[i]);
8001 lana_list.lana[i] = 255;
8003 if (lana_list.lana[i] != 255)
8007 if (lanaRemaining == 0) {
8008 cm_VolStatus_Network_Stopped(cm_NetbiosName
8013 smb_ListenerState = SMB_LISTENER_STOPPED;
8014 smb_LANadapter = -1;
8015 lana_list.length = 0;
8019 } else if (code != 0) {
8022 /* terminate silently if shutdown flag is set */
8023 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
8028 "NCBLISTEN lana=%d failed with code %d",
8029 ncbp->ncb_lana_num, code);
8031 "Client exiting due to network failure. Please restart client.\n");
8034 "Client exiting due to network failure. Please restart client.\n"
8035 "NCBLISTEN lana=%d failed with code %d",
8036 ncbp->ncb_lana_num, code);
8038 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8039 MB_OK|MB_SERVICE_NOTIFICATION);
8040 osi_panic(tbuffer, __FILE__, __LINE__);
8043 /* check for remote conns */
8044 /* first get remote name and insert null terminator */
8045 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8046 for (i=NCBNAMSZ; i>0; i--) {
8047 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8053 /* compare with local name */
8055 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8056 flags |= SMB_VCFLAG_REMOTECONN;
8059 lock_ObtainMutex(&smb_ListenerLock);
8061 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8062 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8064 /* now ncbp->ncb_lsn is the connection ID */
8065 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8066 if (vcp->session == 0) {
8067 /* New generation */
8068 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8071 /* Log session startup */
8073 fprintf(stderr, "New 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, "New 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);
8083 lock_ObtainMutex(&vcp->mx);
8084 strcpy(vcp->rname, rname);
8085 vcp->flags |= flags;
8086 lock_ReleaseMutex(&vcp->mx);
8088 /* Allocate slot in session arrays */
8089 /* Re-use dead session if possible, otherwise add one more */
8090 /* But don't look at session[0], it is reserved */
8091 lock_ObtainWrite(&smb_globalLock);
8092 for (session = 1; session < numSessions; session++) {
8093 if (dead_sessions[session]) {
8094 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8095 dead_sessions[session] = FALSE;
8099 lock_ReleaseWrite(&smb_globalLock);
8101 /* We are re-using an existing VC because the lsn and lana
8103 session = vcp->session;
8105 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8107 /* Log session startup */
8109 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8110 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8111 #endif /* NOTSERVICE */
8112 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8113 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8115 if (reportSessionStartups) {
8116 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8120 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8121 unsigned long code = CM_ERROR_ALLBUSY;
8122 smb_packet_t * outp = GetPacket();
8123 unsigned char *outWctp;
8126 smb_FormatResponsePacket(vcp, NULL, outp);
8129 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8130 unsigned long NTStatus;
8131 smb_MapNTError(code, &NTStatus);
8132 outWctp = outp->wctp;
8133 smbp = (smb_t *) &outp->data;
8137 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8138 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8139 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8140 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8141 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8143 unsigned short errCode;
8144 unsigned char errClass;
8145 smb_MapCoreError(code, vcp, &errCode, &errClass);
8146 outWctp = outp->wctp;
8147 smbp = (smb_t *) &outp->data;
8151 smbp->errLow = (unsigned char) (errCode & 0xff);
8152 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8153 smbp->rcls = errClass;
8155 smb_SendPacket(vcp, outp);
8156 smb_FreePacket(outp);
8158 lock_ObtainMutex(&vcp->mx);
8159 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8160 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8162 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8163 lock_ReleaseMutex(&vcp->mx);
8164 lock_ObtainWrite(&smb_globalLock);
8165 dead_sessions[vcp->session] = TRUE;
8166 lock_ReleaseWrite(&smb_globalLock);
8167 smb_CleanupDeadVC(vcp);
8169 lock_ReleaseMutex(&vcp->mx);
8172 /* assert that we do not exceed the maximum number of sessions or NCBs.
8173 * we should probably want to wait for a session to be freed in case
8176 osi_assert(session < SESSION_MAX - 1);
8177 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8179 lock_ObtainMutex(&vcp->mx);
8180 vcp->session = session;
8181 lock_ReleaseMutex(&vcp->mx);
8182 lock_ObtainWrite(&smb_globalLock);
8183 LSNs[session] = ncbp->ncb_lsn;
8184 lanas[session] = ncbp->ncb_lana_num;
8185 lock_ReleaseWrite(&smb_globalLock);
8187 if (session == numSessions) {
8188 /* Add new NCB for new session */
8189 char eventName[MAX_PATH];
8191 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8193 InitNCBslot(numNCBs);
8194 lock_ObtainWrite(&smb_globalLock);
8196 lock_ReleaseWrite(&smb_globalLock);
8197 thrd_SetEvent(NCBavails[0]);
8198 thrd_SetEvent(NCBevents[0]);
8199 for (thread = 0; thread < smb_NumServerThreads; thread++)
8200 thrd_SetEvent(NCBreturns[thread][0]);
8201 /* Also add new session event */
8202 sprintf(eventName, "SessionEvents[%d]", session);
8203 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8204 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8205 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8206 lock_ObtainWrite(&smb_globalLock);
8208 lock_ReleaseWrite(&smb_globalLock);
8209 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8210 thrd_SetEvent(SessionEvents[0]);
8212 thrd_SetEvent(SessionEvents[session]);
8218 lock_ReleaseMutex(&smb_ListenerLock);
8219 } /* dispatch while loop */
8224 /* initialize Netbios */
8225 int smb_NetbiosInit(void)
8228 int i, lana, code, l;
8230 int delname_tried=0;
8233 lana_number_t lanaNum;
8235 /* setup the NCB system */
8238 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8239 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8240 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8242 if (smb_LANadapter != -1)
8243 afsi_log("LAN adapter number %d", smb_LANadapter);
8245 afsi_log("LAN adapter number not determined");
8248 afsi_log("Set for gateway service");
8250 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8252 /* something went horribly wrong. We can't proceed without a netbios name */
8254 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8255 osi_panic(buf, __FILE__, __LINE__);
8258 /* remember the name */
8259 len = (int)strlen(cm_NetbiosName);
8261 free(smb_localNamep);
8262 smb_localNamep = malloc(len+1);
8263 strcpy(smb_localNamep, cm_NetbiosName);
8264 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8267 if (smb_LANadapter == -1) {
8268 ncbp->ncb_command = NCBENUM;
8269 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8270 ncbp->ncb_length = sizeof(lana_list);
8271 code = Netbios(ncbp);
8273 afsi_log("Netbios NCBENUM error code %d", code);
8274 osi_panic(s, __FILE__, __LINE__);
8278 lana_list.length = 1;
8279 lana_list.lana[0] = smb_LANadapter;
8282 for (i = 0; i < lana_list.length; i++) {
8283 /* reset the adaptor: in Win32, this is required for every process, and
8284 * acts as an init call, not as a real hardware reset.
8286 ncbp->ncb_command = NCBRESET;
8287 ncbp->ncb_callname[0] = 100;
8288 ncbp->ncb_callname[2] = 100;
8289 ncbp->ncb_lana_num = lana_list.lana[i];
8290 code = Netbios(ncbp);
8292 code = ncbp->ncb_retcode;
8294 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8295 lana_list.lana[i] = 255; /* invalid lana */
8297 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8301 /* and declare our name so we can receive connections */
8302 memset(ncbp, 0, sizeof(*ncbp));
8303 len=lstrlen(smb_localNamep);
8304 memset(smb_sharename,' ',NCBNAMSZ);
8305 memcpy(smb_sharename,smb_localNamep,len);
8306 afsi_log("lana_list.length %d", lana_list.length);
8308 /* Keep the name so we can unregister it later */
8309 for (l = 0; l < lana_list.length; l++) {
8310 lana = lana_list.lana[l];
8312 ncbp->ncb_command = NCBADDNAME;
8313 ncbp->ncb_lana_num = lana;
8314 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8315 code = Netbios(ncbp);
8317 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8318 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8320 char name[NCBNAMSZ+1];
8322 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8323 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8327 code = ncbp->ncb_retcode;
8330 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8333 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8334 if (code == NRC_BRIDGE) { /* invalid LANA num */
8335 lana_list.lana[l] = 255;
8338 else if (code == NRC_DUPNAME) {
8339 afsi_log("Name already exists; try to delete it");
8340 memset(ncbp, 0, sizeof(*ncbp));
8341 ncbp->ncb_command = NCBDELNAME;
8342 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8343 ncbp->ncb_lana_num = lana;
8344 code = Netbios(ncbp);
8346 code = ncbp->ncb_retcode;
8348 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8350 if (code != 0 || delname_tried) {
8351 lana_list.lana[l] = 255;
8353 else if (code == 0) {
8354 if (!delname_tried) {
8362 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8363 lana_list.lana[l] = 255; /* invalid lana */
8367 lana_found = 1; /* at least one worked */
8371 osi_assert(lana_list.length >= 0);
8373 afsi_log("No valid LANA numbers found!");
8374 lana_list.length = 0;
8375 smb_LANadapter = -1;
8376 smb_ListenerState = SMB_LISTENER_STOPPED;
8377 cm_VolStatus_Network_Stopped(cm_NetbiosName
8384 /* we're done with the NCB now */
8387 return (lana_list.length > 0 ? 1 : 0);
8390 void smb_StartListeners()
8396 if (smb_ListenerState == SMB_LISTENER_STARTED)
8399 smb_ListenerState = SMB_LISTENER_STARTED;
8400 cm_VolStatus_Network_Started(cm_NetbiosName
8406 for (i = 0; i < lana_list.length; i++) {
8407 if (lana_list.lana[i] == 255)
8409 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8410 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8411 osi_assert(phandle != NULL);
8412 thrd_CloseHandle(phandle);
8416 void smb_RestartListeners()
8418 if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
8419 if (smb_NetbiosInit())
8420 smb_StartListeners();
8424 void smb_StopListener(NCB *ncbp, int lana)
8428 memset(ncbp, 0, sizeof(*ncbp));
8429 ncbp->ncb_command = NCBDELNAME;
8430 ncbp->ncb_lana_num = lana;
8431 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8432 code = Netbios(ncbp);
8434 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8435 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8437 /* and then reset the LANA; this will cause the listener threads to exit */
8438 ncbp->ncb_command = NCBRESET;
8439 ncbp->ncb_callname[0] = 100;
8440 ncbp->ncb_callname[2] = 100;
8441 ncbp->ncb_lana_num = lana;
8442 code = Netbios(ncbp);
8444 code = ncbp->ncb_retcode;
8446 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8448 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8452 void smb_StopListeners(void)
8457 if (smb_ListenerState == SMB_LISTENER_STOPPED)
8460 smb_ListenerState = SMB_LISTENER_STOPPED;
8461 cm_VolStatus_Network_Stopped(cm_NetbiosName
8469 /* Unregister the SMB name */
8470 for (l = 0; l < lana_list.length; l++) {
8471 lana = lana_list.lana[l];
8474 smb_StopListener(ncbp, lana);
8476 /* mark the adapter invalid */
8477 lana_list.lana[l] = 255; /* invalid lana */
8481 /* force a re-evaluation of the network adapters */
8482 lana_list.length = 0;
8483 smb_LANadapter = -1;
8485 Sleep(1000); /* give the listener threads a chance to exit */
8488 void smb_Init(osi_log_t *logp, int useV3,
8498 EVENT_HANDLE retHandle;
8499 char eventName[MAX_PATH];
8501 smb_TlsRequestSlot = TlsAlloc();
8503 smb_MBfunc = aMBfunc;
8507 /* Initialize smb_localZero */
8508 myTime.tm_isdst = -1; /* compute whether on DST or not */
8509 myTime.tm_year = 70;
8515 smb_localZero = mktime(&myTime);
8517 #ifndef USE_NUMERIC_TIME_CONV
8518 /* Initialize kludge-GMT */
8519 smb_CalculateNowTZ();
8520 #endif /* USE_NUMERIC_TIME_CONV */
8521 #ifdef AFS_FREELANCE_CLIENT
8522 /* Make sure the root.afs volume has the correct time */
8523 cm_noteLocalMountPointChange();
8526 /* initialize the remote debugging log */
8529 /* and the global lock */
8530 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8531 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8533 /* Raw I/O data structures */
8534 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8536 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8538 /* 4 Raw I/O buffers */
8539 smb_RawBufs = calloc(65536,1);
8540 *((char **)smb_RawBufs) = NULL;
8541 for (i=0; i<3; i++) {
8542 char *rawBuf = calloc(65536,1);
8543 *((char **)rawBuf) = smb_RawBufs;
8544 smb_RawBufs = rawBuf;
8547 /* global free lists */
8548 smb_ncbFreeListp = NULL;
8549 smb_packetFreeListp = NULL;
8553 /* Initialize listener and server structures */
8555 memset(dead_sessions, 0, sizeof(dead_sessions));
8556 sprintf(eventName, "SessionEvents[0]");
8557 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8558 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8559 afsi_log("Event Object Already Exists: %s", eventName);
8561 smb_NumServerThreads = nThreads;
8562 sprintf(eventName, "NCBavails[0]");
8563 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8564 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8565 afsi_log("Event Object Already Exists: %s", eventName);
8566 sprintf(eventName, "NCBevents[0]");
8567 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8568 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8569 afsi_log("Event Object Already Exists: %s", eventName);
8570 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8571 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8572 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8573 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8574 afsi_log("Event Object Already Exists: %s", eventName);
8575 for (i = 0; i < smb_NumServerThreads; i++) {
8576 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8577 NCBreturns[i][0] = retHandle;
8580 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8581 for (i = 0; i < smb_NumServerThreads; i++) {
8582 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8583 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8584 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8585 afsi_log("Event Object Already Exists: %s", eventName);
8586 InitNCBslot((int)(i+1));
8588 numNCBs = smb_NumServerThreads + 1;
8590 /* Initialize dispatch table */
8591 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8592 /* Prepare the table for unknown operations */
8593 for(i=0; i<= SMB_NOPCODES; i++) {
8594 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8596 /* Fill in the ones we do know */
8597 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8598 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8599 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8600 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8601 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8602 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8603 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8604 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8605 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8606 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8607 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8608 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8609 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8610 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8611 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8612 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8613 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8614 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8615 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8616 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8617 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8618 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8619 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8620 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8621 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8622 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8623 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8624 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8625 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8626 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8627 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8628 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8629 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8630 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8631 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8632 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8633 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8634 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8635 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8636 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8637 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8638 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8639 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8640 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8641 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8642 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8643 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8644 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8645 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8646 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8647 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8648 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8649 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8650 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8651 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8652 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8653 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8654 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8655 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8656 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8657 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8658 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8659 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8660 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8661 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8662 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8663 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8664 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8665 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8666 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8667 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8668 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8669 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8670 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8672 /* setup tran 2 dispatch table */
8673 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8674 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8675 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8676 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8677 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8678 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8679 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8680 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8681 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8682 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8683 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8684 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8685 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8686 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8687 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8688 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8689 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8690 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8692 /* setup the rap dispatch table */
8693 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8694 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8695 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8696 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8697 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8701 /* if we are doing SMB authentication we have register outselves as a logon process */
8702 if (smb_authType != SMB_AUTH_NONE) {
8703 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8704 LSA_STRING afsProcessName;
8705 LSA_OPERATIONAL_MODE dummy; /*junk*/
8707 afsProcessName.Buffer = "OpenAFSClientDaemon";
8708 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8709 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8711 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8713 if (nts == STATUS_SUCCESS) {
8714 LSA_STRING packageName;
8715 /* we are registered. Find out the security package id */
8716 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8717 packageName.Length = (USHORT)strlen(packageName.Buffer);
8718 packageName.MaximumLength = packageName.Length + 1;
8719 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8720 if (nts == STATUS_SUCCESS) {
8722 * This code forces Windows to authenticate against the Logon Cache
8723 * first instead of attempting to authenticate against the Domain
8724 * Controller. When the Windows logon cache is enabled this improves
8725 * performance by removing the network access and works around a bug
8726 * seen at sites which are using a MIT Kerberos principal to login
8727 * to machines joined to a non-root domain in a multi-domain forest.
8728 * MsV1_0SetProcessOption was added in Windows XP.
8730 PVOID pResponse = NULL;
8731 ULONG cbResponse = 0;
8732 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8734 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8735 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8736 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8737 OptionsRequest.DisableOptions = FALSE;
8739 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8742 sizeof(OptionsRequest),
8748 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8750 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8752 OutputDebugString(message);
8755 OutputDebugString("MsV1_0SetProcessOption success");
8756 afsi_log("MsV1_0SetProcessOption success");
8758 /* END - code from Larry */
8760 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8761 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8762 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8764 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8766 /* something went wrong. We report the error and revert back to no authentication
8767 because we can't perform any auth requests without a successful lsa handle
8768 or sec package id. */
8769 afsi_log("Reverting to NO SMB AUTH");
8770 smb_authType = SMB_AUTH_NONE;
8773 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8775 /* something went wrong. We report the error and revert back to no authentication
8776 because we can't perform any auth requests without a successful lsa handle
8777 or sec package id. */
8778 afsi_log("Reverting to NO SMB AUTH");
8779 smb_authType = SMB_AUTH_NONE;
8783 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8784 * time prevents the failure of authentication when logged into Windows with an
8785 * external Kerberos principal mapped to a local account.
8787 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8788 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8789 * then the only option is NTLMSSP anyway; so just fallback.
8794 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8795 if (secBlobLength == 0) {
8796 smb_authType = SMB_AUTH_NTLM;
8797 afsi_log("Reverting to SMB AUTH NTLM");
8806 /* Now get ourselves a domain name. */
8807 /* For now we are using the local computer name as the domain name.
8808 * It is actually the domain for local logins, and we are acting as
8809 * a local SMB server.
8811 bufsize = sizeof(smb_ServerDomainName) - 1;
8812 GetComputerName(smb_ServerDomainName, &bufsize);
8813 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8814 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8817 /* Start listeners, waiters, servers, and daemons */
8819 smb_StartListeners();
8821 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8822 NULL, 0, &lpid, "smb_ClientWaiter");
8823 osi_assert(phandle != NULL);
8824 thrd_CloseHandle(phandle);
8826 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8827 NULL, 0, &lpid, "smb_ServerWaiter");
8828 osi_assert(phandle != NULL);
8829 thrd_CloseHandle(phandle);
8831 for (i=0; i<smb_NumServerThreads; i++) {
8832 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8833 (void *) i, 0, &lpid, "smb_Server");
8834 osi_assert(phandle != NULL);
8835 thrd_CloseHandle(phandle);
8838 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8839 NULL, 0, &lpid, "smb_Daemon");
8840 osi_assert(phandle != NULL);
8841 thrd_CloseHandle(phandle);
8843 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8844 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8845 osi_assert(phandle != NULL);
8846 thrd_CloseHandle(phandle);
8851 void smb_Shutdown(void)
8858 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8860 /* setup the NCB system */
8863 /* Block new sessions by setting shutdown flag */
8864 smbShutdownFlag = 1;
8866 /* Hang up all sessions */
8867 memset((char *)ncbp, 0, sizeof(NCB));
8868 for (i = 1; i < numSessions; i++)
8870 if (dead_sessions[i])
8873 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8874 ncbp->ncb_command = NCBHANGUP;
8875 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8876 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8877 code = Netbios(ncbp);
8878 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8879 if (code == 0) code = ncbp->ncb_retcode;
8881 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8882 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8886 /* Trigger the shutdown of all SMB threads */
8887 for (i = 0; i < smb_NumServerThreads; i++)
8888 thrd_SetEvent(NCBreturns[i][0]);
8890 thrd_SetEvent(NCBevents[0]);
8891 thrd_SetEvent(SessionEvents[0]);
8892 thrd_SetEvent(NCBavails[0]);
8894 for (i = 0;i < smb_NumServerThreads; i++) {
8895 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8896 if (code == WAIT_OBJECT_0) {
8899 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8900 thrd_SetEvent(NCBreturns[i--][0]);
8904 /* Delete Netbios name */
8905 memset((char *)ncbp, 0, sizeof(NCB));
8906 for (i = 0; i < lana_list.length; i++) {
8907 if (lana_list.lana[i] == 255) continue;
8908 ncbp->ncb_command = NCBDELNAME;
8909 ncbp->ncb_lana_num = lana_list.lana[i];
8910 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8911 code = Netbios(ncbp);
8913 code = ncbp->ncb_retcode;
8915 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8916 ncbp->ncb_lana_num, code);
8921 /* Release the reference counts held by the VCs */
8922 lock_ObtainWrite(&smb_rctLock);
8923 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8928 if (vcp->magic != SMB_VC_MAGIC)
8929 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8930 __FILE__, __LINE__);
8932 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8934 if (fidp->scp != NULL) {
8937 lock_ObtainMutex(&fidp->mx);
8938 if (fidp->scp != NULL) {
8941 lock_ObtainMutex(&scp->mx);
8942 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
8943 lock_ReleaseMutex(&scp->mx);
8944 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
8945 cm_ReleaseSCache(scp);
8947 lock_ReleaseMutex(&fidp->mx);
8951 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8953 smb_ReleaseVCNoLock(tidp->vcp);
8955 cm_user_t *userp = tidp->userp;
8957 lock_ReleaseWrite(&smb_rctLock);
8958 cm_ReleaseUser(userp);
8959 lock_ObtainWrite(&smb_rctLock);
8963 lock_ReleaseWrite(&smb_rctLock);
8965 TlsFree(smb_TlsRequestSlot);
8968 /* Get the UNC \\<servername>\<sharename> prefix. */
8969 char *smb_GetSharename()
8973 /* Make sure we have been properly initialized. */
8974 if (smb_localNamep == NULL)
8977 /* Allocate space for \\<servername>\<sharename>, plus the
8980 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8981 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8987 void smb_LogPacket(smb_packet_t *packet)
8990 unsigned length, paramlen, datalen, i, j;
8992 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8994 if (!packet) return;
8996 osi_Log0(smb_logp, "*** SMB packet dump ***");
8998 vp = (BYTE *) packet->data;
9000 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9001 length = paramlen + 2 + datalen;
9004 for (i=0;i < length; i+=16)
9006 memset( buf, ' ', 80 );
9011 buf[strlen(buf)] = ' ';
9013 cp = (BYTE*) buf + 7;
9015 for (j=0;j < 16 && (i+j)<length; j++)
9017 *(cp++) = hex[vp[i+j] >> 4];
9018 *(cp++) = hex[vp[i+j] & 0xf];
9028 for (j=0;j < 16 && (i+j)<length;j++)
9030 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9041 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9044 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9046 #endif /* LOG_PACKET */
9049 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9057 lock_ObtainRead(&smb_rctLock);
9059 sprintf(output, "begin dumping smb_vc_t\r\n");
9060 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9062 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9066 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9067 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9068 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9070 sprintf(output, "begin dumping smb_fid_t\r\n");
9071 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9073 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9075 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",
9076 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9077 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9078 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9079 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9082 sprintf(output, "done dumping smb_fid_t\r\n");
9083 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9086 sprintf(output, "done dumping smb_vc_t\r\n");
9087 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9089 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9090 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9092 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9096 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9097 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9098 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9100 sprintf(output, "begin dumping smb_fid_t\r\n");
9101 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9103 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9105 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",
9106 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9107 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9108 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9109 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9112 sprintf(output, "done dumping smb_fid_t\r\n");
9113 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9116 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9117 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9120 lock_ReleaseRead(&smb_rctLock);
9124 long smb_IsNetworkStarted(void)
9126 return (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);