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;
2411 #ifdef SEND_CANONICAL_PATHNAMES
2412 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2414 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2416 /* copy fields in generic packet area */
2417 op->wctp = &outp->wct;
2420 /* send a (probably response) packet; vcp tells us to whom to send it.
2421 * we compute the length by looking at wct and bcc fields.
2423 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2437 memset((char *)ncbp, 0, sizeof(NCB));
2439 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2440 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2441 extra += tp[0] + (tp[1]<<8);
2442 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2443 extra += 3; /* wct and length fields */
2445 ncbp->ncb_length = extra; /* bytes to send */
2446 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2447 ncbp->ncb_lana_num = vcp->lana;
2448 ncbp->ncb_command = NCBSEND; /* op means send data */
2449 ncbp->ncb_buffer = (char *) inp;/* packet */
2450 code = Netbios(ncbp);
2453 const char * s = ncb_error_string(code);
2454 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2455 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2457 lock_ObtainMutex(&vcp->mx);
2458 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2459 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2461 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2462 lock_ReleaseMutex(&vcp->mx);
2463 lock_ObtainWrite(&smb_globalLock);
2464 dead_sessions[vcp->session] = TRUE;
2465 lock_ReleaseWrite(&smb_globalLock);
2466 smb_CleanupDeadVC(vcp);
2468 lock_ReleaseMutex(&vcp->mx);
2476 void smb_MapNTError(long code, unsigned long *NTStatusp)
2478 unsigned long NTStatus;
2480 /* map CM_ERROR_* errors to NT 32-bit status codes */
2481 /* NT Status codes are listed in ntstatus.h not winerror.h */
2482 if (code == CM_ERROR_NOSUCHCELL) {
2483 NTStatus = 0xC000000FL; /* No such file */
2485 else if (code == CM_ERROR_NOSUCHVOLUME) {
2486 NTStatus = 0xC000000FL; /* No such file */
2488 else if (code == CM_ERROR_TIMEDOUT) {
2490 NTStatus = 0xC00000CFL; /* Sharing Paused */
2492 NTStatus = 0x00000102L; /* Timeout */
2495 else if (code == CM_ERROR_RETRY) {
2496 NTStatus = 0xC000022DL; /* Retry */
2498 else if (code == CM_ERROR_NOACCESS) {
2499 NTStatus = 0xC0000022L; /* Access denied */
2501 else if (code == CM_ERROR_READONLY) {
2502 NTStatus = 0xC00000A2L; /* Write protected */
2504 else if (code == CM_ERROR_NOSUCHFILE ||
2505 code == CM_ERROR_BPLUS_NOMATCH) {
2506 NTStatus = 0xC000000FL; /* No such file */
2508 else if (code == CM_ERROR_NOSUCHPATH) {
2509 NTStatus = 0xC000003AL; /* Object path not found */
2511 else if (code == CM_ERROR_TOOBIG) {
2512 NTStatus = 0xC000007BL; /* Invalid image format */
2514 else if (code == CM_ERROR_INVAL) {
2515 NTStatus = 0xC000000DL; /* Invalid parameter */
2517 else if (code == CM_ERROR_BADFD) {
2518 NTStatus = 0xC0000008L; /* Invalid handle */
2520 else if (code == CM_ERROR_BADFDOP) {
2521 NTStatus = 0xC0000022L; /* Access denied */
2523 else if (code == CM_ERROR_EXISTS) {
2524 NTStatus = 0xC0000035L; /* Object name collision */
2526 else if (code == CM_ERROR_NOTEMPTY) {
2527 NTStatus = 0xC0000101L; /* Directory not empty */
2529 else if (code == CM_ERROR_CROSSDEVLINK) {
2530 NTStatus = 0xC00000D4L; /* Not same device */
2532 else if (code == CM_ERROR_NOTDIR) {
2533 NTStatus = 0xC0000103L; /* Not a directory */
2535 else if (code == CM_ERROR_ISDIR) {
2536 NTStatus = 0xC00000BAL; /* File is a directory */
2538 else if (code == CM_ERROR_BADOP) {
2540 /* I have no idea where this comes from */
2541 NTStatus = 0xC09820FFL; /* SMB no support */
2543 NTStatus = 0xC00000BBL; /* Not supported */
2544 #endif /* COMMENT */
2546 else if (code == CM_ERROR_BADSHARENAME) {
2547 NTStatus = 0xC00000CCL; /* Bad network name */
2549 else if (code == CM_ERROR_NOIPC) {
2551 NTStatus = 0xC0000022L; /* Access Denied */
2553 NTStatus = 0xC000013DL; /* Remote Resources */
2556 else if (code == CM_ERROR_CLOCKSKEW) {
2557 NTStatus = 0xC0000133L; /* Time difference at DC */
2559 else if (code == CM_ERROR_BADTID) {
2560 NTStatus = 0xC0982005L; /* SMB bad TID */
2562 else if (code == CM_ERROR_USESTD) {
2563 NTStatus = 0xC09820FBL; /* SMB use standard */
2565 else if (code == CM_ERROR_QUOTA) {
2567 NTStatus = 0xC0000044L; /* Quota exceeded */
2569 NTStatus = 0xC000007FL; /* Disk full */
2572 else if (code == CM_ERROR_SPACE) {
2573 NTStatus = 0xC000007FL; /* Disk full */
2575 else if (code == CM_ERROR_ATSYS) {
2576 NTStatus = 0xC0000033L; /* Object name invalid */
2578 else if (code == CM_ERROR_BADNTFILENAME) {
2579 NTStatus = 0xC0000033L; /* Object name invalid */
2581 else if (code == CM_ERROR_WOULDBLOCK) {
2582 NTStatus = 0xC0000055L; /* Lock not granted */
2584 else if (code == CM_ERROR_SHARING_VIOLATION) {
2585 NTStatus = 0xC0000043L; /* Sharing violation */
2587 else if (code == CM_ERROR_LOCK_CONFLICT) {
2588 NTStatus = 0xC0000054L; /* Lock conflict */
2590 else if (code == CM_ERROR_PARTIALWRITE) {
2591 NTStatus = 0xC000007FL; /* Disk full */
2593 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2594 NTStatus = 0xC0000023L; /* Buffer too small */
2596 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2597 NTStatus = 0xC0000035L; /* Object name collision */
2599 else if (code == CM_ERROR_BADPASSWORD) {
2600 NTStatus = 0xC000006DL; /* unknown username or bad password */
2602 else if (code == CM_ERROR_BADLOGONTYPE) {
2603 NTStatus = 0xC000015BL; /* logon type not granted */
2605 else if (code == CM_ERROR_GSSCONTINUE) {
2606 NTStatus = 0xC0000016L; /* more processing required */
2608 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2610 NTStatus = 0xC0000280L; /* reparse point not resolved */
2612 NTStatus = 0xC0000022L; /* Access Denied */
2615 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2616 NTStatus = 0xC0000257L; /* Path Not Covered */
2619 else if (code == CM_ERROR_ALLBUSY) {
2620 NTStatus = 0xC00000BFL; /* Network Busy */
2622 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2623 NTStatus = 0xC0000350L; /* Remote Host Down */
2626 /* we do not want to be telling the SMB/CIFS client that
2627 * the AFS Client Service is busy or down.
2629 else if (code == CM_ERROR_ALLBUSY ||
2630 code == CM_ERROR_ALLOFFLINE ||
2631 code == CM_ERROR_ALLDOWN) {
2632 NTStatus = 0xC00000BEL; /* Bad Network Path */
2635 else if (code == RXKADUNKNOWNKEY) {
2636 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2638 else if (code == CM_ERROR_BAD_LEVEL) {
2639 NTStatus = 0xC0000148L; /* Invalid Level */
2641 NTStatus = 0xC0982001L; /* SMB non-specific error */
2644 *NTStatusp = NTStatus;
2645 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2648 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2649 unsigned char *classp)
2651 unsigned char class;
2652 unsigned short error;
2654 /* map CM_ERROR_* errors to SMB errors */
2655 if (code == CM_ERROR_NOSUCHCELL) {
2657 error = 3; /* bad path */
2659 else if (code == CM_ERROR_NOSUCHVOLUME) {
2661 error = 3; /* bad path */
2663 else if (code == CM_ERROR_TIMEDOUT) {
2665 error = 81; /* server is paused */
2667 else if (code == CM_ERROR_RETRY) {
2668 class = 2; /* shouldn't happen */
2671 else if (code == CM_ERROR_NOACCESS) {
2673 error = 4; /* bad access */
2675 else if (code == CM_ERROR_READONLY) {
2677 error = 19; /* read only */
2679 else if (code == CM_ERROR_NOSUCHFILE ||
2680 code == CM_ERROR_BPLUS_NOMATCH) {
2682 error = 2; /* ENOENT! */
2684 else if (code == CM_ERROR_NOSUCHPATH) {
2686 error = 3; /* Bad path */
2688 else if (code == CM_ERROR_TOOBIG) {
2690 error = 11; /* bad format */
2692 else if (code == CM_ERROR_INVAL) {
2693 class = 2; /* server non-specific error code */
2696 else if (code == CM_ERROR_BADFD) {
2698 error = 6; /* invalid file handle */
2700 else if (code == CM_ERROR_BADFDOP) {
2701 class = 1; /* invalid op on FD */
2704 else if (code == CM_ERROR_EXISTS) {
2706 error = 80; /* file already exists */
2708 else if (code == CM_ERROR_NOTEMPTY) {
2710 error = 5; /* delete directory not empty */
2712 else if (code == CM_ERROR_CROSSDEVLINK) {
2714 error = 17; /* EXDEV */
2716 else if (code == CM_ERROR_NOTDIR) {
2717 class = 1; /* bad path */
2720 else if (code == CM_ERROR_ISDIR) {
2721 class = 1; /* access denied; DOS doesn't have a good match */
2724 else if (code == CM_ERROR_BADOP) {
2728 else if (code == CM_ERROR_BADSHARENAME) {
2732 else if (code == CM_ERROR_NOIPC) {
2734 error = 4; /* bad access */
2736 else if (code == CM_ERROR_CLOCKSKEW) {
2737 class = 1; /* invalid function */
2740 else if (code == CM_ERROR_BADTID) {
2744 else if (code == CM_ERROR_USESTD) {
2748 else if (code == CM_ERROR_REMOTECONN) {
2752 else if (code == CM_ERROR_QUOTA) {
2753 if (vcp->flags & SMB_VCFLAG_USEV3) {
2755 error = 39; /* disk full */
2759 error = 5; /* access denied */
2762 else if (code == CM_ERROR_SPACE) {
2763 if (vcp->flags & SMB_VCFLAG_USEV3) {
2765 error = 39; /* disk full */
2769 error = 5; /* access denied */
2772 else if (code == CM_ERROR_PARTIALWRITE) {
2774 error = 39; /* disk full */
2776 else if (code == CM_ERROR_ATSYS) {
2778 error = 2; /* ENOENT */
2780 else if (code == CM_ERROR_WOULDBLOCK) {
2782 error = 33; /* lock conflict */
2784 else if (code == CM_ERROR_LOCK_CONFLICT) {
2786 error = 33; /* lock conflict */
2788 else if (code == CM_ERROR_SHARING_VIOLATION) {
2790 error = 33; /* lock conflict */
2792 else if (code == CM_ERROR_NOFILES) {
2794 error = 18; /* no files in search */
2796 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2798 error = 183; /* Samba uses this */
2800 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2801 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2803 error = 2; /* bad password */
2805 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2807 error = 3; /* bad path */
2816 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2819 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2821 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2822 return CM_ERROR_BADOP;
2825 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2827 unsigned short EchoCount, i;
2828 char *data, *outdata;
2831 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2833 for (i=1; i<=EchoCount; i++) {
2834 data = smb_GetSMBData(inp, &dataSize);
2835 smb_SetSMBParm(outp, 0, i);
2836 smb_SetSMBDataLength(outp, dataSize);
2837 outdata = smb_GetSMBData(outp, NULL);
2838 memcpy(outdata, data, dataSize);
2839 smb_SendPacket(vcp, outp);
2845 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2848 long count, minCount, finalCount;
2853 cm_user_t *userp = NULL;
2856 char *rawBuf = NULL;
2861 fd = smb_GetSMBParm(inp, 0);
2862 count = smb_GetSMBParm(inp, 3);
2863 minCount = smb_GetSMBParm(inp, 4);
2864 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2866 if (*inp->wctp == 10) {
2867 /* we were sent a request with 64-bit file offsets */
2868 #ifdef AFS_LARGEFILES
2869 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2871 if (LargeIntegerLessThanZero(offset)) {
2872 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2876 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2877 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2880 offset.HighPart = 0;
2884 /* we were sent a request with 32-bit file offsets */
2885 offset.HighPart = 0;
2888 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2889 fd, offset.HighPart, offset.LowPart, count);
2891 fidp = smb_FindFID(vcp, fd, 0);
2895 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2896 smb_CloseFID(vcp, fidp, NULL, 0);
2897 code = CM_ERROR_NOSUCHFILE;
2902 pid = ((smb_t *) inp)->pid;
2904 LARGE_INTEGER LOffset, LLength;
2907 key = cm_GenerateKey(vcp->vcID, pid, fd);
2909 LOffset.HighPart = offset.HighPart;
2910 LOffset.LowPart = offset.LowPart;
2911 LLength.HighPart = 0;
2912 LLength.LowPart = count;
2914 lock_ObtainMutex(&fidp->scp->mx);
2915 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2916 lock_ReleaseMutex(&fidp->scp->mx);
2922 lock_ObtainMutex(&smb_RawBufLock);
2924 /* Get a raw buf, from head of list */
2925 rawBuf = smb_RawBufs;
2926 smb_RawBufs = *(char **)smb_RawBufs;
2928 lock_ReleaseMutex(&smb_RawBufLock);
2932 lock_ObtainMutex(&fidp->mx);
2933 if (fidp->flags & SMB_FID_IOCTL)
2935 lock_ReleaseMutex(&fidp->mx);
2936 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2938 /* Give back raw buffer */
2939 lock_ObtainMutex(&smb_RawBufLock);
2940 *((char **) rawBuf) = smb_RawBufs;
2942 smb_RawBufs = rawBuf;
2943 lock_ReleaseMutex(&smb_RawBufLock);
2946 smb_ReleaseFID(fidp);
2949 lock_ReleaseMutex(&fidp->mx);
2951 userp = smb_GetUserFromVCP(vcp, inp);
2953 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2959 cm_ReleaseUser(userp);
2962 smb_ReleaseFID(fidp);
2966 memset((char *)ncbp, 0, sizeof(NCB));
2968 ncbp->ncb_length = (unsigned short) finalCount;
2969 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2970 ncbp->ncb_lana_num = vcp->lana;
2971 ncbp->ncb_command = NCBSEND;
2972 ncbp->ncb_buffer = rawBuf;
2974 code = Netbios(ncbp);
2976 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2979 /* Give back raw buffer */
2980 lock_ObtainMutex(&smb_RawBufLock);
2981 *((char **) rawBuf) = smb_RawBufs;
2983 smb_RawBufs = rawBuf;
2984 lock_ReleaseMutex(&smb_RawBufLock);
2990 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2992 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2997 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2999 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3004 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3011 int VistaProtoIndex;
3012 int protoIndex; /* index we're using */
3017 char protocol_array[10][1024]; /* protocol signature of the client */
3018 int caps; /* capabilities */
3021 TIME_ZONE_INFORMATION tzi;
3023 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3026 namep = smb_GetSMBData(inp, &dbytes);
3029 coreProtoIndex = -1; /* not found */
3032 VistaProtoIndex = -1;
3033 while(namex < dbytes) {
3034 osi_Log1(smb_logp, "Protocol %s",
3035 osi_LogSaveString(smb_logp, namep+1));
3036 strcpy(protocol_array[tcounter], namep+1);
3038 /* namep points at the first protocol, or really, a 0x02
3039 * byte preceding the null-terminated ASCII name.
3041 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3042 coreProtoIndex = tcounter;
3044 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3045 v3ProtoIndex = tcounter;
3047 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3048 NTProtoIndex = tcounter;
3050 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3051 VistaProtoIndex = tcounter;
3054 /* compute size of protocol entry */
3055 entryLength = (int)strlen(namep+1);
3056 entryLength += 2; /* 0x02 bytes and null termination */
3058 /* advance over this protocol entry */
3059 namex += entryLength;
3060 namep += entryLength;
3061 tcounter++; /* which proto entry we're looking at */
3064 lock_ObtainMutex(&vcp->mx);
3066 if (VistaProtoIndex != -1) {
3067 protoIndex = VistaProtoIndex;
3068 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3071 if (NTProtoIndex != -1) {
3072 protoIndex = NTProtoIndex;
3073 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3075 else if (v3ProtoIndex != -1) {
3076 protoIndex = v3ProtoIndex;
3077 vcp->flags |= SMB_VCFLAG_USEV3;
3079 else if (coreProtoIndex != -1) {
3080 protoIndex = coreProtoIndex;
3081 vcp->flags |= SMB_VCFLAG_USECORE;
3083 else protoIndex = -1;
3084 lock_ReleaseMutex(&vcp->mx);
3086 if (protoIndex == -1)
3087 return CM_ERROR_INVAL;
3088 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3089 smb_SetSMBParm(outp, 0, protoIndex);
3090 if (smb_authType != SMB_AUTH_NONE) {
3091 smb_SetSMBParmByte(outp, 1,
3092 NEGOTIATE_SECURITY_USER_LEVEL |
3093 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3095 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3097 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3098 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3099 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3100 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3101 /* The session key is not a well documented field however most clients
3102 * will echo back the session key to the server. Currently we are using
3103 * the same value for all sessions. We should generate a random value
3104 * and store it into the vcp
3106 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3107 smb_SetSMBParm(outp, 8, 1);
3109 * Tried changing the capabilities to support for W2K - defect 117695
3110 * Maybe something else needs to be changed here?
3114 smb_SetSMBParmLong(outp, 9, 0x43fd);
3116 smb_SetSMBParmLong(outp, 9, 0x251);
3119 * 32-bit error codes *
3124 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3126 NTNEGOTIATE_CAPABILITY_DFS |
3128 #ifdef AFS_LARGEFILES
3129 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3131 NTNEGOTIATE_CAPABILITY_NTFIND |
3132 NTNEGOTIATE_CAPABILITY_RAWMODE |
3133 NTNEGOTIATE_CAPABILITY_NTSMB;
3135 if ( smb_authType == SMB_AUTH_EXTENDED )
3136 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3138 smb_SetSMBParmLong(outp, 9, caps);
3140 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3141 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3142 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3144 GetTimeZoneInformation(&tzi);
3145 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3147 if (smb_authType == SMB_AUTH_NTLM) {
3148 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3149 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3150 /* paste in encryption key */
3151 datap = smb_GetSMBData(outp, NULL);
3152 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3153 /* and the faux domain name */
3154 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3155 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3159 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3161 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3163 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3165 datap = smb_GetSMBData(outp, NULL);
3166 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3169 datap += sizeof(smb_ServerGUID);
3170 memcpy(datap, secBlob, secBlobLength);
3174 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3175 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3178 else if (v3ProtoIndex != -1) {
3179 smb_SetSMBParm(outp, 0, protoIndex);
3181 /* NOTE: Extended authentication cannot be negotiated with v3
3182 * therefore we fail over to NTLM
3184 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3185 smb_SetSMBParm(outp, 1,
3186 NEGOTIATE_SECURITY_USER_LEVEL |
3187 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3189 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3191 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3192 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3193 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3194 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3195 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3196 smb_SetSMBParm(outp, 7, 1);
3198 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3199 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3200 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3202 GetTimeZoneInformation(&tzi);
3203 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3205 /* NOTE: Extended authentication cannot be negotiated with v3
3206 * therefore we fail over to NTLM
3208 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3209 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3210 smb_SetSMBParm(outp, 12, 0); /* resvd */
3211 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3212 datap = smb_GetSMBData(outp, NULL);
3213 /* paste in a new encryption key */
3214 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3215 /* and the faux domain name */
3216 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3218 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3219 smb_SetSMBParm(outp, 12, 0); /* resvd */
3220 smb_SetSMBDataLength(outp, 0);
3223 else if (coreProtoIndex != -1) { /* not really supported anymore */
3224 smb_SetSMBParm(outp, 0, protoIndex);
3225 smb_SetSMBDataLength(outp, 0);
3230 void smb_CheckVCs(void)
3232 smb_vc_t * vcp, *nextp;
3233 smb_packet_t * outp = GetPacket();
3236 lock_ObtainWrite(&smb_rctLock);
3237 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3239 if (vcp->magic != SMB_VC_MAGIC)
3240 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3241 __FILE__, __LINE__);
3245 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3248 smb_HoldVCNoLock(vcp);
3250 smb_HoldVCNoLock(nextp);
3251 smb_FormatResponsePacket(vcp, NULL, outp);
3252 smbp = (smb_t *)outp;
3253 outp->inCom = smbp->com = 0x2b /* Echo */;
3261 smb_SetSMBParm(outp, 0, 0);
3262 smb_SetSMBDataLength(outp, 0);
3263 lock_ReleaseWrite(&smb_rctLock);
3265 smb_SendPacket(vcp, outp);
3267 lock_ObtainWrite(&smb_rctLock);
3268 smb_ReleaseVCNoLock(vcp);
3270 smb_ReleaseVCNoLock(nextp);
3272 lock_ReleaseWrite(&smb_rctLock);
3273 smb_FreePacket(outp);
3276 void smb_Daemon(void *parmp)
3278 afs_uint32 count = 0;
3279 smb_username_t **unpp;
3282 while(smbShutdownFlag == 0) {
3286 if (smbShutdownFlag == 1)
3289 if ((count % 72) == 0) { /* every five minutes */
3291 time_t old_localZero = smb_localZero;
3293 /* Initialize smb_localZero */
3294 myTime.tm_isdst = -1; /* compute whether on DST or not */
3295 myTime.tm_year = 70;
3301 smb_localZero = mktime(&myTime);
3303 #ifndef USE_NUMERIC_TIME_CONV
3304 smb_CalculateNowTZ();
3305 #endif /* USE_NUMERIC_TIME_CONV */
3306 #ifdef AFS_FREELANCE
3307 if ( smb_localZero != old_localZero )
3308 cm_noteLocalMountPointChange();
3314 /* GC smb_username_t objects that will no longer be used */
3316 lock_ObtainWrite(&smb_rctLock);
3317 for ( unpp=&usernamesp; *unpp; ) {
3319 smb_username_t *unp;
3321 lock_ObtainMutex(&(*unpp)->mx);
3322 if ( (*unpp)->refCount > 0 ||
3323 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3324 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3326 else if (!smb_LogoffTokenTransfer ||
3327 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3329 lock_ReleaseMutex(&(*unpp)->mx);
3337 lock_FinalizeMutex(&unp->mx);
3343 lock_ReleaseWrite(&smb_rctLock);
3344 cm_ReleaseUser(userp);
3345 lock_ObtainWrite(&smb_rctLock);
3348 unpp = &(*unpp)->nextp;
3351 lock_ReleaseWrite(&smb_rctLock);
3353 /* XXX GC dir search entries */
3357 void smb_WaitingLocksDaemon()
3359 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3360 smb_waitingLock_t *wl, *wlNext;
3363 smb_packet_t *inp, *outp;
3367 while (smbShutdownFlag == 0) {
3368 lock_ObtainWrite(&smb_globalLock);
3369 nwlRequest = smb_allWaitingLocks;
3370 if (nwlRequest == NULL) {
3371 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3376 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3383 lock_ObtainWrite(&smb_globalLock);
3385 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3387 wlRequest = nwlRequest;
3388 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3389 lock_ReleaseWrite(&smb_globalLock);
3393 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3394 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3397 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3399 /* wl->state is either _DONE or _WAITING. _ERROR
3400 would no longer be on the queue. */
3401 code = cm_RetryLock( wl->lockp,
3402 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3405 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3406 } else if (code != CM_ERROR_WOULDBLOCK) {
3407 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3412 if (code == CM_ERROR_WOULDBLOCK) {
3415 if (wlRequest->timeRemaining != 0xffffffff
3416 && (wlRequest->timeRemaining -= 1000) < 0)
3428 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3431 scp = wlRequest->scp;
3432 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3436 lock_ObtainMutex(&scp->mx);
3438 for (wl = wlRequest->locks; wl; wl = wlNext) {
3439 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3441 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3442 wl->LLength, wl->key, NULL, &req);
3444 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3449 lock_ReleaseMutex(&scp->mx);
3453 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3456 for (wl = wlRequest->locks; wl; wl = wlNext) {
3457 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3458 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3463 vcp = wlRequest->vcp;
3464 inp = wlRequest->inp;
3465 outp = wlRequest->outp;
3467 ncbp->ncb_length = inp->ncb_length;
3468 inp->spacep = cm_GetSpace();
3470 /* Remove waitingLock from list */
3471 lock_ObtainWrite(&smb_globalLock);
3472 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3474 lock_ReleaseWrite(&smb_globalLock);
3476 /* Resume packet processing */
3478 smb_SetSMBDataLength(outp, 0);
3479 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3480 outp->resumeCode = code;
3482 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3485 cm_FreeSpace(inp->spacep);
3486 smb_FreePacket(inp);
3487 smb_FreePacket(outp);
3489 cm_ReleaseSCache(wlRequest->scp);
3492 } while (nwlRequest && smbShutdownFlag == 0);
3497 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3499 osi_Log0(smb_logp, "SMB receive get disk attributes");
3501 smb_SetSMBParm(outp, 0, 32000);
3502 smb_SetSMBParm(outp, 1, 64);
3503 smb_SetSMBParm(outp, 2, 1024);
3504 smb_SetSMBParm(outp, 3, 30000);
3505 smb_SetSMBParm(outp, 4, 0);
3506 smb_SetSMBDataLength(outp, 0);
3510 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3514 unsigned short newTid;
3515 char shareName[AFSPATHMAX];
3523 osi_Log0(smb_logp, "SMB receive tree connect");
3525 /* parse input parameters */
3526 tp = smb_GetSMBData(inp, NULL);
3527 pathp = smb_ParseASCIIBlock(tp, &tp);
3528 if (smb_StoreAnsiFilenames)
3529 OemToChar(pathp,pathp);
3530 passwordp = smb_ParseASCIIBlock(tp, &tp);
3531 tp = strrchr(pathp, '\\');
3533 return CM_ERROR_BADSMB;
3534 strcpy(shareName, tp+1);
3536 lock_ObtainMutex(&vcp->mx);
3537 newTid = vcp->tidCounter++;
3538 lock_ReleaseMutex(&vcp->mx);
3540 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3541 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3542 userp = smb_GetUserFromUID(uidp);
3543 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3545 smb_ReleaseUID(uidp);
3547 smb_ReleaseTID(tidp);
3548 return CM_ERROR_BADSHARENAME;
3550 lock_ObtainMutex(&tidp->mx);
3551 tidp->userp = userp;
3552 tidp->pathname = sharePath;
3553 lock_ReleaseMutex(&tidp->mx);
3554 smb_ReleaseTID(tidp);
3556 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3557 smb_SetSMBParm(rsp, 1, newTid);
3558 smb_SetSMBDataLength(rsp, 0);
3560 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3564 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3568 if (*inp++ != 0x1) return NULL;
3569 tlen = inp[0] + (inp[1]<<8);
3570 inp += 2; /* skip length field */
3573 *chainpp = inp + tlen;
3576 if (lengthp) *lengthp = tlen;
3581 /* set maskp to the mask part of the incoming path.
3582 * Mask is 11 bytes long (8.3 with the dot elided).
3583 * Returns true if succeeds with a valid name, otherwise it does
3584 * its best, but returns false.
3586 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3594 /* starts off valid */
3597 /* mask starts out all blanks */
3598 memset(maskp, ' ', 11);
3600 /* find last backslash, or use whole thing if there is none */
3601 tp = strrchr(pathp, '\\');
3602 if (!tp) tp = pathp;
3603 else tp++; /* skip slash */
3607 /* names starting with a dot are illegal */
3608 if (*tp == '.') valid8Dot3 = 0;
3612 if (tc == 0) return valid8Dot3;
3613 if (tc == '.' || tc == '"') break;
3614 if (i < 8) *up++ = tc;
3615 else valid8Dot3 = 0;
3618 /* if we get here, tp point after the dot */
3619 up = maskp+8; /* ext goes here */
3626 if (tc == '.' || tc == '"')
3629 /* copy extension if not too long */
3639 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3649 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3651 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3655 /* otherwise, we have a valid 8.3 name; see if we have a match,
3656 * treating '?' as a wildcard in maskp (but not in the file name).
3658 tp1 = umask; /* real name, in mask format */
3659 tp2 = maskp; /* mask, in mask format */
3660 for(i=0; i<11; i++) {
3661 tc1 = *tp1++; /* char from real name */
3662 tc2 = *tp2++; /* char from mask */
3663 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3664 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3667 if (tc2 == '?' && tc1 != ' ')
3674 /* we got a match */
3678 char *smb_FindMask(char *pathp)
3682 tp = strrchr(pathp, '\\'); /* find last slash */
3685 return tp+1; /* skip the slash */
3687 return pathp; /* no slash, return the entire path */
3690 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3692 unsigned char *pathp;
3694 unsigned char mask[11];
3695 unsigned char *statBlockp;
3696 unsigned char initStatBlock[21];
3699 osi_Log0(smb_logp, "SMB receive search volume");
3701 /* pull pathname and stat block out of request */
3702 tp = smb_GetSMBData(inp, NULL);
3703 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3704 osi_assert(pathp != NULL);
3705 if (smb_StoreAnsiFilenames)
3706 OemToChar(pathp,pathp);
3707 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3708 osi_assert(statBlockp != NULL);
3710 statBlockp = initStatBlock;
3714 /* for returning to caller */
3715 smb_Get8Dot3MaskFromPath(mask, pathp);
3717 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3718 tp = smb_GetSMBData(outp, NULL);
3720 *tp++ = 43; /* bytes in a dir entry */
3721 *tp++ = 0; /* high byte in counter */
3723 /* now marshall the dir entry, starting with the search status */
3724 *tp++ = statBlockp[0]; /* Reserved */
3725 memcpy(tp, mask, 11); tp += 11; /* FileName */
3727 /* now pass back server use info, with 1st byte non-zero */
3729 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3731 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3733 *tp++ = 0x8; /* attribute: volume */
3743 /* 4 byte file size */
3749 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3750 memset(tp, ' ', 13);
3753 /* set the length of the data part of the packet to 43 + 3, for the dir
3754 * entry plus the 5 and the length fields.
3756 smb_SetSMBDataLength(outp, 46);
3760 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3761 cm_user_t *userp, cm_req_t *reqp)
3769 smb_dirListPatch_t *patchp;
3770 smb_dirListPatch_t *npatchp;
3772 for (patchp = *dirPatchespp; patchp; patchp =
3773 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3775 dptr = patchp->dptr;
3777 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3779 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3780 *dptr++ = SMB_ATTR_HIDDEN;
3783 lock_ObtainMutex(&scp->mx);
3784 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3785 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3787 lock_ReleaseMutex(&scp->mx);
3788 cm_ReleaseSCache(scp);
3789 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3790 *dptr++ = SMB_ATTR_HIDDEN;
3794 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3796 attr = smb_Attributes(scp);
3797 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3798 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3799 attr |= SMB_ATTR_HIDDEN;
3803 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3806 shortTemp = (unsigned short) (dosTime & 0xffff);
3807 *((u_short *)dptr) = shortTemp;
3810 /* and copy out date */
3811 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3812 *((u_short *)dptr) = shortTemp;
3815 /* copy out file length */
3816 *((u_long *)dptr) = scp->length.LowPart;
3818 lock_ReleaseMutex(&scp->mx);
3819 cm_ReleaseSCache(scp);
3822 /* now free the patches */
3823 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3824 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3828 /* and mark the list as empty */
3829 *dirPatchespp = NULL;
3834 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3843 smb_dirListPatch_t *dirListPatchesp;
3844 smb_dirListPatch_t *curPatchp;
3848 osi_hyper_t dirLength;
3849 osi_hyper_t bufferOffset;
3850 osi_hyper_t curOffset;
3852 unsigned char *inCookiep;
3853 smb_dirSearch_t *dsp;
3857 unsigned long clientCookie;
3858 cm_pageHeader_t *pageHeaderp;
3859 cm_user_t *userp = NULL;
3866 long nextEntryCookie;
3867 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3868 char resByte; /* reserved byte from the cookie */
3869 char *op; /* output data ptr */
3870 char *origOp; /* original value of op */
3871 cm_space_t *spacep; /* for pathname buffer */
3882 maxCount = smb_GetSMBParm(inp, 0);
3884 dirListPatchesp = NULL;
3886 caseFold = CM_FLAG_CASEFOLD;
3888 tp = smb_GetSMBData(inp, NULL);
3889 pathp = smb_ParseASCIIBlock(tp, &tp);
3890 if (smb_StoreAnsiFilenames)
3891 OemToChar(pathp,pathp);
3892 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3894 /* bail out if request looks bad */
3895 if (!tp || !pathp) {
3896 return CM_ERROR_BADSMB;
3899 /* We can handle long names */
3900 if (vcp->flags & SMB_VCFLAG_USENT)
3901 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3903 /* make sure we got a whole search status */
3904 if (dataLength < 21) {
3905 nextCookie = 0; /* start at the beginning of the dir */
3908 attribute = smb_GetSMBParm(inp, 1);
3910 /* handle volume info in another function */
3911 if (attribute & 0x8)
3912 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3914 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3915 maxCount, osi_LogSaveString(smb_logp, pathp));
3917 if (*pathp == 0) { /* null pathp, treat as root dir */
3918 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3919 return CM_ERROR_NOFILES;
3923 dsp = smb_NewDirSearch(0);
3924 dsp->attribute = attribute;
3925 smb_Get8Dot3MaskFromPath(mask, pathp);
3926 memcpy(dsp->mask, mask, 11);
3928 /* track if this is likely to match a lot of entries */
3929 if (smb_IsStarMask(mask))
3934 /* pull the next cookie value out of the search status block */
3935 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3936 + (inCookiep[16]<<24);
3937 dsp = smb_FindDirSearch(inCookiep[12]);
3939 /* can't find dir search status; fatal error */
3940 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3941 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3942 return CM_ERROR_BADFD;
3944 attribute = dsp->attribute;
3945 resByte = inCookiep[0];
3947 /* copy out client cookie, in host byte order. Don't bother
3948 * interpreting it, since we're just passing it through, anyway.
3950 memcpy(&clientCookie, &inCookiep[17], 4);
3952 memcpy(mask, dsp->mask, 11);
3954 /* assume we're doing a star match if it has continued for more
3960 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3961 nextCookie, dsp->cookie, attribute);
3963 userp = smb_GetUserFromVCP(vcp, inp);
3965 /* try to get the vnode for the path name next */
3966 lock_ObtainMutex(&dsp->mx);
3969 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3973 spacep = inp->spacep;
3974 smb_StripLastComponent(spacep->data, NULL, pathp);
3975 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3977 lock_ReleaseMutex(&dsp->mx);
3978 cm_ReleaseUser(userp);
3979 smb_DeleteDirSearch(dsp);
3980 smb_ReleaseDirSearch(dsp);
3981 return CM_ERROR_NOFILES;
3983 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3984 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3987 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3988 cm_ReleaseSCache(scp);
3989 lock_ReleaseMutex(&dsp->mx);
3990 cm_ReleaseUser(userp);
3991 smb_DeleteDirSearch(dsp);
3992 smb_ReleaseDirSearch(dsp);
3993 if ( WANTS_DFS_PATHNAMES(inp) )
3994 return CM_ERROR_PATH_NOT_COVERED;
3996 return CM_ERROR_BADSHARENAME;
3998 #endif /* DFS_SUPPORT */
4001 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4002 /* we need one hold for the entry we just stored into,
4003 * and one for our own processing. When we're done with this
4004 * function, we'll drop the one for our own processing.
4005 * We held it once from the namei call, and so we do another hold
4009 lock_ObtainMutex(&scp->mx);
4010 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4011 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4012 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4013 dsp->flags |= SMB_DIRSEARCH_BULKST;
4014 dsp->scp->bulkStatProgress = hzero;
4016 lock_ReleaseMutex(&scp->mx);
4019 lock_ReleaseMutex(&dsp->mx);
4021 cm_ReleaseUser(userp);
4022 smb_DeleteDirSearch(dsp);
4023 smb_ReleaseDirSearch(dsp);
4027 /* reserves space for parameter; we'll adjust it again later to the
4028 * real count of the # of entries we returned once we've actually
4029 * assembled the directory listing.
4031 smb_SetSMBParm(outp, 0, 0);
4033 /* get the directory size */
4034 lock_ObtainMutex(&scp->mx);
4035 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4036 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4038 lock_ReleaseMutex(&scp->mx);
4039 cm_ReleaseSCache(scp);
4040 cm_ReleaseUser(userp);
4041 smb_DeleteDirSearch(dsp);
4042 smb_ReleaseDirSearch(dsp);
4046 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4048 dirLength = scp->length;
4050 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4051 curOffset.HighPart = 0;
4052 curOffset.LowPart = nextCookie;
4053 origOp = op = smb_GetSMBData(outp, NULL);
4054 /* and write out the basic header */
4055 *op++ = 5; /* variable block */
4056 op += 2; /* skip vbl block length; we'll fill it in later */
4060 /* make sure that curOffset.LowPart doesn't point to the first
4061 * 32 bytes in the 2nd through last dir page, and that it doesn't
4062 * point at the first 13 32-byte chunks in the first dir page,
4063 * since those are dir and page headers, and don't contain useful
4066 temp = curOffset.LowPart & (2048-1);
4067 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4068 /* we're in the first page */
4069 if (temp < 13*32) temp = 13*32;
4072 /* we're in a later dir page */
4073 if (temp < 32) temp = 32;
4076 /* make sure the low order 5 bits are zero */
4079 /* now put temp bits back ito curOffset.LowPart */
4080 curOffset.LowPart &= ~(2048-1);
4081 curOffset.LowPart |= temp;
4083 /* check if we've returned all the names that will fit in the
4086 if (returnedNames >= maxCount) {
4087 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4088 returnedNames, maxCount);
4092 /* check if we've passed the dir's EOF */
4093 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4095 /* see if we can use the bufferp we have now; compute in which page
4096 * the current offset would be, and check whether that's the offset
4097 * of the buffer we have. If not, get the buffer.
4099 thyper.HighPart = curOffset.HighPart;
4100 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4101 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4104 buf_Release(bufferp);
4107 lock_ReleaseMutex(&scp->mx);
4108 lock_ObtainRead(&scp->bufCreateLock);
4109 code = buf_Get(scp, &thyper, &bufferp);
4110 lock_ReleaseRead(&scp->bufCreateLock);
4111 lock_ObtainMutex(&dsp->mx);
4113 /* now, if we're doing a star match, do bulk fetching of all of
4114 * the status info for files in the dir.
4117 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4118 lock_ObtainMutex(&scp->mx);
4119 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4120 LargeIntegerGreaterThanOrEqualTo(thyper,
4121 scp->bulkStatProgress)) {
4122 /* Don't bulk stat if risking timeout */
4123 int now = GetTickCount();
4124 if (now - req.startTime > RDRtimeout * 1000) {
4125 scp->bulkStatProgress = thyper;
4126 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4127 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4128 dsp->scp->bulkStatProgress = hzero;
4130 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4133 lock_ObtainMutex(&scp->mx);
4135 lock_ReleaseMutex(&dsp->mx);
4137 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4141 bufferOffset = thyper;
4143 /* now get the data in the cache */
4145 code = cm_SyncOp(scp, bufferp, userp, &req,
4147 CM_SCACHESYNC_NEEDCALLBACK |
4148 CM_SCACHESYNC_READ);
4150 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4154 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4156 if (cm_HaveBuffer(scp, bufferp, 0)) {
4157 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4161 /* otherwise, load the buffer and try again */
4162 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4164 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4165 scp, bufferp, code);
4170 buf_Release(bufferp);
4174 } /* if (wrong buffer) ... */
4176 /* now we have the buffer containing the entry we're interested in; copy
4177 * it out if it represents a non-deleted entry.
4179 entryInDir = curOffset.LowPart & (2048-1);
4180 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4182 /* page header will help tell us which entries are free. Page header
4183 * can change more often than once per buffer, since AFS 3 dir page size
4184 * may be less than (but not more than a buffer package buffer.
4186 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4187 temp &= ~(2048 - 1); /* turn off intra-page bits */
4188 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4190 /* now determine which entry we're looking at in the page. If it is
4191 * free (there's a free bitmap at the start of the dir), we should
4192 * skip these 32 bytes.
4194 slotInPage = (entryInDir & 0x7e0) >> 5;
4195 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4196 /* this entry is free */
4197 numDirChunks = 1; /* only skip this guy */
4201 tp = bufferp->datap + entryInBuffer;
4202 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4204 /* while we're here, compute the next entry's location, too,
4205 * since we'll need it when writing out the cookie into the dir
4208 * XXXX Probably should do more sanity checking.
4210 numDirChunks = cm_NameEntries(dep->name, NULL);
4212 /* compute the offset of the cookie representing the next entry */
4213 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4215 /* Compute 8.3 name if necessary */
4216 actualName = dep->name;
4217 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4218 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4219 actualName = shortName;
4222 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4223 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4224 osi_LogSaveString(smb_logp, actualName));
4226 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4227 /* this is one of the entries to use: it is not deleted
4228 * and it matches the star pattern we're looking for.
4231 /* Eliminate entries that don't match requested
4234 /* no hidden files */
4235 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4236 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4240 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4242 /* We have already done the cm_TryBulkStat above */
4243 fid.cell = scp->fid.cell;
4244 fid.volume = scp->fid.volume;
4245 fid.vnode = ntohl(dep->fid.vnode);
4246 fid.unique = ntohl(dep->fid.unique);
4247 fileType = cm_FindFileType(&fid);
4248 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4249 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4251 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4252 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4253 fileType == CM_SCACHETYPE_DFSLINK ||
4254 fileType == CM_SCACHETYPE_INVALID)
4255 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4260 memcpy(op, mask, 11); op += 11;
4261 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4262 *op++ = (char)(nextEntryCookie & 0xff);
4263 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4264 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4265 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4266 memcpy(op, &clientCookie, 4); op += 4;
4268 /* now we emit the attribute. This is sort of tricky,
4269 * since we need to really stat the file to find out
4270 * what type of entry we've got. Right now, we're
4271 * copying out data from a buffer, while holding the
4272 * scp locked, so it isn't really convenient to stat
4273 * something now. We'll put in a place holder now,
4274 * and make a second pass before returning this to get
4275 * the real attributes. So, we just skip the data for
4276 * now, and adjust it later. We allocate a patch
4277 * record to make it easy to find this point later.
4278 * The replay will happen at a time when it is safe to
4279 * unlock the directory.
4281 curPatchp = malloc(sizeof(*curPatchp));
4282 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4283 curPatchp->dptr = op;
4284 curPatchp->fid.cell = scp->fid.cell;
4285 curPatchp->fid.volume = scp->fid.volume;
4286 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4287 curPatchp->fid.unique = ntohl(dep->fid.unique);
4289 /* do hidden attribute here since name won't be around when applying
4293 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4294 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4296 curPatchp->flags = 0;
4298 op += 9; /* skip attr, time, date and size */
4300 /* zero out name area. The spec says to pad with
4301 * spaces, but Samba doesn't, and neither do we.
4305 /* finally, we get to copy out the name; we know that
4306 * it fits in 8.3 or the pattern wouldn't match, but it
4307 * never hurts to be sure.
4309 strncpy(op, actualName, 13);
4310 if (smb_StoreAnsiFilenames)
4313 /* Uppercase if requested by client */
4314 if (!KNOWS_LONG_NAMES(inp))
4319 /* now, adjust the # of entries copied */
4321 } /* if we're including this name */
4324 /* and adjust curOffset to be where the new cookie is */
4325 thyper.HighPart = 0;
4326 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4327 curOffset = LargeIntegerAdd(thyper, curOffset);
4328 } /* while copying data for dir listing */
4330 /* release the mutex */
4331 lock_ReleaseMutex(&scp->mx);
4333 buf_Release(bufferp);
4337 /* apply and free last set of patches; if not doing a star match, this
4338 * will be empty, but better safe (and freeing everything) than sorry.
4340 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4342 /* special return code for unsuccessful search */
4343 if (code == 0 && dataLength < 21 && returnedNames == 0)
4344 code = CM_ERROR_NOFILES;
4346 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4347 returnedNames, code);
4350 smb_DeleteDirSearch(dsp);
4351 smb_ReleaseDirSearch(dsp);
4352 cm_ReleaseSCache(scp);
4353 cm_ReleaseUser(userp);
4357 /* finalize the output buffer */
4358 smb_SetSMBParm(outp, 0, returnedNames);
4359 temp = (long) (op - origOp);
4360 smb_SetSMBDataLength(outp, temp);
4362 /* the data area is a variable block, which has a 5 (already there)
4363 * followed by the length of the # of data bytes. We now know this to
4364 * be "temp," although that includes the 3 bytes of vbl block header.
4365 * Deduct for them and fill in the length field.
4367 temp -= 3; /* deduct vbl block info */
4368 osi_assert(temp == (43 * returnedNames));
4369 origOp[1] = (char)(temp & 0xff);
4370 origOp[2] = (char)((temp>>8) & 0xff);
4371 if (returnedNames == 0)
4372 smb_DeleteDirSearch(dsp);
4373 smb_ReleaseDirSearch(dsp);
4374 cm_ReleaseSCache(scp);
4375 cm_ReleaseUser(userp);
4379 /* verify that this is a valid path to a directory. I don't know why they
4380 * don't use the get file attributes call.
4382 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4386 cm_scache_t *rootScp;
4387 cm_scache_t *newScp;
4396 pathp = smb_GetSMBData(inp, NULL);
4397 pathp = smb_ParseASCIIBlock(pathp, NULL);
4399 return CM_ERROR_BADFD;
4400 if (smb_StoreAnsiFilenames)
4401 OemToChar(pathp,pathp);
4402 osi_Log1(smb_logp, "SMB receive check path %s",
4403 osi_LogSaveString(smb_logp, pathp));
4405 rootScp = cm_data.rootSCachep;
4407 userp = smb_GetUserFromVCP(vcp, inp);
4409 caseFold = CM_FLAG_CASEFOLD;
4411 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4413 cm_ReleaseUser(userp);
4414 return CM_ERROR_NOSUCHPATH;
4416 code = cm_NameI(rootScp, pathp,
4417 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4418 userp, tidPathp, &req, &newScp);
4421 cm_ReleaseUser(userp);
4426 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4427 cm_ReleaseSCache(newScp);
4428 cm_ReleaseUser(userp);
4429 if ( WANTS_DFS_PATHNAMES(inp) )
4430 return CM_ERROR_PATH_NOT_COVERED;
4432 return CM_ERROR_BADSHARENAME;
4434 #endif /* DFS_SUPPORT */
4436 /* now lock the vnode with a callback; returns with newScp locked */
4437 lock_ObtainMutex(&newScp->mx);
4438 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4439 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4441 if (code != CM_ERROR_NOACCESS) {
4442 lock_ReleaseMutex(&newScp->mx);
4443 cm_ReleaseSCache(newScp);
4444 cm_ReleaseUser(userp);
4448 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4451 attrs = smb_Attributes(newScp);
4453 if (!(attrs & SMB_ATTR_DIRECTORY))
4454 code = CM_ERROR_NOTDIR;
4456 lock_ReleaseMutex(&newScp->mx);
4458 cm_ReleaseSCache(newScp);
4459 cm_ReleaseUser(userp);
4463 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4467 cm_scache_t *rootScp;
4468 unsigned short attribute;
4470 cm_scache_t *newScp;
4479 /* decode basic attributes we're passed */
4480 attribute = smb_GetSMBParm(inp, 0);
4481 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4483 pathp = smb_GetSMBData(inp, NULL);
4484 pathp = smb_ParseASCIIBlock(pathp, NULL);
4486 return CM_ERROR_BADSMB;
4487 if (smb_StoreAnsiFilenames)
4488 OemToChar(pathp,pathp);
4490 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4491 dosTime, attribute);
4493 rootScp = cm_data.rootSCachep;
4495 userp = smb_GetUserFromVCP(vcp, inp);
4497 caseFold = CM_FLAG_CASEFOLD;
4499 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4501 cm_ReleaseUser(userp);
4502 return CM_ERROR_NOSUCHFILE;
4504 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4505 tidPathp, &req, &newScp);
4508 cm_ReleaseUser(userp);
4513 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4514 cm_ReleaseSCache(newScp);
4515 cm_ReleaseUser(userp);
4516 if ( WANTS_DFS_PATHNAMES(inp) )
4517 return CM_ERROR_PATH_NOT_COVERED;
4519 return CM_ERROR_BADSHARENAME;
4521 #endif /* DFS_SUPPORT */
4523 /* now lock the vnode with a callback; returns with newScp locked; we
4524 * need the current status to determine what the new status is, in some
4527 lock_ObtainMutex(&newScp->mx);
4528 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4529 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4531 lock_ReleaseMutex(&newScp->mx);
4532 cm_ReleaseSCache(newScp);
4533 cm_ReleaseUser(userp);
4537 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4539 /* Check for RO volume */
4540 if (newScp->flags & CM_SCACHEFLAG_RO) {
4541 lock_ReleaseMutex(&newScp->mx);
4542 cm_ReleaseSCache(newScp);
4543 cm_ReleaseUser(userp);
4544 return CM_ERROR_READONLY;
4547 /* prepare for setattr call */
4550 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4551 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4553 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4554 /* we're told to make a writable file read-only */
4555 attr.unixModeBits = newScp->unixModeBits & ~0222;
4556 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4558 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4559 /* we're told to make a read-only file writable */
4560 attr.unixModeBits = newScp->unixModeBits | 0222;
4561 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4563 lock_ReleaseMutex(&newScp->mx);
4565 /* now call setattr */
4567 code = cm_SetAttr(newScp, &attr, userp, &req);
4571 cm_ReleaseSCache(newScp);
4572 cm_ReleaseUser(userp);
4577 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4581 cm_scache_t *rootScp;
4582 cm_scache_t *newScp, *dscp;
4594 pathp = smb_GetSMBData(inp, NULL);
4595 pathp = smb_ParseASCIIBlock(pathp, NULL);
4597 return CM_ERROR_BADSMB;
4599 if (*pathp == 0) /* null path */
4602 if (smb_StoreAnsiFilenames)
4603 OemToChar(pathp,pathp);
4605 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4606 osi_LogSaveString(smb_logp, pathp));
4608 rootScp = cm_data.rootSCachep;
4610 userp = smb_GetUserFromVCP(vcp, inp);
4612 /* we shouldn't need this for V3 requests, but we seem to */
4613 caseFold = CM_FLAG_CASEFOLD;
4615 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4617 cm_ReleaseUser(userp);
4618 return CM_ERROR_NOSUCHFILE;
4622 * XXX Strange hack XXX
4624 * As of Patch 5 (16 July 97), we are having the following problem:
4625 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4626 * requests to look up "desktop.ini" in all the subdirectories.
4627 * This can cause zillions of timeouts looking up non-existent cells
4628 * and volumes, especially in the top-level directory.
4630 * We have not found any way to avoid this or work around it except
4631 * to explicitly ignore the requests for mount points that haven't
4632 * yet been evaluated and for directories that haven't yet been
4635 * We should modify this hack to provide a fake desktop.ini file
4636 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4638 spacep = inp->spacep;
4639 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4640 #ifndef SPECIAL_FOLDERS
4641 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4642 code = cm_NameI(rootScp, spacep->data,
4643 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4644 userp, tidPathp, &req, &dscp);
4647 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4648 if ( WANTS_DFS_PATHNAMES(inp) )
4649 return CM_ERROR_PATH_NOT_COVERED;
4651 return CM_ERROR_BADSHARENAME;
4653 #endif /* DFS_SUPPORT */
4654 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4655 code = CM_ERROR_NOSUCHFILE;
4656 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4657 cm_buf_t *bp = buf_Find(dscp, &hzero);
4662 code = CM_ERROR_NOSUCHFILE;
4664 cm_ReleaseSCache(dscp);
4666 cm_ReleaseUser(userp);
4671 #endif /* SPECIAL_FOLDERS */
4673 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4674 tidPathp, &req, &newScp);
4676 cm_ReleaseUser(userp);
4681 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4682 cm_ReleaseSCache(newScp);
4683 cm_ReleaseUser(userp);
4684 if ( WANTS_DFS_PATHNAMES(inp) )
4685 return CM_ERROR_PATH_NOT_COVERED;
4687 return CM_ERROR_BADSHARENAME;
4689 #endif /* DFS_SUPPORT */
4691 /* now lock the vnode with a callback; returns with newScp locked */
4692 lock_ObtainMutex(&newScp->mx);
4693 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4694 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4696 lock_ReleaseMutex(&newScp->mx);
4697 cm_ReleaseSCache(newScp);
4698 cm_ReleaseUser(userp);
4702 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4705 /* use smb_Attributes instead. Also the fact that a file is
4706 * in a readonly volume doesn't mean it shojuld be marked as RO
4708 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4709 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4710 newScp->fileType == CM_SCACHETYPE_INVALID)
4711 attrs = SMB_ATTR_DIRECTORY;
4714 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4715 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4717 attrs = smb_Attributes(newScp);
4720 smb_SetSMBParm(outp, 0, attrs);
4722 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4723 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4724 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4725 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4726 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4727 smb_SetSMBParm(outp, 5, 0);
4728 smb_SetSMBParm(outp, 6, 0);
4729 smb_SetSMBParm(outp, 7, 0);
4730 smb_SetSMBParm(outp, 8, 0);
4731 smb_SetSMBParm(outp, 9, 0);
4732 smb_SetSMBDataLength(outp, 0);
4733 lock_ReleaseMutex(&newScp->mx);
4735 cm_ReleaseSCache(newScp);
4736 cm_ReleaseUser(userp);
4741 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4745 osi_Log0(smb_logp, "SMB receive tree disconnect");
4747 /* find the tree and free it */
4748 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4750 lock_ObtainWrite(&smb_rctLock);
4752 lock_ReleaseWrite(&smb_rctLock);
4753 smb_ReleaseTID(tidp);
4759 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4777 pathp = smb_GetSMBData(inp, NULL);
4778 pathp = smb_ParseASCIIBlock(pathp, NULL);
4779 if (smb_StoreAnsiFilenames)
4780 OemToChar(pathp,pathp);
4782 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4784 #ifdef DEBUG_VERBOSE
4788 hexpath = osi_HexifyString( pathp );
4789 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4794 share = smb_GetSMBParm(inp, 0);
4795 attribute = smb_GetSMBParm(inp, 1);
4797 spacep = inp->spacep;
4798 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4799 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4800 /* special case magic file name for receiving IOCTL requests
4801 * (since IOCTL calls themselves aren't getting through).
4803 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4804 smb_SetupIoctlFid(fidp, spacep);
4805 smb_SetSMBParm(outp, 0, fidp->fid);
4806 smb_SetSMBParm(outp, 1, 0); /* attrs */
4807 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4808 smb_SetSMBParm(outp, 3, 0);
4809 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4810 smb_SetSMBParm(outp, 5, 0x7fff);
4811 /* pass the open mode back */
4812 smb_SetSMBParm(outp, 6, (share & 0xf));
4813 smb_SetSMBDataLength(outp, 0);
4814 smb_ReleaseFID(fidp);
4818 userp = smb_GetUserFromVCP(vcp, inp);
4820 caseFold = CM_FLAG_CASEFOLD;
4822 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4824 cm_ReleaseUser(userp);
4825 return CM_ERROR_NOSUCHPATH;
4827 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4828 tidPathp, &req, &scp);
4831 cm_ReleaseUser(userp);
4836 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4837 cm_ReleaseSCache(scp);
4838 cm_ReleaseUser(userp);
4839 if ( WANTS_DFS_PATHNAMES(inp) )
4840 return CM_ERROR_PATH_NOT_COVERED;
4842 return CM_ERROR_BADSHARENAME;
4844 #endif /* DFS_SUPPORT */
4846 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4848 cm_ReleaseSCache(scp);
4849 cm_ReleaseUser(userp);
4853 /* don't need callback to check file type, since file types never
4854 * change, and namei and cm_Lookup all stat the object at least once on
4855 * a successful return.
4857 if (scp->fileType != CM_SCACHETYPE_FILE) {
4858 cm_ReleaseSCache(scp);
4859 cm_ReleaseUser(userp);
4860 return CM_ERROR_ISDIR;
4863 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4866 /* save a pointer to the vnode */
4868 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4869 lock_ObtainMutex(&scp->mx);
4870 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4871 lock_ReleaseMutex(&scp->mx);
4875 fidp->userp = userp;
4877 lock_ObtainMutex(&fidp->mx);
4878 if ((share & 0xf) == 0)
4879 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4880 else if ((share & 0xf) == 1)
4881 fidp->flags |= SMB_FID_OPENWRITE;
4883 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4884 lock_ReleaseMutex(&fidp->mx);
4886 lock_ObtainMutex(&scp->mx);
4887 smb_SetSMBParm(outp, 0, fidp->fid);
4888 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4889 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4890 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4891 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4892 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4893 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4894 /* pass the open mode back; XXXX add access checks */
4895 smb_SetSMBParm(outp, 6, (share & 0xf));
4896 smb_SetSMBDataLength(outp, 0);
4897 lock_ReleaseMutex(&scp->mx);
4900 cm_Open(scp, 0, userp);
4902 /* send and free packet */
4903 smb_ReleaseFID(fidp);
4904 cm_ReleaseUser(userp);
4905 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4909 typedef struct smb_unlinkRock {
4914 char *maskp; /* pointer to the star pattern */
4917 cm_dirEntryList_t * matches;
4920 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4923 smb_unlinkRock_t *rockp;
4931 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4932 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4933 caseFold |= CM_FLAG_8DOT3;
4935 matchName = dep->name;
4936 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4938 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4939 !cm_Is8Dot3(dep->name)) {
4940 cm_Gen8Dot3Name(dep, shortName, NULL);
4941 matchName = shortName;
4942 /* 8.3 matches are always case insensitive */
4943 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4946 osi_Log1(smb_logp, "Found match %s",
4947 osi_LogSaveString(smb_logp, matchName));
4949 cm_DirEntryListAdd(dep->name, &rockp->matches);
4953 /* If we made a case sensitive exact match, we might as well quit now. */
4954 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4955 code = CM_ERROR_STOPNOW;
4964 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4973 smb_unlinkRock_t rock;
4982 attribute = smb_GetSMBParm(inp, 0);
4984 tp = smb_GetSMBData(inp, NULL);
4985 pathp = smb_ParseASCIIBlock(tp, &tp);
4986 if (smb_StoreAnsiFilenames)
4987 OemToChar(pathp,pathp);
4989 osi_Log1(smb_logp, "SMB receive unlink %s",
4990 osi_LogSaveString(smb_logp, pathp));
4992 spacep = inp->spacep;
4993 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4995 userp = smb_GetUserFromVCP(vcp, inp);
4997 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4999 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5001 cm_ReleaseUser(userp);
5002 return CM_ERROR_NOSUCHPATH;
5004 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5007 cm_ReleaseUser(userp);
5012 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5013 cm_ReleaseSCache(dscp);
5014 cm_ReleaseUser(userp);
5015 if ( WANTS_DFS_PATHNAMES(inp) )
5016 return CM_ERROR_PATH_NOT_COVERED;
5018 return CM_ERROR_BADSHARENAME;
5020 #endif /* DFS_SUPPORT */
5022 /* otherwise, scp points to the parent directory. */
5029 rock.maskp = smb_FindMask(pathp);
5030 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5033 thyper.HighPart = 0;
5038 rock.matches = NULL;
5040 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5041 * match. If that fails, we do a case insensitve match.
5043 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5044 !smb_IsStarMask(rock.maskp)) {
5045 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5048 thyper.HighPart = 0;
5049 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5054 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5056 if (code == CM_ERROR_STOPNOW)
5059 if (code == 0 && rock.matches) {
5060 cm_dirEntryList_t * entry;
5062 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5064 osi_Log1(smb_logp, "Unlinking %s",
5065 osi_LogSaveString(smb_logp, entry->name));
5066 code = cm_Unlink(dscp, entry->name, userp, &req);
5068 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5069 smb_NotifyChange(FILE_ACTION_REMOVED,
5070 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5071 dscp, entry->name, NULL, TRUE);
5075 cm_DirEntryListFree(&rock.matches);
5077 cm_ReleaseUser(userp);
5079 cm_ReleaseSCache(dscp);
5081 if (code == 0 && !rock.any)
5082 code = CM_ERROR_NOSUCHFILE;
5086 typedef struct smb_renameRock {
5087 cm_scache_t *odscp; /* old dir */
5088 cm_scache_t *ndscp; /* new dir */
5089 cm_user_t *userp; /* user */
5090 cm_req_t *reqp; /* request struct */
5091 smb_vc_t *vcp; /* virtual circuit */
5092 char *maskp; /* pointer to star pattern of old file name */
5093 int flags; /* tilde, casefold, etc */
5094 char *newNamep; /* ptr to the new file's name */
5095 char oldName[MAX_PATH];
5099 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5102 smb_renameRock_t *rockp;
5105 char shortName[13]="";
5107 rockp = (smb_renameRock_t *) vrockp;
5109 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5110 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5111 caseFold |= CM_FLAG_8DOT3;
5113 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5115 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5116 !cm_Is8Dot3(dep->name)) {
5117 cm_Gen8Dot3Name(dep, shortName, NULL);
5118 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5123 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5124 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5125 code = CM_ERROR_STOPNOW;
5135 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5138 cm_space_t *spacep = NULL;
5139 smb_renameRock_t rock;
5140 cm_scache_t *oldDscp = NULL;
5141 cm_scache_t *newDscp = NULL;
5142 cm_scache_t *tmpscp= NULL;
5143 cm_scache_t *tmpscp2 = NULL;
5153 userp = smb_GetUserFromVCP(vcp, inp);
5154 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5156 cm_ReleaseUser(userp);
5157 return CM_ERROR_NOSUCHPATH;
5161 spacep = inp->spacep;
5162 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5164 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5165 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5166 userp, tidPathp, &req, &oldDscp);
5168 cm_ReleaseUser(userp);
5173 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5174 cm_ReleaseSCache(oldDscp);
5175 cm_ReleaseUser(userp);
5176 if ( WANTS_DFS_PATHNAMES(inp) )
5177 return CM_ERROR_PATH_NOT_COVERED;
5179 return CM_ERROR_BADSHARENAME;
5181 #endif /* DFS_SUPPORT */
5183 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5184 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5185 userp, tidPathp, &req, &newDscp);
5188 cm_ReleaseSCache(oldDscp);
5189 cm_ReleaseUser(userp);
5194 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5195 cm_ReleaseSCache(oldDscp);
5196 cm_ReleaseSCache(newDscp);
5197 cm_ReleaseUser(userp);
5198 if ( WANTS_DFS_PATHNAMES(inp) )
5199 return CM_ERROR_PATH_NOT_COVERED;
5201 return CM_ERROR_BADSHARENAME;
5203 #endif /* DFS_SUPPORT */
5206 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5207 * next, get the component names, and lower case them.
5210 /* handle the old name first */
5212 oldLastNamep = oldPathp;
5216 /* and handle the new name, too */
5218 newLastNamep = newPathp;
5222 /* TODO: The old name could be a wildcard. The new name must not be */
5224 /* do the vnode call */
5225 rock.odscp = oldDscp;
5226 rock.ndscp = newDscp;
5230 rock.maskp = oldLastNamep;
5231 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5232 rock.newNamep = newLastNamep;
5233 rock.oldName[0] = '\0';
5236 /* Check if the file already exists; if so return error */
5237 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5238 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5239 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5241 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5242 osi_LogSaveString(smb_logp, newLastNamep));
5244 /* Check if the old and the new names differ only in case. If so return
5245 * success, else return CM_ERROR_EXISTS
5247 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5249 /* This would be a success only if the old file is *as same as* the new file */
5250 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5252 if (tmpscp == tmpscp2)
5255 code = CM_ERROR_EXISTS;
5256 cm_ReleaseSCache(tmpscp2);
5259 code = CM_ERROR_NOSUCHFILE;
5262 /* file exist, do not rename, also fixes move */
5263 osi_Log0(smb_logp, "Can't rename. Target already exists");
5264 code = CM_ERROR_EXISTS;
5268 cm_ReleaseSCache(tmpscp);
5269 cm_ReleaseSCache(newDscp);
5270 cm_ReleaseSCache(oldDscp);
5271 cm_ReleaseUser(userp);
5275 /* Now search the directory for the pattern, and do the appropriate rename when found */
5276 thyper.LowPart = 0; /* search dir from here */
5277 thyper.HighPart = 0;
5279 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5280 if (code == 0 && !rock.any) {
5282 thyper.HighPart = 0;
5283 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5284 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5286 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5288 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5289 code = cm_Rename(rock.odscp, rock.oldName,
5290 rock.ndscp, rock.newNamep, rock.userp,
5292 /* if the call worked, stop doing the search now, since we
5293 * really only want to rename one file.
5295 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5296 } else if (code == 0) {
5297 code = CM_ERROR_NOSUCHFILE;
5300 /* Handle Change Notification */
5302 * Being lazy, not distinguishing between files and dirs in this
5303 * filter, since we'd have to do a lookup.
5306 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5307 if (oldDscp == newDscp) {
5308 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5309 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5310 filter, oldDscp, oldLastNamep,
5311 newLastNamep, TRUE);
5313 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5314 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5315 filter, oldDscp, oldLastNamep,
5317 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5318 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5319 filter, newDscp, newLastNamep,
5325 cm_ReleaseSCache(tmpscp);
5326 cm_ReleaseUser(userp);
5327 cm_ReleaseSCache(oldDscp);
5328 cm_ReleaseSCache(newDscp);
5333 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5336 cm_space_t *spacep = NULL;
5337 cm_scache_t *oldDscp = NULL;
5338 cm_scache_t *newDscp = NULL;
5339 cm_scache_t *tmpscp= NULL;
5340 cm_scache_t *tmpscp2 = NULL;
5341 cm_scache_t *sscp = NULL;
5350 userp = smb_GetUserFromVCP(vcp, inp);
5352 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5354 cm_ReleaseUser(userp);
5355 return CM_ERROR_NOSUCHPATH;
5360 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5362 spacep = inp->spacep;
5363 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5365 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5366 userp, tidPathp, &req, &oldDscp);
5368 cm_ReleaseUser(userp);
5373 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5374 cm_ReleaseSCache(oldDscp);
5375 cm_ReleaseUser(userp);
5376 if ( WANTS_DFS_PATHNAMES(inp) )
5377 return CM_ERROR_PATH_NOT_COVERED;
5379 return CM_ERROR_BADSHARENAME;
5381 #endif /* DFS_SUPPORT */
5383 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5384 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5385 userp, tidPathp, &req, &newDscp);
5387 cm_ReleaseSCache(oldDscp);
5388 cm_ReleaseUser(userp);
5393 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5394 cm_ReleaseSCache(newDscp);
5395 cm_ReleaseSCache(oldDscp);
5396 cm_ReleaseUser(userp);
5397 if ( WANTS_DFS_PATHNAMES(inp) )
5398 return CM_ERROR_PATH_NOT_COVERED;
5400 return CM_ERROR_BADSHARENAME;
5402 #endif /* DFS_SUPPORT */
5404 /* Now, although we did two lookups for the two directories (because the same
5405 * directory can be referenced through different paths), we only allow hard links
5406 * within the same directory. */
5407 if (oldDscp != newDscp) {
5408 cm_ReleaseSCache(oldDscp);
5409 cm_ReleaseSCache(newDscp);
5410 cm_ReleaseUser(userp);
5411 return CM_ERROR_CROSSDEVLINK;
5414 /* handle the old name first */
5416 oldLastNamep = oldPathp;
5420 /* and handle the new name, too */
5422 newLastNamep = newPathp;
5426 /* now lookup the old name */
5427 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5428 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5430 cm_ReleaseSCache(oldDscp);
5431 cm_ReleaseSCache(newDscp);
5432 cm_ReleaseUser(userp);
5436 /* Check if the file already exists; if so return error */
5437 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5438 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5439 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5441 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5442 osi_LogSaveString(smb_logp, newLastNamep));
5444 /* if the existing link is to the same file, then we return success */
5446 if(sscp == tmpscp) {
5449 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5450 code = CM_ERROR_EXISTS;
5455 cm_ReleaseSCache(tmpscp);
5456 cm_ReleaseSCache(sscp);
5457 cm_ReleaseSCache(newDscp);
5458 cm_ReleaseSCache(oldDscp);
5459 cm_ReleaseUser(userp);
5463 /* now create the hardlink */
5464 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5465 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5466 osi_Log1(smb_logp," Link returns 0x%x", code);
5468 /* Handle Change Notification */
5470 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5471 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5472 smb_NotifyChange(FILE_ACTION_ADDED,
5473 filter, newDscp, newLastNamep,
5478 cm_ReleaseSCache(tmpscp);
5479 cm_ReleaseUser(userp);
5480 cm_ReleaseSCache(sscp);
5481 cm_ReleaseSCache(oldDscp);
5482 cm_ReleaseSCache(newDscp);
5487 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5494 tp = smb_GetSMBData(inp, NULL);
5495 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5496 if (smb_StoreAnsiFilenames)
5497 OemToChar(oldPathp,oldPathp);
5498 newPathp = smb_ParseASCIIBlock(tp, &tp);
5499 if (smb_StoreAnsiFilenames)
5500 OemToChar(newPathp,newPathp);
5502 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5503 osi_LogSaveString(smb_logp, oldPathp),
5504 osi_LogSaveString(smb_logp, newPathp));
5506 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5508 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5514 typedef struct smb_rmdirRock {
5518 char *maskp; /* pointer to the star pattern */
5521 cm_dirEntryList_t * matches;
5524 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5527 smb_rmdirRock_t *rockp;
5532 rockp = (smb_rmdirRock_t *) vrockp;
5534 matchName = dep->name;
5535 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5536 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5538 match = (strcmp(matchName, rockp->maskp) == 0);
5540 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5541 !cm_Is8Dot3(dep->name)) {
5542 cm_Gen8Dot3Name(dep, shortName, NULL);
5543 matchName = shortName;
5544 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5549 cm_DirEntryListAdd(dep->name, &rockp->matches);
5555 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5563 smb_rmdirRock_t rock;
5572 tp = smb_GetSMBData(inp, NULL);
5573 pathp = smb_ParseASCIIBlock(tp, &tp);
5574 if (smb_StoreAnsiFilenames)
5575 OemToChar(pathp,pathp);
5577 spacep = inp->spacep;
5578 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5580 userp = smb_GetUserFromVCP(vcp, inp);
5582 caseFold = CM_FLAG_CASEFOLD;
5584 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5586 cm_ReleaseUser(userp);
5587 return CM_ERROR_NOSUCHPATH;
5589 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5590 userp, tidPathp, &req, &dscp);
5593 cm_ReleaseUser(userp);
5598 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5599 cm_ReleaseSCache(dscp);
5600 cm_ReleaseUser(userp);
5601 if ( WANTS_DFS_PATHNAMES(inp) )
5602 return CM_ERROR_PATH_NOT_COVERED;
5604 return CM_ERROR_BADSHARENAME;
5606 #endif /* DFS_SUPPORT */
5608 /* otherwise, scp points to the parent directory. */
5615 rock.maskp = lastNamep;
5616 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5619 thyper.HighPart = 0;
5623 rock.matches = NULL;
5625 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5626 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5627 if (code == 0 && !rock.any) {
5629 thyper.HighPart = 0;
5630 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5631 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5634 if (code == 0 && rock.matches) {
5635 cm_dirEntryList_t * entry;
5637 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5638 osi_Log1(smb_logp, "Removing directory %s",
5639 osi_LogSaveString(smb_logp, entry->name));
5641 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5643 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5644 smb_NotifyChange(FILE_ACTION_REMOVED,
5645 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5646 dscp, entry->name, NULL, TRUE);
5650 cm_DirEntryListFree(&rock.matches);
5652 cm_ReleaseUser(userp);
5654 cm_ReleaseSCache(dscp);
5656 if (code == 0 && !rock.any)
5657 code = CM_ERROR_NOSUCHFILE;
5661 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5671 fid = smb_GetSMBParm(inp, 0);
5673 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5675 fid = smb_ChainFID(fid, inp);
5676 fidp = smb_FindFID(vcp, fid, 0);
5678 return CM_ERROR_BADFD;
5680 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5681 smb_CloseFID(vcp, fidp, NULL, 0);
5682 smb_ReleaseFID(fidp);
5683 return CM_ERROR_NOSUCHFILE;
5686 lock_ObtainMutex(&fidp->mx);
5687 if (fidp->flags & SMB_FID_IOCTL) {
5688 lock_ReleaseMutex(&fidp->mx);
5689 smb_ReleaseFID(fidp);
5690 return CM_ERROR_BADFD;
5692 lock_ReleaseMutex(&fidp->mx);
5694 userp = smb_GetUserFromVCP(vcp, inp);
5696 lock_ObtainMutex(&fidp->mx);
5697 if (fidp->flags & SMB_FID_OPENWRITE) {
5698 cm_scache_t * scp = fidp->scp;
5700 lock_ReleaseMutex(&fidp->mx);
5701 code = cm_FSync(scp, userp, &req);
5702 cm_ReleaseSCache(scp);
5705 lock_ReleaseMutex(&fidp->mx);
5708 smb_ReleaseFID(fidp);
5710 cm_ReleaseUser(userp);
5715 struct smb_FullNameRock {
5721 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5725 struct smb_FullNameRock *vrockp;
5727 vrockp = (struct smb_FullNameRock *)rockp;
5729 if (!cm_Is8Dot3(dep->name)) {
5730 cm_Gen8Dot3Name(dep, shortName, NULL);
5732 if (cm_stricmp(shortName, vrockp->name) == 0) {
5733 vrockp->fullName = strdup(dep->name);
5734 return CM_ERROR_STOPNOW;
5737 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5738 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5739 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5740 vrockp->fullName = strdup(dep->name);
5741 return CM_ERROR_STOPNOW;
5746 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5747 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5749 struct smb_FullNameRock rock;
5755 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5756 if (code == CM_ERROR_STOPNOW)
5757 *newPathp = rock.fullName;
5759 *newPathp = strdup(pathp);
5762 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5763 afs_uint32 dosTime) {
5766 cm_scache_t *dscp = NULL;
5768 cm_scache_t * scp = NULL;
5770 int nullcreator = 0;
5772 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5773 fidp, fidp->fid, scp, vcp);
5776 lock_ObtainMutex(&fidp->mx);
5777 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5778 lock_ReleaseMutex(&fidp->mx);
5779 osi_Log0(smb_logp, " No user specified. Not closing fid");
5780 return CM_ERROR_BADFD;
5783 userp = fidp->userp; /* no hold required since fidp is held
5784 throughout the function */
5785 lock_ReleaseMutex(&fidp->mx);
5790 lock_ObtainWrite(&smb_rctLock);
5792 osi_Log0(smb_logp, " Fid already closed.");
5793 lock_ReleaseWrite(&smb_rctLock);
5794 return CM_ERROR_BADFD;
5797 lock_ReleaseWrite(&smb_rctLock);
5799 lock_ObtainMutex(&fidp->mx);
5800 if (fidp->NTopen_dscp) {
5801 dscp = fidp->NTopen_dscp;
5802 cm_HoldSCache(dscp);
5805 if (fidp->NTopen_pathp) {
5806 pathp = strdup(fidp->NTopen_pathp);
5814 /* Don't jump the gun on an async raw write */
5815 while (fidp->raw_writers) {
5816 lock_ReleaseMutex(&fidp->mx);
5817 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5818 lock_ObtainMutex(&fidp->mx);
5821 /* watch for ioctl closes, and read-only opens */
5823 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5824 == SMB_FID_OPENWRITE) {
5825 if (dosTime != 0 && dosTime != -1) {
5826 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5827 /* This fixes defect 10958 */
5828 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5829 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5831 lock_ReleaseMutex(&fidp->mx);
5832 code = cm_FSync(scp, userp, &req);
5833 lock_ObtainMutex(&fidp->mx);
5838 /* unlock any pending locks */
5839 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5840 scp->fileType == CM_SCACHETYPE_FILE) {
5844 lock_ReleaseMutex(&fidp->mx);
5846 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5848 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5849 lock_ObtainMutex(&scp->mx);
5851 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5852 CM_SCACHESYNC_NEEDCALLBACK
5853 | CM_SCACHESYNC_GETSTATUS
5854 | CM_SCACHESYNC_LOCK);
5858 "smb CoreClose SyncOp failure code 0x%x", tcode);
5859 goto post_syncopdone;
5862 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5864 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5868 lock_ReleaseMutex(&scp->mx);
5869 lock_ObtainMutex(&fidp->mx);
5872 if (fidp->flags & SMB_FID_DELONCLOSE) {
5875 lock_ReleaseMutex(&fidp->mx);
5876 smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
5877 if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5878 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5881 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5882 smb_NotifyChange(FILE_ACTION_REMOVED,
5883 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5884 dscp, fullPathp, NULL, TRUE);
5887 code = cm_Unlink(dscp, fullPathp, userp, &req);
5890 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5891 smb_NotifyChange(FILE_ACTION_REMOVED,
5892 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5893 dscp, fullPathp, NULL, TRUE);
5897 lock_ObtainMutex(&fidp->mx);
5898 fidp->flags &= ~SMB_FID_DELONCLOSE;
5901 /* if this was a newly created file, then clear the creator
5902 * in the stat cache entry. */
5903 if (fidp->flags & SMB_FID_CREATED) {
5905 fidp->flags &= ~SMB_FID_CREATED;
5908 if (fidp->flags & SMB_FID_NTOPEN) {
5909 cm_ReleaseSCache(fidp->NTopen_dscp);
5910 fidp->NTopen_dscp = NULL;
5911 free(fidp->NTopen_pathp);
5912 fidp->NTopen_pathp = NULL;
5913 fidp->flags &= ~SMB_FID_NTOPEN;
5915 osi_assert(fidp->NTopen_dscp == NULL);
5916 osi_assert(fidp->NTopen_pathp == NULL);
5919 if (fidp->NTopen_wholepathp) {
5920 free(fidp->NTopen_wholepathp);
5921 fidp->NTopen_wholepathp = NULL;
5925 cm_ReleaseSCache(fidp->scp);
5928 lock_ReleaseMutex(&fidp->mx);
5931 cm_ReleaseSCache(dscp);
5934 if (deleted || nullcreator) {
5935 lock_ObtainMutex(&scp->mx);
5936 if (nullcreator && scp->creator == userp)
5937 scp->creator = NULL;
5939 scp->flags |= CM_SCACHEFLAG_DELETED;
5940 lock_ReleaseMutex(&scp->mx);
5942 lock_ObtainMutex(&scp->mx);
5943 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5944 lock_ReleaseMutex(&scp->mx);
5945 cm_ReleaseSCache(scp);
5954 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5962 fid = smb_GetSMBParm(inp, 0);
5963 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5965 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5967 fid = smb_ChainFID(fid, inp);
5968 fidp = smb_FindFID(vcp, fid, 0);
5970 return CM_ERROR_BADFD;
5973 userp = smb_GetUserFromVCP(vcp, inp);
5975 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5977 smb_ReleaseFID(fidp);
5978 cm_ReleaseUser(userp);
5983 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5985 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5986 cm_user_t *userp, long *readp)
5992 osi_hyper_t fileLength;
5994 osi_hyper_t lastByte;
5995 osi_hyper_t bufferOffset;
5996 long bufIndex, nbytes;
5998 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6006 lock_ObtainMutex(&fidp->mx);
6009 lock_ObtainMutex(&scp->mx);
6011 if (offset.HighPart == 0) {
6012 chunk = offset.LowPart >> cm_logChunkSize;
6013 if (chunk != fidp->curr_chunk) {
6014 fidp->prev_chunk = fidp->curr_chunk;
6015 fidp->curr_chunk = chunk;
6017 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6020 lock_ReleaseMutex(&fidp->mx);
6022 /* start by looking up the file's end */
6023 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6024 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6028 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6030 /* now we have the entry locked, look up the length */
6031 fileLength = scp->length;
6033 /* adjust count down so that it won't go past EOF */
6034 thyper.LowPart = count;
6035 thyper.HighPart = 0;
6036 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6038 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6039 /* we'd read past EOF, so just stop at fileLength bytes.
6040 * Start by computing how many bytes remain in the file.
6042 thyper = LargeIntegerSubtract(fileLength, offset);
6044 /* if we are past EOF, read 0 bytes */
6045 if (LargeIntegerLessThanZero(thyper))
6048 count = thyper.LowPart;
6053 /* now, copy the data one buffer at a time,
6054 * until we've filled the request packet
6057 /* if we've copied all the data requested, we're done */
6058 if (count <= 0) break;
6060 /* otherwise, load up a buffer of data */
6061 thyper.HighPart = offset.HighPart;
6062 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6063 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6066 buf_Release(bufferp);
6069 lock_ReleaseMutex(&scp->mx);
6071 lock_ObtainRead(&scp->bufCreateLock);
6072 code = buf_Get(scp, &thyper, &bufferp);
6073 lock_ReleaseRead(&scp->bufCreateLock);
6075 lock_ObtainMutex(&scp->mx);
6076 if (code) goto done;
6077 bufferOffset = thyper;
6079 /* now get the data in the cache */
6081 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6082 CM_SCACHESYNC_NEEDCALLBACK |
6083 CM_SCACHESYNC_READ);
6087 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6089 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6091 /* otherwise, load the buffer and try again */
6092 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6096 buf_Release(bufferp);
6100 } /* if (wrong buffer) ... */
6102 /* now we have the right buffer loaded. Copy out the
6103 * data from here to the user's buffer.
6105 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6107 /* and figure out how many bytes we want from this buffer */
6108 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6109 if (nbytes > count) nbytes = count; /* don't go past EOF */
6111 /* now copy the data */
6112 memcpy(op, bufferp->datap + bufIndex, nbytes);
6114 /* adjust counters, pointers, etc. */
6117 thyper.LowPart = nbytes;
6118 thyper.HighPart = 0;
6119 offset = LargeIntegerAdd(thyper, offset);
6123 lock_ReleaseMutex(&scp->mx);
6125 buf_Release(bufferp);
6127 if (code == 0 && sequential)
6128 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6130 cm_ReleaseSCache(scp);
6136 * smb_WriteData -- common code for Write and Raw Write
6138 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6139 cm_user_t *userp, long *writtenp)
6145 osi_hyper_t fileLength; /* file's length at start of write */
6146 osi_hyper_t minLength; /* don't read past this */
6147 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6149 osi_hyper_t thyper; /* hyper tmp variable */
6150 osi_hyper_t bufferOffset;
6151 afs_uint32 bufIndex; /* index in buffer where our data is */
6153 osi_hyper_t writeBackOffset;/* offset of region to write back when
6158 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6159 fidp->fid, offsetp->LowPart, count);
6169 lock_ObtainMutex(&fidp->mx);
6170 /* make sure we have a writable FD */
6171 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6172 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6173 fidp->fid, fidp->flags);
6174 lock_ReleaseMutex(&fidp->mx);
6175 code = CM_ERROR_BADFDOP;
6181 lock_ReleaseMutex(&fidp->mx);
6183 lock_ObtainMutex(&scp->mx);
6184 /* start by looking up the file's end */
6185 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6186 CM_SCACHESYNC_NEEDCALLBACK
6187 | CM_SCACHESYNC_SETSTATUS
6188 | CM_SCACHESYNC_GETSTATUS);
6192 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6194 /* now we have the entry locked, look up the length */
6195 fileLength = scp->length;
6196 minLength = fileLength;
6197 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6198 minLength = scp->serverLength;
6200 /* adjust file length if we extend past EOF */
6201 thyper.LowPart = count;
6202 thyper.HighPart = 0;
6203 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6204 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6205 /* we'd write past EOF, so extend the file */
6206 scp->mask |= CM_SCACHEMASK_LENGTH;
6207 scp->length = thyper;
6208 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6210 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6212 /* now, if the new position (thyper) and the old (offset) are in
6213 * different storeback windows, remember to store back the previous
6214 * storeback window when we're done with the write.
6216 if ((thyper.LowPart & (-cm_chunkSize)) !=
6217 (offset.LowPart & (-cm_chunkSize))) {
6218 /* they're different */
6220 writeBackOffset.HighPart = offset.HighPart;
6221 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6226 /* now, copy the data one buffer at a time, until we've filled the
6229 /* if we've copied all the data requested, we're done */
6233 /* handle over quota or out of space */
6234 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6235 *writtenp = written;
6236 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6240 /* otherwise, load up a buffer of data */
6241 thyper.HighPart = offset.HighPart;
6242 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6243 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6246 lock_ReleaseMutex(&bufferp->mx);
6247 buf_Release(bufferp);
6250 lock_ReleaseMutex(&scp->mx);
6252 lock_ObtainRead(&scp->bufCreateLock);
6253 code = buf_Get(scp, &thyper, &bufferp);
6254 lock_ReleaseRead(&scp->bufCreateLock);
6256 lock_ObtainMutex(&bufferp->mx);
6257 lock_ObtainMutex(&scp->mx);
6258 if (code) goto done;
6260 bufferOffset = thyper;
6262 /* now get the data in the cache */
6264 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6265 CM_SCACHESYNC_NEEDCALLBACK
6266 | CM_SCACHESYNC_WRITE
6267 | CM_SCACHESYNC_BUFLOCKED);
6271 cm_SyncOpDone(scp, bufferp,
6272 CM_SCACHESYNC_NEEDCALLBACK
6273 | CM_SCACHESYNC_WRITE
6274 | CM_SCACHESYNC_BUFLOCKED);
6276 /* If we're overwriting the entire buffer, or
6277 * if we're writing at or past EOF, mark the
6278 * buffer as current so we don't call
6279 * cm_GetBuffer. This skips the fetch from the
6280 * server in those cases where we're going to
6281 * obliterate all the data in the buffer anyway,
6282 * or in those cases where there is no useful
6283 * data at the server to start with.
6285 * Use minLength instead of scp->length, since
6286 * the latter has already been updated by this
6289 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6290 || LargeIntegerEqualTo(offset, bufferp->offset)
6291 && (count >= cm_data.buf_blockSize
6292 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6293 ConvertLongToLargeInteger(count)),
6295 if (count < cm_data.buf_blockSize
6296 && bufferp->dataVersion == -1)
6297 memset(bufferp->datap, 0,
6298 cm_data.buf_blockSize);
6299 bufferp->dataVersion = scp->dataVersion;
6302 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6304 /* otherwise, load the buffer and try again */
6305 lock_ReleaseMutex(&bufferp->mx);
6306 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6308 lock_ReleaseMutex(&scp->mx);
6309 lock_ObtainMutex(&bufferp->mx);
6310 lock_ObtainMutex(&scp->mx);
6314 lock_ReleaseMutex(&bufferp->mx);
6315 buf_Release(bufferp);
6319 } /* if (wrong buffer) ... */
6321 /* now we have the right buffer loaded. Copy out the
6322 * data from here to the user's buffer.
6324 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6326 /* and figure out how many bytes we want from this buffer */
6327 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6329 nbytes = count; /* don't go past end of request */
6331 /* now copy the data */
6332 memcpy(bufferp->datap + bufIndex, op, nbytes);
6333 buf_SetDirty(bufferp, bufIndex, nbytes);
6335 /* and record the last writer */
6336 if (bufferp->userp != userp) {
6339 cm_ReleaseUser(bufferp->userp);
6340 bufferp->userp = userp;
6343 /* adjust counters, pointers, etc. */
6347 thyper.LowPart = nbytes;
6348 thyper.HighPart = 0;
6349 offset = LargeIntegerAdd(thyper, offset);
6353 lock_ReleaseMutex(&scp->mx);
6356 lock_ReleaseMutex(&bufferp->mx);
6357 buf_Release(bufferp);
6360 lock_ObtainMutex(&fidp->mx);
6361 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6362 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6363 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6364 fidp->NTopen_dscp, fidp->NTopen_pathp,
6367 lock_ReleaseMutex(&fidp->mx);
6369 if (code == 0 && doWriteBack) {
6371 lock_ObtainMutex(&scp->mx);
6372 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6374 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6375 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6377 lock_ReleaseMutex(&scp->mx);
6378 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6379 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6380 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6383 cm_ReleaseSCache(scp);
6385 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6386 fidp->fid, code, *writtenp);
6390 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6393 unsigned short count;
6395 unsigned short hint;
6396 long written = 0, total_written = 0;
6401 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6403 int inDataBlockCount;
6405 fd = smb_GetSMBParm(inp, 0);
6406 count = smb_GetSMBParm(inp, 1);
6407 offset.HighPart = 0; /* too bad */
6408 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6409 hint = smb_GetSMBParm(inp, 4);
6411 op = smb_GetSMBData(inp, NULL);
6412 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6414 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6415 fd, offset.LowPart, count);
6417 fd = smb_ChainFID(fd, inp);
6418 fidp = smb_FindFID(vcp, fd, 0);
6420 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6421 return CM_ERROR_BADFD;
6424 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6425 smb_CloseFID(vcp, fidp, NULL, 0);
6426 smb_ReleaseFID(fidp);
6427 return CM_ERROR_NOSUCHFILE;
6430 lock_ObtainMutex(&fidp->mx);
6431 if (fidp->flags & SMB_FID_IOCTL) {
6432 lock_ReleaseMutex(&fidp->mx);
6433 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6434 smb_ReleaseFID(fidp);
6435 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6438 lock_ReleaseMutex(&fidp->mx);
6439 userp = smb_GetUserFromVCP(vcp, inp);
6443 LARGE_INTEGER LOffset;
6444 LARGE_INTEGER LLength;
6446 pid = ((smb_t *) inp)->pid;
6447 key = cm_GenerateKey(vcp->vcID, pid, fd);
6449 LOffset.HighPart = offset.HighPart;
6450 LOffset.LowPart = offset.LowPart;
6451 LLength.HighPart = 0;
6452 LLength.LowPart = count;
6454 lock_ObtainMutex(&fidp->scp->mx);
6455 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6456 lock_ReleaseMutex(&fidp->scp->mx);
6459 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6464 /* special case: 0 bytes transferred means truncate to this position */
6468 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6472 truncAttr.mask = CM_ATTRMASK_LENGTH;
6473 truncAttr.length.LowPart = offset.LowPart;
6474 truncAttr.length.HighPart = 0;
6475 lock_ObtainMutex(&fidp->mx);
6476 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6477 fidp->flags |= SMB_FID_LENGTHSETDONE;
6478 lock_ReleaseMutex(&fidp->mx);
6479 smb_SetSMBParm(outp, 0, 0 /* count */);
6480 smb_SetSMBDataLength(outp, 0);
6485 * Work around bug in NT client
6487 * When copying a file, the NT client should first copy the data,
6488 * then copy the last write time. But sometimes the NT client does
6489 * these in the wrong order, so the data copies would inadvertently
6490 * cause the last write time to be overwritten. We try to detect this,
6491 * and don't set client mod time if we think that would go against the
6494 lock_ObtainMutex(&fidp->mx);
6495 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6496 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6497 fidp->scp->clientModTime = time(NULL);
6499 lock_ReleaseMutex(&fidp->mx);
6502 while ( code == 0 && count > 0 ) {
6503 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6504 if (code == 0 && written == 0)
6505 code = CM_ERROR_PARTIALWRITE;
6507 offset = LargeIntegerAdd(offset,
6508 ConvertLongToLargeInteger(written));
6509 count -= (unsigned short)written;
6510 total_written += written;
6514 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6515 total_written, code);
6517 /* set the packet data length to 3 bytes for the data block header,
6518 * plus the size of the data.
6520 smb_SetSMBParm(outp, 0, total_written);
6521 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6522 smb_SetSMBParm(outp, 3, hint);
6523 smb_SetSMBDataLength(outp, 0);
6526 smb_ReleaseFID(fidp);
6527 cm_ReleaseUser(userp);
6532 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6533 NCB *ncbp, raw_write_cont_t *rwcp)
6542 fd = smb_GetSMBParm(inp, 0);
6543 fidp = smb_FindFID(vcp, fd, 0);
6545 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6546 smb_CloseFID(vcp, fidp, NULL, 0);
6547 smb_ReleaseFID(fidp);
6551 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6552 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6554 userp = smb_GetUserFromVCP(vcp, inp);
6557 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6559 if (rwcp->writeMode & 0x1) { /* synchronous */
6562 smb_FormatResponsePacket(vcp, inp, outp);
6563 op = (smb_t *) outp;
6564 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6565 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6566 smb_SetSMBDataLength(outp, 0);
6567 smb_SendPacket(vcp, outp);
6568 smb_FreePacket(outp);
6570 else { /* asynchronous */
6571 lock_ObtainMutex(&fidp->mx);
6572 fidp->raw_writers--;
6573 if (fidp->raw_writers == 0)
6574 thrd_SetEvent(fidp->raw_write_event);
6575 lock_ReleaseMutex(&fidp->mx);
6578 /* Give back raw buffer */
6579 lock_ObtainMutex(&smb_RawBufLock);
6580 *((char **)rawBuf) = smb_RawBufs;
6581 smb_RawBufs = rawBuf;
6582 lock_ReleaseMutex(&smb_RawBufLock);
6584 smb_ReleaseFID(fidp);
6585 cm_ReleaseUser(userp);
6588 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6593 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6596 long count, written = 0, total_written = 0;
6603 unsigned short writeMode;
6605 fd = smb_GetSMBParm(inp, 0);
6606 totalCount = smb_GetSMBParm(inp, 1);
6607 count = smb_GetSMBParm(inp, 10);
6608 writeMode = smb_GetSMBParm(inp, 7);
6610 op = (char *) inp->data;
6611 op += smb_GetSMBParm(inp, 11);
6613 offset.HighPart = 0;
6614 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6616 if (*inp->wctp == 14) {
6617 /* we received a 64-bit file offset */
6618 #ifdef AFS_LARGEFILES
6619 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6621 if (LargeIntegerLessThanZero(offset)) {
6623 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6624 offset.HighPart, offset.LowPart);
6625 return CM_ERROR_BADSMB;
6628 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6630 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6631 return CM_ERROR_BADSMB;
6634 offset.HighPart = 0;
6637 offset.HighPart = 0; /* 32-bit file offset */
6641 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6642 fd, offset.HighPart, offset.LowPart, count);
6644 " WriteRaw WriteMode 0x%x",
6647 fd = smb_ChainFID(fd, inp);
6648 fidp = smb_FindFID(vcp, fd, 0);
6650 return CM_ERROR_BADFD;
6653 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6654 smb_CloseFID(vcp, fidp, NULL, 0);
6655 smb_ReleaseFID(fidp);
6656 return CM_ERROR_NOSUCHFILE;
6662 LARGE_INTEGER LOffset;
6663 LARGE_INTEGER LLength;
6665 pid = ((smb_t *) inp)->pid;
6666 key = cm_GenerateKey(vcp->vcID, pid, fd);
6668 LOffset.HighPart = offset.HighPart;
6669 LOffset.LowPart = offset.LowPart;
6670 LLength.HighPart = 0;
6671 LLength.LowPart = count;
6673 lock_ObtainMutex(&fidp->scp->mx);
6674 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6675 lock_ReleaseMutex(&fidp->scp->mx);
6678 smb_ReleaseFID(fidp);
6683 userp = smb_GetUserFromVCP(vcp, inp);
6686 * Work around bug in NT client
6688 * When copying a file, the NT client should first copy the data,
6689 * then copy the last write time. But sometimes the NT client does
6690 * these in the wrong order, so the data copies would inadvertently
6691 * cause the last write time to be overwritten. We try to detect this,
6692 * and don't set client mod time if we think that would go against the
6695 lock_ObtainMutex(&fidp->mx);
6696 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6697 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6698 fidp->scp->clientModTime = time(NULL);
6700 lock_ReleaseMutex(&fidp->mx);
6703 while ( code == 0 && count > 0 ) {
6704 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6705 if (code == 0 && written == 0)
6706 code = CM_ERROR_PARTIALWRITE;
6708 offset = LargeIntegerAdd(offset,
6709 ConvertLongToLargeInteger(written));
6712 total_written += written;
6716 /* Get a raw buffer */
6719 lock_ObtainMutex(&smb_RawBufLock);
6721 /* Get a raw buf, from head of list */
6722 rawBuf = smb_RawBufs;
6723 smb_RawBufs = *(char **)smb_RawBufs;
6726 code = CM_ERROR_USESTD;
6728 lock_ReleaseMutex(&smb_RawBufLock);
6731 /* Don't allow a premature Close */
6732 if (code == 0 && (writeMode & 1) == 0) {
6733 lock_ObtainMutex(&fidp->mx);
6734 fidp->raw_writers++;
6735 thrd_ResetEvent(fidp->raw_write_event);
6736 lock_ReleaseMutex(&fidp->mx);
6739 smb_ReleaseFID(fidp);
6740 cm_ReleaseUser(userp);
6743 smb_SetSMBParm(outp, 0, total_written);
6744 smb_SetSMBDataLength(outp, 0);
6745 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6750 offset = LargeIntegerAdd(offset,
6751 ConvertLongToLargeInteger(count));
6755 rwcp->offset.HighPart = offset.HighPart;
6756 rwcp->offset.LowPart = offset.LowPart;
6757 rwcp->count = totalCount - count;
6758 rwcp->writeMode = writeMode;
6759 rwcp->alreadyWritten = total_written;
6761 /* set the packet data length to 3 bytes for the data block header,
6762 * plus the size of the data.
6764 smb_SetSMBParm(outp, 0, 0xffff);
6765 smb_SetSMBDataLength(outp, 0);
6770 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6773 long count, finalCount;
6781 fd = smb_GetSMBParm(inp, 0);
6782 count = smb_GetSMBParm(inp, 1);
6783 offset.HighPart = 0; /* too bad */
6784 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6786 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6787 fd, offset.LowPart, count);
6789 fd = smb_ChainFID(fd, inp);
6790 fidp = smb_FindFID(vcp, fd, 0);
6792 return CM_ERROR_BADFD;
6794 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6795 smb_CloseFID(vcp, fidp, NULL, 0);
6796 smb_ReleaseFID(fidp);
6797 return CM_ERROR_NOSUCHFILE;
6800 lock_ObtainMutex(&fidp->mx);
6801 if (fidp->flags & SMB_FID_IOCTL) {
6802 lock_ReleaseMutex(&fidp->mx);
6803 code = smb_IoctlRead(fidp, vcp, inp, outp);
6804 smb_ReleaseFID(fidp);
6807 lock_ReleaseMutex(&fidp->mx);
6810 LARGE_INTEGER LOffset, LLength;
6813 pid = ((smb_t *) inp)->pid;
6814 key = cm_GenerateKey(vcp->vcID, pid, fd);
6816 LOffset.HighPart = 0;
6817 LOffset.LowPart = offset.LowPart;
6818 LLength.HighPart = 0;
6819 LLength.LowPart = count;
6821 lock_ObtainMutex(&fidp->scp->mx);
6822 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6823 lock_ReleaseMutex(&fidp->scp->mx);
6826 smb_ReleaseFID(fidp);
6830 userp = smb_GetUserFromVCP(vcp, inp);
6832 /* remember this for final results */
6833 smb_SetSMBParm(outp, 0, count);
6834 smb_SetSMBParm(outp, 1, 0);
6835 smb_SetSMBParm(outp, 2, 0);
6836 smb_SetSMBParm(outp, 3, 0);
6837 smb_SetSMBParm(outp, 4, 0);
6839 /* set the packet data length to 3 bytes for the data block header,
6840 * plus the size of the data.
6842 smb_SetSMBDataLength(outp, count+3);
6844 /* get op ptr after putting in the parms, since otherwise we don't
6845 * know where the data really is.
6847 op = smb_GetSMBData(outp, NULL);
6849 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6850 *op++ = 1; /* data block marker */
6851 *op++ = (unsigned char) (count & 0xff);
6852 *op++ = (unsigned char) ((count >> 8) & 0xff);
6854 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6856 /* fix some things up */
6857 smb_SetSMBParm(outp, 0, finalCount);
6858 smb_SetSMBDataLength(outp, finalCount+3);
6860 smb_ReleaseFID(fidp);
6862 cm_ReleaseUser(userp);
6866 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6873 cm_scache_t *dscp; /* dir we're dealing with */
6874 cm_scache_t *scp; /* file we're creating */
6876 int initialModeBits;
6886 /* compute initial mode bits based on read-only flag in attributes */
6887 initialModeBits = 0777;
6889 tp = smb_GetSMBData(inp, NULL);
6890 pathp = smb_ParseASCIIBlock(tp, &tp);
6891 if (smb_StoreAnsiFilenames)
6892 OemToChar(pathp,pathp);
6894 if (strcmp(pathp, "\\") == 0)
6895 return CM_ERROR_EXISTS;
6897 spacep = inp->spacep;
6898 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6900 userp = smb_GetUserFromVCP(vcp, inp);
6902 caseFold = CM_FLAG_CASEFOLD;
6904 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6906 cm_ReleaseUser(userp);
6907 return CM_ERROR_NOSUCHPATH;
6910 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6911 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6912 userp, tidPathp, &req, &dscp);
6915 cm_ReleaseUser(userp);
6920 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6921 cm_ReleaseSCache(dscp);
6922 cm_ReleaseUser(userp);
6923 if ( WANTS_DFS_PATHNAMES(inp) )
6924 return CM_ERROR_PATH_NOT_COVERED;
6926 return CM_ERROR_BADSHARENAME;
6928 #endif /* DFS_SUPPORT */
6930 /* otherwise, scp points to the parent directory. Do a lookup, and
6931 * fail if we find it. Otherwise, we do the create.
6937 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6938 if (scp) cm_ReleaseSCache(scp);
6939 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6940 if (code == 0) code = CM_ERROR_EXISTS;
6941 cm_ReleaseSCache(dscp);
6942 cm_ReleaseUser(userp);
6946 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6947 setAttr.clientModTime = time(NULL);
6948 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6949 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6950 smb_NotifyChange(FILE_ACTION_ADDED,
6951 FILE_NOTIFY_CHANGE_DIR_NAME,
6952 dscp, lastNamep, NULL, TRUE);
6954 /* we don't need this any longer */
6955 cm_ReleaseSCache(dscp);
6958 /* something went wrong creating or truncating the file */
6959 cm_ReleaseUser(userp);
6963 /* otherwise we succeeded */
6964 smb_SetSMBDataLength(outp, 0);
6965 cm_ReleaseUser(userp);
6970 BOOL smb_IsLegalFilename(char *filename)
6973 * Find the longest substring of filename that does not contain
6974 * any of the chars in illegalChars. If that substring is less
6975 * than the length of the whole string, then one or more of the
6976 * illegal chars is in filename.
6978 if (strcspn(filename, illegalChars) < strlen(filename))
6984 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6992 cm_scache_t *dscp; /* dir we're dealing with */
6993 cm_scache_t *scp; /* file we're creating */
6995 int initialModeBits;
7003 int created = 0; /* the file was new */
7008 excl = (inp->inCom == 0x03)? 0 : 1;
7010 attributes = smb_GetSMBParm(inp, 0);
7011 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7013 /* compute initial mode bits based on read-only flag in attributes */
7014 initialModeBits = 0666;
7015 if (attributes & SMB_ATTR_READONLY)
7016 initialModeBits &= ~0222;
7018 tp = smb_GetSMBData(inp, NULL);
7019 pathp = smb_ParseASCIIBlock(tp, &tp);
7020 if (smb_StoreAnsiFilenames)
7021 OemToChar(pathp,pathp);
7023 spacep = inp->spacep;
7024 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7026 userp = smb_GetUserFromVCP(vcp, inp);
7028 caseFold = CM_FLAG_CASEFOLD;
7030 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7032 cm_ReleaseUser(userp);
7033 return CM_ERROR_NOSUCHPATH;
7035 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7036 userp, tidPathp, &req, &dscp);
7039 cm_ReleaseUser(userp);
7044 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7045 cm_ReleaseSCache(dscp);
7046 cm_ReleaseUser(userp);
7047 if ( WANTS_DFS_PATHNAMES(inp) )
7048 return CM_ERROR_PATH_NOT_COVERED;
7050 return CM_ERROR_BADSHARENAME;
7052 #endif /* DFS_SUPPORT */
7054 /* otherwise, scp points to the parent directory. Do a lookup, and
7055 * truncate the file if we find it, otherwise we create the file.
7062 if (!smb_IsLegalFilename(lastNamep))
7063 return CM_ERROR_BADNTFILENAME;
7065 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7066 #ifdef DEBUG_VERBOSE
7069 hexp = osi_HexifyString( lastNamep );
7070 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7075 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7076 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7077 cm_ReleaseSCache(dscp);
7078 cm_ReleaseUser(userp);
7082 /* if we get here, if code is 0, the file exists and is represented by
7083 * scp. Otherwise, we have to create it.
7087 /* oops, file shouldn't be there */
7088 cm_ReleaseSCache(dscp);
7089 cm_ReleaseSCache(scp);
7090 cm_ReleaseUser(userp);
7091 return CM_ERROR_EXISTS;
7094 setAttr.mask = CM_ATTRMASK_LENGTH;
7095 setAttr.length.LowPart = 0;
7096 setAttr.length.HighPart = 0;
7097 code = cm_SetAttr(scp, &setAttr, userp, &req);
7100 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7101 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7102 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7106 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7107 smb_NotifyChange(FILE_ACTION_ADDED,
7108 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7109 dscp, lastNamep, NULL, TRUE);
7110 } else if (!excl && code == CM_ERROR_EXISTS) {
7111 /* not an exclusive create, and someone else tried
7112 * creating it already, then we open it anyway. We
7113 * don't bother retrying after this, since if this next
7114 * fails, that means that the file was deleted after
7115 * we started this call.
7117 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7120 setAttr.mask = CM_ATTRMASK_LENGTH;
7121 setAttr.length.LowPart = 0;
7122 setAttr.length.HighPart = 0;
7123 code = cm_SetAttr(scp, &setAttr, userp, &req);
7128 /* we don't need this any longer */
7129 cm_ReleaseSCache(dscp);
7132 /* something went wrong creating or truncating the file */
7133 if (scp) cm_ReleaseSCache(scp);
7134 cm_ReleaseUser(userp);
7138 /* make sure we only open files */
7139 if (scp->fileType != CM_SCACHETYPE_FILE) {
7140 cm_ReleaseSCache(scp);
7141 cm_ReleaseUser(userp);
7142 return CM_ERROR_ISDIR;
7145 /* now all we have to do is open the file itself */
7146 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7151 lock_ObtainMutex(&fidp->mx);
7152 /* always create it open for read/write */
7153 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7155 /* remember that the file was newly created */
7157 fidp->flags |= SMB_FID_CREATED;
7159 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7161 /* save a pointer to the vnode */
7163 lock_ObtainMutex(&scp->mx);
7164 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7165 lock_ReleaseMutex(&scp->mx);
7168 fidp->userp = userp;
7169 lock_ReleaseMutex(&fidp->mx);
7171 smb_SetSMBParm(outp, 0, fidp->fid);
7172 smb_SetSMBDataLength(outp, 0);
7174 cm_Open(scp, 0, userp);
7176 smb_ReleaseFID(fidp);
7177 cm_ReleaseUser(userp);
7178 /* leave scp held since we put it in fidp->scp */
7182 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7185 osi_hyper_t new_offset;
7196 fd = smb_GetSMBParm(inp, 0);
7197 whence = smb_GetSMBParm(inp, 1);
7198 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7200 /* try to find the file descriptor */
7201 fd = smb_ChainFID(fd, inp);
7202 fidp = smb_FindFID(vcp, fd, 0);
7204 return CM_ERROR_BADFD;
7206 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7207 smb_CloseFID(vcp, fidp, NULL, 0);
7208 smb_ReleaseFID(fidp);
7209 return CM_ERROR_NOSUCHFILE;
7212 lock_ObtainMutex(&fidp->mx);
7213 if (fidp->flags & SMB_FID_IOCTL) {
7214 lock_ReleaseMutex(&fidp->mx);
7215 smb_ReleaseFID(fidp);
7216 return CM_ERROR_BADFD;
7218 lock_ReleaseMutex(&fidp->mx);
7220 userp = smb_GetUserFromVCP(vcp, inp);
7222 lock_ObtainMutex(&fidp->mx);
7225 lock_ReleaseMutex(&fidp->mx);
7226 lock_ObtainMutex(&scp->mx);
7227 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7228 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7230 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7232 /* offset from current offset */
7233 new_offset = LargeIntegerAdd(fidp->offset,
7234 ConvertLongToLargeInteger(offset));
7236 else if (whence == 2) {
7237 /* offset from current EOF */
7238 new_offset = LargeIntegerAdd(scp->length,
7239 ConvertLongToLargeInteger(offset));
7241 new_offset = ConvertLongToLargeInteger(offset);
7244 fidp->offset = new_offset;
7245 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7246 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7247 smb_SetSMBDataLength(outp, 0);
7249 lock_ReleaseMutex(&scp->mx);
7250 smb_ReleaseFID(fidp);
7251 cm_ReleaseSCache(scp);
7252 cm_ReleaseUser(userp);
7256 /* dispatch all of the requests received in a packet. Due to chaining, this may
7257 * be more than one request.
7259 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7260 NCB *ncbp, raw_write_cont_t *rwcp)
7264 unsigned long code = 0;
7265 unsigned char *outWctp;
7266 int nparms; /* # of bytes of parameters */
7268 int nbytes; /* bytes of data, excluding count */
7271 unsigned short errCode;
7272 unsigned long NTStatus;
7274 unsigned char errClass;
7275 unsigned int oldGen;
7276 DWORD oldTime, newTime;
7278 /* get easy pointer to the data */
7279 smbp = (smb_t *) inp->data;
7281 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7282 /* setup the basic parms for the initial request in the packet */
7283 inp->inCom = smbp->com;
7284 inp->wctp = &smbp->wct;
7286 inp->ncb_length = ncbp->ncb_length;
7291 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7292 /* log it and discard it */
7293 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7294 __FILE__, __LINE__, ncbp->ncb_length);
7295 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7299 /* We are an ongoing op */
7300 thrd_Increment(&ongoingOps);
7302 /* set up response packet for receiving output */
7303 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7304 smb_FormatResponsePacket(vcp, inp, outp);
7305 outWctp = outp->wctp;
7307 /* Remember session generation number and time */
7308 oldGen = sessionGen;
7309 oldTime = GetTickCount();
7311 while (inp->inCom != 0xff) {
7312 dp = &smb_dispatchTable[inp->inCom];
7314 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7315 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7316 code = outp->resumeCode;
7320 /* process each request in the packet; inCom, wctp and inCount
7321 * are already set up.
7323 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7326 /* now do the dispatch */
7327 /* start by formatting the response record a little, as a default */
7328 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7330 outWctp[1] = 0xff; /* no operation */
7331 outWctp[2] = 0; /* padding */
7336 /* not a chained request, this is a more reasonable default */
7337 outWctp[0] = 0; /* wct of zero */
7338 outWctp[1] = 0; /* and bcc (word) of zero */
7342 /* once set, stays set. Doesn't matter, since we never chain
7343 * "no response" calls.
7345 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7349 /* we have a recognized operation */
7351 if (inp->inCom == 0x1d)
7353 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7355 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7356 code = (*(dp->procp)) (vcp, inp, outp);
7357 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7359 if ( code == CM_ERROR_BADSMB ||
7360 code == CM_ERROR_BADOP )
7362 #endif /* LOG_PACKET */
7365 if (oldGen != sessionGen) {
7366 newTime = GetTickCount();
7367 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7368 newTime - oldTime, ncbp->ncb_length);
7369 osi_Log2(smb_logp, "Pkt straddled session startup, "
7370 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7374 /* bad opcode, fail the request, after displaying it */
7375 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7378 #endif /* LOG_PACKET */
7381 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7382 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7383 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7384 if (code == IDCANCEL)
7387 code = CM_ERROR_BADOP;
7390 /* catastrophic failure: log as much as possible */
7391 if (code == CM_ERROR_BADSMB) {
7392 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7396 #endif /* LOG_PACKET */
7397 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7400 code = CM_ERROR_INVAL;
7403 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7404 thrd_Decrement(&ongoingOps);
7409 /* now, if we failed, turn the current response into an empty
7410 * one, and fill in the response packet's error code.
7413 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7414 smb_MapNTError(code, &NTStatus);
7415 outWctp = outp->wctp;
7416 smbp = (smb_t *) &outp->data;
7417 if (code != CM_ERROR_PARTIALWRITE
7418 && code != CM_ERROR_BUFFERTOOSMALL
7419 && code != CM_ERROR_GSSCONTINUE) {
7420 /* nuke wct and bcc. For a partial
7421 * write or an in-process authentication handshake,
7422 * assume they're OK.
7428 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7429 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7430 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7431 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7432 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7436 smb_MapCoreError(code, vcp, &errCode, &errClass);
7437 outWctp = outp->wctp;
7438 smbp = (smb_t *) &outp->data;
7439 if (code != CM_ERROR_PARTIALWRITE) {
7440 /* nuke wct and bcc. For a partial
7441 * write, assume they're OK.
7447 smbp->errLow = (unsigned char) (errCode & 0xff);
7448 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7449 smbp->rcls = errClass;
7452 } /* error occurred */
7454 /* if we're here, we've finished one request. Look to see if
7455 * this is a chained opcode. If it is, setup things to process
7456 * the chained request, and setup the output buffer to hold the
7457 * chained response. Start by finding the next input record.
7459 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7460 break; /* not a chained req */
7461 tp = inp->wctp; /* points to start of last request */
7462 /* in a chained request, the first two
7463 * parm fields are required, and are
7464 * AndXCommand/AndXReserved and
7466 if (tp[0] < 2) break;
7467 if (tp[1] == 0xff) break; /* no more chained opcodes */
7469 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7472 /* and now append the next output request to the end of this
7473 * last request. Begin by finding out where the last response
7474 * ends, since that's where we'll put our new response.
7476 outWctp = outp->wctp; /* ptr to out parameters */
7477 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7478 nparms = outWctp[0] << 1;
7479 tp = outWctp + nparms + 1; /* now points to bcc field */
7480 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7481 tp += 2 /* for the count itself */ + nbytes;
7482 /* tp now points to the new output record; go back and patch the
7483 * second parameter (off2) to point to the new record.
7485 temp = (unsigned int)(tp - outp->data);
7486 outWctp[3] = (unsigned char) (temp & 0xff);
7487 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7488 outWctp[2] = 0; /* padding */
7489 outWctp[1] = inp->inCom; /* next opcode */
7491 /* finally, setup for the next iteration */
7494 } /* while loop over all requests in the packet */
7496 /* now send the output packet, and return */
7498 smb_SendPacket(vcp, outp);
7499 thrd_Decrement(&ongoingOps);
7504 /* Wait for Netbios() calls to return, and make the results available to server
7505 * threads. Note that server threads can't wait on the NCBevents array
7506 * themselves, because NCB events are manual-reset, and the servers would race
7507 * each other to reset them.
7509 void smb_ClientWaiter(void *parmp)
7514 while (smbShutdownFlag == 0) {
7515 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7517 if (code == WAIT_OBJECT_0)
7520 /* error checking */
7521 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7523 int abandonIdx = code - WAIT_ABANDONED_0;
7524 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7527 if (code == WAIT_IO_COMPLETION)
7529 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7533 if (code == WAIT_TIMEOUT)
7535 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7538 if (code == WAIT_FAILED)
7540 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7543 idx = code - WAIT_OBJECT_0;
7545 /* check idx range! */
7546 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7548 /* this is fatal - log as much as possible */
7549 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7553 thrd_ResetEvent(NCBevents[idx]);
7554 thrd_SetEvent(NCBreturns[0][idx]);
7559 * Try to have one NCBRECV request waiting for every live session. Not more
7560 * than one, because if there is more than one, it's hard to handle Write Raw.
7562 void smb_ServerWaiter(void *parmp)
7565 int idx_session, idx_NCB;
7568 while (smbShutdownFlag == 0) {
7570 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7572 if (code == WAIT_OBJECT_0)
7575 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7577 int abandonIdx = code - WAIT_ABANDONED_0;
7578 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7581 if (code == WAIT_IO_COMPLETION)
7583 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7587 if (code == WAIT_TIMEOUT)
7589 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7592 if (code == WAIT_FAILED)
7594 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7597 idx_session = code - WAIT_OBJECT_0;
7599 /* check idx range! */
7600 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7602 /* this is fatal - log as much as possible */
7603 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7609 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7611 if (code == WAIT_OBJECT_0) {
7612 if (smbShutdownFlag == 1)
7618 /* error checking */
7619 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7621 int abandonIdx = code - WAIT_ABANDONED_0;
7622 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7625 if (code == WAIT_IO_COMPLETION)
7627 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7631 if (code == WAIT_TIMEOUT)
7633 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7636 if (code == WAIT_FAILED)
7638 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7641 idx_NCB = code - WAIT_OBJECT_0;
7643 /* check idx range! */
7644 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7646 /* this is fatal - log as much as possible */
7647 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7651 /* Link them together */
7652 NCBsessions[idx_NCB] = idx_session;
7655 ncbp = NCBs[idx_NCB];
7656 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7657 ncbp->ncb_command = NCBRECV | ASYNCH;
7658 ncbp->ncb_lana_num = lanas[idx_session];
7659 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7660 ncbp->ncb_event = NCBevents[idx_NCB];
7661 ncbp->ncb_length = SMB_PACKETSIZE;
7667 * The top level loop for handling SMB request messages. Each server thread
7668 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7669 * NCB and buffer for the incoming request are loaned to us.
7671 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7672 * to immediately send a request for the rest of the data. This must come
7673 * before any other traffic for that session, so we delay setting the session
7674 * event until that data has come in.
7676 void smb_Server(VOID *parmp)
7678 INT_PTR myIdx = (INT_PTR) parmp;
7682 smb_packet_t *outbufp;
7684 int idx_NCB, idx_session;
7686 smb_vc_t *vcp = NULL;
7689 rx_StartClientThread();
7692 outbufp = GetPacket();
7693 outbufp->ncbp = outncbp;
7701 smb_ResetServerPriority();
7703 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7706 /* terminate silently if shutdown flag is set */
7707 if (code == WAIT_OBJECT_0) {
7708 if (smbShutdownFlag == 1) {
7709 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7715 /* error checking */
7716 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7718 int abandonIdx = code - WAIT_ABANDONED_0;
7719 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7722 if (code == WAIT_IO_COMPLETION)
7724 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7728 if (code == WAIT_TIMEOUT)
7730 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7733 if (code == WAIT_FAILED)
7735 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7738 idx_NCB = code - WAIT_OBJECT_0;
7740 /* check idx range! */
7741 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7743 /* this is fatal - log as much as possible */
7744 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7748 ncbp = NCBs[idx_NCB];
7749 idx_session = NCBsessions[idx_NCB];
7750 rc = ncbp->ncb_retcode;
7752 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7753 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7757 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7761 /* Can this happen? Or is it just my UNIX paranoia? */
7762 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7767 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7770 /* Client closed session */
7771 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7773 lock_ObtainMutex(&vcp->mx);
7774 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7775 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7777 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7778 lock_ReleaseMutex(&vcp->mx);
7779 lock_ObtainWrite(&smb_globalLock);
7780 dead_sessions[vcp->session] = TRUE;
7781 lock_ReleaseWrite(&smb_globalLock);
7782 smb_CleanupDeadVC(vcp);
7786 lock_ReleaseMutex(&vcp->mx);
7792 /* Treat as transient error */
7793 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7796 "dispatch smb recv failed, message incomplete, ncb_length %d",
7799 "SMB message incomplete, "
7800 "length %d", ncbp->ncb_length);
7803 * We used to discard the packet.
7804 * Instead, try handling it normally.
7808 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7812 /* A weird error code. Log it, sleep, and continue. */
7813 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7815 lock_ObtainMutex(&vcp->mx);
7816 if (vcp && vcp->errorCount++ > 3) {
7817 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7818 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7819 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7821 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7822 lock_ReleaseMutex(&vcp->mx);
7823 lock_ObtainWrite(&smb_globalLock);
7824 dead_sessions[vcp->session] = TRUE;
7825 lock_ReleaseWrite(&smb_globalLock);
7826 smb_CleanupDeadVC(vcp);
7830 lock_ReleaseMutex(&vcp->mx);
7836 lock_ReleaseMutex(&vcp->mx);
7838 thrd_SetEvent(SessionEvents[idx_session]);
7843 /* Success, so now dispatch on all the data in the packet */
7845 smb_concurrentCalls++;
7846 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7847 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7850 * If at this point vcp is NULL (implies that packet was invalid)
7851 * then we are in big trouble. This means either :
7852 * a) we have the wrong NCB.
7853 * b) Netbios screwed up the call.
7854 * c) The VC was already marked dead before we were able to
7856 * Obviously this implies that
7857 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7858 * lanas[idx_session] != ncbp->ncb_lana_num )
7859 * Either way, we can't do anything with this packet.
7860 * Log, sleep and resume.
7863 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7867 ncbp->ncb_lana_num);
7869 /* Also log in the trace log. */
7870 osi_Log4(smb_logp, "Server: VCP does not exist!"
7871 "LSNs[idx_session]=[%d],"
7872 "lanas[idx_session]=[%d],"
7873 "ncbp->ncb_lsn=[%d],"
7874 "ncbp->ncb_lana_num=[%d]",
7878 ncbp->ncb_lana_num);
7880 /* thrd_Sleep(1000); Don't bother sleeping */
7881 thrd_SetEvent(SessionEvents[idx_session]);
7882 smb_concurrentCalls--;
7886 smb_SetRequestStartTime();
7888 vcp->errorCount = 0;
7889 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7890 smbp = (smb_t *)bufp->data;
7895 if (smbp->com == 0x1d) {
7896 /* Special handling for Write Raw */
7897 raw_write_cont_t rwc;
7898 EVENT_HANDLE rwevent;
7899 char eventName[MAX_PATH];
7901 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7902 if (rwc.code == 0) {
7903 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7904 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7905 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7906 ncbp->ncb_command = NCBRECV | ASYNCH;
7907 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7908 ncbp->ncb_lana_num = vcp->lana;
7909 ncbp->ncb_buffer = rwc.buf;
7910 ncbp->ncb_length = 65535;
7911 ncbp->ncb_event = rwevent;
7913 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7914 thrd_CloseHandle(rwevent);
7916 thrd_SetEvent(SessionEvents[idx_session]);
7918 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7920 else if (smbp->com == 0xa0) {
7922 * Serialize the handling for NT Transact
7925 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7926 thrd_SetEvent(SessionEvents[idx_session]);
7928 thrd_SetEvent(SessionEvents[idx_session]);
7929 /* TODO: what else needs to be serialized? */
7930 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7933 __except( smb_ServerExceptionFilter() ) {
7936 smb_concurrentCalls--;
7939 thrd_SetEvent(NCBavails[idx_NCB]);
7946 * Exception filter for the server threads. If an exception occurs in the
7947 * dispatch routines, which is where exceptions are most common, then do a
7948 * force trace and give control to upstream exception handlers. Useful for
7951 DWORD smb_ServerExceptionFilter(void) {
7952 /* While this is not the best time to do a trace, if it succeeds, then
7953 * we have a trace (assuming tracing was enabled). Otherwise, this should
7954 * throw a second exception.
7956 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7957 afsd_ForceTrace(TRUE);
7958 buf_ForceTrace(TRUE);
7959 return EXCEPTION_CONTINUE_SEARCH;
7963 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7964 * If the number of server threads is M, and the number of live sessions is
7965 * N, then the number of NCB's in use at any time either waiting for, or
7966 * holding, received messages is M + N, so that is how many NCB's get created.
7968 void InitNCBslot(int idx)
7970 struct smb_packet *bufp;
7971 EVENT_HANDLE retHandle;
7973 char eventName[MAX_PATH];
7975 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7977 NCBs[idx] = GetNCB();
7978 sprintf(eventName,"NCBavails[%d]", idx);
7979 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7980 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7981 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7982 sprintf(eventName,"NCBevents[%d]", idx);
7983 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7984 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7985 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7986 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7987 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7988 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7989 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7990 for (i=0; i<smb_NumServerThreads; i++)
7991 NCBreturns[i][idx] = retHandle;
7993 bufp->spacep = cm_GetSpace();
7997 /* listen for new connections */
7998 void smb_Listener(void *parmp)
8004 int session, thread;
8005 smb_vc_t *vcp = NULL;
8007 char rname[NCBNAMSZ+1];
8008 char cname[MAX_COMPUTERNAME_LENGTH+1];
8009 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8010 INT_PTR lana = (INT_PTR) parmp;
8014 /* retrieve computer name */
8015 GetComputerName(cname, &cnamelen);
8018 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8019 memset(ncbp, 0, sizeof(NCB));
8022 ncbp->ncb_command = NCBLISTEN;
8023 ncbp->ncb_rto = 0; /* No receive timeout */
8024 ncbp->ncb_sto = 0; /* No send timeout */
8026 /* pad out with spaces instead of null termination */
8027 len = (long)strlen(smb_localNamep);
8028 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8029 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8031 strcpy(ncbp->ncb_callname, "*");
8032 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8034 ncbp->ncb_lana_num = (UCHAR)lana;
8036 code = Netbios(ncbp);
8038 if (code == NRC_BRIDGE) {
8039 int lanaRemaining = 0;
8041 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
8046 "NCBLISTEN lana=%d failed with NRC_BRIDGE. Listener thread exiting.",
8047 ncbp->ncb_lana_num, code);
8049 for (i = 0; i < lana_list.length; i++) {
8050 if (lana_list.lana[i] == ncbp->ncb_lana_num) {
8051 smb_StopListener(ncbp, lana_list.lana[i]);
8052 lana_list.lana[i] = 255;
8054 if (lana_list.lana[i] != 255)
8058 if (lanaRemaining == 0) {
8059 cm_VolStatus_Network_Stopped(cm_NetbiosName
8064 smb_ListenerState = SMB_LISTENER_STOPPED;
8065 smb_LANadapter = -1;
8066 lana_list.length = 0;
8070 } else if (code != 0) {
8071 char tbuffer[AFSPATHMAX];
8073 /* terminate silently if shutdown flag is set */
8074 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
8079 "NCBLISTEN lana=%d failed with code %d",
8080 ncbp->ncb_lana_num, code);
8082 "Client exiting due to network failure. Please restart client.\n");
8085 "Client exiting due to network failure. Please restart client.\n"
8086 "NCBLISTEN lana=%d failed with code %d",
8087 ncbp->ncb_lana_num, code);
8089 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8090 MB_OK|MB_SERVICE_NOTIFICATION);
8091 osi_panic(tbuffer, __FILE__, __LINE__);
8094 /* check for remote conns */
8095 /* first get remote name and insert null terminator */
8096 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8097 for (i=NCBNAMSZ; i>0; i--) {
8098 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8104 /* compare with local name */
8106 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8107 flags |= SMB_VCFLAG_REMOTECONN;
8110 lock_ObtainMutex(&smb_ListenerLock);
8112 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8113 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8115 /* now ncbp->ncb_lsn is the connection ID */
8116 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8117 if (vcp->session == 0) {
8118 /* New generation */
8119 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8122 /* Log session startup */
8124 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8125 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8126 #endif /* NOTSERVICE */
8127 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8128 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8130 if (reportSessionStartups) {
8131 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8134 lock_ObtainMutex(&vcp->mx);
8135 strcpy(vcp->rname, rname);
8136 vcp->flags |= flags;
8137 lock_ReleaseMutex(&vcp->mx);
8139 /* Allocate slot in session arrays */
8140 /* Re-use dead session if possible, otherwise add one more */
8141 /* But don't look at session[0], it is reserved */
8142 lock_ObtainWrite(&smb_globalLock);
8143 for (session = 1; session < numSessions; session++) {
8144 if (dead_sessions[session]) {
8145 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8146 dead_sessions[session] = FALSE;
8150 lock_ReleaseWrite(&smb_globalLock);
8152 /* We are re-using an existing VC because the lsn and lana
8154 session = vcp->session;
8156 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8158 /* Log session startup */
8160 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8161 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8162 #endif /* NOTSERVICE */
8163 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8164 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8166 if (reportSessionStartups) {
8167 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8171 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8172 unsigned long code = CM_ERROR_ALLBUSY;
8173 smb_packet_t * outp = GetPacket();
8174 unsigned char *outWctp;
8177 smb_FormatResponsePacket(vcp, NULL, outp);
8180 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8181 unsigned long NTStatus;
8182 smb_MapNTError(code, &NTStatus);
8183 outWctp = outp->wctp;
8184 smbp = (smb_t *) &outp->data;
8188 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8189 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8190 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8191 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8192 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8194 unsigned short errCode;
8195 unsigned char errClass;
8196 smb_MapCoreError(code, vcp, &errCode, &errClass);
8197 outWctp = outp->wctp;
8198 smbp = (smb_t *) &outp->data;
8202 smbp->errLow = (unsigned char) (errCode & 0xff);
8203 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8204 smbp->rcls = errClass;
8206 smb_SendPacket(vcp, outp);
8207 smb_FreePacket(outp);
8209 lock_ObtainMutex(&vcp->mx);
8210 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8211 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8213 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8214 lock_ReleaseMutex(&vcp->mx);
8215 lock_ObtainWrite(&smb_globalLock);
8216 dead_sessions[vcp->session] = TRUE;
8217 lock_ReleaseWrite(&smb_globalLock);
8218 smb_CleanupDeadVC(vcp);
8220 lock_ReleaseMutex(&vcp->mx);
8223 /* assert that we do not exceed the maximum number of sessions or NCBs.
8224 * we should probably want to wait for a session to be freed in case
8227 osi_assert(session < SESSION_MAX - 1);
8228 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8230 lock_ObtainMutex(&vcp->mx);
8231 vcp->session = session;
8232 lock_ReleaseMutex(&vcp->mx);
8233 lock_ObtainWrite(&smb_globalLock);
8234 LSNs[session] = ncbp->ncb_lsn;
8235 lanas[session] = ncbp->ncb_lana_num;
8236 lock_ReleaseWrite(&smb_globalLock);
8238 if (session == numSessions) {
8239 /* Add new NCB for new session */
8240 char eventName[MAX_PATH];
8242 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8244 InitNCBslot(numNCBs);
8245 lock_ObtainWrite(&smb_globalLock);
8247 lock_ReleaseWrite(&smb_globalLock);
8248 thrd_SetEvent(NCBavails[0]);
8249 thrd_SetEvent(NCBevents[0]);
8250 for (thread = 0; thread < smb_NumServerThreads; thread++)
8251 thrd_SetEvent(NCBreturns[thread][0]);
8252 /* Also add new session event */
8253 sprintf(eventName, "SessionEvents[%d]", session);
8254 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8255 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8256 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8257 lock_ObtainWrite(&smb_globalLock);
8259 lock_ReleaseWrite(&smb_globalLock);
8260 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8261 thrd_SetEvent(SessionEvents[0]);
8263 thrd_SetEvent(SessionEvents[session]);
8269 lock_ReleaseMutex(&smb_ListenerLock);
8270 } /* dispatch while loop */
8275 /* initialize Netbios */
8276 int smb_NetbiosInit(void)
8279 int i, lana, code, l;
8281 int delname_tried=0;
8284 lana_number_t lanaNum;
8286 /* setup the NCB system */
8289 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8290 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8291 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8293 if (smb_LANadapter != -1)
8294 afsi_log("LAN adapter number %d", smb_LANadapter);
8296 afsi_log("LAN adapter number not determined");
8299 afsi_log("Set for gateway service");
8301 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8303 /* something went horribly wrong. We can't proceed without a netbios name */
8305 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8306 osi_panic(buf, __FILE__, __LINE__);
8309 /* remember the name */
8310 len = (int)strlen(cm_NetbiosName);
8312 free(smb_localNamep);
8313 smb_localNamep = malloc(len+1);
8314 strcpy(smb_localNamep, cm_NetbiosName);
8315 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8318 if (smb_LANadapter == -1) {
8319 ncbp->ncb_command = NCBENUM;
8320 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8321 ncbp->ncb_length = sizeof(lana_list);
8322 code = Netbios(ncbp);
8324 afsi_log("Netbios NCBENUM error code %d", code);
8325 osi_panic(s, __FILE__, __LINE__);
8329 lana_list.length = 1;
8330 lana_list.lana[0] = smb_LANadapter;
8333 for (i = 0; i < lana_list.length; i++) {
8334 /* reset the adaptor: in Win32, this is required for every process, and
8335 * acts as an init call, not as a real hardware reset.
8337 ncbp->ncb_command = NCBRESET;
8338 ncbp->ncb_callname[0] = 100;
8339 ncbp->ncb_callname[2] = 100;
8340 ncbp->ncb_lana_num = lana_list.lana[i];
8341 code = Netbios(ncbp);
8343 code = ncbp->ncb_retcode;
8345 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8346 lana_list.lana[i] = 255; /* invalid lana */
8348 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8352 /* and declare our name so we can receive connections */
8353 memset(ncbp, 0, sizeof(*ncbp));
8354 len=lstrlen(smb_localNamep);
8355 memset(smb_sharename,' ',NCBNAMSZ);
8356 memcpy(smb_sharename,smb_localNamep,len);
8357 afsi_log("lana_list.length %d", lana_list.length);
8359 /* Keep the name so we can unregister it later */
8360 for (l = 0; l < lana_list.length; l++) {
8361 lana = lana_list.lana[l];
8363 ncbp->ncb_command = NCBADDNAME;
8364 ncbp->ncb_lana_num = lana;
8365 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8366 code = Netbios(ncbp);
8368 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8369 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8371 char name[NCBNAMSZ+1];
8373 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8374 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8378 code = ncbp->ncb_retcode;
8381 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8384 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8385 if (code == NRC_BRIDGE) { /* invalid LANA num */
8386 lana_list.lana[l] = 255;
8389 else if (code == NRC_DUPNAME) {
8390 afsi_log("Name already exists; try to delete it");
8391 memset(ncbp, 0, sizeof(*ncbp));
8392 ncbp->ncb_command = NCBDELNAME;
8393 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8394 ncbp->ncb_lana_num = lana;
8395 code = Netbios(ncbp);
8397 code = ncbp->ncb_retcode;
8399 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8401 if (code != 0 || delname_tried) {
8402 lana_list.lana[l] = 255;
8404 else if (code == 0) {
8405 if (!delname_tried) {
8413 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8414 lana_list.lana[l] = 255; /* invalid lana */
8418 lana_found = 1; /* at least one worked */
8422 osi_assert(lana_list.length >= 0);
8424 afsi_log("No valid LANA numbers found!");
8425 lana_list.length = 0;
8426 smb_LANadapter = -1;
8427 smb_ListenerState = SMB_LISTENER_STOPPED;
8428 cm_VolStatus_Network_Stopped(cm_NetbiosName
8435 /* we're done with the NCB now */
8438 return (lana_list.length > 0 ? 1 : 0);
8441 void smb_StartListeners()
8447 if (smb_ListenerState == SMB_LISTENER_STARTED)
8450 smb_ListenerState = SMB_LISTENER_STARTED;
8451 cm_VolStatus_Network_Started(cm_NetbiosName
8457 for (i = 0; i < lana_list.length; i++) {
8458 if (lana_list.lana[i] == 255)
8460 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8461 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8462 osi_assert(phandle != NULL);
8463 thrd_CloseHandle(phandle);
8467 void smb_RestartListeners()
8469 if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
8470 if (smb_NetbiosInit())
8471 smb_StartListeners();
8475 void smb_StopListener(NCB *ncbp, int lana)
8479 memset(ncbp, 0, sizeof(*ncbp));
8480 ncbp->ncb_command = NCBDELNAME;
8481 ncbp->ncb_lana_num = lana;
8482 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8483 code = Netbios(ncbp);
8485 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8486 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8488 /* and then reset the LANA; this will cause the listener threads to exit */
8489 ncbp->ncb_command = NCBRESET;
8490 ncbp->ncb_callname[0] = 100;
8491 ncbp->ncb_callname[2] = 100;
8492 ncbp->ncb_lana_num = lana;
8493 code = Netbios(ncbp);
8495 code = ncbp->ncb_retcode;
8497 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8499 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8503 void smb_StopListeners(void)
8508 if (smb_ListenerState == SMB_LISTENER_STOPPED)
8511 smb_ListenerState = SMB_LISTENER_STOPPED;
8512 cm_VolStatus_Network_Stopped(cm_NetbiosName
8520 /* Unregister the SMB name */
8521 for (l = 0; l < lana_list.length; l++) {
8522 lana = lana_list.lana[l];
8525 smb_StopListener(ncbp, lana);
8527 /* mark the adapter invalid */
8528 lana_list.lana[l] = 255; /* invalid lana */
8532 /* force a re-evaluation of the network adapters */
8533 lana_list.length = 0;
8534 smb_LANadapter = -1;
8536 Sleep(1000); /* give the listener threads a chance to exit */
8539 void smb_Init(osi_log_t *logp, int useV3,
8549 EVENT_HANDLE retHandle;
8550 char eventName[MAX_PATH];
8552 smb_TlsRequestSlot = TlsAlloc();
8554 smb_MBfunc = aMBfunc;
8558 /* Initialize smb_localZero */
8559 myTime.tm_isdst = -1; /* compute whether on DST or not */
8560 myTime.tm_year = 70;
8566 smb_localZero = mktime(&myTime);
8568 #ifndef USE_NUMERIC_TIME_CONV
8569 /* Initialize kludge-GMT */
8570 smb_CalculateNowTZ();
8571 #endif /* USE_NUMERIC_TIME_CONV */
8572 #ifdef AFS_FREELANCE_CLIENT
8573 /* Make sure the root.afs volume has the correct time */
8574 cm_noteLocalMountPointChange();
8577 /* initialize the remote debugging log */
8580 /* and the global lock */
8581 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8582 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8584 /* Raw I/O data structures */
8585 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8587 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8589 /* 4 Raw I/O buffers */
8590 smb_RawBufs = calloc(65536,1);
8591 *((char **)smb_RawBufs) = NULL;
8592 for (i=0; i<3; i++) {
8593 char *rawBuf = calloc(65536,1);
8594 *((char **)rawBuf) = smb_RawBufs;
8595 smb_RawBufs = rawBuf;
8598 /* global free lists */
8599 smb_ncbFreeListp = NULL;
8600 smb_packetFreeListp = NULL;
8604 /* Initialize listener and server structures */
8606 memset(dead_sessions, 0, sizeof(dead_sessions));
8607 sprintf(eventName, "SessionEvents[0]");
8608 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8609 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8610 afsi_log("Event Object Already Exists: %s", eventName);
8612 smb_NumServerThreads = nThreads;
8613 sprintf(eventName, "NCBavails[0]");
8614 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8615 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8616 afsi_log("Event Object Already Exists: %s", eventName);
8617 sprintf(eventName, "NCBevents[0]");
8618 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8619 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8620 afsi_log("Event Object Already Exists: %s", eventName);
8621 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8622 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8623 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8624 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8625 afsi_log("Event Object Already Exists: %s", eventName);
8626 for (i = 0; i < smb_NumServerThreads; i++) {
8627 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8628 NCBreturns[i][0] = retHandle;
8631 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8632 for (i = 0; i < smb_NumServerThreads; i++) {
8633 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8634 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8635 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8636 afsi_log("Event Object Already Exists: %s", eventName);
8637 InitNCBslot((int)(i+1));
8639 numNCBs = smb_NumServerThreads + 1;
8641 /* Initialize dispatch table */
8642 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8643 /* Prepare the table for unknown operations */
8644 for(i=0; i<= SMB_NOPCODES; i++) {
8645 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8647 /* Fill in the ones we do know */
8648 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8649 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8650 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8651 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8652 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8653 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8654 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8655 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8656 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8657 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8658 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8659 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8660 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8661 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8662 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8663 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8664 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8665 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8666 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8667 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8668 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8669 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8670 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8671 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8672 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8673 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8674 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8675 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8676 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8677 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8678 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8679 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8680 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8681 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8682 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8683 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8684 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8685 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8686 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8687 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8688 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8689 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8690 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8691 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8692 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8693 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8694 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8695 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8696 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8697 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8698 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8699 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8700 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8701 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8702 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8703 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8704 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8705 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8706 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8707 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8708 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8709 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8710 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8711 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8712 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8713 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8714 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8715 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8716 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8717 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8718 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8719 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8720 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8721 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8723 /* setup tran 2 dispatch table */
8724 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8725 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8726 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8727 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8728 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8729 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8730 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8731 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8732 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8733 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8734 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8735 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8736 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8737 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8738 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8739 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8740 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8741 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8743 /* setup the rap dispatch table */
8744 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8745 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8746 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8747 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8748 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8752 /* if we are doing SMB authentication we have register outselves as a logon process */
8753 if (smb_authType != SMB_AUTH_NONE) {
8754 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8755 LSA_STRING afsProcessName;
8756 LSA_OPERATIONAL_MODE dummy; /*junk*/
8758 afsProcessName.Buffer = "OpenAFSClientDaemon";
8759 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8760 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8762 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8764 if (nts == STATUS_SUCCESS) {
8765 LSA_STRING packageName;
8766 /* we are registered. Find out the security package id */
8767 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8768 packageName.Length = (USHORT)strlen(packageName.Buffer);
8769 packageName.MaximumLength = packageName.Length + 1;
8770 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8771 if (nts == STATUS_SUCCESS) {
8773 * This code forces Windows to authenticate against the Logon Cache
8774 * first instead of attempting to authenticate against the Domain
8775 * Controller. When the Windows logon cache is enabled this improves
8776 * performance by removing the network access and works around a bug
8777 * seen at sites which are using a MIT Kerberos principal to login
8778 * to machines joined to a non-root domain in a multi-domain forest.
8779 * MsV1_0SetProcessOption was added in Windows XP.
8781 PVOID pResponse = NULL;
8782 ULONG cbResponse = 0;
8783 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8785 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8786 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8787 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8788 OptionsRequest.DisableOptions = FALSE;
8790 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8793 sizeof(OptionsRequest),
8799 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8800 char message[AFSPATHMAX];
8801 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8803 OutputDebugString(message);
8806 OutputDebugString("MsV1_0SetProcessOption success");
8807 afsi_log("MsV1_0SetProcessOption success");
8809 /* END - code from Larry */
8811 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8812 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8813 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8815 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8817 /* something went wrong. We report the error and revert back to no authentication
8818 because we can't perform any auth requests without a successful lsa handle
8819 or sec package id. */
8820 afsi_log("Reverting to NO SMB AUTH");
8821 smb_authType = SMB_AUTH_NONE;
8824 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8826 /* something went wrong. We report the error and revert back to no authentication
8827 because we can't perform any auth requests without a successful lsa handle
8828 or sec package id. */
8829 afsi_log("Reverting to NO SMB AUTH");
8830 smb_authType = SMB_AUTH_NONE;
8834 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8835 * time prevents the failure of authentication when logged into Windows with an
8836 * external Kerberos principal mapped to a local account.
8838 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8839 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8840 * then the only option is NTLMSSP anyway; so just fallback.
8845 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8846 if (secBlobLength == 0) {
8847 smb_authType = SMB_AUTH_NTLM;
8848 afsi_log("Reverting to SMB AUTH NTLM");
8857 /* Now get ourselves a domain name. */
8858 /* For now we are using the local computer name as the domain name.
8859 * It is actually the domain for local logins, and we are acting as
8860 * a local SMB server.
8862 bufsize = sizeof(smb_ServerDomainName) - 1;
8863 GetComputerName(smb_ServerDomainName, &bufsize);
8864 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8865 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8868 /* Start listeners, waiters, servers, and daemons */
8870 smb_StartListeners();
8872 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8873 NULL, 0, &lpid, "smb_ClientWaiter");
8874 osi_assert(phandle != NULL);
8875 thrd_CloseHandle(phandle);
8877 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8878 NULL, 0, &lpid, "smb_ServerWaiter");
8879 osi_assert(phandle != NULL);
8880 thrd_CloseHandle(phandle);
8882 for (i=0; i<smb_NumServerThreads; i++) {
8883 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8884 (void *) i, 0, &lpid, "smb_Server");
8885 osi_assert(phandle != NULL);
8886 thrd_CloseHandle(phandle);
8889 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8890 NULL, 0, &lpid, "smb_Daemon");
8891 osi_assert(phandle != NULL);
8892 thrd_CloseHandle(phandle);
8894 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8895 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8896 osi_assert(phandle != NULL);
8897 thrd_CloseHandle(phandle);
8902 void smb_Shutdown(void)
8909 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8911 /* setup the NCB system */
8914 /* Block new sessions by setting shutdown flag */
8915 smbShutdownFlag = 1;
8917 /* Hang up all sessions */
8918 memset((char *)ncbp, 0, sizeof(NCB));
8919 for (i = 1; i < numSessions; i++)
8921 if (dead_sessions[i])
8924 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8925 ncbp->ncb_command = NCBHANGUP;
8926 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8927 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8928 code = Netbios(ncbp);
8929 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8930 if (code == 0) code = ncbp->ncb_retcode;
8932 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8933 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8937 /* Trigger the shutdown of all SMB threads */
8938 for (i = 0; i < smb_NumServerThreads; i++)
8939 thrd_SetEvent(NCBreturns[i][0]);
8941 thrd_SetEvent(NCBevents[0]);
8942 thrd_SetEvent(SessionEvents[0]);
8943 thrd_SetEvent(NCBavails[0]);
8945 for (i = 0;i < smb_NumServerThreads; i++) {
8946 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8947 if (code == WAIT_OBJECT_0) {
8950 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8951 thrd_SetEvent(NCBreturns[i--][0]);
8955 /* Delete Netbios name */
8956 memset((char *)ncbp, 0, sizeof(NCB));
8957 for (i = 0; i < lana_list.length; i++) {
8958 if (lana_list.lana[i] == 255) continue;
8959 ncbp->ncb_command = NCBDELNAME;
8960 ncbp->ncb_lana_num = lana_list.lana[i];
8961 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8962 code = Netbios(ncbp);
8964 code = ncbp->ncb_retcode;
8966 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8967 ncbp->ncb_lana_num, code);
8972 /* Release the reference counts held by the VCs */
8973 lock_ObtainWrite(&smb_rctLock);
8974 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8979 if (vcp->magic != SMB_VC_MAGIC)
8980 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8981 __FILE__, __LINE__);
8983 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8985 if (fidp->scp != NULL) {
8988 lock_ObtainMutex(&fidp->mx);
8989 if (fidp->scp != NULL) {
8992 lock_ObtainMutex(&scp->mx);
8993 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
8994 lock_ReleaseMutex(&scp->mx);
8995 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
8996 cm_ReleaseSCache(scp);
8998 lock_ReleaseMutex(&fidp->mx);
9002 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9004 smb_ReleaseVCNoLock(tidp->vcp);
9006 cm_user_t *userp = tidp->userp;
9008 lock_ReleaseWrite(&smb_rctLock);
9009 cm_ReleaseUser(userp);
9010 lock_ObtainWrite(&smb_rctLock);
9014 lock_ReleaseWrite(&smb_rctLock);
9016 TlsFree(smb_TlsRequestSlot);
9019 /* Get the UNC \\<servername>\<sharename> prefix. */
9020 char *smb_GetSharename()
9024 /* Make sure we have been properly initialized. */
9025 if (smb_localNamep == NULL)
9028 /* Allocate space for \\<servername>\<sharename>, plus the
9031 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9032 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9038 void smb_LogPacket(smb_packet_t *packet)
9041 unsigned length, paramlen, datalen, i, j;
9043 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9045 if (!packet) return;
9047 osi_Log0(smb_logp, "*** SMB packet dump ***");
9049 vp = (BYTE *) packet->data;
9051 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9052 length = paramlen + 2 + datalen;
9055 for (i=0;i < length; i+=16)
9057 memset( buf, ' ', 80 );
9062 buf[strlen(buf)] = ' ';
9064 cp = (BYTE*) buf + 7;
9066 for (j=0;j < 16 && (i+j)<length; j++)
9068 *(cp++) = hex[vp[i+j] >> 4];
9069 *(cp++) = hex[vp[i+j] & 0xf];
9079 for (j=0;j < 16 && (i+j)<length;j++)
9081 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9092 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9095 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9097 #endif /* LOG_PACKET */
9100 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9108 lock_ObtainRead(&smb_rctLock);
9110 sprintf(output, "begin dumping smb_vc_t\r\n");
9111 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9113 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9117 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9118 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9119 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9121 sprintf(output, "begin dumping smb_fid_t\r\n");
9122 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9124 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9126 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",
9127 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9128 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9129 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9130 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9133 sprintf(output, "done dumping smb_fid_t\r\n");
9134 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9137 sprintf(output, "done dumping smb_vc_t\r\n");
9138 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9140 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9141 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9143 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9147 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9148 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9149 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9151 sprintf(output, "begin dumping smb_fid_t\r\n");
9152 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9154 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9156 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",
9157 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9158 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9159 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9160 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9163 sprintf(output, "done dumping smb_fid_t\r\n");
9164 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9167 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9168 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9171 lock_ReleaseRead(&smb_rctLock);
9175 long smb_IsNetworkStarted(void)
9177 return (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);