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>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 #define STRSAFE_NO_DEPRECATE
37 /* These characters are illegal in Windows filenames */
38 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
40 static int smbShutdownFlag = 0;
41 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
43 int smb_LogoffTokenTransfer;
44 time_t smb_LogoffTransferTimeout;
46 int smb_StoreAnsiFilenames = 0;
48 DWORD last_msg_time = 0;
52 unsigned int sessionGen = 0;
54 extern void afsi_log(char *pattern, ...);
55 extern HANDLE afsi_file;
56 extern int powerStateSuspended;
58 osi_hyper_t hzero = {0, 0};
59 osi_hyper_t hones = {0xFFFFFFFF, -1};
62 osi_rwlock_t smb_globalLock;
63 osi_rwlock_t smb_rctLock;
64 osi_mutex_t smb_ListenerLock;
65 osi_mutex_t smb_StartedLock;
67 unsigned char smb_LANadapter = LANA_INVALID;
68 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
69 int smb_LanAdapterChangeDetected = 0;
70 afs_uint32 smb_AsyncStore = 1;
71 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
73 BOOL isGateway = FALSE;
76 long smb_maxObsConcurrentCalls=0;
77 long smb_concurrentCalls=0;
79 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
81 smb_packet_t *smb_packetFreeListp;
82 smb_ncb_t *smb_ncbFreeListp;
84 afs_uint32 smb_NumServerThreads;
86 afs_uint32 numNCBs, numSessions, numVCs;
88 int smb_maxVCPerServer;
89 int smb_maxMpxRequests;
91 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
93 ULONG smb_lsaSecPackage;
94 LSA_STRING smb_lsaLogonOrigin;
96 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
97 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
98 EVENT_HANDLE **NCBreturns;
99 EVENT_HANDLE **NCBShutdown;
100 EVENT_HANDLE *smb_ServerShutdown;
101 EVENT_HANDLE ListenerShutdown[256];
102 DWORD NCBsessions[NCB_MAX];
104 struct smb_packet *bufs[NCB_MAX];
106 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
107 EVENT_HANDLE SessionEvents[SESSION_MAX];
108 unsigned short LSNs[SESSION_MAX];
109 int lanas[SESSION_MAX];
110 BOOL dead_sessions[SESSION_MAX];
113 osi_mutex_t smb_RawBufLock;
116 #define SMB_MASKFLAG_TILDE 1
117 #define SMB_MASKFLAG_CASEFOLD 2
119 #define RAWTIMEOUT INFINITE
122 typedef struct raw_write_cont {
131 /* dir search stuff */
132 long smb_dirSearchCounter = 1;
133 smb_dirSearch_t *smb_firstDirSearchp;
134 smb_dirSearch_t *smb_lastDirSearchp;
136 /* hide dot files? */
137 int smb_hideDotFiles;
139 /* Negotiate Unicode support? */
142 /* global state about V3 protocols */
143 int smb_useV3; /* try to negotiate V3 */
145 static int showErrors = 0;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
151 * Time in Unix format of midnight, 1/1/1970 local time.
152 * When added to dosUTime, gives Unix (AFS) time.
154 time_t smb_localZero = 0;
156 #define USE_NUMERIC_TIME_CONV 1
158 #ifndef USE_NUMERIC_TIME_CONV
159 /* Time difference for converting to kludge-GMT */
160 afs_uint32 smb_NowTZ;
161 #endif /* USE_NUMERIC_TIME_CONV */
163 char *smb_localNamep = NULL;
165 smb_vc_t *smb_allVCsp;
166 smb_vc_t *smb_deadVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLockRequest_t *smb_allWaitingLocks;
172 DWORD smb_TlsRequestSlot = -1;
175 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
176 NCB *ncbp, raw_write_cont_t *rwcp);
177 int smb_NetbiosInit(int);
180 void smb_LogPacket(smb_packet_t *packet);
181 #endif /* LOG_PACKET */
183 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
184 int smb_ServerDomainNameLength = 0;
185 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
186 int smb_ServerOSLength = lengthof(smb_ServerOS);
187 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
188 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
190 /* Faux server GUID. This is never checked. */
191 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
193 void smb_ResetServerPriority()
195 void * p = TlsGetValue(smb_TlsRequestSlot);
198 TlsSetValue(smb_TlsRequestSlot, NULL);
199 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
203 void smb_SetRequestStartTime()
205 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
207 tp = malloc(sizeof(time_t));
211 if (!TlsSetValue(smb_TlsRequestSlot, tp))
216 void smb_UpdateServerPriority()
218 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
221 time_t now = osi_Time();
223 /* Give one priority boost for each 15 seconds */
224 SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
229 const char * ncb_error_string(int code)
233 case 0x01: s = "llegal buffer length"; break;
234 case 0x03: s = "illegal command"; break;
235 case 0x05: s = "command timed out"; break;
236 case 0x06: s = "message incomplete, issue another command"; break;
237 case 0x07: s = "illegal buffer address"; break;
238 case 0x08: s = "session number out of range"; break;
239 case 0x09: s = "no resource available"; break;
240 case 0x0a: s = "session closed"; break;
241 case 0x0b: s = "command cancelled"; break;
242 case 0x0d: s = "duplicate name"; break;
243 case 0x0e: s = "name table full"; break;
244 case 0x0f: s = "no deletions, name has active sessions"; break;
245 case 0x11: s = "local session table full"; break;
246 case 0x12: s = "remote session table full"; break;
247 case 0x13: s = "illegal name number"; break;
248 case 0x14: s = "no callname"; break;
249 case 0x15: s = "cannot put * in NCB_NAME"; break;
250 case 0x16: s = "name in use on remote adapter"; break;
251 case 0x17: s = "name deleted"; break;
252 case 0x18: s = "session ended abnormally"; break;
253 case 0x19: s = "name conflict detected"; break;
254 case 0x21: s = "interface busy, IRET before retrying"; break;
255 case 0x22: s = "too many commands outstanding, retry later";break;
256 case 0x23: s = "ncb_lana_num field invalid"; break;
257 case 0x24: s = "command completed while cancel occurring "; break;
258 case 0x26: s = "command not valid to cancel"; break;
259 case 0x30: s = "name defined by anther local process"; break;
260 case 0x34: s = "environment undefined. RESET required"; break;
261 case 0x35: s = "required OS resources exhausted"; break;
262 case 0x36: s = "max number of applications exceeded"; break;
263 case 0x37: s = "no saps available for netbios"; break;
264 case 0x38: s = "requested resources are not available"; break;
265 case 0x39: s = "invalid ncb address or length > segment"; break;
266 case 0x3B: s = "invalid NCB DDID"; break;
267 case 0x3C: s = "lock of user area failed"; break;
268 case 0x3f: s = "NETBIOS not loaded"; break;
269 case 0x40: s = "system error"; break;
270 default: s = "unknown error";
276 char * myCrt_Dispatch(int i)
281 return "(00)ReceiveCoreMakeDir";
283 return "(01)ReceiveCoreRemoveDir";
285 return "(02)ReceiveCoreOpen";
287 return "(03)ReceiveCoreCreate";
289 return "(04)ReceiveCoreClose";
291 return "(05)ReceiveCoreFlush";
293 return "(06)ReceiveCoreUnlink";
295 return "(07)ReceiveCoreRename";
297 return "(08)ReceiveCoreGetFileAttributes";
299 return "(09)ReceiveCoreSetFileAttributes";
301 return "(0a)ReceiveCoreRead";
303 return "(0b)ReceiveCoreWrite";
305 return "(0c)ReceiveCoreLockRecord";
307 return "(0d)ReceiveCoreUnlockRecord";
309 return "(0e)SendCoreBadOp";
311 return "(0f)ReceiveCoreCreate";
313 return "(10)ReceiveCoreCheckPath";
315 return "(11)SendCoreBadOp";
317 return "(12)ReceiveCoreSeek";
319 return "(1a)ReceiveCoreReadRaw";
321 return "(1d)ReceiveCoreWriteRawDummy";
323 return "(22)ReceiveV3SetAttributes";
325 return "(23)ReceiveV3GetAttributes";
327 return "(24)ReceiveV3LockingX";
329 return "(25)ReceiveV3Trans";
331 return "(26)ReceiveV3Trans[aux]";
333 return "(29)SendCoreBadOp";
335 return "(2b)ReceiveCoreEcho";
337 return "(2d)ReceiveV3OpenX";
339 return "(2e)ReceiveV3ReadX";
341 return "(2f)ReceiveV3WriteX";
343 return "(32)ReceiveV3Tran2A";
345 return "(33)ReceiveV3Tran2A[aux]";
347 return "(34)ReceiveV3FindClose";
349 return "(35)ReceiveV3FindNotifyClose";
351 return "(70)ReceiveCoreTreeConnect";
353 return "(71)ReceiveCoreTreeDisconnect";
355 return "(72)ReceiveNegotiate";
357 return "(73)ReceiveV3SessionSetupX";
359 return "(74)ReceiveV3UserLogoffX";
361 return "(75)ReceiveV3TreeConnectX";
363 return "(80)ReceiveCoreGetDiskAttributes";
365 return "(81)ReceiveCoreSearchDir";
369 return "(83)FindUnique";
371 return "(84)FindClose";
373 return "(A0)ReceiveNTTransact";
375 return "(A2)ReceiveNTCreateX";
377 return "(A4)ReceiveNTCancel";
379 return "(A5)ReceiveNTRename";
381 return "(C0)OpenPrintFile";
383 return "(C1)WritePrintFile";
385 return "(C2)ClosePrintFile";
387 return "(C3)GetPrintQueue";
389 return "(D8)ReadBulk";
391 return "(D9)WriteBulk";
393 return "(DA)WriteBulkData";
395 return "unknown SMB op";
399 char * myCrt_2Dispatch(int i)
404 return "unknown SMB op-2";
406 return "S(00)CreateFile_ReceiveTran2Open";
408 return "S(01)FindFirst_ReceiveTran2SearchDir";
410 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
412 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
414 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
416 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
418 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
420 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
422 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
424 return "S(09)_ReceiveTran2FSCTL";
426 return "S(0a)_ReceiveTran2IOCTL";
428 return "S(0b)_ReceiveTran2FindNotifyFirst";
430 return "S(0c)_ReceiveTran2FindNotifyNext";
432 return "S(0d)_ReceiveTran2CreateDirectory";
434 return "S(0e)_ReceiveTran2SessionSetup";
436 return "S(0f)_QueryFileSystemInformationFid";
438 return "S(10)_ReceiveTran2GetDfsReferral";
440 return "S(11)_ReceiveTran2ReportDfsInconsistency";
444 char * myCrt_RapDispatch(int i)
449 return "unknown RAP OP";
451 return "RAP(0)NetShareEnum";
453 return "RAP(1)NetShareGetInfo";
455 return "RAP(13)NetServerGetInfo";
457 return "RAP(63)NetWkStaGetInfo";
461 /* scache must be locked */
462 unsigned int smb_Attributes(cm_scache_t *scp)
466 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
467 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
468 scp->fileType == CM_SCACHETYPE_INVALID)
470 attrs = SMB_ATTR_DIRECTORY;
471 #ifdef SPECIAL_FOLDERS
472 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
473 #endif /* SPECIAL_FOLDERS */
474 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
475 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
480 * We used to mark a file RO if it was in an RO volume, but that
481 * turns out to be impolitic in NT. See defect 10007.
484 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
485 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
487 if ((scp->unixModeBits & 0222) == 0)
488 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
494 /* Check if the named file/dir is a dotfile/dotdir */
495 /* String pointed to by lastComp can have leading slashes, but otherwise should have
496 no other patch components */
497 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
501 /* skip over slashes */
502 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
507 /* nulls, curdir and parent dir doesn't count */
513 if(*(s+1) == _C('.') && !*(s + 2))
520 static int ExtractBits(WORD bits, short start, short len)
527 num = bits << (16 - end);
528 num = num >> ((16 - end) + start);
533 void ShowUnixTime(char *FuncName, time_t unixTime)
538 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
540 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
541 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
543 int day, month, year, sec, min, hour;
546 day = ExtractBits(wDate, 0, 5);
547 month = ExtractBits(wDate, 5, 4);
548 year = ExtractBits(wDate, 9, 7) + 1980;
550 sec = ExtractBits(wTime, 0, 5);
551 min = ExtractBits(wTime, 5, 6);
552 hour = ExtractBits(wTime, 11, 5);
554 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
555 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
559 /* Determine if we are observing daylight savings time */
560 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
562 TIME_ZONE_INFORMATION timeZoneInformation;
563 SYSTEMTIME utc, local, localDST;
565 /* Get the time zone info. NT uses this to calc if we are in DST. */
566 GetTimeZoneInformation(&timeZoneInformation);
568 /* Return the daylight bias */
569 *pDstBias = timeZoneInformation.DaylightBias;
571 /* Return the bias */
572 *pBias = timeZoneInformation.Bias;
574 /* Now determine if DST is being observed */
576 /* Get the UTC (GMT) time */
579 /* Convert UTC time to local time using the time zone info. If we are
580 observing DST, the calculated local time will include this.
582 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
584 /* Set the daylight bias to 0. The daylight bias is the amount of change
585 * in time that we use for daylight savings time. By setting this to 0
586 * we cause there to be no change in time during daylight savings time.
588 timeZoneInformation.DaylightBias = 0;
590 /* Convert the utc time to local time again, but this time without any
591 adjustment for daylight savings time.
593 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
595 /* If the two times are different, then it means that the localDST that
596 we calculated includes the daylight bias, and therefore we are
597 observing daylight savings time.
599 *pDST = localDST.wHour != local.wHour;
603 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
605 BOOL dst; /* Will be TRUE if observing DST */
606 LONG dstBias; /* Offset from local time if observing DST */
607 LONG bias; /* Offset from GMT for local time */
610 * This function will adjust the last write time to compensate
611 * for two bugs in the smb client:
613 * 1) During Daylight Savings Time, the LastWriteTime is ahead
614 * in time by the DaylightBias (ignoring the sign - the
615 * DaylightBias is always stored as a negative number). If
616 * the DaylightBias is -60, then the LastWriteTime will be
617 * ahead by 60 minutes.
619 * 2) If the local time zone is a positive offset from GMT, then
620 * the LastWriteTime will be the correct local time plus the
621 * Bias (ignoring the sign - a positive offset from GMT is
622 * always stored as a negative Bias). If the Bias is -120,
623 * then the LastWriteTime will be ahead by 120 minutes.
625 * These bugs can occur at the same time.
628 GetTimeZoneInfo(&dst, &dstBias, &bias);
630 /* First adjust for DST */
632 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
634 /* Now adjust for a positive offset from GMT (a negative bias). */
636 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
639 #ifndef USE_NUMERIC_TIME_CONV
641 * Calculate the difference (in seconds) between local time and GMT.
642 * This enables us to convert file times to kludge-GMT.
648 struct tm gmt_tm, local_tm;
649 int days, hours, minutes, seconds;
652 gmt_tm = *(gmtime(&t));
653 local_tm = *(localtime(&t));
655 days = local_tm.tm_yday - gmt_tm.tm_yday;
656 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
657 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
658 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
662 #endif /* USE_NUMERIC_TIME_CONV */
664 #ifdef USE_NUMERIC_TIME_CONV
665 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
667 // Note that LONGLONG is a 64-bit value
670 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
671 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
672 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
675 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
680 time_t ersatz_unixTime;
683 * Must use kludge-GMT instead of real GMT.
684 * kludge-GMT is computed by adding time zone difference to localtime.
687 * ltp = gmtime(&unixTime);
689 ersatz_unixTime = unixTime - smb_NowTZ;
690 ltp = localtime(&ersatz_unixTime);
692 /* if we fail, make up something */
695 localJunk.tm_year = 89 - 20;
696 localJunk.tm_mon = 4;
697 localJunk.tm_mday = 12;
698 localJunk.tm_hour = 0;
699 localJunk.tm_min = 0;
700 localJunk.tm_sec = 0;
703 stm.wYear = ltp->tm_year + 1900;
704 stm.wMonth = ltp->tm_mon + 1;
705 stm.wDayOfWeek = ltp->tm_wday;
706 stm.wDay = ltp->tm_mday;
707 stm.wHour = ltp->tm_hour;
708 stm.wMinute = ltp->tm_min;
709 stm.wSecond = ltp->tm_sec;
710 stm.wMilliseconds = 0;
712 SystemTimeToFileTime(&stm, largeTimep);
714 #endif /* USE_NUMERIC_TIME_CONV */
716 #ifdef USE_NUMERIC_TIME_CONV
717 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
719 // Note that LONGLONG is a 64-bit value
722 ll = largeTimep->dwHighDateTime;
724 ll += largeTimep->dwLowDateTime;
726 ll -= 116444736000000000;
729 *unixTimep = (DWORD)ll;
731 #else /* USE_NUMERIC_TIME_CONV */
732 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
738 FileTimeToSystemTime(largeTimep, &stm);
740 lt.tm_year = stm.wYear - 1900;
741 lt.tm_mon = stm.wMonth - 1;
742 lt.tm_wday = stm.wDayOfWeek;
743 lt.tm_mday = stm.wDay;
744 lt.tm_hour = stm.wHour;
745 lt.tm_min = stm.wMinute;
746 lt.tm_sec = stm.wSecond;
749 save_timezone = _timezone;
750 _timezone += smb_NowTZ;
751 *unixTimep = mktime(<);
752 _timezone = save_timezone;
754 #endif /* USE_NUMERIC_TIME_CONV */
756 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
766 /* if we fail, make up something */
769 localJunk.tm_year = 89 - 20;
770 localJunk.tm_mon = 4;
771 localJunk.tm_mday = 12;
772 localJunk.tm_hour = 0;
773 localJunk.tm_min = 0;
774 localJunk.tm_sec = 0;
777 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
778 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
779 *searchTimep = (dosDate<<16) | dosTime;
782 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
784 unsigned short dosDate;
785 unsigned short dosTime;
788 dosDate = (unsigned short) (searchTime & 0xffff);
789 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
791 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
792 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
793 localTm.tm_mday = (dosDate) & 0x1f;
794 localTm.tm_hour = (dosTime>>11) & 0x1f;
795 localTm.tm_min = (dosTime >> 5) & 0x3f;
796 localTm.tm_sec = (dosTime & 0x1f) * 2;
797 localTm.tm_isdst = -1; /* compute whether DST in effect */
799 *unixTimep = mktime(&localTm);
802 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
804 time_t diff_t = unixTime - smb_localZero;
805 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
806 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
808 *dosUTimep = (afs_uint32)diff_t;
811 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
813 *unixTimep = dosTime + smb_localZero;
816 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
820 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
821 lock_ObtainWrite(&smb_rctLock);
822 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
823 if (vcp->magic != SMB_VC_MAGIC)
824 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
827 if (lsn == vcp->lsn && lana == vcp->lana &&
828 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
829 smb_HoldVCNoLock(vcp);
833 if (!vcp && (flags & SMB_FLAG_CREATE)) {
834 vcp = malloc(sizeof(*vcp));
835 memset(vcp, 0, sizeof(*vcp));
836 vcp->vcID = ++numVCs;
837 vcp->magic = SMB_VC_MAGIC;
838 vcp->refCount = 2; /* smb_allVCsp and caller */
841 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
842 vcp->nextp = smb_allVCsp;
844 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
849 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
850 /* We must obtain a challenge for extended auth
851 * in case the client negotiates smb v3
853 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
854 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
855 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
856 ULONG lsaRespSize = 0;
858 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
860 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
867 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
868 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
869 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
870 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
871 nts, ntsEx, lsaRespSize);
873 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
875 if (ntsEx == STATUS_SUCCESS) {
876 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
877 LsaFreeReturnBuffer(lsaResp);
880 * This will cause the subsequent authentication to fail but
881 * that is better than us dereferencing a NULL pointer and
884 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
888 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
890 if (numVCs >= CM_SESSION_RESERVED) {
892 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
895 lock_ReleaseWrite(&smb_rctLock);
896 lock_ReleaseWrite(&smb_globalLock);
900 int smb_IsStarMask(clientchar_t *maskp)
905 for(i=0; i<11; i++) {
907 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
913 void smb_ReleaseVCInternal(smb_vc_t *vcp)
920 if (vcp->refCount == 0) {
921 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
922 /* remove VCP from smb_deadVCsp */
923 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
929 lock_FinalizeMutex(&vcp->mx);
930 memset(vcp,0,sizeof(smb_vc_t));
933 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
937 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
938 avcp?"not ":"",vcp, vcp->refCount);
940 GenerateMiniDump(NULL);
942 /* This is a wrong. However, I suspect that there is an undercount
943 * and I don't want to release 1.4.1 in a state that will allow
944 * smb_vc_t objects to be deallocated while still in the
945 * smb_allVCsp list. The list is supposed to keep a reference
946 * to the smb_vc_t. Put it back.
950 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
951 /* The reference count is non-zero but the VC is dead.
952 * This implies that some FIDs, TIDs, etc on the VC have yet to
953 * be cleaned up. Add a reference that will be dropped by
954 * smb_CleanupDeadVC() and try to cleanup the VC again.
955 * Eventually the refCount will drop to zero when all of the
956 * active threads working with the VC end their task.
958 vcp->refCount++; /* put the refCount back */
959 lock_ReleaseWrite(&smb_rctLock);
960 smb_CleanupDeadVC(vcp);
961 lock_ObtainWrite(&smb_rctLock);
965 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
967 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
968 smb_ReleaseVCInternal(vcp);
971 void smb_ReleaseVC(smb_vc_t *vcp)
973 lock_ObtainWrite(&smb_rctLock);
974 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
975 smb_ReleaseVCInternal(vcp);
976 lock_ReleaseWrite(&smb_rctLock);
979 void smb_HoldVCNoLock(smb_vc_t *vcp)
982 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
985 void smb_HoldVC(smb_vc_t *vcp)
987 lock_ObtainWrite(&smb_rctLock);
989 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
990 lock_ReleaseWrite(&smb_rctLock);
993 void smb_CleanupDeadVC(smb_vc_t *vcp)
1001 smb_user_t *uidpIter;
1002 smb_user_t *uidpNext;
1006 lock_ObtainMutex(&vcp->mx);
1007 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1008 lock_ReleaseMutex(&vcp->mx);
1009 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1012 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1013 lock_ReleaseMutex(&vcp->mx);
1014 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1016 lock_ObtainWrite(&smb_rctLock);
1017 /* remove VCP from smb_allVCsp */
1018 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1019 if ((*vcpp)->magic != SMB_VC_MAGIC)
1020 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1021 __FILE__, __LINE__);
1024 vcp->nextp = smb_deadVCsp;
1026 /* Hold onto the reference until we are done with this function */
1031 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1032 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1034 if (fidpIter->deleteOk)
1037 fid = fidpIter->fid;
1038 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1040 smb_HoldFIDNoLock(fidpIter);
1041 lock_ReleaseWrite(&smb_rctLock);
1043 smb_CloseFID(vcp, fidpIter, NULL, 0);
1044 smb_ReleaseFID(fidpIter);
1046 lock_ObtainWrite(&smb_rctLock);
1047 fidpNext = vcp->fidsp;
1050 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1051 tidpNext = tidpIter->nextp;
1052 if (tidpIter->deleteOk)
1054 tidpIter->deleteOk = 1;
1056 tid = tidpIter->tid;
1057 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1059 smb_HoldTIDNoLock(tidpIter);
1060 smb_ReleaseTID(tidpIter, TRUE);
1061 tidpNext = vcp->tidsp;
1064 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1065 uidpNext = uidpIter->nextp;
1066 if (uidpIter->deleteOk)
1068 uidpIter->deleteOk = 1;
1070 /* do not add an additional reference count for the smb_user_t
1071 * as the smb_vc_t already is holding a reference */
1072 lock_ReleaseWrite(&smb_rctLock);
1074 smb_ReleaseUID(uidpIter);
1076 lock_ObtainWrite(&smb_rctLock);
1077 uidpNext = vcp->usersp;
1080 lock_ObtainMutex(&vcp->mx);
1081 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1082 lock_ReleaseMutex(&vcp->mx);
1084 /* The vcp is now on the deadVCsp list. We intentionally drop the
1085 * reference so that the refcount can reach 0 and we can delete it */
1086 smb_ReleaseVCNoLock(vcp);
1088 lock_ReleaseWrite(&smb_rctLock);
1089 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1092 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1096 lock_ObtainWrite(&smb_rctLock);
1098 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1099 if (tidp->refCount == 0 && tidp->deleteOk) {
1101 smb_ReleaseTID(tidp, TRUE);
1105 if (tid == tidp->tid) {
1110 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1111 tidp = malloc(sizeof(*tidp));
1112 memset(tidp, 0, sizeof(*tidp));
1113 tidp->nextp = vcp->tidsp;
1116 smb_HoldVCNoLock(vcp);
1118 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1121 lock_ReleaseWrite(&smb_rctLock);
1125 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1130 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1138 lock_ObtainWrite(&smb_rctLock);
1139 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1140 if (tidp->refCount == 0 && (tidp->deleteOk)) {
1141 ltpp = &tidp->vcp->tidsp;
1142 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1146 osi_assertx(tp != NULL, "null smb_tid_t");
1148 lock_FinalizeMutex(&tidp->mx);
1149 userp = tidp->userp; /* remember to drop ref later */
1151 smb_ReleaseVCNoLock(tidp->vcp);
1155 lock_ReleaseWrite(&smb_rctLock);
1157 cm_ReleaseUser(userp);
1160 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1162 smb_user_t *uidp = NULL;
1164 lock_ObtainWrite(&smb_rctLock);
1165 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1166 if (uid == uidp->userID) {
1168 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1170 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1174 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1175 uidp = malloc(sizeof(*uidp));
1176 memset(uidp, 0, sizeof(*uidp));
1177 uidp->nextp = vcp->usersp;
1178 uidp->refCount = 2; /* one for the vcp and one for the caller */
1180 smb_HoldVCNoLock(vcp);
1182 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1184 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1186 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1188 lock_ReleaseWrite(&smb_rctLock);
1192 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1195 smb_username_t *unp= NULL;
1197 lock_ObtainWrite(&smb_rctLock);
1198 for(unp = usernamesp; unp; unp = unp->nextp) {
1199 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1200 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1205 if (!unp && (flags & SMB_FLAG_CREATE)) {
1206 unp = malloc(sizeof(*unp));
1207 memset(unp, 0, sizeof(*unp));
1209 unp->nextp = usernamesp;
1210 unp->name = cm_ClientStrDup(usern);
1211 unp->machine = cm_ClientStrDup(machine);
1213 lock_InitializeMutex(&unp->mx, "username_t mutex");
1214 if (flags & SMB_FLAG_AFSLOGON)
1215 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1218 lock_ReleaseWrite(&smb_rctLock);
1222 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1224 smb_user_t *uidp= NULL;
1226 lock_ObtainWrite(&smb_rctLock);
1227 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1230 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1232 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1233 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1238 lock_ReleaseWrite(&smb_rctLock);
1242 void smb_ReleaseUsername(smb_username_t *unp)
1245 smb_username_t **lupp;
1246 cm_user_t *userp = NULL;
1247 time_t now = osi_Time();
1249 lock_ObtainWrite(&smb_rctLock);
1250 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1251 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1252 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1254 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1258 osi_assertx(up != NULL, "null smb_username_t");
1260 up->nextp = NULL; /* do not remove this */
1261 lock_FinalizeMutex(&unp->mx);
1267 lock_ReleaseWrite(&smb_rctLock);
1269 cm_ReleaseUser(userp);
1272 void smb_HoldUIDNoLock(smb_user_t *uidp)
1277 void smb_ReleaseUID(smb_user_t *uidp)
1281 smb_username_t *unp = NULL;
1283 lock_ObtainWrite(&smb_rctLock);
1284 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1285 if (uidp->refCount == 0) {
1286 lupp = &uidp->vcp->usersp;
1287 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1291 osi_assertx(up != NULL, "null smb_user_t");
1293 lock_FinalizeMutex(&uidp->mx);
1295 smb_ReleaseVCNoLock(uidp->vcp);
1299 lock_ReleaseWrite(&smb_rctLock);
1303 cm_ReleaseUserVCRef(unp->userp);
1304 smb_ReleaseUsername(unp);
1308 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1310 cm_user_t *up = NULL;
1315 lock_ObtainMutex(&uidp->mx);
1317 up = uidp->unp->userp;
1320 lock_ReleaseMutex(&uidp->mx);
1326 /* retrieve a held reference to a user structure corresponding to an incoming
1328 * corresponding release function is cm_ReleaseUser.
1330 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1333 cm_user_t *up = NULL;
1336 smbp = (smb_t *) inp;
1337 uidp = smb_FindUID(vcp, smbp->uid, 0);
1341 up = smb_GetUserFromUID(uidp);
1343 smb_ReleaseUID(uidp);
1348 * Return a pointer to a pathname extracted from a TID structure. The
1349 * TID structure is not held; assume it won't go away.
1351 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1356 tidp = smb_FindTID(vcp, tid, 0);
1360 if (tidp->flags & SMB_TIDFLAG_IPC) {
1361 code = CM_ERROR_TIDIPC;
1362 /* tidp->pathname would be NULL, but that's fine */
1364 *treepath = tidp->pathname;
1365 smb_ReleaseTID(tidp, FALSE);
1370 /* check to see if we have a chained fid, that is, a fid that comes from an
1371 * OpenAndX message that ran earlier in this packet. In this case, the fid
1372 * field in a read, for example, request, isn't set, since the value is
1373 * supposed to be inherited from the openAndX call.
1375 int smb_ChainFID(int fid, smb_packet_t *inp)
1377 if (inp->fid == 0 || inp->inCount == 0)
1383 /* are we a priv'd user? What does this mean on NT? */
1384 int smb_SUser(cm_user_t *userp)
1389 /* find a file ID. If we pass in 0 we select an unused File ID.
1390 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1391 * smb_fid_t data structure if desired File ID cannot be found.
1393 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1398 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1401 lock_ObtainWrite(&smb_rctLock);
1402 /* figure out if we need to allocate a new file ID */
1405 fid = vcp->fidCounter;
1409 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1410 if (fidp->refCount == 0 && fidp->deleteOk) {
1412 lock_ReleaseWrite(&smb_rctLock);
1413 smb_ReleaseFID(fidp);
1414 lock_ObtainWrite(&smb_rctLock);
1417 if (fid == fidp->fid) {
1420 if (fid == 0xFFFF) {
1422 "New FID number wraps on vcp 0x%x", vcp);
1432 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1433 char eventName[MAX_PATH];
1435 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1436 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1437 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1438 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1439 thrd_CloseHandle(event);
1441 if (fid == 0xFFFF) {
1442 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1448 fidp = malloc(sizeof(*fidp));
1449 memset(fidp, 0, sizeof(*fidp));
1450 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1453 smb_HoldVCNoLock(vcp);
1454 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1456 fidp->curr_chunk = fidp->prev_chunk = -2;
1457 fidp->raw_write_event = event;
1459 vcp->fidCounter = fid+1;
1460 if (vcp->fidCounter == 0xFFFF) {
1461 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1463 vcp->fidCounter = 1;
1468 lock_ReleaseWrite(&smb_rctLock);
1472 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1474 smb_fid_t *fidp = NULL;
1480 lock_ObtainWrite(&smb_rctLock);
1481 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1482 if (scp == fidp->scp) {
1487 lock_ReleaseWrite(&smb_rctLock);
1491 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1497 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1498 /* the sm_fid_t->mx and smb_rctLock must not be held */
1499 void smb_ReleaseFID(smb_fid_t *fidp)
1501 cm_scache_t *scp = NULL;
1502 cm_user_t *userp = NULL;
1503 smb_vc_t *vcp = NULL;
1504 smb_ioctl_t *ioctlp;
1506 lock_ObtainMutex(&fidp->mx);
1507 lock_ObtainWrite(&smb_rctLock);
1508 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1509 if (fidp->refCount == 0 && (fidp->deleteOk)) {
1512 scp = fidp->scp; /* release after lock is released */
1514 lock_ObtainWrite(&scp->rw);
1515 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1516 lock_ReleaseWrite(&scp->rw);
1517 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1520 userp = fidp->userp;
1524 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1525 thrd_CloseHandle(fidp->raw_write_event);
1527 /* and see if there is ioctl stuff to free */
1528 ioctlp = fidp->ioctlp;
1531 cm_FreeSpace(ioctlp->prefix);
1532 if (ioctlp->ioctl.inAllocp)
1533 free(ioctlp->ioctl.inAllocp);
1534 if (ioctlp->ioctl.outAllocp)
1535 free(ioctlp->ioctl.outAllocp);
1538 lock_ReleaseMutex(&fidp->mx);
1539 lock_FinalizeMutex(&fidp->mx);
1543 smb_ReleaseVCNoLock(vcp);
1545 lock_ReleaseMutex(&fidp->mx);
1547 lock_ReleaseWrite(&smb_rctLock);
1549 /* now release the scache structure */
1551 cm_ReleaseSCache(scp);
1554 cm_ReleaseUser(userp);
1558 * Case-insensitive search for one string in another;
1559 * used to find variable names in submount pathnames.
1561 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1563 clientchar_t *cursor;
1565 for (cursor = str1; *cursor; cursor++)
1566 if (cm_ClientStrCmpI(cursor, str2) == 0)
1573 * Substitute a variable value for its name in a submount pathname. Variable
1574 * name has been identified by smb_stristr() and is in substr. Variable name
1575 * length (plus one) is in substr_size. Variable value is in newstr.
1577 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1578 unsigned int substr_size, clientchar_t *newstr)
1580 clientchar_t temp[1024];
1582 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1583 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1584 cm_ClientStrCat(str1, cchstr1, temp);
1587 clientchar_t VNUserName[] = _C("%USERNAME%");
1588 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1589 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1590 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1592 typedef struct smb_findShare_rock {
1593 clientchar_t * shareName;
1594 clientchar_t * match;
1596 } smb_findShare_rock_t;
1598 #define SMB_FINDSHARE_EXACT_MATCH 1
1599 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1601 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1605 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1606 normchar_t normName[MAX_PATH];
1608 cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
1610 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1611 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1612 matchType = SMB_FINDSHARE_EXACT_MATCH;
1614 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1615 if(vrock->match) free(vrock->match);
1616 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1617 vrock->matchType = matchType;
1619 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1620 return CM_ERROR_STOPNOW;
1626 /* find a shareName in the table of submounts */
1627 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1628 clientchar_t *shareName,
1629 clientchar_t **pathNamep)
1633 clientchar_t pathName[1024];
1636 clientchar_t *p, *q;
1637 fschar_t *cellname = NULL;
1640 DWORD allSubmount = 1;
1642 /* if allSubmounts == 0, only return the //mountRoot/all share
1643 * if in fact it has been been created in the subMounts table.
1644 * This is to allow sites that want to restrict access to the
1647 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1648 0, KEY_QUERY_VALUE, &parmKey);
1649 if (code == ERROR_SUCCESS) {
1650 cblen = sizeof(allSubmount);
1651 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1652 (BYTE *) &allSubmount, &cblen);
1653 if (code != ERROR_SUCCESS) {
1656 RegCloseKey (parmKey);
1659 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1664 /* In case, the all share is disabled we need to still be able
1665 * to handle ioctl requests
1667 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1668 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1672 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1673 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1674 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1675 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1676 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1682 /* Check for volume references
1684 * They look like <cell>{%,#}<volume>
1686 if (cm_ClientStrChr(shareName, '%') != NULL ||
1687 cm_ClientStrChr(shareName, '#') != NULL) {
1688 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1689 /* make room for '/@vol:' + mountchar + NULL terminator*/
1691 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1692 osi_LogSaveClientString(smb_logp, shareName));
1694 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1695 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1696 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1698 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1700 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1701 cm_ClientStrLwr(*pathNamep);
1702 osi_Log1(smb_logp, " returning pathname [%S]",
1703 osi_LogSaveClientString(smb_logp, *pathNamep));
1711 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1712 0, KEY_QUERY_VALUE, &parmKey);
1713 if (code == ERROR_SUCCESS) {
1714 cblen = sizeof(pathName);
1715 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1716 (BYTE *) pathName, &cblen);
1717 if (code != ERROR_SUCCESS)
1719 RegCloseKey (parmKey);
1723 cchlen = cblen / sizeof(clientchar_t);
1724 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1725 /* We can accept either unix or PC style AFS pathnames. Convert
1726 * Unix-style to PC style here for internal use.
1729 cchlen = lengthof(pathName);
1731 /* within this code block, we maintain, cchlen = writeable
1732 buffer length of p */
1734 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1735 p += cm_mountRootCLen; /* skip mount path */
1736 cchlen -= (p - pathName);
1741 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1747 clientchar_t temp[1024];
1749 if (var = smb_stristr(p, VNUserName)) {
1750 if (uidp && uidp->unp)
1751 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1753 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1755 else if (var = smb_stristr(p, VNLCUserName))
1757 if (uidp && uidp->unp)
1758 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1760 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1761 cm_ClientStrLwr(temp);
1762 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1764 else if (var = smb_stristr(p, VNComputerName))
1766 sizeTemp = lengthof(temp);
1767 GetComputerNameW(temp, &sizeTemp);
1768 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1770 else if (var = smb_stristr(p, VNLCComputerName))
1772 sizeTemp = lengthof(temp);
1773 GetComputerName((LPTSTR)temp, &sizeTemp);
1774 cm_ClientStrLwr(temp);
1775 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1780 *pathNamep = cm_ClientStrDup(p);
1785 /* First lookup shareName in root.afs */
1787 smb_findShare_rock_t vrock;
1789 fschar_t ftemp[1024];
1790 clientchar_t * p = shareName;
1793 /* attempt to locate a partial match in root.afs. This is because
1794 when using the ANSI RAP calls, the share name is limited to 13 chars
1795 and hence is truncated. Of course we prefer exact matches. */
1797 thyper.HighPart = 0;
1800 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1802 vrock.matchType = 0;
1804 cm_HoldSCache(cm_data.rootSCachep);
1805 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1806 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1807 cm_ReleaseSCache(cm_data.rootSCachep);
1809 free(vrock.shareName);
1810 vrock.shareName = NULL;
1812 if (vrock.matchType) {
1813 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1814 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1819 /* if we get here, there was no match for the share in root.afs */
1820 /* so try to create \\<netbiosName>\<cellname> */
1825 /* Get the full name for this cell */
1826 cellname = cm_ClientStringToFsStringAlloc(p, cm_ClientStrLen(p), NULL);
1827 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1828 #ifdef AFS_AFSDB_ENV
1829 if (code && cm_dnsEnabled) {
1831 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1837 /* construct the path */
1839 clientchar_t temp[1024];
1841 cm_FsStringToClientString(ftemp, cm_FsStrLen(ftemp), temp, 1024);
1842 cm_ClientStrPrintfN(pathName, lengthof(pathName),
1843 rw ? _C("/.%S/") : _C("/%S/"), temp);
1844 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1853 /* Client-side offline caching policy types */
1854 #define CSC_POLICY_MANUAL 0
1855 #define CSC_POLICY_DOCUMENTS 1
1856 #define CSC_POLICY_PROGRAMS 2
1857 #define CSC_POLICY_DISABLE 3
1859 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1862 clientchar_t policy[1024];
1865 int retval = CSC_POLICY_MANUAL;
1867 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1868 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1871 REG_OPTION_NON_VOLATILE,
1877 len = sizeof(policy);
1878 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
1880 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1882 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
1884 retval = CSC_POLICY_DOCUMENTS;
1886 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
1888 retval = CSC_POLICY_PROGRAMS;
1890 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
1892 retval = CSC_POLICY_DISABLE;
1895 RegCloseKey(hkCSCPolicy);
1899 /* find a dir search structure by cookie value, and return it held.
1900 * Must be called with smb_globalLock held.
1902 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1904 smb_dirSearch_t *dsp;
1906 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1907 if (dsp->cookie == cookie) {
1908 if (dsp != smb_firstDirSearchp) {
1909 /* move to head of LRU queue, too, if we're not already there */
1910 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1911 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1912 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1913 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1914 if (!smb_lastDirSearchp)
1915 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1917 lock_ObtainMutex(&dsp->mx);
1919 lock_ReleaseMutex(&dsp->mx);
1925 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1926 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1927 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1933 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1935 lock_ObtainWrite(&smb_globalLock);
1936 lock_ObtainMutex(&dsp->mx);
1937 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1938 dsp->cookie, dsp, dsp->scp);
1939 dsp->flags |= SMB_DIRSEARCH_DELETE;
1940 if (dsp->scp != NULL) {
1941 lock_ObtainWrite(&dsp->scp->rw);
1942 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1943 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1944 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1945 dsp->scp->bulkStatProgress = hzero;
1947 lock_ReleaseWrite(&dsp->scp->rw);
1949 lock_ReleaseMutex(&dsp->mx);
1950 lock_ReleaseWrite(&smb_globalLock);
1953 /* Must be called with the smb_globalLock held */
1954 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1956 cm_scache_t *scp = NULL;
1958 lock_ObtainMutex(&dsp->mx);
1959 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1960 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1961 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1962 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1963 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1964 lock_ReleaseMutex(&dsp->mx);
1965 lock_FinalizeMutex(&dsp->mx);
1967 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1968 dsp->cookie, dsp, scp);
1971 lock_ReleaseMutex(&dsp->mx);
1973 /* do this now to avoid spurious locking hierarchy creation */
1975 cm_ReleaseSCache(scp);
1978 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1980 lock_ObtainWrite(&smb_globalLock);
1981 smb_ReleaseDirSearchNoLock(dsp);
1982 lock_ReleaseWrite(&smb_globalLock);
1985 /* find a dir search structure by cookie value, and return it held */
1986 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1988 smb_dirSearch_t *dsp;
1990 lock_ObtainWrite(&smb_globalLock);
1991 dsp = smb_FindDirSearchNoLock(cookie);
1992 lock_ReleaseWrite(&smb_globalLock);
1996 /* GC some dir search entries, in the address space expected by the specific protocol.
1997 * Must be called with smb_globalLock held; release the lock temporarily.
1999 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2000 void smb_GCDirSearches(int isV3)
2002 smb_dirSearch_t *prevp;
2003 smb_dirSearch_t *tp;
2004 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2008 victimCount = 0; /* how many have we got so far */
2009 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
2010 /* we'll move tp from queue, so
2013 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
2014 /* if no one is using this guy, and we're either in the new protocol,
2015 * or we're in the old one and this is a small enough ID to be useful
2016 * to the old protocol, GC this guy.
2018 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2019 /* hold and delete */
2020 lock_ObtainMutex(&tp->mx);
2021 tp->flags |= SMB_DIRSEARCH_DELETE;
2022 lock_ReleaseMutex(&tp->mx);
2023 victimsp[victimCount++] = tp;
2027 /* don't do more than this */
2028 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2032 /* now release them */
2033 for (i = 0; i < victimCount; i++) {
2034 smb_ReleaseDirSearchNoLock(victimsp[i]);
2038 /* function for allocating a dir search entry. We need these to remember enough context
2039 * since we don't get passed the path from call to call during a directory search.
2041 * Returns a held dir search structure, and bumps the reference count on the vnode,
2042 * since it saves a pointer to the vnode.
2044 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2046 smb_dirSearch_t *dsp;
2052 lock_ObtainWrite(&smb_globalLock);
2055 /* what's the biggest ID allowed in this version of the protocol */
2056 /* TODO: do we really want a non v3 dir search request to wrap
2057 smb_dirSearchCounter? */
2058 maxAllowed = isV3 ? 65535 : 255;
2059 if (smb_dirSearchCounter > maxAllowed)
2060 smb_dirSearchCounter = 1;
2062 start = smb_dirSearchCounter;
2065 /* twice so we have enough tries to find guys we GC after one pass;
2066 * 10 extra is just in case I mis-counted.
2068 if (++counter > 2*maxAllowed+10)
2069 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2071 if (smb_dirSearchCounter > maxAllowed) {
2072 smb_dirSearchCounter = 1;
2074 if (smb_dirSearchCounter == start) {
2076 smb_GCDirSearches(isV3);
2079 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2081 /* don't need to watch for refcount zero and deleted, since
2082 * we haven't dropped the global lock.
2084 lock_ObtainMutex(&dsp->mx);
2086 lock_ReleaseMutex(&dsp->mx);
2087 ++smb_dirSearchCounter;
2091 dsp = malloc(sizeof(*dsp));
2092 memset(dsp, 0, sizeof(*dsp));
2093 dsp->cookie = smb_dirSearchCounter;
2094 ++smb_dirSearchCounter;
2096 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2097 dsp->lastTime = osi_Time();
2098 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2099 if (!smb_lastDirSearchp)
2100 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2102 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2106 lock_ReleaseWrite(&smb_globalLock);
2110 static smb_packet_t *GetPacket(void)
2114 lock_ObtainWrite(&smb_globalLock);
2115 tbp = smb_packetFreeListp;
2117 smb_packetFreeListp = tbp->nextp;
2118 lock_ReleaseWrite(&smb_globalLock);
2120 tbp = calloc(sizeof(*tbp),1);
2121 tbp->magic = SMB_PACKETMAGIC;
2124 tbp->resumeCode = 0;
2130 tbp->ncb_length = 0;
2133 tbp->stringsp = NULL;
2135 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2140 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2144 memcpy(tbp, pkt, sizeof(smb_packet_t));
2145 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2146 tbp->stringsp = NULL;
2148 smb_HoldVC(tbp->vcp);
2152 static NCB *GetNCB(void)
2157 lock_ObtainWrite(&smb_globalLock);
2158 tbp = smb_ncbFreeListp;
2160 smb_ncbFreeListp = tbp->nextp;
2161 lock_ReleaseWrite(&smb_globalLock);
2163 tbp = calloc(sizeof(*tbp),1);
2164 tbp->magic = SMB_NCBMAGIC;
2167 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2169 memset(&tbp->ncb, 0, sizeof(NCB));
2174 static void FreeSMBStrings(smb_packet_t * pkt)
2179 for (s = pkt->stringsp; s; s = ns) {
2183 pkt->stringsp = NULL;
2186 void smb_FreePacket(smb_packet_t *tbp)
2188 smb_vc_t * vcp = NULL;
2189 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2191 lock_ObtainWrite(&smb_globalLock);
2192 tbp->nextp = smb_packetFreeListp;
2193 smb_packetFreeListp = tbp;
2194 tbp->magic = SMB_PACKETMAGIC;
2198 tbp->resumeCode = 0;
2204 tbp->ncb_length = 0;
2206 FreeSMBStrings(tbp);
2207 lock_ReleaseWrite(&smb_globalLock);
2213 static void FreeNCB(NCB *bufferp)
2217 tbp = (smb_ncb_t *) bufferp;
2218 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2220 lock_ObtainWrite(&smb_globalLock);
2221 tbp->nextp = smb_ncbFreeListp;
2222 smb_ncbFreeListp = tbp;
2223 lock_ReleaseWrite(&smb_globalLock);
2226 /* get a ptr to the data part of a packet, and its count */
2227 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2231 unsigned char *afterParmsp;
2233 parmBytes = *smbp->wctp << 1;
2234 afterParmsp = smbp->wctp + parmBytes + 1;
2236 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2237 if (nbytesp) *nbytesp = dataBytes;
2239 /* don't forget to skip the data byte count, since it follows
2240 * the parameters; that's where the "2" comes from below.
2242 return (unsigned char *) (afterParmsp + 2);
2245 /* must set all the returned parameters before playing around with the
2246 * data region, since the data region is located past the end of the
2247 * variable number of parameters.
2249 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2251 unsigned char *afterParmsp;
2253 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2255 *afterParmsp++ = dsize & 0xff;
2256 *afterParmsp = (dsize>>8) & 0xff;
2259 /* return the parm'th parameter in the smbp packet */
2260 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2263 unsigned char *parmDatap;
2265 parmCount = *smbp->wctp;
2267 if (parm >= parmCount) {
2270 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2271 parm, parmCount, smbp->ncb_length);
2272 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2273 parm, parmCount, smbp->ncb_length);
2274 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2275 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2276 osi_panic(s, __FILE__, __LINE__);
2278 parmDatap = smbp->wctp + (2*parm) + 1;
2280 return parmDatap[0] + (parmDatap[1] << 8);
2283 /* return the parm'th parameter in the smbp packet */
2284 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2287 unsigned char *parmDatap;
2289 parmCount = *smbp->wctp;
2291 if (parm >= parmCount) {
2294 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2295 parm, parmCount, smbp->ncb_length);
2296 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2297 parm, parmCount, smbp->ncb_length);
2298 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2299 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2300 osi_panic(s, __FILE__, __LINE__);
2302 parmDatap = smbp->wctp + (2*parm) + 1;
2304 return parmDatap[0];
2307 /* return the parm'th parameter in the smbp packet */
2308 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2311 unsigned char *parmDatap;
2313 parmCount = *smbp->wctp;
2315 if (parm + 1 >= parmCount) {
2318 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2319 parm, parmCount, smbp->ncb_length);
2320 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2321 parm, parmCount, smbp->ncb_length);
2322 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2323 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2324 osi_panic(s, __FILE__, __LINE__);
2326 parmDatap = smbp->wctp + (2*parm) + 1;
2328 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2331 /* return the parm'th parameter in the smbp packet */
2332 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2335 unsigned char *parmDatap;
2337 parmCount = *smbp->wctp;
2339 if (parm * 2 + offset >= parmCount * 2) {
2342 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2343 parm, offset, parmCount, smbp->ncb_length);
2344 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2345 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2346 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2347 parm, offset, parmCount, smbp->ncb_length);
2348 osi_panic(s, __FILE__, __LINE__);
2350 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2352 return parmDatap[0] + (parmDatap[1] << 8);
2355 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2357 unsigned char *parmDatap;
2359 /* make sure we have enough slots */
2360 if (*smbp->wctp <= slot)
2361 *smbp->wctp = slot+1;
2363 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2364 *parmDatap++ = parmValue & 0xff;
2365 *parmDatap = (parmValue>>8) & 0xff;
2368 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2370 unsigned char *parmDatap;
2372 /* make sure we have enough slots */
2373 if (*smbp->wctp <= slot)
2374 *smbp->wctp = slot+2;
2376 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2377 *parmDatap++ = parmValue & 0xff;
2378 *parmDatap++ = (parmValue>>8) & 0xff;
2379 *parmDatap++ = (parmValue>>16) & 0xff;
2380 *parmDatap = (parmValue>>24) & 0xff;
2383 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2385 unsigned char *parmDatap;
2388 /* make sure we have enough slots */
2389 if (*smbp->wctp <= slot)
2390 *smbp->wctp = slot+4;
2392 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2394 *parmDatap++ = *parmValuep++;
2397 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2399 unsigned char *parmDatap;
2401 /* make sure we have enough slots */
2402 if (*smbp->wctp <= slot) {
2403 if (smbp->oddByte) {
2405 *smbp->wctp = slot+1;
2410 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2411 *parmDatap++ = parmValue & 0xff;
2416 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2417 clientchar_t *inPathp)
2419 clientchar_t *lastSlashp;
2421 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2423 *lastComponentp = lastSlashp;
2426 if (inPathp == lastSlashp)
2428 *outPathp++ = *inPathp++;
2437 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2438 char **chainpp, int flags)
2446 if (!WANTS_UNICODE(pktp))
2447 flags |= SMB_STRF_FORCEASCII;
2450 cb = sizeof(pktp->data) - (inp - pktp->data);
2451 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2452 #ifdef DEBUG_UNICODE
2455 cb = sizeof(pktp->data);
2457 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2460 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2461 char ** chainpp, int flags)
2466 if (!WANTS_UNICODE(pktp))
2467 flags |= SMB_STRF_FORCEASCII;
2470 cb = sizeof(pktp->data) - (inp - pktp->data);
2471 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2472 #ifdef DEBUG_UNICODE
2475 cb = sizeof(pktp->data);
2477 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2480 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2481 size_t cb, char ** chainpp, int flags)
2484 if (!WANTS_UNICODE(pktp))
2485 flags |= SMB_STRF_FORCEASCII;
2488 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2491 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2492 size_t cch, char ** chainpp, int flags)
2497 if (!WANTS_UNICODE(pktp))
2498 flags |= SMB_STRF_FORCEASCII;
2500 cb = cch * sizeof(wchar_t);
2503 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2507 smb_ParseStringBuf(const char * bufbase,
2508 cm_space_t ** stringspp,
2509 unsigned char *inp, size_t *pcb_max,
2510 char **chainpp, int flags)
2513 if (!(flags & SMB_STRF_FORCEASCII)) {
2515 cm_space_t * spacep;
2518 if (bufbase && ((inp - bufbase) % 2) != 0) {
2519 inp++; /* unicode strings are always word aligned */
2523 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2525 cch_src = *pcb_max / sizeof(wchar_t);
2529 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2536 spacep = cm_GetSpace();
2537 spacep->nextp = *stringspp;
2538 *stringspp = spacep;
2542 *chainpp = inp + sizeof(wchar_t);
2545 *(spacep->wdata) = 0;
2546 return spacep->wdata;
2549 StringCchCopyNW(spacep->wdata,
2550 lengthof(spacep->wdata),
2551 (const clientchar_t *) inp, cch_src);
2554 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2556 return spacep->wdata;
2560 cm_space_t * spacep;
2563 /* Not using Unicode */
2565 *chainpp = inp + strlen(inp) + 1;
2568 spacep = cm_GetSpace();
2569 spacep->nextp = *stringspp;
2570 *stringspp = spacep;
2572 cchdest = lengthof(spacep->wdata);
2573 cm_Utf8ToUtf16(inp, *pcb_max, spacep->wdata, cchdest);
2575 return spacep->wdata;
2581 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2583 size_t * plen, int flags)
2589 /* we are only calculating the required size */
2596 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2598 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2599 if (!(flags & SMB_STRF_IGNORENULL))
2600 *plen += sizeof(wchar_t);
2602 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2612 cch_str = cm_ClientStrLen(str);
2613 cch_dest = cm_ClientStringToUtf8(str, cch_str, NULL, 0);
2616 *plen = ((flags & SMB_STRF_IGNORENULL)? cch_dest: cch_dest+1);
2624 /* if outp != NULL ... */
2626 /* Number of bytes left in the buffer.
2628 If outp lies inside the packet data buffer, we assume that the
2629 buffer is the packet data buffer. Otherwise we assume that the
2630 buffer is sizeof(packet->data).
2633 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2634 align = ((outp - pktp->data) % 2);
2635 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2637 align = (((size_t) outp) % 2);
2638 buffersize = sizeof(pktp->data);
2643 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2649 if (*str == _C('\0')) {
2651 if (buffersize < sizeof(wchar_t))
2654 *((wchar_t *) outp) = L'\0';
2655 if (plen && !(flags & SMB_STRF_IGNORENULL))
2656 *plen += sizeof(wchar_t);
2657 return outp + sizeof(wchar_t);
2660 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, buffersize / sizeof(wchar_t));
2662 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2663 osi_LogSaveClientString(smb_logp, str),
2669 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1: nchars);
2671 return outp + sizeof(wchar_t) * nchars;
2679 cch_dest = cm_ClientStringToUtf8(str, -1, outp, buffersize);
2682 *plen += ((flags & SMB_STRF_IGNORENULL)? cch_dest - 1: cch_dest);
2684 return outp + cch_dest;
2688 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2694 tlen = inp[0] + (inp[1]<<8);
2695 inp += 2; /* skip length field */
2698 *chainpp = inp + tlen;
2707 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2711 if (*inp++ != 0x1) return NULL;
2712 tlen = inp[0] + (inp[1]<<8);
2713 inp += 2; /* skip length field */
2716 *chainpp = inp + tlen;
2719 if (lengthp) *lengthp = tlen;
2724 /* format a packet as a response */
2725 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2730 outp = (smb_t *) op;
2732 /* zero the basic structure through the smb_wct field, and zero the data
2733 * size field, assuming that wct stays zero; otherwise, you have to
2734 * explicitly set the data size field, too.
2736 inSmbp = (smb_t *) inp;
2737 memset(outp, 0, sizeof(smb_t)+2);
2743 outp->com = inSmbp->com;
2744 outp->tid = inSmbp->tid;
2745 outp->pid = inSmbp->pid;
2746 outp->uid = inSmbp->uid;
2747 outp->mid = inSmbp->mid;
2748 outp->res[0] = inSmbp->res[0];
2749 outp->res[1] = inSmbp->res[1];
2750 op->inCom = inSmbp->com;
2752 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2753 #ifdef SEND_CANONICAL_PATHNAMES
2754 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2756 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2758 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2759 outp->flg2 |= SMB_FLAGS2_UNICODE;
2762 /* copy fields in generic packet area */
2763 op->wctp = &outp->wct;
2766 /* send a (probably response) packet; vcp tells us to whom to send it.
2767 * we compute the length by looking at wct and bcc fields.
2769 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2783 memset((char *)ncbp, 0, sizeof(NCB));
2785 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2786 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2787 extra += tp[0] + (tp[1]<<8);
2788 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2789 extra += 3; /* wct and length fields */
2791 ncbp->ncb_length = extra; /* bytes to send */
2792 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2793 ncbp->ncb_lana_num = vcp->lana;
2794 ncbp->ncb_command = NCBSEND; /* op means send data */
2795 ncbp->ncb_buffer = (char *) inp;/* packet */
2796 code = Netbios(ncbp);
2799 const char * s = ncb_error_string(code);
2800 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2801 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2803 lock_ObtainMutex(&vcp->mx);
2804 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2805 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2807 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2808 lock_ReleaseMutex(&vcp->mx);
2809 lock_ObtainWrite(&smb_globalLock);
2810 dead_sessions[vcp->session] = TRUE;
2811 lock_ReleaseWrite(&smb_globalLock);
2812 smb_CleanupDeadVC(vcp);
2814 lock_ReleaseMutex(&vcp->mx);
2822 void smb_MapNTError(long code, unsigned long *NTStatusp)
2824 unsigned long NTStatus;
2826 /* map CM_ERROR_* errors to NT 32-bit status codes */
2827 /* NT Status codes are listed in ntstatus.h not winerror.h */
2828 if (code == CM_ERROR_NOSUCHCELL) {
2829 NTStatus = 0xC000000FL; /* No such file */
2831 else if (code == CM_ERROR_NOSUCHVOLUME) {
2832 NTStatus = 0xC000000FL; /* No such file */
2834 else if (code == CM_ERROR_TIMEDOUT) {
2836 NTStatus = 0xC00000CFL; /* Sharing Paused */
2838 NTStatus = 0x00000102L; /* Timeout */
2841 else if (code == CM_ERROR_RETRY) {
2842 NTStatus = 0xC000022DL; /* Retry */
2844 else if (code == CM_ERROR_NOACCESS) {
2845 NTStatus = 0xC0000022L; /* Access denied */
2847 else if (code == CM_ERROR_READONLY) {
2848 NTStatus = 0xC00000A2L; /* Write protected */
2850 else if (code == CM_ERROR_NOSUCHFILE ||
2851 code == CM_ERROR_BPLUS_NOMATCH) {
2852 NTStatus = 0xC000000FL; /* No such file */
2854 else if (code == CM_ERROR_NOSUCHPATH) {
2855 NTStatus = 0xC000003AL; /* Object path not found */
2857 else if (code == CM_ERROR_TOOBIG) {
2858 NTStatus = 0xC000007BL; /* Invalid image format */
2860 else if (code == CM_ERROR_INVAL) {
2861 NTStatus = 0xC000000DL; /* Invalid parameter */
2863 else if (code == CM_ERROR_BADFD) {
2864 NTStatus = 0xC0000008L; /* Invalid handle */
2866 else if (code == CM_ERROR_BADFDOP) {
2867 NTStatus = 0xC0000022L; /* Access denied */
2869 else if (code == CM_ERROR_EXISTS) {
2870 NTStatus = 0xC0000035L; /* Object name collision */
2872 else if (code == CM_ERROR_NOTEMPTY) {
2873 NTStatus = 0xC0000101L; /* Directory not empty */
2875 else if (code == CM_ERROR_CROSSDEVLINK) {
2876 NTStatus = 0xC00000D4L; /* Not same device */
2878 else if (code == CM_ERROR_NOTDIR) {
2879 NTStatus = 0xC0000103L; /* Not a directory */
2881 else if (code == CM_ERROR_ISDIR) {
2882 NTStatus = 0xC00000BAL; /* File is a directory */
2884 else if (code == CM_ERROR_BADOP) {
2886 /* I have no idea where this comes from */
2887 NTStatus = 0xC09820FFL; /* SMB no support */
2889 NTStatus = 0xC00000BBL; /* Not supported */
2890 #endif /* COMMENT */
2892 else if (code == CM_ERROR_BADSHARENAME) {
2893 NTStatus = 0xC00000CCL; /* Bad network name */
2895 else if (code == CM_ERROR_NOIPC) {
2897 NTStatus = 0xC0000022L; /* Access Denied */
2899 NTStatus = 0xC000013DL; /* Remote Resources */
2902 else if (code == CM_ERROR_CLOCKSKEW) {
2903 NTStatus = 0xC0000133L; /* Time difference at DC */
2905 else if (code == CM_ERROR_BADTID) {
2906 NTStatus = 0xC0982005L; /* SMB bad TID */
2908 else if (code == CM_ERROR_USESTD) {
2909 NTStatus = 0xC09820FBL; /* SMB use standard */
2911 else if (code == CM_ERROR_QUOTA) {
2912 NTStatus = 0xC0000044L; /* Quota exceeded */
2914 else if (code == CM_ERROR_SPACE) {
2915 NTStatus = 0xC000007FL; /* Disk full */
2917 else if (code == CM_ERROR_ATSYS) {
2918 NTStatus = 0xC0000033L; /* Object name invalid */
2920 else if (code == CM_ERROR_BADNTFILENAME) {
2921 NTStatus = 0xC0000033L; /* Object name invalid */
2923 else if (code == CM_ERROR_WOULDBLOCK) {
2924 NTStatus = 0xC0000055L; /* Lock not granted */
2926 else if (code == CM_ERROR_SHARING_VIOLATION) {
2927 NTStatus = 0xC0000043L; /* Sharing violation */
2929 else if (code == CM_ERROR_LOCK_CONFLICT) {
2930 NTStatus = 0xC0000054L; /* Lock conflict */
2932 else if (code == CM_ERROR_PARTIALWRITE) {
2933 NTStatus = 0xC000007FL; /* Disk full */
2935 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2936 NTStatus = 0xC0000023L; /* Buffer too small */
2938 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2939 NTStatus = 0xC0000035L; /* Object name collision */
2941 else if (code == CM_ERROR_BADPASSWORD) {
2942 NTStatus = 0xC000006DL; /* unknown username or bad password */
2944 else if (code == CM_ERROR_BADLOGONTYPE) {
2945 NTStatus = 0xC000015BL; /* logon type not granted */
2947 else if (code == CM_ERROR_GSSCONTINUE) {
2948 NTStatus = 0xC0000016L; /* more processing required */
2950 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2952 NTStatus = 0xC0000280L; /* reparse point not resolved */
2954 NTStatus = 0xC0000022L; /* Access Denied */
2957 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2958 NTStatus = 0xC0000257L; /* Path Not Covered */
2960 else if (code == CM_ERROR_ALLBUSY) {
2961 NTStatus = 0xC000022DL; /* Retry */
2963 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2964 NTStatus = 0xC00000BEL; /* Bad Network Path */
2966 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
2967 NTStatus = 0xC0000322L; /* No Kerberos key */
2969 else if (code == CM_ERROR_BAD_LEVEL) {
2970 NTStatus = 0xC0000148L; /* Invalid Level */
2972 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
2973 NTStatus = 0xC000007EL; /* Range Not Locked */
2975 else if (code == CM_ERROR_NOSUCHDEVICE) {
2976 NTStatus = 0xC000000EL; /* No Such Device */
2978 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
2979 NTStatus = 0xC0000055L; /* Lock Not Granted */
2981 NTStatus = 0xC0982001L; /* SMB non-specific error */
2984 *NTStatusp = NTStatus;
2985 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2988 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2989 unsigned char *classp)
2991 unsigned char class;
2992 unsigned short error;
2994 /* map CM_ERROR_* errors to SMB errors */
2995 if (code == CM_ERROR_NOSUCHCELL) {
2997 error = 3; /* bad path */
2999 else if (code == CM_ERROR_NOSUCHVOLUME) {
3001 error = 3; /* bad path */
3003 else if (code == CM_ERROR_TIMEDOUT) {
3005 error = 81; /* server is paused */
3007 else if (code == CM_ERROR_RETRY) {
3008 class = 2; /* shouldn't happen */
3011 else if (code == CM_ERROR_NOACCESS) {
3013 error = 4; /* bad access */
3015 else if (code == CM_ERROR_READONLY) {
3017 error = 19; /* read only */
3019 else if (code == CM_ERROR_NOSUCHFILE ||
3020 code == CM_ERROR_BPLUS_NOMATCH) {
3022 error = 2; /* ENOENT! */
3024 else if (code == CM_ERROR_NOSUCHPATH) {
3026 error = 3; /* Bad path */
3028 else if (code == CM_ERROR_TOOBIG) {
3030 error = 11; /* bad format */
3032 else if (code == CM_ERROR_INVAL) {
3033 class = 2; /* server non-specific error code */
3036 else if (code == CM_ERROR_BADFD) {
3038 error = 6; /* invalid file handle */
3040 else if (code == CM_ERROR_BADFDOP) {
3041 class = 1; /* invalid op on FD */
3044 else if (code == CM_ERROR_EXISTS) {
3046 error = 80; /* file already exists */
3048 else if (code == CM_ERROR_NOTEMPTY) {
3050 error = 5; /* delete directory not empty */
3052 else if (code == CM_ERROR_CROSSDEVLINK) {
3054 error = 17; /* EXDEV */
3056 else if (code == CM_ERROR_NOTDIR) {
3057 class = 1; /* bad path */
3060 else if (code == CM_ERROR_ISDIR) {
3061 class = 1; /* access denied; DOS doesn't have a good match */
3064 else if (code == CM_ERROR_BADOP) {
3068 else if (code == CM_ERROR_BADSHARENAME) {
3072 else if (code == CM_ERROR_NOIPC) {
3074 error = 4; /* bad access */
3076 else if (code == CM_ERROR_CLOCKSKEW) {
3077 class = 1; /* invalid function */
3080 else if (code == CM_ERROR_BADTID) {
3084 else if (code == CM_ERROR_USESTD) {
3088 else if (code == CM_ERROR_REMOTECONN) {
3092 else if (code == CM_ERROR_QUOTA) {
3093 if (vcp->flags & SMB_VCFLAG_USEV3) {
3095 error = 39; /* disk full */
3099 error = 5; /* access denied */
3102 else if (code == CM_ERROR_SPACE) {
3103 if (vcp->flags & SMB_VCFLAG_USEV3) {
3105 error = 39; /* disk full */
3109 error = 5; /* access denied */
3112 else if (code == CM_ERROR_PARTIALWRITE) {
3114 error = 39; /* disk full */
3116 else if (code == CM_ERROR_ATSYS) {
3118 error = 2; /* ENOENT */
3120 else if (code == CM_ERROR_WOULDBLOCK) {
3122 error = 33; /* lock conflict */
3124 else if (code == CM_ERROR_LOCK_CONFLICT) {
3126 error = 33; /* lock conflict */
3128 else if (code == CM_ERROR_SHARING_VIOLATION) {
3130 error = 33; /* lock conflict */
3132 else if (code == CM_ERROR_NOFILES) {
3134 error = 18; /* no files in search */
3136 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3138 error = 183; /* Samba uses this */
3140 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3141 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3143 error = 2; /* bad password */
3145 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3147 error = 3; /* bad path */
3156 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3159 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3161 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3162 return CM_ERROR_BADOP;
3166 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3168 unsigned short EchoCount, i;
3169 char *data, *outdata;
3172 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3174 for (i=1; i<=EchoCount; i++) {
3175 data = smb_GetSMBData(inp, &dataSize);
3176 smb_SetSMBParm(outp, 0, i);
3177 smb_SetSMBDataLength(outp, dataSize);
3178 outdata = smb_GetSMBData(outp, NULL);
3179 memcpy(outdata, data, dataSize);
3180 smb_SendPacket(vcp, outp);
3186 /* SMB_COM_READ_RAW */
3187 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3190 long count, minCount, finalCount;
3194 smb_t *smbp = (smb_t*) inp;
3196 cm_user_t *userp = NULL;
3199 char *rawBuf = NULL;
3204 fd = smb_GetSMBParm(inp, 0);
3205 count = smb_GetSMBParm(inp, 3);
3206 minCount = smb_GetSMBParm(inp, 4);
3207 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3209 if (*inp->wctp == 10) {
3210 /* we were sent a request with 64-bit file offsets */
3211 #ifdef AFS_LARGEFILES
3212 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3214 if (LargeIntegerLessThanZero(offset)) {
3215 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3219 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3220 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3223 offset.HighPart = 0;
3227 /* we were sent a request with 32-bit file offsets */
3228 offset.HighPart = 0;
3231 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3232 fd, offset.HighPart, offset.LowPart, count);
3234 fidp = smb_FindFID(vcp, fd, 0);
3238 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3239 smb_CloseFID(vcp, fidp, NULL, 0);
3240 code = CM_ERROR_NOSUCHFILE;
3247 LARGE_INTEGER LOffset, LLength;
3250 key = cm_GenerateKey(vcp->vcID, pid, fd);
3252 LOffset.HighPart = offset.HighPart;
3253 LOffset.LowPart = offset.LowPart;
3254 LLength.HighPart = 0;
3255 LLength.LowPart = count;
3257 lock_ObtainWrite(&fidp->scp->rw);
3258 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3259 lock_ReleaseWrite(&fidp->scp->rw);
3265 lock_ObtainMutex(&smb_RawBufLock);
3267 /* Get a raw buf, from head of list */
3268 rawBuf = smb_RawBufs;
3269 smb_RawBufs = *(char **)smb_RawBufs;
3271 lock_ReleaseMutex(&smb_RawBufLock);
3275 lock_ObtainMutex(&fidp->mx);
3276 if (fidp->flags & SMB_FID_IOCTL)
3278 lock_ReleaseMutex(&fidp->mx);
3279 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3281 /* Give back raw buffer */
3282 lock_ObtainMutex(&smb_RawBufLock);
3283 *((char **) rawBuf) = smb_RawBufs;
3285 smb_RawBufs = rawBuf;
3286 lock_ReleaseMutex(&smb_RawBufLock);
3289 lock_ReleaseMutex(&fidp->mx);
3290 smb_ReleaseFID(fidp);
3293 lock_ReleaseMutex(&fidp->mx);
3295 userp = smb_GetUserFromVCP(vcp, inp);
3297 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3303 cm_ReleaseUser(userp);
3306 smb_ReleaseFID(fidp);
3310 memset((char *)ncbp, 0, sizeof(NCB));
3312 ncbp->ncb_length = (unsigned short) finalCount;
3313 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3314 ncbp->ncb_lana_num = vcp->lana;
3315 ncbp->ncb_command = NCBSEND;
3316 ncbp->ncb_buffer = rawBuf;
3318 code = Netbios(ncbp);
3320 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3323 /* Give back raw buffer */
3324 lock_ObtainMutex(&smb_RawBufLock);
3325 *((char **) rawBuf) = smb_RawBufs;
3327 smb_RawBufs = rawBuf;
3328 lock_ReleaseMutex(&smb_RawBufLock);
3334 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3336 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3341 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3343 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3348 /* SMB_COM_NEGOTIATE */
3349 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3356 int VistaProtoIndex;
3357 int protoIndex; /* index we're using */
3362 char protocol_array[10][1024]; /* protocol signature of the client */
3363 int caps; /* capabilities */
3366 TIME_ZONE_INFORMATION tzi;
3368 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3371 namep = smb_GetSMBData(inp, &dbytes);
3374 coreProtoIndex = -1; /* not found */
3377 VistaProtoIndex = -1;
3378 while(namex < dbytes) {
3379 osi_Log1(smb_logp, "Protocol %s",
3380 osi_LogSaveString(smb_logp, namep+1));
3381 strcpy(protocol_array[tcounter], namep+1);
3383 /* namep points at the first protocol, or really, a 0x02
3384 * byte preceding the null-terminated ASCII name.
3386 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3387 coreProtoIndex = tcounter;
3389 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3390 v3ProtoIndex = tcounter;
3392 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3393 NTProtoIndex = tcounter;
3395 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3396 VistaProtoIndex = tcounter;
3399 /* compute size of protocol entry */
3400 entryLength = (int)strlen(namep+1);
3401 entryLength += 2; /* 0x02 bytes and null termination */
3403 /* advance over this protocol entry */
3404 namex += entryLength;
3405 namep += entryLength;
3406 tcounter++; /* which proto entry we're looking at */
3409 lock_ObtainMutex(&vcp->mx);
3411 if (VistaProtoIndex != -1) {
3412 protoIndex = VistaProtoIndex;
3413 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3416 if (NTProtoIndex != -1) {
3417 protoIndex = NTProtoIndex;
3418 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3420 else if (v3ProtoIndex != -1) {
3421 protoIndex = v3ProtoIndex;
3422 vcp->flags |= SMB_VCFLAG_USEV3;
3424 else if (coreProtoIndex != -1) {
3425 protoIndex = coreProtoIndex;
3426 vcp->flags |= SMB_VCFLAG_USECORE;
3428 else protoIndex = -1;
3429 lock_ReleaseMutex(&vcp->mx);
3431 if (protoIndex == -1)
3432 return CM_ERROR_INVAL;
3433 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3434 smb_SetSMBParm(outp, 0, protoIndex);
3435 if (smb_authType != SMB_AUTH_NONE) {
3436 smb_SetSMBParmByte(outp, 1,
3437 NEGOTIATE_SECURITY_USER_LEVEL |
3438 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3440 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3442 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3443 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3444 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3445 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3446 /* The session key is not a well documented field however most clients
3447 * will echo back the session key to the server. Currently we are using
3448 * the same value for all sessions. We should generate a random value
3449 * and store it into the vcp
3451 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3452 smb_SetSMBParm(outp, 8, 1);
3454 * Tried changing the capabilities to support for W2K - defect 117695
3455 * Maybe something else needs to be changed here?
3459 smb_SetSMBParmLong(outp, 9, 0x43fd);
3461 smb_SetSMBParmLong(outp, 9, 0x251);
3464 * 32-bit error codes *
3470 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3472 NTNEGOTIATE_CAPABILITY_DFS |
3474 #ifdef AFS_LARGEFILES
3475 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3477 NTNEGOTIATE_CAPABILITY_NTFIND |
3478 NTNEGOTIATE_CAPABILITY_RAWMODE |
3479 NTNEGOTIATE_CAPABILITY_NTSMB;
3481 if ( smb_authType == SMB_AUTH_EXTENDED )
3482 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3485 if ( smb_UseUnicode ) {
3486 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3490 smb_SetSMBParmLong(outp, 9, caps);
3492 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3493 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3494 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3496 GetTimeZoneInformation(&tzi);
3497 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3499 if (smb_authType == SMB_AUTH_NTLM) {
3500 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3501 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3502 /* paste in encryption key */
3503 datap = smb_GetSMBData(outp, NULL);
3504 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3505 /* and the faux domain name */
3506 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3507 datap + MSV1_0_CHALLENGE_LENGTH,
3508 sizeof(outp->data)/sizeof(char) - (datap - outp->data));
3509 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3513 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3515 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3517 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3519 datap = smb_GetSMBData(outp, NULL);
3520 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3523 datap += sizeof(smb_ServerGUID);
3524 memcpy(datap, secBlob, secBlobLength);
3528 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3529 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3532 else if (v3ProtoIndex != -1) {
3533 smb_SetSMBParm(outp, 0, protoIndex);
3535 /* NOTE: Extended authentication cannot be negotiated with v3
3536 * therefore we fail over to NTLM
3538 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3539 smb_SetSMBParm(outp, 1,
3540 NEGOTIATE_SECURITY_USER_LEVEL |
3541 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3543 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3545 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3546 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3547 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3548 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3549 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3550 smb_SetSMBParm(outp, 7, 1);
3552 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3553 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3554 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3556 GetTimeZoneInformation(&tzi);
3557 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3559 /* NOTE: Extended authentication cannot be negotiated with v3
3560 * therefore we fail over to NTLM
3562 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3563 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3564 smb_SetSMBParm(outp, 12, 0); /* resvd */
3565 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3566 datap = smb_GetSMBData(outp, NULL);
3567 /* paste in a new encryption key */
3568 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3569 /* and the faux domain name */
3570 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3571 datap + MSV1_0_CHALLENGE_LENGTH,
3572 sizeof(outp->data)/sizeof(char) - (datap - outp->data));
3574 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3575 smb_SetSMBParm(outp, 12, 0); /* resvd */
3576 smb_SetSMBDataLength(outp, 0);
3579 else if (coreProtoIndex != -1) { /* not really supported anymore */
3580 smb_SetSMBParm(outp, 0, protoIndex);
3581 smb_SetSMBDataLength(outp, 0);
3586 void smb_CheckVCs(void)
3588 smb_vc_t * vcp, *nextp;
3589 smb_packet_t * outp = GetPacket();
3592 lock_ObtainWrite(&smb_rctLock);
3593 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3595 if (vcp->magic != SMB_VC_MAGIC)
3596 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3597 __FILE__, __LINE__);
3601 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3604 smb_HoldVCNoLock(vcp);
3606 smb_HoldVCNoLock(nextp);
3607 smb_FormatResponsePacket(vcp, NULL, outp);
3608 smbp = (smb_t *)outp;
3609 outp->inCom = smbp->com = 0x2b /* Echo */;
3617 smb_SetSMBParm(outp, 0, 0);
3618 smb_SetSMBDataLength(outp, 0);
3619 lock_ReleaseWrite(&smb_rctLock);
3621 smb_SendPacket(vcp, outp);
3623 lock_ObtainWrite(&smb_rctLock);
3624 smb_ReleaseVCNoLock(vcp);
3626 smb_ReleaseVCNoLock(nextp);
3628 lock_ReleaseWrite(&smb_rctLock);
3629 smb_FreePacket(outp);
3632 void smb_Daemon(void *parmp)
3634 afs_uint32 count = 0;
3635 smb_username_t **unpp;
3638 while(smbShutdownFlag == 0) {
3642 if (smbShutdownFlag == 1)
3645 if ((count % 72) == 0) { /* every five minutes */
3647 time_t old_localZero = smb_localZero;
3649 /* Initialize smb_localZero */
3650 myTime.tm_isdst = -1; /* compute whether on DST or not */
3651 myTime.tm_year = 70;
3657 smb_localZero = mktime(&myTime);
3659 #ifndef USE_NUMERIC_TIME_CONV
3660 smb_CalculateNowTZ();
3661 #endif /* USE_NUMERIC_TIME_CONV */
3662 #ifdef AFS_FREELANCE
3663 if ( smb_localZero != old_localZero )
3664 cm_noteLocalMountPointChange();
3670 /* GC smb_username_t objects that will no longer be used */
3672 lock_ObtainWrite(&smb_rctLock);
3673 for ( unpp=&usernamesp; *unpp; ) {
3675 smb_username_t *unp;
3677 lock_ObtainMutex(&(*unpp)->mx);
3678 if ( (*unpp)->refCount > 0 ||
3679 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3680 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3682 else if (!smb_LogoffTokenTransfer ||
3683 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3685 lock_ReleaseMutex(&(*unpp)->mx);
3693 lock_FinalizeMutex(&unp->mx);
3699 cm_ReleaseUser(userp);
3701 unpp = &(*unpp)->nextp;
3704 lock_ReleaseWrite(&smb_rctLock);
3706 /* XXX GC dir search entries */
3710 void smb_WaitingLocksDaemon()
3712 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3713 smb_waitingLock_t *wl, *wlNext;
3716 smb_packet_t *inp, *outp;
3720 while (smbShutdownFlag == 0) {
3721 lock_ObtainWrite(&smb_globalLock);
3722 nwlRequest = smb_allWaitingLocks;
3723 if (nwlRequest == NULL) {
3724 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3729 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3736 lock_ObtainWrite(&smb_globalLock);
3738 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3740 wlRequest = nwlRequest;
3741 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3742 lock_ReleaseWrite(&smb_globalLock);
3746 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3747 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3750 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3751 code = CM_ERROR_LOCK_NOT_GRANTED;
3755 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3757 /* wl->state is either _DONE or _WAITING. _ERROR
3758 would no longer be on the queue. */
3759 code = cm_RetryLock( wl->lockp,
3760 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3763 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3764 } else if (code != CM_ERROR_WOULDBLOCK) {
3765 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3770 if (code == CM_ERROR_WOULDBLOCK) {
3773 if (wlRequest->msTimeout != 0xffffffff
3774 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3786 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3789 scp = wlRequest->scp;
3790 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3794 lock_ObtainWrite(&scp->rw);
3796 for (wl = wlRequest->locks; wl; wl = wlNext) {
3797 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3799 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3800 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3801 wl->LLength, wl->key, NULL, &req);
3803 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3808 lock_ReleaseWrite(&scp->rw);
3812 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3815 for (wl = wlRequest->locks; wl; wl = wlNext) {
3816 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3817 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3822 vcp = wlRequest->vcp;
3823 inp = wlRequest->inp;
3824 outp = wlRequest->outp;
3826 ncbp->ncb_length = inp->ncb_length;
3827 inp->spacep = cm_GetSpace();
3829 /* Remove waitingLock from list */
3830 lock_ObtainWrite(&smb_globalLock);
3831 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3833 lock_ReleaseWrite(&smb_globalLock);
3835 /* Resume packet processing */
3837 smb_SetSMBDataLength(outp, 0);
3838 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3839 outp->resumeCode = code;
3841 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3844 cm_FreeSpace(inp->spacep);
3845 smb_FreePacket(inp);
3846 smb_FreePacket(outp);
3848 cm_ReleaseSCache(wlRequest->scp);
3851 } while (nwlRequest && smbShutdownFlag == 0);
3856 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3858 osi_Log0(smb_logp, "SMB receive get disk attributes");
3860 smb_SetSMBParm(outp, 0, 32000);
3861 smb_SetSMBParm(outp, 1, 64);
3862 smb_SetSMBParm(outp, 2, 1024);
3863 smb_SetSMBParm(outp, 3, 30000);
3864 smb_SetSMBParm(outp, 4, 0);
3865 smb_SetSMBDataLength(outp, 0);
3869 /* SMB_COM_TREE_CONNECT */
3870 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3874 unsigned short newTid;
3875 clientchar_t shareName[AFSPATHMAX];
3876 clientchar_t *sharePath;
3879 clientchar_t *pathp;
3882 osi_Log0(smb_logp, "SMB receive tree connect");
3884 /* parse input parameters */
3887 tbp = smb_GetSMBData(inp, NULL);
3888 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
3890 tp = cm_ClientStrRChr(pathp, '\\');
3892 return CM_ERROR_BADSMB;
3893 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
3895 lock_ObtainMutex(&vcp->mx);
3896 newTid = vcp->tidCounter++;
3897 lock_ReleaseMutex(&vcp->mx);
3899 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3900 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3901 userp = smb_GetUserFromUID(uidp);
3902 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3904 smb_ReleaseUID(uidp);
3906 smb_ReleaseTID(tidp, FALSE);
3907 return CM_ERROR_BADSHARENAME;
3909 lock_ObtainMutex(&tidp->mx);
3910 tidp->userp = userp;
3911 tidp->pathname = sharePath;
3912 lock_ReleaseMutex(&tidp->mx);
3913 smb_ReleaseTID(tidp, FALSE);
3915 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3916 smb_SetSMBParm(rsp, 1, newTid);
3917 smb_SetSMBDataLength(rsp, 0);
3919 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3923 /* set maskp to the mask part of the incoming path.
3924 * Mask is 11 bytes long (8.3 with the dot elided).
3925 * Returns true if succeeds with a valid name, otherwise it does
3926 * its best, but returns false.
3928 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
3936 /* starts off valid */
3939 /* mask starts out all blanks */
3940 memset(maskp, ' ', 11);
3943 /* find last backslash, or use whole thing if there is none */
3944 tp = cm_ClientStrRChr(pathp, '\\');
3948 tp++; /* skip slash */
3952 /* names starting with a dot are illegal */
3960 if (tc == '.' || tc == '"')
3968 /* if we get here, tp point after the dot */
3969 up = maskp+8; /* ext goes here */
3976 if (tc == '.' || tc == '"')
3979 /* copy extension if not too long */
3989 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
3991 clientchar_t umask[11];
3999 /* XXX redo this, calling cm_MatchMask with a converted mask */
4001 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4005 /* otherwise, we have a valid 8.3 name; see if we have a match,
4006 * treating '?' as a wildcard in maskp (but not in the file name).
4008 tp1 = umask; /* real name, in mask format */
4009 tp2 = maskp; /* mask, in mask format */
4010 for(i=0; i<11; i++) {
4011 tc1 = *tp1++; /* clientchar_t from real name */
4012 tc2 = *tp2++; /* clientchar_t from mask */
4013 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4014 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4017 if (tc2 == '?' && tc1 != ' ')
4024 /* we got a match */
4028 clientchar_t *smb_FindMask(clientchar_t *pathp)
4032 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4035 return tp+1; /* skip the slash */
4037 return pathp; /* no slash, return the entire path */
4040 /* SMB_COM_SEARCH for a volume label
4042 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4043 dispatch function.) */
4044 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4046 clientchar_t *pathp;
4048 clientchar_t mask[12];
4049 unsigned char *statBlockp;
4050 unsigned char initStatBlock[21];
4053 osi_Log0(smb_logp, "SMB receive search volume");
4055 /* pull pathname and stat block out of request */
4056 tp = smb_GetSMBData(inp, NULL);
4057 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4058 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4059 osi_assertx(pathp != NULL, "null path");
4060 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4061 osi_assertx(statBlockp != NULL, "null statBlock");
4063 statBlockp = initStatBlock;
4067 /* for returning to caller */
4068 smb_Get8Dot3MaskFromPath(mask, pathp);
4070 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4071 tp = smb_GetSMBData(outp, NULL);
4073 *tp++ = 43; /* bytes in a dir entry */
4074 *tp++ = 0; /* high byte in counter */
4076 /* now marshall the dir entry, starting with the search status */
4077 *tp++ = statBlockp[0]; /* Reserved */
4078 memcpy(tp, mask, 11); tp += 11; /* FileName */
4080 /* now pass back server use info, with 1st byte non-zero */
4082 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4084 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4086 *tp++ = 0x8; /* attribute: volume */
4096 /* 4 byte file size */
4102 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4105 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4106 memset(tp, ' ', 13);
4109 /* set the length of the data part of the packet to 43 + 3, for the dir
4110 * entry plus the 5 and the length fields.
4112 smb_SetSMBDataLength(outp, 46);
4117 smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
4118 clientchar_t * tidPathp, clientchar_t * relPathp,
4119 cm_user_t *userp, cm_req_t *reqp)
4127 smb_dirListPatch_t *patchp;
4128 smb_dirListPatch_t *npatchp;
4129 clientchar_t path[AFSPATHMAX];
4131 for (patchp = *dirPatchespp; patchp; patchp =
4132 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4134 dptr = patchp->dptr;
4136 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4137 relPathp ? relPathp : _C(""), patchp->dep->name);
4138 reqp->relPathp = path;
4139 reqp->tidPathp = tidPathp;
4141 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4142 reqp->relPathp = reqp->tidPathp = NULL;
4145 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4146 *dptr++ = SMB_ATTR_HIDDEN;
4149 lock_ObtainWrite(&scp->rw);
4150 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
4151 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4153 lock_ReleaseWrite(&scp->rw);
4154 cm_ReleaseSCache(scp);
4155 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4156 *dptr++ = SMB_ATTR_HIDDEN;
4160 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4162 lock_ConvertWToR(&scp->rw);
4163 attr = smb_Attributes(scp);
4164 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4165 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4166 attr |= SMB_ATTR_HIDDEN;
4170 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4173 shortTemp = (unsigned short) (dosTime & 0xffff);
4174 *((u_short *)dptr) = shortTemp;
4177 /* and copy out date */
4178 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4179 *((u_short *)dptr) = shortTemp;
4182 /* copy out file length */
4183 *((u_long *)dptr) = scp->length.LowPart;
4185 lock_ReleaseRead(&scp->rw);
4186 cm_ReleaseSCache(scp);
4189 /* now free the patches */
4190 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4191 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4195 /* and mark the list as empty */
4196 *dirPatchespp = NULL;
4201 /* SMB_COM_SEARCH */
4202 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4208 clientchar_t *pathp;
4209 cm_dirEntry_t *dep = 0;
4211 smb_dirListPatch_t *dirListPatchesp;
4212 smb_dirListPatch_t *curPatchp;
4216 osi_hyper_t dirLength;
4217 osi_hyper_t bufferOffset;
4218 osi_hyper_t curOffset;
4220 unsigned char *inCookiep;
4221 smb_dirSearch_t *dsp;
4225 unsigned long clientCookie;
4226 cm_pageHeader_t *pageHeaderp;
4227 cm_user_t *userp = NULL;
4229 clientchar_t mask[12];
4231 long nextEntryCookie;
4232 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4233 char resByte; /* reserved byte from the cookie */
4234 char *op; /* output data ptr */
4235 char *origOp; /* original value of op */
4236 cm_space_t *spacep; /* for pathname buffer */
4240 clientchar_t *tidPathp = 0;
4247 maxCount = smb_GetSMBParm(inp, 0);
4249 dirListPatchesp = NULL;
4251 caseFold = CM_FLAG_CASEFOLD;
4253 tp = smb_GetSMBData(inp, NULL);
4254 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4255 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4256 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4258 /* bail out if request looks bad */
4259 if (!tp || !pathp) {
4260 return CM_ERROR_BADSMB;
4263 /* We can handle long names */
4264 if (vcp->flags & SMB_VCFLAG_USENT)
4265 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4267 /* make sure we got a whole search status */
4268 if (dataLength < 21) {
4269 nextCookie = 0; /* start at the beginning of the dir */
4272 attribute = smb_GetSMBParm(inp, 1);
4274 /* handle volume info in another function */
4275 if (attribute & 0x8)
4276 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4278 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4279 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4281 if (*pathp == 0) { /* null pathp, treat as root dir */
4282 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4283 return CM_ERROR_NOFILES;
4287 dsp = smb_NewDirSearch(0);
4288 dsp->attribute = attribute;
4289 smb_Get8Dot3MaskFromPath(mask, pathp);
4290 memcpy(dsp->mask, mask, 12);
4292 /* track if this is likely to match a lot of entries */
4293 if (smb_IsStarMask(mask))
4298 /* pull the next cookie value out of the search status block */
4299 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4300 + (inCookiep[16]<<24);
4301 dsp = smb_FindDirSearch(inCookiep[12]);
4303 /* can't find dir search status; fatal error */
4304 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4305 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4306 return CM_ERROR_BADFD;
4308 attribute = dsp->attribute;
4309 resByte = inCookiep[0];
4311 /* copy out client cookie, in host byte order. Don't bother
4312 * interpreting it, since we're just passing it through, anyway.
4314 memcpy(&clientCookie, &inCookiep[17], 4);
4316 memcpy(mask, dsp->mask, 12);
4318 /* assume we're doing a star match if it has continued for more
4324 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4325 nextCookie, dsp->cookie, attribute);
4327 userp = smb_GetUserFromVCP(vcp, inp);
4329 /* try to get the vnode for the path name next */
4330 lock_ObtainMutex(&dsp->mx);
4333 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4337 spacep = inp->spacep;
4338 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4339 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4341 lock_ReleaseMutex(&dsp->mx);
4342 cm_ReleaseUser(userp);
4343 smb_DeleteDirSearch(dsp);
4344 smb_ReleaseDirSearch(dsp);
4345 return CM_ERROR_NOFILES;
4347 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4348 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4350 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4351 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4354 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4357 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4358 cm_ReleaseSCache(scp);
4359 lock_ReleaseMutex(&dsp->mx);
4360 cm_ReleaseUser(userp);
4361 smb_DeleteDirSearch(dsp);
4362 smb_ReleaseDirSearch(dsp);
4363 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4364 return CM_ERROR_PATH_NOT_COVERED;
4366 return CM_ERROR_BADSHARENAME;
4368 #endif /* DFS_SUPPORT */
4371 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4372 /* we need one hold for the entry we just stored into,
4373 * and one for our own processing. When we're done with this
4374 * function, we'll drop the one for our own processing.
4375 * We held it once from the namei call, and so we do another hold
4379 lock_ObtainWrite(&scp->rw);
4380 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4381 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4382 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4383 dsp->flags |= SMB_DIRSEARCH_BULKST;
4384 dsp->scp->bulkStatProgress = hzero;
4386 lock_ReleaseWrite(&scp->rw);
4389 lock_ReleaseMutex(&dsp->mx);
4391 cm_ReleaseUser(userp);
4392 smb_DeleteDirSearch(dsp);
4393 smb_ReleaseDirSearch(dsp);
4397 /* reserves space for parameter; we'll adjust it again later to the
4398 * real count of the # of entries we returned once we've actually
4399 * assembled the directory listing.
4401 smb_SetSMBParm(outp, 0, 0);
4403 /* get the directory size */
4404 lock_ObtainWrite(&scp->rw);
4405 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4406 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4408 lock_ReleaseWrite(&scp->rw);
4409 cm_ReleaseSCache(scp);
4410 cm_ReleaseUser(userp);
4411 smb_DeleteDirSearch(dsp);
4412 smb_ReleaseDirSearch(dsp);
4416 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4418 dirLength = scp->length;
4420 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4421 curOffset.HighPart = 0;
4422 curOffset.LowPart = nextCookie;
4423 origOp = op = smb_GetSMBData(outp, NULL);
4424 /* and write out the basic header */
4425 *op++ = 5; /* variable block */
4426 op += 2; /* skip vbl block length; we'll fill it in later */
4430 clientchar_t *actualName;
4431 clientchar_t shortName[13];
4432 clientchar_t *shortNameEnd;
4434 /* make sure that curOffset.LowPart doesn't point to the first
4435 * 32 bytes in the 2nd through last dir page, and that it doesn't
4436 * point at the first 13 32-byte chunks in the first dir page,
4437 * since those are dir and page headers, and don't contain useful
4440 temp = curOffset.LowPart & (2048-1);
4441 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4442 /* we're in the first page */
4443 if (temp < 13*32) temp = 13*32;
4446 /* we're in a later dir page */
4447 if (temp < 32) temp = 32;
4450 /* make sure the low order 5 bits are zero */
4453 /* now put temp bits back ito curOffset.LowPart */
4454 curOffset.LowPart &= ~(2048-1);
4455 curOffset.LowPart |= temp;
4457 /* check if we've returned all the names that will fit in the
4460 if (returnedNames >= maxCount) {
4461 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4462 returnedNames, maxCount);
4466 /* check if we've passed the dir's EOF */
4467 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4469 /* see if we can use the bufferp we have now; compute in which page
4470 * the current offset would be, and check whether that's the offset
4471 * of the buffer we have. If not, get the buffer.
4473 thyper.HighPart = curOffset.HighPart;
4474 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4475 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4478 buf_Release(bufferp);
4481 lock_ReleaseWrite(&scp->rw);
4482 code = buf_Get(scp, &thyper, &bufferp);
4483 lock_ObtainMutex(&dsp->mx);
4485 /* now, if we're doing a star match, do bulk fetching of all of
4486 * the status info for files in the dir.
4489 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4490 lock_ObtainWrite(&scp->rw);
4491 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4492 LargeIntegerGreaterThanOrEqualTo(thyper,
4493 scp->bulkStatProgress)) {
4494 /* Don't bulk stat if risking timeout */
4495 int now = GetTickCount();
4496 if (now - req.startTime > RDRtimeout * 1000) {
4497 scp->bulkStatProgress = thyper;
4498 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4499 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4500 dsp->scp->bulkStatProgress = hzero;
4502 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4505 lock_ObtainWrite(&scp->rw);
4507 lock_ReleaseMutex(&dsp->mx);
4509 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4513 bufferOffset = thyper;
4515 /* now get the data in the cache */
4517 code = cm_SyncOp(scp, bufferp, userp, &req,
4519 CM_SCACHESYNC_NEEDCALLBACK |
4520 CM_SCACHESYNC_READ);
4522 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4526 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4528 if (cm_HaveBuffer(scp, bufferp, 0)) {
4529 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4533 /* otherwise, load the buffer and try again */
4534 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4536 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4537 scp, bufferp, code);
4542 buf_Release(bufferp);
4546 } /* if (wrong buffer) ... */
4548 /* now we have the buffer containing the entry we're interested in; copy
4549 * it out if it represents a non-deleted entry.
4551 entryInDir = curOffset.LowPart & (2048-1);
4552 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4554 /* page header will help tell us which entries are free. Page header
4555 * can change more often than once per buffer, since AFS 3 dir page size
4556 * may be less than (but not more than a buffer package buffer.
4558 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4559 temp &= ~(2048 - 1); /* turn off intra-page bits */
4560 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4562 /* now determine which entry we're looking at in the page. If it is
4563 * free (there's a free bitmap at the start of the dir), we should
4564 * skip these 32 bytes.
4566 slotInPage = (entryInDir & 0x7e0) >> 5;
4567 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4568 /* this entry is free */
4569 numDirChunks = 1; /* only skip this guy */
4573 tp = bufferp->datap + entryInBuffer;
4574 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4576 /* while we're here, compute the next entry's location, too,
4577 * since we'll need it when writing out the cookie into the dir
4580 * XXXX Probably should do more sanity checking.
4582 numDirChunks = cm_NameEntries(dep->name, NULL);
4584 /* compute the offset of the cookie representing the next entry */
4585 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4587 /* Compute 8.3 name if necessary */
4588 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4589 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4591 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4592 actualName = shortName;
4595 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
4596 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4597 osi_LogSaveClientString(smb_logp, actualName));
4599 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4600 /* this is one of the entries to use: it is not deleted
4601 * and it matches the star pattern we're looking for.
4604 /* Eliminate entries that don't match requested
4607 /* no hidden files */
4608 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4609 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4613 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4615 /* We have already done the cm_TryBulkStat above */
4616 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4617 fileType = cm_FindFileType(&fid);
4618 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4619 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4621 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4622 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4623 fileType == CM_SCACHETYPE_DFSLINK ||
4624 fileType == CM_SCACHETYPE_INVALID)
4625 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4630 memcpy(op, mask, 11); op += 11;
4631 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
4632 *op++ = (unsigned char)(nextEntryCookie & 0xff);
4633 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
4634 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
4635 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
4636 memcpy(op, &clientCookie, 4); op += 4;
4638 /* now we emit the attribute. This is sort of tricky,
4639 * since we need to really stat the file to find out
4640 * what type of entry we've got. Right now, we're
4641 * copying out data from a buffer, while holding the
4642 * scp locked, so it isn't really convenient to stat
4643 * something now. We'll put in a place holder now,
4644 * and make a second pass before returning this to get
4645 * the real attributes. So, we just skip the data for
4646 * now, and adjust it later. We allocate a patch
4647 * record to make it easy to find this point later.
4648 * The replay will happen at a time when it is safe to
4649 * unlock the directory.
4651 curPatchp = malloc(sizeof(*curPatchp));
4652 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4653 curPatchp->dptr = op;
4654 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4656 /* do hidden attribute here since name won't be around when applying
4660 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4661 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4663 curPatchp->flags = 0;
4665 op += 9; /* skip attr, time, date and size */
4667 /* zero out name area. The spec says to pad with
4668 * spaces, but Samba doesn't, and neither do we.
4672 /* finally, we get to copy out the name; we know that
4673 * it fits in 8.3 or the pattern wouldn't match, but it
4674 * never hurts to be sure.
4676 cm_ClientStringToUtf8(actualName, -1, op, 13);
4677 if (smb_StoreAnsiFilenames)
4679 /* This is a UCHAR field, which is ASCII even if Unicode
4682 /* Uppercase if requested by client */
4683 if (!KNOWS_LONG_NAMES(inp))
4688 /* now, adjust the # of entries copied */
4690 } /* if we're including this name */
4693 /* and adjust curOffset to be where the new cookie is */
4694 thyper.HighPart = 0;
4695 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4696 curOffset = LargeIntegerAdd(thyper, curOffset);
4697 } /* while copying data for dir listing */
4699 /* release the mutex */
4700 lock_ReleaseWrite(&scp->rw);
4702 buf_Release(bufferp);
4706 /* apply and free last set of patches; if not doing a star match, this
4707 * will be empty, but better safe (and freeing everything) than sorry.
4709 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4711 /* special return code for unsuccessful search */
4712 if (code == 0 && dataLength < 21 && returnedNames == 0)
4713 code = CM_ERROR_NOFILES;
4715 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4716 returnedNames, code);
4719 smb_DeleteDirSearch(dsp);
4720 smb_ReleaseDirSearch(dsp);
4721 cm_ReleaseSCache(scp);
4722 cm_ReleaseUser(userp);
4726 /* finalize the output buffer */
4727 smb_SetSMBParm(outp, 0, returnedNames);
4728 temp = (long) (op - origOp);
4729 smb_SetSMBDataLength(outp, temp);
4731 /* the data area is a variable block, which has a 5 (already there)
4732 * followed by the length of the # of data bytes. We now know this to
4733 * be "temp," although that includes the 3 bytes of vbl block header.
4734 * Deduct for them and fill in the length field.
4736 temp -= 3; /* deduct vbl block info */
4737 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4738 origOp[1] = (unsigned char)(temp & 0xff);
4739 origOp[2] = (unsigned char)((temp>>8) & 0xff);
4740 if (returnedNames == 0)
4741 smb_DeleteDirSearch(dsp);
4742 smb_ReleaseDirSearch(dsp);
4743 cm_ReleaseSCache(scp);
4744 cm_ReleaseUser(userp);
4749 /* verify that this is a valid path to a directory. I don't know why they
4750 * don't use the get file attributes call.
4752 * SMB_COM_CHECK_DIRECTORY
4754 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4756 clientchar_t *pathp;
4758 cm_scache_t *rootScp;
4759 cm_scache_t *newScp;
4763 clientchar_t *tidPathp;
4769 pdata = smb_GetSMBData(inp, NULL);
4770 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
4772 return CM_ERROR_BADFD;
4773 osi_Log1(smb_logp, "SMB receive check path %S",
4774 osi_LogSaveClientString(smb_logp, pathp));
4776 rootScp = cm_data.rootSCachep;
4778 userp = smb_GetUserFromVCP(vcp, inp);
4780 caseFold = CM_FLAG_CASEFOLD;
4782 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4784 cm_ReleaseUser(userp);
4785 return CM_ERROR_NOSUCHPATH;
4787 code = cm_NameI(rootScp, pathp,
4788 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4789 userp, tidPathp, &req, &newScp);
4792 cm_ReleaseUser(userp);
4797 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4798 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4799 cm_ReleaseSCache(newScp);
4800 cm_ReleaseUser(userp);
4801 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4802 return CM_ERROR_PATH_NOT_COVERED;
4804 return CM_ERROR_BADSHARENAME;
4806 #endif /* DFS_SUPPORT */
4808 /* now lock the vnode with a callback; returns with newScp locked */
4809 lock_ObtainWrite(&newScp->rw);
4810 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4811 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4813 if (code != CM_ERROR_NOACCESS) {
4814 lock_ReleaseWrite(&newScp->rw);
4815 cm_ReleaseSCache(newScp);
4816 cm_ReleaseUser(userp);
4820 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4823 attrs = smb_Attributes(newScp);
4825 if (!(attrs & SMB_ATTR_DIRECTORY))
4826 code = CM_ERROR_NOTDIR;
4828 lock_ReleaseWrite(&newScp->rw);
4830 cm_ReleaseSCache(newScp);
4831 cm_ReleaseUser(userp);
4835 /* SMB_COM_SET_INFORMATION */
4836 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4838 clientchar_t *pathp;
4840 cm_scache_t *rootScp;
4841 unsigned short attribute;
4843 cm_scache_t *newScp;
4847 clientchar_t *tidPathp;
4853 /* decode basic attributes we're passed */
4854 attribute = smb_GetSMBParm(inp, 0);
4855 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4857 datap = smb_GetSMBData(inp, NULL);
4858 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
4860 return CM_ERROR_BADSMB;
4862 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4863 dosTime, attribute);
4865 rootScp = cm_data.rootSCachep;
4867 userp = smb_GetUserFromVCP(vcp, inp);
4869 caseFold = CM_FLAG_CASEFOLD;
4871 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4873 cm_ReleaseUser(userp);
4874 return CM_ERROR_NOSUCHFILE;
4876 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4877 tidPathp, &req, &newScp);
4880 cm_ReleaseUser(userp);
4885 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4886 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4887 cm_ReleaseSCache(newScp);
4888 cm_ReleaseUser(userp);
4889 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4890 return CM_ERROR_PATH_NOT_COVERED;
4892 return CM_ERROR_BADSHARENAME;
4894 #endif /* DFS_SUPPORT */
4896 /* now lock the vnode with a callback; returns with newScp locked; we
4897 * need the current status to determine what the new status is, in some
4900 lock_ObtainWrite(&newScp->rw);
4901 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4902 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4904 lock_ReleaseWrite(&newScp->rw);
4905 cm_ReleaseSCache(newScp);
4906 cm_ReleaseUser(userp);
4910 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4912 /* Check for RO volume */
4913 if (newScp->flags & CM_SCACHEFLAG_RO) {
4914 lock_ReleaseWrite(&newScp->rw);
4915 cm_ReleaseSCache(newScp);
4916 cm_ReleaseUser(userp);
4917 return CM_ERROR_READONLY;
4920 /* prepare for setattr call */
4923 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4924 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4926 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4927 /* we're told to make a writable file read-only */
4928 attr.unixModeBits = newScp->unixModeBits & ~0222;
4929 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4931 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4932 /* we're told to make a read-only file writable */
4933 attr.unixModeBits = newScp->unixModeBits | 0222;
4934 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4936 lock_ReleaseWrite(&newScp->rw);
4938 /* now call setattr */
4940 code = cm_SetAttr(newScp, &attr, userp, &req);
4944 cm_ReleaseSCache(newScp);
4945 cm_ReleaseUser(userp);
4951 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4953 clientchar_t *pathp;
4955 cm_scache_t *rootScp;
4956 cm_scache_t *newScp, *dscp;
4961 clientchar_t *tidPathp;
4963 clientchar_t *lastComp;
4969 datap = smb_GetSMBData(inp, NULL);
4970 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
4972 return CM_ERROR_BADSMB;
4974 if (*pathp == 0) /* null path */
4977 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
4978 osi_LogSaveClientString(smb_logp, pathp));
4980 rootScp = cm_data.rootSCachep;
4982 userp = smb_GetUserFromVCP(vcp, inp);
4984 /* we shouldn't need this for V3 requests, but we seem to */
4985 caseFold = CM_FLAG_CASEFOLD;
4987 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4989 cm_ReleaseUser(userp);
4990 return CM_ERROR_NOSUCHFILE;
4994 * XXX Strange hack XXX
4996 * As of Patch 5 (16 July 97), we are having the following problem:
4997 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4998 * requests to look up "desktop.ini" in all the subdirectories.
4999 * This can cause zillions of timeouts looking up non-existent cells
5000 * and volumes, especially in the top-level directory.
5002 * We have not found any way to avoid this or work around it except
5003 * to explicitly ignore the requests for mount points that haven't
5004 * yet been evaluated and for directories that haven't yet been
5007 * We should modify this hack to provide a fake desktop.ini file
5008 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5010 spacep = inp->spacep;
5011 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5012 #ifndef SPECIAL_FOLDERS
5013 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5014 code = cm_NameI(rootScp, spacep->wdata,
5015 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5016 userp, tidPathp, &req, &dscp);
5019 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5020 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5022 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5023 return CM_ERROR_PATH_NOT_COVERED;
5025 return CM_ERROR_BADSHARENAME;
5027 #endif /* DFS_SUPPORT */
5028 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5029 code = CM_ERROR_NOSUCHFILE;
5030 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5031 cm_buf_t *bp = buf_Find(dscp, &hzero);
5036 code = CM_ERROR_NOSUCHFILE;
5038 cm_ReleaseSCache(dscp);
5040 cm_ReleaseUser(userp);
5045 #endif /* SPECIAL_FOLDERS */
5047 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5048 tidPathp, &req, &newScp);
5050 cm_ReleaseUser(userp);
5055 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5056 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5057 cm_ReleaseSCache(newScp);
5058 cm_ReleaseUser(userp);
5059 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5060 return CM_ERROR_PATH_NOT_COVERED;
5062 return CM_ERROR_BADSHARENAME;
5064 #endif /* DFS_SUPPORT */
5066 /* now lock the vnode with a callback; returns with newScp locked */
5067 lock_ObtainWrite(&newScp->rw);
5068 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5069 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5071 lock_ReleaseWrite(&newScp->rw);
5072 cm_ReleaseSCache(newScp);
5073 cm_ReleaseUser(userp);
5077 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5080 /* use smb_Attributes instead. Also the fact that a file is
5081 * in a readonly volume doesn't mean it shojuld be marked as RO
5083 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5084 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5085 newScp->fileType == CM_SCACHETYPE_INVALID)
5086 attrs = SMB_ATTR_DIRECTORY;
5089 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
5090 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
5092 attrs = smb_Attributes(newScp);
5095 smb_SetSMBParm(outp, 0, attrs);
5097 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5098 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5099 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5100 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5101 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5102 smb_SetSMBParm(outp, 5, 0);
5103 smb_SetSMBParm(outp, 6, 0);
5104 smb_SetSMBParm(outp, 7, 0);
5105 smb_SetSMBParm(outp, 8, 0);
5106 smb_SetSMBParm(outp, 9, 0);
5107 smb_SetSMBDataLength(outp, 0);
5108 lock_ReleaseWrite(&newScp->rw);
5110 cm_ReleaseSCache(newScp);
5111 cm_ReleaseUser(userp);
5116 /* SMB_COM_TREE_DISCONNECT */
5117 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5121 osi_Log0(smb_logp, "SMB receive tree disconnect");
5123 /* find the tree and free it */
5124 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5126 lock_ObtainWrite(&smb_rctLock);
5128 smb_ReleaseTID(tidp, TRUE);
5129 lock_ReleaseWrite(&smb_rctLock);
5136 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5139 clientchar_t *pathp;
5140 clientchar_t *lastNamep;
5149 clientchar_t *tidPathp;
5155 datap = smb_GetSMBData(inp, NULL);
5156 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5158 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5160 #ifdef DEBUG_VERBOSE
5164 hexpath = osi_HexifyString( pathp );
5165 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5170 share = smb_GetSMBParm(inp, 0);
5171 attribute = smb_GetSMBParm(inp, 1);
5173 spacep = inp->spacep;
5174 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5175 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5176 /* special case magic file name for receiving IOCTL requests
5177 * (since IOCTL calls themselves aren't getting through).
5179 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5180 smb_SetupIoctlFid(fidp, spacep);
5181 smb_SetSMBParm(outp, 0, fidp->fid);
5182 smb_SetSMBParm(outp, 1, 0); /* attrs */
5183 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5184 smb_SetSMBParm(outp, 3, 0);
5185 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5186 smb_SetSMBParm(outp, 5, 0x7fff);
5187 /* pass the open mode back */
5188 smb_SetSMBParm(outp, 6, (share & 0xf));
5189 smb_SetSMBDataLength(outp, 0);
5190 smb_ReleaseFID(fidp);
5194 userp = smb_GetUserFromVCP(vcp, inp);
5196 caseFold = CM_FLAG_CASEFOLD;
5198 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5200 cm_ReleaseUser(userp);
5201 return CM_ERROR_NOSUCHPATH;
5203 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5204 tidPathp, &req, &scp);
5207 cm_ReleaseUser(userp);
5212 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5213 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5214 cm_ReleaseSCache(scp);
5215 cm_ReleaseUser(userp);
5216 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5217 return CM_ERROR_PATH_NOT_COVERED;
5219 return CM_ERROR_BADSHARENAME;
5221 #endif /* DFS_SUPPORT */
5223 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5225 cm_ReleaseSCache(scp);
5226 cm_ReleaseUser(userp);
5230 /* don't need callback to check file type, since file types never
5231 * change, and namei and cm_Lookup all stat the object at least once on
5232 * a successful return.
5234 if (scp->fileType != CM_SCACHETYPE_FILE) {
5235 cm_ReleaseSCache(scp);
5236 cm_ReleaseUser(userp);
5237 return CM_ERROR_ISDIR;
5240 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5241 osi_assertx(fidp, "null smb_fid_t");
5243 /* save a pointer to the vnode */
5245 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5246 lock_ObtainWrite(&scp->rw);
5247 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5248 lock_ReleaseWrite(&scp->rw);
5252 fidp->userp = userp;
5254 lock_ObtainMutex(&fidp->mx);
5255 if ((share & 0xf) == 0)
5256 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5257 else if ((share & 0xf) == 1)
5258 fidp->flags |= SMB_FID_OPENWRITE;
5260 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5261 lock_ReleaseMutex(&fidp->mx);
5263 lock_ObtainRead(&scp->rw);
5264 smb_SetSMBParm(outp, 0, fidp->fid);
5265 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5266 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5267 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5268 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5269 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5270 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5271 /* pass the open mode back; XXXX add access checks */
5272 smb_SetSMBParm(outp, 6, (share & 0xf));
5273 smb_SetSMBDataLength(outp, 0);
5274 lock_ReleaseRead(&scp->rw);
5277 cm_Open(scp, 0, userp);
5279 /* send and free packet */
5280 smb_ReleaseFID(fidp);
5281 cm_ReleaseUser(userp);
5282 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5286 typedef struct smb_unlinkRock {
5291 clientchar_t *maskp; /* pointer to the star pattern */
5294 cm_dirEntryList_t * matches;
5297 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5300 smb_unlinkRock_t *rockp;
5303 normchar_t matchName[MAX_PATH];
5307 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5308 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5309 caseFold |= CM_FLAG_8DOT3;
5311 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5312 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5314 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5315 !cm_Is8Dot3(matchName)) {
5316 cm_Gen8Dot3Name(dep, matchName, NULL);
5317 /* 8.3 matches are always case insensitive */
5318 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5321 osi_Log1(smb_logp, "Found match %S",
5322 osi_LogSaveClientString(smb_logp, matchName));
5324 cm_DirEntryListAdd(dep->name, &rockp->matches);
5328 /* If we made a case sensitive exact match, we might as well quit now. */
5329 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5330 code = CM_ERROR_STOPNOW;
5339 /* SMB_COM_DELETE */
5340 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5344 clientchar_t *pathp;
5348 clientchar_t *lastNamep;
5349 smb_unlinkRock_t rock;
5353 clientchar_t *tidPathp;
5358 attribute = smb_GetSMBParm(inp, 0);
5360 tp = smb_GetSMBData(inp, NULL);
5361 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5363 osi_Log1(smb_logp, "SMB receive unlink %S",
5364 osi_LogSaveClientString(smb_logp, pathp));
5366 spacep = inp->spacep;
5367 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5369 userp = smb_GetUserFromVCP(vcp, inp);
5371 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5373 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5375 cm_ReleaseUser(userp);
5376 return CM_ERROR_NOSUCHPATH;
5378 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5381 cm_ReleaseUser(userp);
5386 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5387 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5388 cm_ReleaseSCache(dscp);
5389 cm_ReleaseUser(userp);
5390 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5391 return CM_ERROR_PATH_NOT_COVERED;
5393 return CM_ERROR_BADSHARENAME;
5395 #endif /* DFS_SUPPORT */
5397 /* otherwise, scp points to the parent directory. */
5404 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5405 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5408 thyper.HighPart = 0;
5413 rock.matches = NULL;
5415 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5416 * match. If that fails, we do a case insensitve match.
5418 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5419 !smb_IsStarMask(rock.maskp)) {
5420 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5423 thyper.HighPart = 0;
5424 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5429 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5431 if (code == CM_ERROR_STOPNOW)
5434 if (code == 0 && rock.matches) {
5435 cm_dirEntryList_t * entry;
5437 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5438 normchar_t normalizedName[MAX_PATH];
5440 /* Note: entry->name is a non-normalized name */
5442 osi_Log1(smb_logp, "Unlinking %s",
5443 osi_LogSaveString(smb_logp, entry->name));
5445 cm_FsStringToNormString(entry->name, -1,
5446 normalizedName, lengthof(normalizedName));
5448 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5450 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5451 smb_NotifyChange(FILE_ACTION_REMOVED,
5452 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5453 dscp, normalizedName, NULL, TRUE);
5457 cm_DirEntryListFree(&rock.matches);
5459 cm_ReleaseUser(userp);
5461 cm_ReleaseSCache(dscp);
5465 if (code == 0 && !rock.any)
5466 code = CM_ERROR_NOSUCHFILE;
5470 typedef struct smb_renameRock {
5471 cm_scache_t *odscp; /* old dir */
5472 cm_scache_t *ndscp; /* new dir */
5473 cm_user_t *userp; /* user */
5474 cm_req_t *reqp; /* request struct */
5475 smb_vc_t *vcp; /* virtual circuit */
5476 normchar_t *maskp; /* pointer to star pattern of old file name */
5477 int flags; /* tilde, casefold, etc */
5478 clientchar_t *newNamep; /* ptr to the new file's name */
5479 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5480 clientchar_t clOldName[MAX_PATH]; /* client name */
5484 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5487 smb_renameRock_t *rockp;
5490 normchar_t matchName[MAX_PATH];
5492 rockp = (smb_renameRock_t *) vrockp;
5494 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5495 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5496 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5497 caseFold |= CM_FLAG_8DOT3;
5499 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5501 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5502 !cm_Is8Dot3(matchName)) {
5503 cm_Gen8Dot3Name(dep, matchName, NULL);
5504 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5509 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5510 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5512 code = CM_ERROR_STOPNOW;
5522 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5525 cm_space_t *spacep = NULL;
5526 smb_renameRock_t rock;
5527 cm_scache_t *oldDscp = NULL;
5528 cm_scache_t *newDscp = NULL;
5529 cm_scache_t *tmpscp= NULL;
5530 cm_scache_t *tmpscp2 = NULL;
5531 clientchar_t *oldLastNamep;
5532 clientchar_t *newLastNamep;
5536 clientchar_t *tidPathp;
5540 userp = smb_GetUserFromVCP(vcp, inp);
5541 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5543 cm_ReleaseUser(userp);
5544 return CM_ERROR_NOSUCHPATH;
5548 spacep = inp->spacep;
5549 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5551 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5552 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5553 userp, tidPathp, &req, &oldDscp);
5555 cm_ReleaseUser(userp);
5560 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5561 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5562 cm_ReleaseSCache(oldDscp);
5563 cm_ReleaseUser(userp);
5564 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5565 return CM_ERROR_PATH_NOT_COVERED;
5567 return CM_ERROR_BADSHARENAME;
5569 #endif /* DFS_SUPPORT */
5571 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5572 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5573 userp, tidPathp, &req, &newDscp);
5576 cm_ReleaseSCache(oldDscp);
5577 cm_ReleaseUser(userp);
5582 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5583 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5584 cm_ReleaseSCache(oldDscp);
5585 cm_ReleaseSCache(newDscp);
5586 cm_ReleaseUser(userp);
5587 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5588 return CM_ERROR_PATH_NOT_COVERED;
5590 return CM_ERROR_BADSHARENAME;
5592 #endif /* DFS_SUPPORT */
5595 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5596 * next, get the component names, and lower case them.
5599 /* handle the old name first */
5601 oldLastNamep = oldPathp;
5605 /* and handle the new name, too */
5607 newLastNamep = newPathp;
5611 /* TODO: The old name could be a wildcard. The new name must not be */
5613 /* do the vnode call */
5614 rock.odscp = oldDscp;
5615 rock.ndscp = newDscp;
5619 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
5620 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5621 rock.newNamep = newLastNamep;
5622 rock.fsOldName[0] = '\0';
5623 rock.clOldName[0] = '\0';
5626 /* Check if the file already exists; if so return error */
5627 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5628 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5629 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5631 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5632 osi_LogSaveClientString(smb_logp, newLastNamep));
5634 /* Check if the old and the new names differ only in case. If so return
5635 * success, else return CM_ERROR_EXISTS
5637 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
5639 /* This would be a success only if the old file is *as same as* the new file */
5640 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5642 if (tmpscp == tmpscp2)
5645 code = CM_ERROR_EXISTS;
5646 cm_ReleaseSCache(tmpscp2);
5649 code = CM_ERROR_NOSUCHFILE;
5652 /* file exist, do not rename, also fixes move */
5653 osi_Log0(smb_logp, "Can't rename. Target already exists");
5654 code = CM_ERROR_EXISTS;
5658 cm_ReleaseSCache(tmpscp);
5659 cm_ReleaseSCache(newDscp);
5660 cm_ReleaseSCache(oldDscp);
5661 cm_ReleaseUser(userp);
5668 /* Now search the directory for the pattern, and do the appropriate rename when found */
5669 thyper.LowPart = 0; /* search dir from here */
5670 thyper.HighPart = 0;
5672 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5673 if (code == 0 && !rock.any) {
5675 thyper.HighPart = 0;
5676 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5677 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5679 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5681 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
5682 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
5683 rock.ndscp, rock.newNamep, rock.userp,
5685 /* if the call worked, stop doing the search now, since we
5686 * really only want to rename one file.
5688 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5689 } else if (code == 0) {
5690 code = CM_ERROR_NOSUCHFILE;
5693 /* Handle Change Notification */
5695 * Being lazy, not distinguishing between files and dirs in this
5696 * filter, since we'd have to do a lookup.
5699 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5700 if (oldDscp == newDscp) {
5701 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5702 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5703 filter, oldDscp, rock.clOldName,
5704 newLastNamep, TRUE);
5706 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5707 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5708 filter, oldDscp, rock.clOldName,
5710 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5711 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5712 filter, newDscp, newLastNamep,
5718 cm_ReleaseSCache(tmpscp);
5719 cm_ReleaseUser(userp);
5720 cm_ReleaseSCache(oldDscp);
5721 cm_ReleaseSCache(newDscp);
5730 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
5733 cm_space_t *spacep = NULL;
5734 cm_scache_t *oldDscp = NULL;
5735 cm_scache_t *newDscp = NULL;
5736 cm_scache_t *tmpscp= NULL;
5737 cm_scache_t *tmpscp2 = NULL;
5738 cm_scache_t *sscp = NULL;
5739 clientchar_t *oldLastNamep;
5740 clientchar_t *newLastNamep;
5743 clientchar_t *tidPathp;
5747 userp = smb_GetUserFromVCP(vcp, inp);
5749 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5751 cm_ReleaseUser(userp);
5752 return CM_ERROR_NOSUCHPATH;
5757 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5759 spacep = inp->spacep;
5760 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5762 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5763 userp, tidPathp, &req, &oldDscp);
5765 cm_ReleaseUser(userp);
5770 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5771 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5772 cm_ReleaseSCache(oldDscp);
5773 cm_ReleaseUser(userp);
5774 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5775 return CM_ERROR_PATH_NOT_COVERED;
5777 return CM_ERROR_BADSHARENAME;
5779 #endif /* DFS_SUPPORT */
5781 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5782 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5783 userp, tidPathp, &req, &newDscp);
5785 cm_ReleaseSCache(oldDscp);
5786 cm_ReleaseUser(userp);
5791 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5792 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5793 cm_ReleaseSCache(newDscp);
5794 cm_ReleaseSCache(oldDscp);
5795 cm_ReleaseUser(userp);
5796 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5797 return CM_ERROR_PATH_NOT_COVERED;
5799 return CM_ERROR_BADSHARENAME;
5801 #endif /* DFS_SUPPORT */
5803 /* Now, although we did two lookups for the two directories (because the same
5804 * directory can be referenced through different paths), we only allow hard links
5805 * within the same directory. */
5806 if (oldDscp != newDscp) {
5807 cm_ReleaseSCache(oldDscp);
5808 cm_ReleaseSCache(newDscp);
5809 cm_ReleaseUser(userp);
5810 return CM_ERROR_CROSSDEVLINK;
5813 /* handle the old name first */
5815 oldLastNamep = oldPathp;
5819 /* and handle the new name, too */
5821 newLastNamep = newPathp;
5825 /* now lookup the old name */
5826 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
5827 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5829 cm_ReleaseSCache(oldDscp);
5830 cm_ReleaseSCache(newDscp);
5831 cm_ReleaseUser(userp);
5835 /* Check if the file already exists; if so return error */
5836 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5837 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5838 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5840 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5841 osi_LogSaveClientString(smb_logp, newLastNamep));
5843 /* if the existing link is to the same file, then we return success */
5845 if(sscp == tmpscp) {
5848 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5849 code = CM_ERROR_EXISTS;
5854 cm_ReleaseSCache(tmpscp);
5855 cm_ReleaseSCache(sscp);
5856 cm_ReleaseSCache(newDscp);
5857 cm_ReleaseSCache(oldDscp);
5858 cm_ReleaseUser(userp);
5862 /* now create the hardlink */
5863 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
5864 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5865 osi_Log1(smb_logp," Link returns 0x%x", code);
5867 /* Handle Change Notification */
5869 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5870 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5871 smb_NotifyChange(FILE_ACTION_ADDED,
5872 filter, newDscp, newLastNamep,
5877 cm_ReleaseSCache(tmpscp);
5878 cm_ReleaseUser(userp);
5879 cm_ReleaseSCache(sscp);
5880 cm_ReleaseSCache(oldDscp);
5881 cm_ReleaseSCache(newDscp);
5885 /* SMB_COM_RENAME */
5887 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5889 clientchar_t *oldPathp;
5890 clientchar_t *newPathp;
5894 tp = smb_GetSMBData(inp, NULL);
5895 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5896 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5898 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
5899 osi_LogSaveClientString(smb_logp, oldPathp),
5900 osi_LogSaveClientString(smb_logp, newPathp));
5902 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5904 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5910 typedef struct smb_rmdirRock {
5914 normchar_t *maskp; /* pointer to the star pattern */
5917 cm_dirEntryList_t * matches;
5920 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5923 smb_rmdirRock_t *rockp;
5925 normchar_t matchName[MAX_PATH];
5927 rockp = (smb_rmdirRock_t *) vrockp;
5929 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5930 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5931 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
5933 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
5935 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5936 !cm_Is8Dot3(matchName)) {
5937 cm_Gen8Dot3Name(dep, matchName, NULL);
5938 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
5943 cm_DirEntryListAdd(dep->name, &rockp->matches);
5950 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5953 clientchar_t *pathp;
5957 clientchar_t *lastNamep;
5958 smb_rmdirRock_t rock;
5962 clientchar_t *tidPathp;
5967 tp = smb_GetSMBData(inp, NULL);
5968 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5970 spacep = inp->spacep;
5971 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5973 userp = smb_GetUserFromVCP(vcp, inp);
5975 caseFold = CM_FLAG_CASEFOLD;
5977 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5979 cm_ReleaseUser(userp);
5980 return CM_ERROR_NOSUCHPATH;
5982 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
5983 userp, tidPathp, &req, &dscp);
5986 cm_ReleaseUser(userp);
5991 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5992 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5993 cm_ReleaseSCache(dscp);
5994 cm_ReleaseUser(userp);
5995 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5996 return CM_ERROR_PATH_NOT_COVERED;
5998 return CM_ERROR_BADSHARENAME;
6000 #endif /* DFS_SUPPORT */
6002 /* otherwise, scp points to the parent directory. */
6009 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6010 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6013 thyper.HighPart = 0;
6017 rock.matches = NULL;
6019 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6020 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6021 if (code == 0 && !rock.any) {
6023 thyper.HighPart = 0;
6024 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6025 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6028 if (code == 0 && rock.matches) {
6029 cm_dirEntryList_t * entry;
6031 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6032 clientchar_t clientName[MAX_PATH];
6034 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6036 osi_Log1(smb_logp, "Removing directory %s",
6037 osi_LogSaveString(smb_logp, entry->name));
6039 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6041 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6042 smb_NotifyChange(FILE_ACTION_REMOVED,
6043 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6044 dscp, clientName, NULL, TRUE);
6048 cm_DirEntryListFree(&rock.matches);
6050 cm_ReleaseUser(userp);
6052 cm_ReleaseSCache(dscp);
6054 if (code == 0 && !rock.any)
6055 code = CM_ERROR_NOSUCHFILE;
6064 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6074 fid = smb_GetSMBParm(inp, 0);
6076 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6078 fid = smb_ChainFID(fid, inp);
6079 fidp = smb_FindFID(vcp, fid, 0);
6081 return CM_ERROR_BADFD;
6083 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6084 smb_CloseFID(vcp, fidp, NULL, 0);
6085 smb_ReleaseFID(fidp);
6086 return CM_ERROR_NOSUCHFILE;
6089 lock_ObtainMutex(&fidp->mx);
6090 if (fidp->flags & SMB_FID_IOCTL) {
6091 lock_ReleaseMutex(&fidp->mx);
6092 smb_ReleaseFID(fidp);
6093 return CM_ERROR_BADFD;
6095 lock_ReleaseMutex(&fidp->mx);
6097 userp = smb_GetUserFromVCP(vcp, inp);
6099 lock_ObtainMutex(&fidp->mx);
6100 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6101 cm_scache_t * scp = fidp->scp;
6103 lock_ReleaseMutex(&fidp->mx);
6104 code = cm_FSync(scp, userp, &req);
6105 cm_ReleaseSCache(scp);
6108 lock_ReleaseMutex(&fidp->mx);
6111 smb_ReleaseFID(fidp);
6113 cm_ReleaseUser(userp);
6118 struct smb_FullNameRock {
6121 clientchar_t *fullName;
6122 fschar_t *originalName;
6125 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6128 normchar_t matchName[MAX_PATH];
6129 struct smb_FullNameRock *vrockp;
6131 vrockp = (struct smb_FullNameRock *)rockp;
6133 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
6135 if (!cm_Is8Dot3(matchName)) {
6136 clientchar_t shortName[13];
6138 cm_Gen8Dot3Name(dep, shortName, NULL);
6140 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6141 vrockp->fullName = cm_ClientStrDup(matchName);
6142 vrockp->originalName = cm_FsStrDup(dep->name);
6143 return CM_ERROR_STOPNOW;
6146 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6147 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6148 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6149 vrockp->fullName = cm_ClientStrDup(matchName);
6150 vrockp->originalName = cm_FsStrDup(dep->name);
6151 return CM_ERROR_STOPNOW;
6156 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6157 clientchar_t **newPathp, fschar_t ** originalPathp,
6158 cm_user_t *userp, cm_req_t *reqp)
6160 struct smb_FullNameRock rock;
6163 memset(&rock, 0, sizeof(rock));
6167 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6168 if (code == CM_ERROR_STOPNOW) {
6169 *newPathp = rock.fullName;
6170 *originalPathp = rock.originalName;
6172 *newPathp = cm_ClientStrDup(pathp);
6173 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6177 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6178 afs_uint32 dosTime) {
6181 cm_scache_t *dscp = NULL;
6182 clientchar_t *pathp = NULL;
6183 cm_scache_t * scp = NULL;
6184 cm_scache_t *delscp = NULL;
6185 int nullcreator = 0;
6187 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6188 fidp, fidp->fid, scp, vcp);
6191 lock_ObtainMutex(&fidp->mx);
6192 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6193 lock_ReleaseMutex(&fidp->mx);
6194 osi_Log0(smb_logp, " No user specified. Not closing fid");
6195 return CM_ERROR_BADFD;
6198 userp = fidp->userp; /* no hold required since fidp is held
6199 throughout the function */
6200 lock_ReleaseMutex(&fidp->mx);
6205 lock_ObtainWrite(&smb_rctLock);
6206 if (fidp->deleteOk) {
6207 osi_Log0(smb_logp, " Fid already closed.");
6208 lock_ReleaseWrite(&smb_rctLock);
6209 return CM_ERROR_BADFD;
6212 lock_ReleaseWrite(&smb_rctLock);
6214 lock_ObtainMutex(&fidp->mx);
6215 if (fidp->NTopen_dscp) {
6216 dscp = fidp->NTopen_dscp;
6217 cm_HoldSCache(dscp);
6220 if (fidp->NTopen_pathp) {
6221 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6229 /* Don't jump the gun on an async raw write */
6230 while (fidp->raw_writers) {
6231 lock_ReleaseMutex(&fidp->mx);
6232 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6233 lock_ObtainMutex(&fidp->mx);
6236 /* watch for ioctl closes, and read-only opens */
6238 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6239 == SMB_FID_OPENWRITE) {
6240 if (dosTime != 0 && dosTime != -1) {
6241 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6242 /* This fixes defect 10958 */
6243 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6244 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6246 if (smb_AsyncStore != 2) {
6247 lock_ReleaseMutex(&fidp->mx);
6248 code = cm_FSync(scp, userp, &req);
6249 lock_ObtainMutex(&fidp->mx);
6255 /* unlock any pending locks */
6256 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6257 scp->fileType == CM_SCACHETYPE_FILE) {
6261 lock_ReleaseMutex(&fidp->mx);
6263 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6265 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6266 lock_ObtainWrite(&scp->rw);
6268 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6269 CM_SCACHESYNC_NEEDCALLBACK
6270 | CM_SCACHESYNC_GETSTATUS
6271 | CM_SCACHESYNC_LOCK);
6275 "smb CoreClose SyncOp failure code 0x%x", tcode);
6276 goto post_syncopdone;
6279 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6281 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6285 lock_ReleaseWrite(&scp->rw);
6286 lock_ObtainMutex(&fidp->mx);
6289 if (fidp->flags & SMB_FID_DELONCLOSE) {
6290 clientchar_t *fullPathp = NULL;
6291 fschar_t *originalNamep = NULL;
6293 lock_ReleaseMutex(&fidp->mx);
6295 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6300 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6301 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6302 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6304 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6305 smb_NotifyChange(FILE_ACTION_REMOVED,
6306 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6307 dscp, fullPathp, NULL, TRUE);
6310 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6312 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6313 smb_NotifyChange(FILE_ACTION_REMOVED,
6314 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6315 dscp, fullPathp, NULL, TRUE);
6322 free(originalNamep);
6324 lock_ObtainMutex(&fidp->mx);
6325 fidp->flags &= ~SMB_FID_DELONCLOSE;
6328 /* if this was a newly created file, then clear the creator
6329 * in the stat cache entry. */
6330 if (fidp->flags & SMB_FID_CREATED) {
6332 fidp->flags &= ~SMB_FID_CREATED;
6335 if (fidp->flags & SMB_FID_NTOPEN) {
6336 cm_ReleaseSCache(fidp->NTopen_dscp);
6337 fidp->NTopen_dscp = NULL;
6338 free(fidp->NTopen_pathp);
6339 fidp->NTopen_pathp = NULL;
6340 fidp->flags &= ~SMB_FID_NTOPEN;
6342 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6343 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6346 if (fidp->NTopen_wholepathp) {
6347 free(fidp->NTopen_wholepathp);
6348 fidp->NTopen_wholepathp = NULL;
6352 cm_ReleaseSCache(fidp->scp);
6355 lock_ReleaseMutex(&fidp->mx);
6358 cm_ReleaseSCache(dscp);
6361 cm_ReleaseSCache(delscp);
6365 lock_ObtainWrite(&scp->rw);
6366 if (nullcreator && scp->creator == userp)
6367 scp->creator = NULL;
6368 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6369 lock_ReleaseWrite(&scp->rw);
6370 cm_ReleaseSCache(scp);
6380 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6388 fid = smb_GetSMBParm(inp, 0);
6389 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6391 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6393 fid = smb_ChainFID(fid, inp);
6394 fidp = smb_FindFID(vcp, fid, 0);
6396 return CM_ERROR_BADFD;
6399 userp = smb_GetUserFromVCP(vcp, inp);
6401 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6403 smb_ReleaseFID(fidp);
6404 cm_ReleaseUser(userp);
6409 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6411 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6412 cm_user_t *userp, long *readp)
6418 osi_hyper_t fileLength;
6420 osi_hyper_t lastByte;
6421 osi_hyper_t bufferOffset;
6425 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6428 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6429 fidp->fid, offsetp->LowPart, count);
6433 lock_ObtainMutex(&fidp->mx);
6434 /* make sure we have a readable FD */
6435 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6436 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6437 fidp->fid, fidp->flags);
6438 lock_ReleaseMutex(&fidp->mx);
6439 code = CM_ERROR_BADFDOP;
6450 lock_ObtainWrite(&scp->rw);
6452 if (offset.HighPart == 0) {
6453 chunk = offset.LowPart >> cm_logChunkSize;
6454 if (chunk != fidp->curr_chunk) {
6455 fidp->prev_chunk = fidp->curr_chunk;
6456 fidp->curr_chunk = chunk;
6458 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6461 lock_ReleaseMutex(&fidp->mx);
6463 /* start by looking up the file's end */
6464 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6465 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6469 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6471 /* now we have the entry locked, look up the length */
6472 fileLength = scp->length;
6474 /* adjust count down so that it won't go past EOF */
6475 thyper.LowPart = count;
6476 thyper.HighPart = 0;
6477 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6479 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6480 /* we'd read past EOF, so just stop at fileLength bytes.
6481 * Start by computing how many bytes remain in the file.
6483 thyper = LargeIntegerSubtract(fileLength, offset);
6485 /* if we are past EOF, read 0 bytes */
6486 if (LargeIntegerLessThanZero(thyper))
6489 count = thyper.LowPart;
6494 /* now, copy the data one buffer at a time,
6495 * until we've filled the request packet
6498 /* if we've copied all the data requested, we're done */
6499 if (count <= 0) break;
6501 /* otherwise, load up a buffer of data */
6502 thyper.HighPart = offset.HighPart;
6503 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6504 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6507 buf_Release(bufferp);
6510 lock_ReleaseWrite(&scp->rw);
6512 code = buf_Get(scp, &thyper, &bufferp);
6514 lock_ObtainWrite(&scp->rw);
6515 if (code) goto done;
6516 bufferOffset = thyper;
6518 /* now get the data in the cache */
6520 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6521 CM_SCACHESYNC_NEEDCALLBACK |
6522 CM_SCACHESYNC_READ);
6526 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6528 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6530 /* otherwise, load the buffer and try again */
6531 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6535 buf_Release(bufferp);
6539 } /* if (wrong buffer) ... */
6541 /* now we have the right buffer loaded. Copy out the
6542 * data from here to the user's buffer.
6544 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6546 /* and figure out how many bytes we want from this buffer */
6547 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6548 if (nbytes > count) nbytes = count; /* don't go past EOF */
6550 /* now copy the data */
6551 memcpy(op, bufferp->datap + bufIndex, nbytes);
6553 /* adjust counters, pointers, etc. */
6556 thyper.LowPart = nbytes;
6557 thyper.HighPart = 0;
6558 offset = LargeIntegerAdd(thyper, offset);
6562 lock_ReleaseWrite(&scp->rw);
6564 buf_Release(bufferp);
6566 if (code == 0 && sequential)
6567 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6569 cm_ReleaseSCache(scp);
6572 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6573 fidp->fid, code, *readp);
6578 * smb_WriteData -- common code for Write and Raw Write
6580 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6581 cm_user_t *userp, long *writtenp)
6583 osi_hyper_t offset = *offsetp;
6586 cm_scache_t *scp = NULL;
6587 osi_hyper_t fileLength; /* file's length at start of write */
6588 osi_hyper_t minLength; /* don't read past this */
6589 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6590 cm_buf_t *bufferp = NULL;
6591 osi_hyper_t thyper; /* hyper tmp variable */
6592 osi_hyper_t bufferOffset;
6593 afs_uint32 bufIndex; /* index in buffer where our data is */
6594 int doWriteBack = 0;
6595 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6599 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6600 fidp->fid, offsetp->LowPart, count);
6604 lock_ObtainMutex(&fidp->mx);
6605 /* make sure we have a writable FD */
6606 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6607 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6608 fidp->fid, fidp->flags);
6609 lock_ReleaseMutex(&fidp->mx);
6610 code = CM_ERROR_BADFDOP;
6618 lock_ReleaseMutex(&fidp->mx);
6620 lock_ObtainWrite(&scp->rw);
6621 /* start by looking up the file's end */
6622 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6623 CM_SCACHESYNC_NEEDCALLBACK
6624 | CM_SCACHESYNC_SETSTATUS
6625 | CM_SCACHESYNC_GETSTATUS);
6629 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6631 /* now we have the entry locked, look up the length */
6632 fileLength = scp->length;
6633 minLength = fileLength;
6634 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6635 minLength = scp->serverLength;
6637 /* adjust file length if we extend past EOF */
6638 thyper.LowPart = count;
6639 thyper.HighPart = 0;
6640 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6641 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6642 /* we'd write past EOF, so extend the file */
6643 scp->mask |= CM_SCACHEMASK_LENGTH;
6644 scp->length = thyper;
6645 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6647 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6649 /* now, if the new position (thyper) and the old (offset) are in
6650 * different storeback windows, remember to store back the previous
6651 * storeback window when we're done with the write.
6653 * the purpose of this logic is to slow down the CIFS client
6654 * in order to avoid the client disconnecting during the CLOSE
6655 * operation if there are too many dirty buffers left to write
6656 * than can be accomplished during 45 seconds. This used to be
6657 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6658 * so that we can read larger amounts of data at a time.
6660 if (smb_AsyncStore == 1 &&
6661 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
6662 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
6663 /* they're different */
6665 writeBackOffset.HighPart = offset.HighPart;
6666 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
6671 /* now, copy the data one buffer at a time, until we've filled the
6674 /* if we've copied all the data requested, we're done */
6678 /* handle over quota or out of space */
6679 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6680 *writtenp = written;
6681 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6685 /* otherwise, load up a buffer of data */
6686 thyper.HighPart = offset.HighPart;
6687 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6688 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6691 lock_ReleaseMutex(&bufferp->mx);
6692 buf_Release(bufferp);
6695 lock_ReleaseWrite(&scp->rw);
6697 code = buf_Get(scp, &thyper, &bufferp);
6699 lock_ObtainMutex(&bufferp->mx);
6700 lock_ObtainWrite(&scp->rw);
6701 if (code) goto done;
6703 bufferOffset = thyper;
6705 /* now get the data in the cache */
6707 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6708 CM_SCACHESYNC_NEEDCALLBACK
6709 | CM_SCACHESYNC_WRITE
6710 | CM_SCACHESYNC_BUFLOCKED);
6714 cm_SyncOpDone(scp, bufferp,
6715 CM_SCACHESYNC_NEEDCALLBACK
6716 | CM_SCACHESYNC_WRITE
6717 | CM_SCACHESYNC_BUFLOCKED);
6719 /* If we're overwriting the entire buffer, or
6720 * if we're writing at or past EOF, mark the
6721 * buffer as current so we don't call
6722 * cm_GetBuffer. This skips the fetch from the
6723 * server in those cases where we're going to
6724 * obliterate all the data in the buffer anyway,
6725 * or in those cases where there is no useful
6726 * data at the server to start with.
6728 * Use minLength instead of scp->length, since
6729 * the latter has already been updated by this
6732 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6733 || LargeIntegerEqualTo(offset, bufferp->offset)
6734 && (count >= cm_data.buf_blockSize
6735 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6736 ConvertLongToLargeInteger(count)),
6738 if (count < cm_data.buf_blockSize
6739 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
6740 memset(bufferp->datap, 0,
6741 cm_data.buf_blockSize);
6742 bufferp->dataVersion = scp->dataVersion;
6745 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6747 /* otherwise, load the buffer and try again */
6748 lock_ReleaseMutex(&bufferp->mx);
6749 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6751 lock_ReleaseWrite(&scp->rw);
6752 lock_ObtainMutex(&bufferp->mx);
6753 lock_ObtainWrite(&scp->rw);
6757 lock_ReleaseMutex(&bufferp->mx);
6758 buf_Release(bufferp);
6762 } /* if (wrong buffer) ... */
6764 /* now we have the right buffer loaded. Copy out the
6765 * data from here to the user's buffer.
6767 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6769 /* and figure out how many bytes we want from this buffer */
6770 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6772 nbytes = count; /* don't go past end of request */
6774 /* now copy the data */
6775 memcpy(bufferp->datap + bufIndex, op, nbytes);
6776 buf_SetDirty(bufferp, bufIndex, nbytes);
6778 /* and record the last writer */
6779 if (bufferp->userp != userp) {
6782 cm_ReleaseUser(bufferp->userp);
6783 bufferp->userp = userp;
6786 /* adjust counters, pointers, etc. */
6790 thyper.LowPart = nbytes;
6791 thyper.HighPart = 0;
6792 offset = LargeIntegerAdd(thyper, offset);
6796 lock_ReleaseWrite(&scp->rw);
6799 lock_ReleaseMutex(&bufferp->mx);
6800 buf_Release(bufferp);
6803 lock_ObtainMutex(&fidp->mx);
6804 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6805 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6806 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6807 fidp->NTopen_dscp, fidp->NTopen_pathp,
6810 lock_ReleaseMutex(&fidp->mx);
6813 if (smb_AsyncStore > 0) {
6817 lock_ObtainWrite(&scp->rw);
6818 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6820 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6821 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6823 lock_ReleaseWrite(&scp->rw);
6824 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6825 writeBackOffset.HighPart,
6826 smb_AsyncStoreSize, 0, userp);
6827 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6830 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
6834 cm_ReleaseSCache(scp);
6837 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6838 fidp->fid, code, *writtenp);
6843 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6846 unsigned short count;
6848 unsigned short hint;
6849 long written = 0, total_written = 0;
6852 smb_t* smbp = (smb_t*) inp;
6855 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6857 int inDataBlockCount;
6859 fd = smb_GetSMBParm(inp, 0);
6860 count = smb_GetSMBParm(inp, 1);
6861 offset.HighPart = 0; /* too bad */
6862 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6863 hint = smb_GetSMBParm(inp, 4);
6865 op = smb_GetSMBData(inp, NULL);
6866 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6868 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6869 fd, offset.LowPart, count);
6871 fd = smb_ChainFID(fd, inp);
6872 fidp = smb_FindFID(vcp, fd, 0);
6874 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6875 return CM_ERROR_BADFD;
6878 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6879 smb_CloseFID(vcp, fidp, NULL, 0);
6880 smb_ReleaseFID(fidp);
6881 return CM_ERROR_NOSUCHFILE;
6884 lock_ObtainMutex(&fidp->mx);
6885 if (fidp->flags & SMB_FID_IOCTL) {
6886 lock_ReleaseMutex(&fidp->mx);
6887 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6888 smb_ReleaseFID(fidp);
6889 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6892 lock_ReleaseMutex(&fidp->mx);
6893 userp = smb_GetUserFromVCP(vcp, inp);
6897 LARGE_INTEGER LOffset;
6898 LARGE_INTEGER LLength;
6901 key = cm_GenerateKey(vcp->vcID, pid, fd);
6903 LOffset.HighPart = offset.HighPart;
6904 LOffset.LowPart = offset.LowPart;
6905 LLength.HighPart = 0;
6906 LLength.LowPart = count;
6908 lock_ObtainWrite(&fidp->scp->rw);
6909 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6910 lock_ReleaseWrite(&fidp->scp->rw);
6913 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6918 /* special case: 0 bytes transferred means truncate to this position */
6922 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6926 truncAttr.mask = CM_ATTRMASK_LENGTH;
6927 truncAttr.length.LowPart = offset.LowPart;
6928 truncAttr.length.HighPart = 0;
6929 lock_ObtainMutex(&fidp->mx);
6930 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6931 fidp->flags |= SMB_FID_LENGTHSETDONE;
6932 lock_ReleaseMutex(&fidp->mx);
6933 smb_SetSMBParm(outp, 0, 0 /* count */);
6934 smb_SetSMBDataLength(outp, 0);
6939 * Work around bug in NT client
6941 * When copying a file, the NT client should first copy the data,
6942 * then copy the last write time. But sometimes the NT client does
6943 * these in the wrong order, so the data copies would inadvertently
6944 * cause the last write time to be overwritten. We try to detect this,
6945 * and don't set client mod time if we think that would go against the
6948 lock_ObtainMutex(&fidp->mx);
6949 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6950 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6951 fidp->scp->clientModTime = time(NULL);
6953 lock_ReleaseMutex(&fidp->mx);
6956 while ( code == 0 && count > 0 ) {
6957 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6958 if (code == 0 && written == 0)
6959 code = CM_ERROR_PARTIALWRITE;
6961 offset = LargeIntegerAdd(offset,
6962 ConvertLongToLargeInteger(written));
6963 count -= (unsigned short)written;
6964 total_written += written;
6968 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6969 total_written, code);
6971 /* set the packet data length to 3 bytes for the data block header,
6972 * plus the size of the data.
6974 smb_SetSMBParm(outp, 0, total_written);
6975 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6976 smb_SetSMBParm(outp, 3, hint);
6977 smb_SetSMBDataLength(outp, 0);
6980 smb_ReleaseFID(fidp);
6981 cm_ReleaseUser(userp);
6986 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6987 NCB *ncbp, raw_write_cont_t *rwcp)
6996 fd = smb_GetSMBParm(inp, 0);
6997 fidp = smb_FindFID(vcp, fd, 0);
6999 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7000 smb_CloseFID(vcp, fidp, NULL, 0);
7001 smb_ReleaseFID(fidp);
7005 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7006 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7008 userp = smb_GetUserFromVCP(vcp, inp);
7011 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7013 if (rwcp->writeMode & 0x1) { /* synchronous */
7016 smb_FormatResponsePacket(vcp, inp, outp);
7017 op = (smb_t *) outp;
7018 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7019 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7020 smb_SetSMBDataLength(outp, 0);
7021 smb_SendPacket(vcp, outp);
7022 smb_FreePacket(outp);
7024 else { /* asynchronous */
7025 lock_ObtainMutex(&fidp->mx);
7026 fidp->raw_writers--;
7027 if (fidp->raw_writers == 0)
7028 thrd_SetEvent(fidp->raw_write_event);
7029 lock_ReleaseMutex(&fidp->mx);
7032 /* Give back raw buffer */
7033 lock_ObtainMutex(&smb_RawBufLock);
7034 *((char **)rawBuf) = smb_RawBufs;
7035 smb_RawBufs = rawBuf;
7036 lock_ReleaseMutex(&smb_RawBufLock);
7038 smb_ReleaseFID(fidp);
7039 cm_ReleaseUser(userp);
7042 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7047 /* SMB_COM_WRITE_RAW */
7048 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7051 long count, written = 0, total_written = 0;
7055 smb_t *smbp = (smb_t*) inp;
7059 unsigned short writeMode;
7061 fd = smb_GetSMBParm(inp, 0);
7062 totalCount = smb_GetSMBParm(inp, 1);
7063 count = smb_GetSMBParm(inp, 10);
7064 writeMode = smb_GetSMBParm(inp, 7);
7066 op = (char *) inp->data;
7067 op += smb_GetSMBParm(inp, 11);
7069 offset.HighPart = 0;
7070 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7072 if (*inp->wctp == 14) {
7073 /* we received a 64-bit file offset */
7074 #ifdef AFS_LARGEFILES
7075 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7077 if (LargeIntegerLessThanZero(offset)) {
7079 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7080 offset.HighPart, offset.LowPart);
7081 return CM_ERROR_BADSMB;
7084 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7086 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7087 return CM_ERROR_BADSMB;
7090 offset.HighPart = 0;
7093 offset.HighPart = 0; /* 32-bit file offset */
7097 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7098 fd, offset.HighPart, offset.LowPart, count);
7100 " WriteRaw WriteMode 0x%x",
7103 fd = smb_ChainFID(fd, inp);
7104 fidp = smb_FindFID(vcp, fd, 0);
7106 return CM_ERROR_BADFD;
7109 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7110 smb_CloseFID(vcp, fidp, NULL, 0);
7111 smb_ReleaseFID(fidp);
7112 return CM_ERROR_NOSUCHFILE;
7118 LARGE_INTEGER LOffset;
7119 LARGE_INTEGER LLength;
7122 key = cm_GenerateKey(vcp->vcID, pid, fd);
7124 LOffset.HighPart = offset.HighPart;
7125 LOffset.LowPart = offset.LowPart;
7126 LLength.HighPart = 0;
7127 LLength.LowPart = count;
7129 lock_ObtainWrite(&fidp->scp->rw);
7130 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7131 lock_ReleaseWrite(&fidp->scp->rw);
7134 smb_ReleaseFID(fidp);
7139 userp = smb_GetUserFromVCP(vcp, inp);
7142 * Work around bug in NT client
7144 * When copying a file, the NT client should first copy the data,
7145 * then copy the last write time. But sometimes the NT client does
7146 * these in the wrong order, so the data copies would inadvertently
7147 * cause the last write time to be overwritten. We try to detect this,
7148 * and don't set client mod time if we think that would go against the
7151 lock_ObtainMutex(&fidp->mx);
7152 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7153 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7154 fidp->scp->clientModTime = time(NULL);
7156 lock_ReleaseMutex(&fidp->mx);
7159 while ( code == 0 && count > 0 ) {
7160 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7161 if (code == 0 && written == 0)
7162 code = CM_ERROR_PARTIALWRITE;
7164 offset = LargeIntegerAdd(offset,
7165 ConvertLongToLargeInteger(written));
7168 total_written += written;
7172 /* Get a raw buffer */
7175 lock_ObtainMutex(&smb_RawBufLock);
7177 /* Get a raw buf, from head of list */
7178 rawBuf = smb_RawBufs;
7179 smb_RawBufs = *(char **)smb_RawBufs;
7182 code = CM_ERROR_USESTD;
7184 lock_ReleaseMutex(&smb_RawBufLock);
7187 /* Don't allow a premature Close */
7188 if (code == 0 && (writeMode & 1) == 0) {
7189 lock_ObtainMutex(&fidp->mx);
7190 fidp->raw_writers++;
7191 thrd_ResetEvent(fidp->raw_write_event);
7192 lock_ReleaseMutex(&fidp->mx);
7195 smb_ReleaseFID(fidp);
7196 cm_ReleaseUser(userp);
7199 smb_SetSMBParm(outp, 0, total_written);
7200 smb_SetSMBDataLength(outp, 0);
7201 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7206 offset = LargeIntegerAdd(offset,
7207 ConvertLongToLargeInteger(count));
7211 rwcp->offset.HighPart = offset.HighPart;
7212 rwcp->offset.LowPart = offset.LowPart;
7213 rwcp->count = totalCount - count;
7214 rwcp->writeMode = writeMode;
7215 rwcp->alreadyWritten = total_written;
7217 /* set the packet data length to 3 bytes for the data block header,
7218 * plus the size of the data.
7220 smb_SetSMBParm(outp, 0, 0xffff);
7221 smb_SetSMBDataLength(outp, 0);
7227 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7230 long count, finalCount;
7234 smb_t *smbp = (smb_t*) inp;
7239 fd = smb_GetSMBParm(inp, 0);
7240 count = smb_GetSMBParm(inp, 1);
7241 offset.HighPart = 0; /* too bad */
7242 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7244 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7245 fd, offset.LowPart, count);
7247 fd = smb_ChainFID(fd, inp);
7248 fidp = smb_FindFID(vcp, fd, 0);
7250 return CM_ERROR_BADFD;
7252 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7253 smb_CloseFID(vcp, fidp, NULL, 0);
7254 smb_ReleaseFID(fidp);
7255 return CM_ERROR_NOSUCHFILE;
7258 lock_ObtainMutex(&fidp->mx);
7259 if (fidp->flags & SMB_FID_IOCTL) {
7260 lock_ReleaseMutex(&fidp->mx);
7261 code = smb_IoctlRead(fidp, vcp, inp, outp);
7262 smb_ReleaseFID(fidp);
7265 lock_ReleaseMutex(&fidp->mx);
7268 LARGE_INTEGER LOffset, LLength;
7272 key = cm_GenerateKey(vcp->vcID, pid, fd);
7274 LOffset.HighPart = 0;
7275 LOffset.LowPart = offset.LowPart;
7276 LLength.HighPart = 0;
7277 LLength.LowPart = count;
7279 lock_ObtainWrite(&fidp->scp->rw);
7280 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7281 lock_ReleaseWrite(&fidp->scp->rw);
7284 smb_ReleaseFID(fidp);
7288 userp = smb_GetUserFromVCP(vcp, inp);
7290 /* remember this for final results */
7291 smb_SetSMBParm(outp, 0, count);
7292 smb_SetSMBParm(outp, 1, 0);
7293 smb_SetSMBParm(outp, 2, 0);
7294 smb_SetSMBParm(outp, 3, 0);
7295 smb_SetSMBParm(outp, 4, 0);
7297 /* set the packet data length to 3 bytes for the data block header,
7298 * plus the size of the data.
7300 smb_SetSMBDataLength(outp, count+3);
7302 /* get op ptr after putting in the parms, since otherwise we don't
7303 * know where the data really is.
7305 op = smb_GetSMBData(outp, NULL);
7307 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7308 *op++ = 1; /* data block marker */
7309 *op++ = (unsigned char) (count & 0xff);
7310 *op++ = (unsigned char) ((count >> 8) & 0xff);
7312 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7314 /* fix some things up */
7315 smb_SetSMBParm(outp, 0, finalCount);
7316 smb_SetSMBDataLength(outp, finalCount+3);
7318 smb_ReleaseFID(fidp);
7320 cm_ReleaseUser(userp);
7324 /* SMB_COM_CREATE_DIRECTORY */
7325 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7327 clientchar_t *pathp;
7332 cm_scache_t *dscp; /* dir we're dealing with */
7333 cm_scache_t *scp; /* file we're creating */
7335 int initialModeBits;
7336 clientchar_t *lastNamep;
7338 clientchar_t *tidPathp;
7345 /* compute initial mode bits based on read-only flag in attributes */
7346 initialModeBits = 0777;
7348 tp = smb_GetSMBData(inp, NULL);
7349 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7351 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7352 return CM_ERROR_EXISTS;
7354 spacep = inp->spacep;
7355 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7357 userp = smb_GetUserFromVCP(vcp, inp);
7359 caseFold = CM_FLAG_CASEFOLD;
7361 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7363 cm_ReleaseUser(userp);
7364 return CM_ERROR_NOSUCHPATH;
7367 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7368 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7369 userp, tidPathp, &req, &dscp);
7372 cm_ReleaseUser(userp);
7377 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7378 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7379 cm_ReleaseSCache(dscp);
7380 cm_ReleaseUser(userp);
7381 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7382 return CM_ERROR_PATH_NOT_COVERED;
7384 return CM_ERROR_BADSHARENAME;
7386 #endif /* DFS_SUPPORT */
7388 /* otherwise, scp points to the parent directory. Do a lookup, and
7389 * fail if we find it. Otherwise, we do the create.
7395 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7396 if (scp) cm_ReleaseSCache(scp);
7397 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7398 if (code == 0) code = CM_ERROR_EXISTS;
7399 cm_ReleaseSCache(dscp);
7400 cm_ReleaseUser(userp);
7404 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7405 setAttr.clientModTime = time(NULL);
7406 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7407 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7408 smb_NotifyChange(FILE_ACTION_ADDED,
7409 FILE_NOTIFY_CHANGE_DIR_NAME,
7410 dscp, lastNamep, NULL, TRUE);
7412 /* we don't need this any longer */
7413 cm_ReleaseSCache(dscp);
7416 /* something went wrong creating or truncating the file */
7417 cm_ReleaseUser(userp);
7421 /* otherwise we succeeded */
7422 smb_SetSMBDataLength(outp, 0);
7423 cm_ReleaseUser(userp);
7428 BOOL smb_IsLegalFilename(clientchar_t *filename)
7431 * Find the longest substring of filename that does not contain
7432 * any of the chars in illegalChars. If that substring is less
7433 * than the length of the whole string, then one or more of the
7434 * illegal chars is in filename.
7436 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7442 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7443 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7445 clientchar_t *pathp;
7451 cm_scache_t *dscp; /* dir we're dealing with */
7452 cm_scache_t *scp; /* file we're creating */
7454 int initialModeBits;
7457 clientchar_t *lastNamep;
7460 clientchar_t *tidPathp;
7462 int created = 0; /* the file was new */
7467 excl = (inp->inCom == 0x03)? 0 : 1;
7469 attributes = smb_GetSMBParm(inp, 0);
7470 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7472 /* compute initial mode bits based on read-only flag in attributes */
7473 initialModeBits = 0666;
7474 if (attributes & SMB_ATTR_READONLY)
7475 initialModeBits &= ~0222;
7477 tp = smb_GetSMBData(inp, NULL);
7478 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7480 spacep = inp->spacep;
7481 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7483 userp = smb_GetUserFromVCP(vcp, inp);
7485 caseFold = CM_FLAG_CASEFOLD;
7487 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7489 cm_ReleaseUser(userp);
7490 return CM_ERROR_NOSUCHPATH;
7492 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7493 userp, tidPathp, &req, &dscp);
7496 cm_ReleaseUser(userp);
7501 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7502 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7503 cm_ReleaseSCache(dscp);
7504 cm_ReleaseUser(userp);
7505 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7506 return CM_ERROR_PATH_NOT_COVERED;
7508 return CM_ERROR_BADSHARENAME;
7510 #endif /* DFS_SUPPORT */
7512 /* otherwise, scp points to the parent directory. Do a lookup, and
7513 * truncate the file if we find it, otherwise we create the file.
7520 if (!smb_IsLegalFilename(lastNamep))
7521 return CM_ERROR_BADNTFILENAME;
7523 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
7524 #ifdef DEBUG_VERBOSE
7527 hexp = osi_HexifyString( lastNamep );
7528 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7533 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7534 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7535 cm_ReleaseSCache(dscp);
7536 cm_ReleaseUser(userp);
7540 /* if we get here, if code is 0, the file exists and is represented by
7541 * scp. Otherwise, we have to create it.
7545 /* oops, file shouldn't be there */
7546 cm_ReleaseSCache(dscp);
7547 cm_ReleaseSCache(scp);
7548 cm_ReleaseUser(userp);
7549 return CM_ERROR_EXISTS;
7552 setAttr.mask = CM_ATTRMASK_LENGTH;
7553 setAttr.length.LowPart = 0;
7554 setAttr.length.HighPart = 0;
7555 code = cm_SetAttr(scp, &setAttr, userp, &req);
7558 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7559 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7560 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7564 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7565 smb_NotifyChange(FILE_ACTION_ADDED,
7566 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7567 dscp, lastNamep, NULL, TRUE);
7568 } else if (!excl && code == CM_ERROR_EXISTS) {
7569 /* not an exclusive create, and someone else tried
7570 * creating it already, then we open it anyway. We
7571 * don't bother retrying after this, since if this next
7572 * fails, that means that the file was deleted after
7573 * we started this call.
7575 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7578 setAttr.mask = CM_ATTRMASK_LENGTH;
7579 setAttr.length.LowPart = 0;
7580 setAttr.length.HighPart = 0;
7581 code = cm_SetAttr(scp, &setAttr, userp, &req);
7586 /* we don't need this any longer */
7587 cm_ReleaseSCache(dscp);
7590 /* something went wrong creating or truncating the file */
7591 if (scp) cm_ReleaseSCache(scp);
7592 cm_ReleaseUser(userp);
7596 /* make sure we only open files */
7597 if (scp->fileType != CM_SCACHETYPE_FILE) {
7598 cm_ReleaseSCache(scp);
7599 cm_ReleaseUser(userp);
7600 return CM_ERROR_ISDIR;
7603 /* now all we have to do is open the file itself */
7604 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7605 osi_assertx(fidp, "null smb_fid_t");
7609 lock_ObtainMutex(&fidp->mx);
7610 /* always create it open for read/write */
7611 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7613 /* remember that the file was newly created */
7615 fidp->flags |= SMB_FID_CREATED;
7617 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7619 /* save a pointer to the vnode */
7621 lock_ObtainWrite(&scp->rw);
7622 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7623 lock_ReleaseWrite(&scp->rw);
7626 fidp->userp = userp;
7627 lock_ReleaseMutex(&fidp->mx);
7629 smb_SetSMBParm(outp, 0, fidp->fid);
7630 smb_SetSMBDataLength(outp, 0);
7632 cm_Open(scp, 0, userp);
7634 smb_ReleaseFID(fidp);
7635 cm_ReleaseUser(userp);
7636 /* leave scp held since we put it in fidp->scp */
7641 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7644 osi_hyper_t new_offset;
7655 fd = smb_GetSMBParm(inp, 0);
7656 whence = smb_GetSMBParm(inp, 1);
7657 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7659 /* try to find the file descriptor */
7660 fd = smb_ChainFID(fd, inp);
7661 fidp = smb_FindFID(vcp, fd, 0);
7663 return CM_ERROR_BADFD;
7665 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7666 smb_CloseFID(vcp, fidp, NULL, 0);
7667 smb_ReleaseFID(fidp);
7668 return CM_ERROR_NOSUCHFILE;
7671 lock_ObtainMutex(&fidp->mx);
7672 if (fidp->flags & SMB_FID_IOCTL) {
7673 lock_ReleaseMutex(&fidp->mx);
7674 smb_ReleaseFID(fidp);
7675 return CM_ERROR_BADFD;
7677 lock_ReleaseMutex(&fidp->mx);
7679 userp = smb_GetUserFromVCP(vcp, inp);
7681 lock_ObtainMutex(&fidp->mx);
7684 lock_ReleaseMutex(&fidp->mx);
7685 lock_ObtainWrite(&scp->rw);
7686 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7687 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7689 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7691 /* offset from current offset */
7692 new_offset = LargeIntegerAdd(fidp->offset,
7693 ConvertLongToLargeInteger(offset));
7695 else if (whence == 2) {
7696 /* offset from current EOF */
7697 new_offset = LargeIntegerAdd(scp->length,
7698 ConvertLongToLargeInteger(offset));
7700 new_offset = ConvertLongToLargeInteger(offset);
7703 fidp->offset = new_offset;
7704 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7705 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7706 smb_SetSMBDataLength(outp, 0);
7708 lock_ReleaseWrite(&scp->rw);
7709 smb_ReleaseFID(fidp);
7710 cm_ReleaseSCache(scp);
7711 cm_ReleaseUser(userp);
7715 /* dispatch all of the requests received in a packet. Due to chaining, this may
7716 * be more than one request.
7718 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7719 NCB *ncbp, raw_write_cont_t *rwcp)
7723 unsigned long code = 0;
7724 unsigned char *outWctp;
7725 int nparms; /* # of bytes of parameters */
7727 int nbytes; /* bytes of data, excluding count */
7730 unsigned short errCode;
7731 unsigned long NTStatus;
7733 unsigned char errClass;
7734 unsigned int oldGen;
7735 DWORD oldTime, newTime;
7737 /* get easy pointer to the data */
7738 smbp = (smb_t *) inp->data;
7740 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7741 /* setup the basic parms for the initial request in the packet */
7742 inp->inCom = smbp->com;
7743 inp->wctp = &smbp->wct;
7745 inp->ncb_length = ncbp->ncb_length;
7750 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7751 /* log it and discard it */
7752 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7753 __FILE__, __LINE__, ncbp->ncb_length);
7754 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7758 /* We are an ongoing op */
7759 thrd_Increment(&ongoingOps);
7761 /* set up response packet for receiving output */
7762 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7763 smb_FormatResponsePacket(vcp, inp, outp);
7764 outWctp = outp->wctp;
7766 /* Remember session generation number and time */
7767 oldGen = sessionGen;
7768 oldTime = GetTickCount();
7770 while (inp->inCom != 0xff) {
7771 dp = &smb_dispatchTable[inp->inCom];
7773 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7774 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7775 code = outp->resumeCode;
7779 /* process each request in the packet; inCom, wctp and inCount
7780 * are already set up.
7782 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7785 /* now do the dispatch */
7786 /* start by formatting the response record a little, as a default */
7787 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7789 outWctp[1] = 0xff; /* no operation */
7790 outWctp[2] = 0; /* padding */
7795 /* not a chained request, this is a more reasonable default */
7796 outWctp[0] = 0; /* wct of zero */
7797 outWctp[1] = 0; /* and bcc (word) of zero */
7801 /* once set, stays set. Doesn't matter, since we never chain
7802 * "no response" calls.
7804 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7808 /* we have a recognized operation */
7809 char * opName = myCrt_Dispatch(inp->inCom);
7811 if (inp->inCom == 0x1d)
7813 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7815 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
7816 opName,vcp,vcp->lana,vcp->lsn);
7817 code = (*(dp->procp)) (vcp, inp, outp);
7818 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
7819 code,vcp,vcp->lana,vcp->lsn);
7821 if ( code == CM_ERROR_BADSMB ||
7822 code == CM_ERROR_BADOP )
7824 #endif /* LOG_PACKET */
7827 newTime = GetTickCount();
7828 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
7830 if (oldGen != sessionGen) {
7831 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7832 newTime - oldTime, ncbp->ncb_length);
7833 osi_Log3(smb_logp, "Request %s straddled session startup, "
7834 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
7837 FreeSMBStrings(inp);
7839 /* bad opcode, fail the request, after displaying it */
7840 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7843 #endif /* LOG_PACKET */
7846 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7847 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7848 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7849 if (code == IDCANCEL)
7852 code = CM_ERROR_BADOP;
7855 /* catastrophic failure: log as much as possible */
7856 if (code == CM_ERROR_BADSMB) {
7857 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7861 #endif /* LOG_PACKET */
7862 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7865 code = CM_ERROR_INVAL;
7868 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7869 thrd_Decrement(&ongoingOps);
7874 /* now, if we failed, turn the current response into an empty
7875 * one, and fill in the response packet's error code.
7878 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7879 smb_MapNTError(code, &NTStatus);
7880 outWctp = outp->wctp;
7881 smbp = (smb_t *) &outp->data;
7882 if (code != CM_ERROR_PARTIALWRITE
7883 && code != CM_ERROR_BUFFERTOOSMALL
7884 && code != CM_ERROR_GSSCONTINUE) {
7885 /* nuke wct and bcc. For a partial
7886 * write or an in-process authentication handshake,
7887 * assume they're OK.
7893 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7894 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7895 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7896 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7897 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7901 smb_MapCoreError(code, vcp, &errCode, &errClass);
7902 outWctp = outp->wctp;
7903 smbp = (smb_t *) &outp->data;
7904 if (code != CM_ERROR_PARTIALWRITE) {
7905 /* nuke wct and bcc. For a partial
7906 * write, assume they're OK.
7912 smbp->errLow = (unsigned char) (errCode & 0xff);
7913 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7914 smbp->rcls = errClass;
7917 } /* error occurred */
7919 /* if we're here, we've finished one request. Look to see if
7920 * this is a chained opcode. If it is, setup things to process
7921 * the chained request, and setup the output buffer to hold the
7922 * chained response. Start by finding the next input record.
7924 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7925 break; /* not a chained req */
7926 tp = inp->wctp; /* points to start of last request */
7927 /* in a chained request, the first two
7928 * parm fields are required, and are
7929 * AndXCommand/AndXReserved and
7931 if (tp[0] < 2) break;
7932 if (tp[1] == 0xff) break; /* no more chained opcodes */
7934 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7937 /* and now append the next output request to the end of this
7938 * last request. Begin by finding out where the last response
7939 * ends, since that's where we'll put our new response.
7941 outWctp = outp->wctp; /* ptr to out parameters */
7942 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7943 nparms = outWctp[0] << 1;
7944 tp = outWctp + nparms + 1; /* now points to bcc field */
7945 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7946 tp += 2 /* for the count itself */ + nbytes;
7947 /* tp now points to the new output record; go back and patch the
7948 * second parameter (off2) to point to the new record.
7950 temp = (unsigned int)(tp - outp->data);
7951 outWctp[3] = (unsigned char) (temp & 0xff);
7952 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7953 outWctp[2] = 0; /* padding */
7954 outWctp[1] = inp->inCom; /* next opcode */
7956 /* finally, setup for the next iteration */
7959 } /* while loop over all requests in the packet */
7961 /* now send the output packet, and return */
7963 smb_SendPacket(vcp, outp);
7964 thrd_Decrement(&ongoingOps);
7969 /* Wait for Netbios() calls to return, and make the results available to server
7970 * threads. Note that server threads can't wait on the NCBevents array
7971 * themselves, because NCB events are manual-reset, and the servers would race
7972 * each other to reset them.
7974 void smb_ClientWaiter(void *parmp)
7979 while (smbShutdownFlag == 0) {
7980 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7982 if (code == WAIT_OBJECT_0)
7985 /* error checking */
7986 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7988 int abandonIdx = code - WAIT_ABANDONED_0;
7989 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7992 if (code == WAIT_IO_COMPLETION)
7994 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7998 if (code == WAIT_TIMEOUT)
8000 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8003 if (code == WAIT_FAILED)
8005 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8008 idx = code - WAIT_OBJECT_0;
8010 /* check idx range! */
8011 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8013 /* this is fatal - log as much as possible */
8014 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8015 osi_assertx(0, "invalid index");
8018 thrd_ResetEvent(NCBevents[idx]);
8019 thrd_SetEvent(NCBreturns[0][idx]);
8024 * Try to have one NCBRECV request waiting for every live session. Not more
8025 * than one, because if there is more than one, it's hard to handle Write Raw.
8027 void smb_ServerWaiter(void *parmp)
8030 int idx_session, idx_NCB;
8033 while (smbShutdownFlag == 0) {
8035 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8037 if (code == WAIT_OBJECT_0)
8040 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8042 int abandonIdx = code - WAIT_ABANDONED_0;
8043 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8046 if (code == WAIT_IO_COMPLETION)
8048 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8052 if (code == WAIT_TIMEOUT)
8054 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8057 if (code == WAIT_FAILED)
8059 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8062 idx_session = code - WAIT_OBJECT_0;
8064 /* check idx range! */
8065 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8067 /* this is fatal - log as much as possible */
8068 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8069 osi_assertx(0, "invalid index");
8074 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8076 if (code == WAIT_OBJECT_0) {
8077 if (smbShutdownFlag == 1)
8083 /* error checking */
8084 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8086 int abandonIdx = code - WAIT_ABANDONED_0;
8087 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8090 if (code == WAIT_IO_COMPLETION)
8092 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8096 if (code == WAIT_TIMEOUT)
8098 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8101 if (code == WAIT_FAILED)
8103 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8106 idx_NCB = code - WAIT_OBJECT_0;
8108 /* check idx range! */
8109 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8111 /* this is fatal - log as much as possible */
8112 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8113 osi_assertx(0, "invalid index");
8116 /* Link them together */
8117 NCBsessions[idx_NCB] = idx_session;
8120 ncbp = NCBs[idx_NCB];
8121 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8122 ncbp->ncb_command = NCBRECV | ASYNCH;
8123 ncbp->ncb_lana_num = lanas[idx_session];
8124 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8125 ncbp->ncb_event = NCBevents[idx_NCB];
8126 ncbp->ncb_length = SMB_PACKETSIZE;
8132 * The top level loop for handling SMB request messages. Each server thread
8133 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8134 * NCB and buffer for the incoming request are loaned to us.
8136 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8137 * to immediately send a request for the rest of the data. This must come
8138 * before any other traffic for that session, so we delay setting the session
8139 * event until that data has come in.
8141 void smb_Server(VOID *parmp)
8143 INT_PTR myIdx = (INT_PTR) parmp;
8147 smb_packet_t *outbufp;
8149 int idx_NCB, idx_session;
8151 smb_vc_t *vcp = NULL;
8153 extern void rx_StartClientThread(void);
8155 rx_StartClientThread();
8158 outbufp = GetPacket();
8159 outbufp->ncbp = outncbp;
8167 smb_ResetServerPriority();
8169 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8172 /* terminate silently if shutdown flag is set */
8173 if (code == WAIT_OBJECT_0) {
8174 if (smbShutdownFlag == 1) {
8175 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8181 /* error checking */
8182 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8184 int abandonIdx = code - WAIT_ABANDONED_0;
8185 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8188 if (code == WAIT_IO_COMPLETION)
8190 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8194 if (code == WAIT_TIMEOUT)
8196 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8199 if (code == WAIT_FAILED)
8201 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8204 idx_NCB = code - WAIT_OBJECT_0;
8206 /* check idx range! */
8207 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8209 /* this is fatal - log as much as possible */
8210 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8211 osi_assertx(0, "invalid index");
8214 ncbp = NCBs[idx_NCB];
8215 idx_session = NCBsessions[idx_NCB];
8216 rc = ncbp->ncb_retcode;
8218 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8219 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8223 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8227 /* Can this happen? Or is it just my UNIX paranoia? */
8228 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8233 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8236 /* Client closed session */
8237 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8239 lock_ObtainMutex(&vcp->mx);
8240 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8241 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8243 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8244 lock_ReleaseMutex(&vcp->mx);
8245 lock_ObtainWrite(&smb_globalLock);
8246 dead_sessions[vcp->session] = TRUE;
8247 lock_ReleaseWrite(&smb_globalLock);
8248 smb_CleanupDeadVC(vcp);
8252 lock_ReleaseMutex(&vcp->mx);
8258 /* Treat as transient error */
8259 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8262 "dispatch smb recv failed, message incomplete, ncb_length %d",
8265 "SMB message incomplete, "
8266 "length %d", ncbp->ncb_length);
8269 * We used to discard the packet.
8270 * Instead, try handling it normally.
8274 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8278 /* A weird error code. Log it, sleep, and continue. */
8279 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8281 lock_ObtainMutex(&vcp->mx);
8282 if (vcp && vcp->errorCount++ > 3) {
8283 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8284 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8285 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8287 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8288 lock_ReleaseMutex(&vcp->mx);
8289 lock_ObtainWrite(&smb_globalLock);
8290 dead_sessions[vcp->session] = TRUE;
8291 lock_ReleaseWrite(&smb_globalLock);
8292 smb_CleanupDeadVC(vcp);
8296 lock_ReleaseMutex(&vcp->mx);
8302 lock_ReleaseMutex(&vcp->mx);
8304 thrd_SetEvent(SessionEvents[idx_session]);
8309 /* Success, so now dispatch on all the data in the packet */
8311 smb_concurrentCalls++;
8312 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8313 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8316 * If at this point vcp is NULL (implies that packet was invalid)
8317 * then we are in big trouble. This means either :
8318 * a) we have the wrong NCB.
8319 * b) Netbios screwed up the call.
8320 * c) The VC was already marked dead before we were able to
8322 * Obviously this implies that
8323 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8324 * lanas[idx_session] != ncbp->ncb_lana_num )
8325 * Either way, we can't do anything with this packet.
8326 * Log, sleep and resume.
8329 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8333 ncbp->ncb_lana_num);
8335 /* Also log in the trace log. */
8336 osi_Log4(smb_logp, "Server: VCP does not exist!"
8337 "LSNs[idx_session]=[%d],"
8338 "lanas[idx_session]=[%d],"
8339 "ncbp->ncb_lsn=[%d],"
8340 "ncbp->ncb_lana_num=[%d]",
8344 ncbp->ncb_lana_num);
8346 /* thrd_Sleep(1000); Don't bother sleeping */
8347 thrd_SetEvent(SessionEvents[idx_session]);
8348 smb_concurrentCalls--;
8352 smb_SetRequestStartTime();
8354 vcp->errorCount = 0;
8355 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8356 smbp = (smb_t *)bufp->data;
8363 if (smbp->com == 0x1d) {
8364 /* Special handling for Write Raw */
8365 raw_write_cont_t rwc;
8366 EVENT_HANDLE rwevent;
8367 char eventName[MAX_PATH];
8369 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8370 if (rwc.code == 0) {
8371 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8372 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8373 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8374 ncbp->ncb_command = NCBRECV | ASYNCH;
8375 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8376 ncbp->ncb_lana_num = vcp->lana;
8377 ncbp->ncb_buffer = rwc.buf;
8378 ncbp->ncb_length = 65535;
8379 ncbp->ncb_event = rwevent;
8381 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8382 thrd_CloseHandle(rwevent);
8384 thrd_SetEvent(SessionEvents[idx_session]);
8386 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8388 else if (smbp->com == 0xa0) {
8390 * Serialize the handling for NT Transact
8393 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8394 thrd_SetEvent(SessionEvents[idx_session]);
8396 thrd_SetEvent(SessionEvents[idx_session]);
8397 /* TODO: what else needs to be serialized? */
8398 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8402 __except( smb_ServerExceptionFilter() ) {
8406 smb_concurrentCalls--;
8409 thrd_SetEvent(NCBavails[idx_NCB]);
8416 * Exception filter for the server threads. If an exception occurs in the
8417 * dispatch routines, which is where exceptions are most common, then do a
8418 * force trace and give control to upstream exception handlers. Useful for
8421 DWORD smb_ServerExceptionFilter(void) {
8422 /* While this is not the best time to do a trace, if it succeeds, then
8423 * we have a trace (assuming tracing was enabled). Otherwise, this should
8424 * throw a second exception.
8426 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8427 afsd_ForceTrace(TRUE);
8428 buf_ForceTrace(TRUE);
8429 return EXCEPTION_CONTINUE_SEARCH;
8433 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8434 * If the number of server threads is M, and the number of live sessions is
8435 * N, then the number of NCB's in use at any time either waiting for, or
8436 * holding, received messages is M + N, so that is how many NCB's get created.
8438 void InitNCBslot(int idx)
8440 struct smb_packet *bufp;
8441 EVENT_HANDLE retHandle;
8443 char eventName[MAX_PATH];
8445 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8447 NCBs[idx] = GetNCB();
8448 sprintf(eventName,"NCBavails[%d]", idx);
8449 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8450 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8451 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8452 sprintf(eventName,"NCBevents[%d]", idx);
8453 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8454 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8455 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8456 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8457 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8458 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8459 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8460 for (i=0; i<smb_NumServerThreads; i++)
8461 NCBreturns[i][idx] = retHandle;
8463 bufp->spacep = cm_GetSpace();
8467 /* listen for new connections */
8468 void smb_Listener(void *parmp)
8474 afs_uint32 session, thread;
8475 smb_vc_t *vcp = NULL;
8477 char rname[NCBNAMSZ+1];
8478 char cname[MAX_COMPUTERNAME_LENGTH+1];
8479 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8480 INT_PTR lana = (INT_PTR) parmp;
8481 char eventName[MAX_PATH];
8483 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
8484 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8485 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8486 thrd_ResetEvent(ListenerShutdown[lana]);
8490 /* retrieve computer name */
8491 GetComputerName(cname, &cnamelen);
8494 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8495 memset(ncbp, 0, sizeof(NCB));
8498 ncbp->ncb_command = NCBLISTEN;
8499 ncbp->ncb_rto = 0; /* No receive timeout */
8500 ncbp->ncb_sto = 0; /* No send timeout */
8502 /* pad out with spaces instead of null termination */
8503 len = (long)strlen(smb_localNamep);
8504 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8505 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8507 strcpy(ncbp->ncb_callname, "*");
8508 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8510 ncbp->ncb_lana_num = (UCHAR)lana;
8512 code = Netbios(ncbp);
8514 if (code == NRC_NAMERR) {
8515 /* An smb shutdown or Vista resume must have taken place */
8517 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8518 ncbp->ncb_lana_num, code);
8520 if (lock_TryMutex(&smb_StartedLock)) {
8521 lana_list.lana[i] = LANA_INVALID;
8522 lock_ReleaseMutex(&smb_StartedLock);
8525 } else if (code == NRC_BRIDGE || code != 0) {
8526 int lanaRemaining = 0;
8528 while (!lock_TryMutex(&smb_StartedLock)) {
8529 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8535 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8536 ncbp->ncb_lana_num, ncb_error_string(code));
8538 for (i = 0; i < lana_list.length; i++) {
8539 if (lana_list.lana[i] == lana) {
8540 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8541 lana_list.lana[i] = LANA_INVALID;
8543 if (lana_list.lana[i] != LANA_INVALID)
8547 if (lanaRemaining == 0) {
8548 cm_VolStatus_Network_Stopped(cm_NetbiosName
8553 smb_ListenerState = SMB_LISTENER_STOPPED;
8554 smb_LANadapter = LANA_INVALID;
8555 lana_list.length = 0;
8557 lock_ReleaseMutex(&smb_StartedLock);
8561 else if (code != 0) {
8562 char tbuffer[AFSPATHMAX];
8564 /* terminate silently if shutdown flag is set */
8565 while (!lock_TryMutex(&smb_StartedLock)) {
8566 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8572 "NCBLISTEN lana=%d failed with code %d [%s]",
8573 ncbp->ncb_lana_num, code, ncb_error_string(code));
8575 "Client exiting due to network failure. Please restart client.\n");
8578 "Client exiting due to network failure. Please restart client.\n"
8579 "NCBLISTEN lana=%d failed with code %d [%s]",
8580 ncbp->ncb_lana_num, code, ncb_error_string(code));
8582 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8583 MB_OK|MB_SERVICE_NOTIFICATION);
8584 osi_panic(tbuffer, __FILE__, __LINE__);
8586 lock_ReleaseMutex(&smb_StartedLock);
8591 /* check for remote conns */
8592 /* first get remote name and insert null terminator */
8593 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8594 for (i=NCBNAMSZ; i>0; i--) {
8595 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8601 /* compare with local name */
8603 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8604 flags |= SMB_VCFLAG_REMOTECONN;
8607 lock_ObtainMutex(&smb_ListenerLock);
8609 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8610 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8612 /* now ncbp->ncb_lsn is the connection ID */
8613 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8614 if (vcp->session == 0) {
8615 /* New generation */
8616 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8619 /* Log session startup */
8621 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8622 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8623 #endif /* NOTSERVICE */
8624 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8625 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8627 if (reportSessionStartups) {
8628 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8631 lock_ObtainMutex(&vcp->mx);
8632 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
8633 vcp->flags |= flags;
8634 lock_ReleaseMutex(&vcp->mx);
8636 /* Allocate slot in session arrays */
8637 /* Re-use dead session if possible, otherwise add one more */
8638 /* But don't look at session[0], it is reserved */
8639 lock_ObtainWrite(&smb_globalLock);
8640 for (session = 1; session < numSessions; session++) {
8641 if (dead_sessions[session]) {
8642 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8643 dead_sessions[session] = FALSE;
8647 lock_ReleaseWrite(&smb_globalLock);
8649 /* We are re-using an existing VC because the lsn and lana
8651 session = vcp->session;
8653 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8655 /* Log session startup */
8657 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8658 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8659 #endif /* NOTSERVICE */
8660 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8661 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8663 if (reportSessionStartups) {
8664 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8668 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8669 unsigned long code = CM_ERROR_ALLBUSY;
8670 smb_packet_t * outp = GetPacket();
8671 unsigned char *outWctp;
8674 smb_FormatResponsePacket(vcp, NULL, outp);
8677 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8678 unsigned long NTStatus;
8679 smb_MapNTError(code, &NTStatus);
8680 outWctp = outp->wctp;
8681 smbp = (smb_t *) &outp->data;
8685 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8686 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8687 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8688 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8689 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8691 unsigned short errCode;
8692 unsigned char errClass;
8693 smb_MapCoreError(code, vcp, &errCode, &errClass);
8694 outWctp = outp->wctp;
8695 smbp = (smb_t *) &outp->data;
8699 smbp->errLow = (unsigned char) (errCode & 0xff);
8700 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8701 smbp->rcls = errClass;
8704 smb_SendPacket(vcp, outp);
8705 smb_FreePacket(outp);
8707 lock_ObtainMutex(&vcp->mx);
8708 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8709 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8711 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8712 lock_ReleaseMutex(&vcp->mx);
8713 lock_ObtainWrite(&smb_globalLock);
8714 dead_sessions[vcp->session] = TRUE;
8715 lock_ReleaseWrite(&smb_globalLock);
8716 smb_CleanupDeadVC(vcp);
8718 lock_ReleaseMutex(&vcp->mx);
8721 /* assert that we do not exceed the maximum number of sessions or NCBs.
8722 * we should probably want to wait for a session to be freed in case
8725 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8726 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8728 lock_ObtainMutex(&vcp->mx);
8729 vcp->session = session;
8730 lock_ReleaseMutex(&vcp->mx);
8731 lock_ObtainWrite(&smb_globalLock);
8732 LSNs[session] = ncbp->ncb_lsn;
8733 lanas[session] = ncbp->ncb_lana_num;
8734 lock_ReleaseWrite(&smb_globalLock);
8736 if (session == numSessions) {
8737 /* Add new NCB for new session */
8738 char eventName[MAX_PATH];
8740 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8742 InitNCBslot(numNCBs);
8743 lock_ObtainWrite(&smb_globalLock);
8745 lock_ReleaseWrite(&smb_globalLock);
8746 thrd_SetEvent(NCBavails[0]);
8747 thrd_SetEvent(NCBevents[0]);
8748 for (thread = 0; thread < smb_NumServerThreads; thread++)
8749 thrd_SetEvent(NCBreturns[thread][0]);
8750 /* Also add new session event */
8751 sprintf(eventName, "SessionEvents[%d]", session);
8752 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8753 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8754 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8755 lock_ObtainWrite(&smb_globalLock);
8757 lock_ReleaseWrite(&smb_globalLock);
8758 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8759 thrd_SetEvent(SessionEvents[0]);
8761 thrd_SetEvent(SessionEvents[session]);
8767 lock_ReleaseMutex(&smb_ListenerLock);
8768 } /* dispatch while loop */
8772 thrd_SetEvent(ListenerShutdown[lana]);
8777 smb_LanAdapterChangeThread(void *param)
8780 * Give the IPAddrDaemon thread a chance
8781 * to block before we trigger.
8784 smb_LanAdapterChange(0);
8787 void smb_SetLanAdapterChangeDetected(void)
8792 lock_ObtainMutex(&smb_StartedLock);
8794 if (!powerStateSuspended) {
8795 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
8796 NULL, 0, &lpid, "smb_LanAdapterChange");
8797 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
8798 thrd_CloseHandle(phandle);
8801 smb_LanAdapterChangeDetected = 1;
8802 lock_ReleaseMutex(&smb_StartedLock);
8805 void smb_LanAdapterChange(int locked) {
8806 lana_number_t lanaNum;
8808 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
8810 LANA_ENUM temp_list;
8815 afsi_log("smb_LanAdapterChange");
8818 lock_ObtainMutex(&smb_StartedLock);
8820 smb_LanAdapterChangeDetected = 0;
8822 if (!powerStateSuspended &&
8823 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
8824 LANA_NETBIOS_NAME_FULL)) &&
8825 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
8826 if ( isGateway != bGateway ||
8827 strcmp(cm_NetbiosName, NetbiosName) ) {
8830 NCB *ncbp = GetNCB();
8831 ncbp->ncb_command = NCBENUM;
8832 ncbp->ncb_buffer = (PUCHAR)&temp_list;
8833 ncbp->ncb_length = sizeof(temp_list);
8834 code = Netbios(ncbp);
8836 if (temp_list.length != lana_list.length)
8839 for (i=0; i<lana_list.length; i++) {
8840 if ( temp_list.lana[i] != lana_list.lana[i] ) {
8852 afsi_log("Lan Adapter Change detected");
8853 smb_StopListeners(1);
8854 smb_RestartListeners(1);
8857 lock_ReleaseMutex(&smb_StartedLock);
8860 /* initialize Netbios */
8861 int smb_NetbiosInit(int locked)
8864 int i, lana, code, l;
8866 int delname_tried=0;
8869 lana_number_t lanaNum;
8872 lock_ObtainMutex(&smb_StartedLock);
8874 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
8875 smb_ListenerState != SMB_LISTENER_STOPPED) {
8878 lock_ReleaseMutex(&smb_StartedLock);
8881 /* setup the NCB system */
8884 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8885 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8886 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8888 if (smb_LANadapter != LANA_INVALID)
8889 afsi_log("LAN adapter number %d", smb_LANadapter);
8891 afsi_log("LAN adapter number not determined");
8894 afsi_log("Set for gateway service");
8896 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8898 /* something went horribly wrong. We can't proceed without a netbios name */
8900 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8901 osi_panic(buf, __FILE__, __LINE__);
8904 /* remember the name */
8905 len = (int)strlen(cm_NetbiosName);
8907 free(smb_localNamep);
8908 smb_localNamep = malloc(len+1);
8909 strcpy(smb_localNamep, cm_NetbiosName);
8910 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8912 /* Also copy the value to the client character encoded string */
8913 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
8915 if (smb_LANadapter == LANA_INVALID) {
8916 ncbp->ncb_command = NCBENUM;
8917 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8918 ncbp->ncb_length = sizeof(lana_list);
8919 code = Netbios(ncbp);
8921 afsi_log("Netbios NCBENUM error code %d", code);
8922 osi_panic(s, __FILE__, __LINE__);
8926 lana_list.length = 1;
8927 lana_list.lana[0] = smb_LANadapter;
8930 for (i = 0; i < lana_list.length; i++) {
8931 /* reset the adaptor: in Win32, this is required for every process, and
8932 * acts as an init call, not as a real hardware reset.
8934 ncbp->ncb_command = NCBRESET;
8935 ncbp->ncb_callname[0] = 100;
8936 ncbp->ncb_callname[2] = 100;
8937 ncbp->ncb_lana_num = lana_list.lana[i];
8938 code = Netbios(ncbp);
8940 code = ncbp->ncb_retcode;
8942 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8943 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
8945 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8949 /* and declare our name so we can receive connections */
8950 memset(ncbp, 0, sizeof(*ncbp));
8951 len=lstrlen(smb_localNamep);
8952 memset(smb_sharename,' ',NCBNAMSZ);
8953 memcpy(smb_sharename,smb_localNamep,len);
8954 afsi_log("lana_list.length %d", lana_list.length);
8956 /* Keep the name so we can unregister it later */
8957 for (l = 0; l < lana_list.length; l++) {
8958 lana = lana_list.lana[l];
8960 ncbp->ncb_command = NCBADDNAME;
8961 ncbp->ncb_lana_num = lana;
8962 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8963 code = Netbios(ncbp);
8965 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8966 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8968 char name[NCBNAMSZ+1];
8970 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8971 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8975 code = ncbp->ncb_retcode;
8978 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8981 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8982 if (code == NRC_BRIDGE) { /* invalid LANA num */
8983 lana_list.lana[l] = LANA_INVALID;
8986 else if (code == NRC_DUPNAME) {
8987 afsi_log("Name already exists; try to delete it");
8988 memset(ncbp, 0, sizeof(*ncbp));
8989 ncbp->ncb_command = NCBDELNAME;
8990 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8991 ncbp->ncb_lana_num = lana;
8992 code = Netbios(ncbp);
8994 code = ncbp->ncb_retcode;
8996 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8998 if (code != 0 || delname_tried) {
8999 lana_list.lana[l] = LANA_INVALID;
9001 else if (code == 0) {
9002 if (!delname_tried) {
9010 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9011 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9015 smb_LANadapter = lana;
9016 lana_found = 1; /* at least one worked */
9020 osi_assertx(lana_list.length >= 0, "empty lana list");
9022 afsi_log("No valid LANA numbers found!");
9023 lana_list.length = 0;
9024 smb_LANadapter = LANA_INVALID;
9025 smb_ListenerState = SMB_LISTENER_STOPPED;
9026 cm_VolStatus_Network_Stopped(cm_NetbiosName
9033 /* we're done with the NCB now */
9036 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9037 if (lana_list.length > 0)
9038 osi_assert(smb_LANadapter != LANA_INVALID);
9041 lock_ReleaseMutex(&smb_StartedLock);
9043 return (lana_list.length > 0 ? 1 : 0);
9046 void smb_StartListeners(int locked)
9053 lock_ObtainMutex(&smb_StartedLock);
9055 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9057 lock_ReleaseMutex(&smb_StartedLock);
9061 afsi_log("smb_StartListeners");
9062 smb_ListenerState = SMB_LISTENER_STARTED;
9063 cm_VolStatus_Network_Started(cm_NetbiosName
9069 for (i = 0; i < lana_list.length; i++) {
9070 if (lana_list.lana[i] == LANA_INVALID)
9072 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9073 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9074 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9075 thrd_CloseHandle(phandle);
9078 lock_ReleaseMutex(&smb_StartedLock);
9081 void smb_RestartListeners(int locked)
9084 lock_ObtainMutex(&smb_StartedLock);
9086 if (powerStateSuspended)
9087 afsi_log("smb_RestartListeners called while suspended");
9089 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9090 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9091 if (smb_NetbiosInit(1))
9092 smb_StartListeners(1);
9093 } else if (smb_LanAdapterChangeDetected) {
9094 smb_LanAdapterChange(1);
9098 lock_ReleaseMutex(&smb_StartedLock);
9101 void smb_StopListener(NCB *ncbp, int lana, int wait)
9105 memset(ncbp, 0, sizeof(*ncbp));
9106 ncbp->ncb_command = NCBDELNAME;
9107 ncbp->ncb_lana_num = lana;
9108 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9109 code = Netbios(ncbp);
9111 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9112 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9114 /* and then reset the LANA; this will cause the listener threads to exit */
9115 ncbp->ncb_command = NCBRESET;
9116 ncbp->ncb_callname[0] = 100;
9117 ncbp->ncb_callname[2] = 100;
9118 ncbp->ncb_lana_num = lana;
9119 code = Netbios(ncbp);
9121 code = ncbp->ncb_retcode;
9123 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
9125 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
9129 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9132 void smb_StopListeners(int locked)
9138 lock_ObtainMutex(&smb_StartedLock);
9140 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9142 lock_ReleaseMutex(&smb_StartedLock);
9146 afsi_log("smb_StopListeners");
9147 smb_ListenerState = SMB_LISTENER_STOPPED;
9148 cm_VolStatus_Network_Stopped(cm_NetbiosName
9156 /* Unregister the SMB name */
9157 for (l = 0; l < lana_list.length; l++) {
9158 lana = lana_list.lana[l];
9160 if (lana != LANA_INVALID) {
9161 smb_StopListener(ncbp, lana, TRUE);
9163 /* mark the adapter invalid */
9164 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9168 /* force a re-evaluation of the network adapters */
9169 lana_list.length = 0;
9170 smb_LANadapter = LANA_INVALID;
9173 lock_ReleaseMutex(&smb_StartedLock);
9176 void smb_Init(osi_log_t *logp, int useV3,
9186 EVENT_HANDLE retHandle;
9187 char eventName[MAX_PATH];
9188 int startListeners = 0;
9190 smb_TlsRequestSlot = TlsAlloc();
9192 smb_MBfunc = aMBfunc;
9196 /* Initialize smb_localZero */
9197 myTime.tm_isdst = -1; /* compute whether on DST or not */
9198 myTime.tm_year = 70;
9204 smb_localZero = mktime(&myTime);
9206 #ifndef USE_NUMERIC_TIME_CONV
9207 /* Initialize kludge-GMT */
9208 smb_CalculateNowTZ();
9209 #endif /* USE_NUMERIC_TIME_CONV */
9210 #ifdef AFS_FREELANCE_CLIENT
9211 /* Make sure the root.afs volume has the correct time */
9212 cm_noteLocalMountPointChange();
9215 /* initialize the remote debugging log */
9218 /* and the global lock */
9219 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
9220 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
9222 /* Raw I/O data structures */
9223 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
9225 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
9226 lock_InitializeMutex(&smb_StartedLock, "smb started lock");
9228 /* 4 Raw I/O buffers */
9229 smb_RawBufs = calloc(65536,1);
9230 *((char **)smb_RawBufs) = NULL;
9231 for (i=0; i<3; i++) {
9232 char *rawBuf = calloc(65536,1);
9233 *((char **)rawBuf) = smb_RawBufs;
9234 smb_RawBufs = rawBuf;
9237 /* global free lists */
9238 smb_ncbFreeListp = NULL;
9239 smb_packetFreeListp = NULL;
9241 lock_ObtainMutex(&smb_StartedLock);
9242 startListeners = smb_NetbiosInit(1);
9244 /* Initialize listener and server structures */
9246 memset(dead_sessions, 0, sizeof(dead_sessions));
9247 sprintf(eventName, "SessionEvents[0]");
9248 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9249 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9250 afsi_log("Event Object Already Exists: %s", eventName);
9252 smb_NumServerThreads = nThreads;
9253 sprintf(eventName, "NCBavails[0]");
9254 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9255 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9256 afsi_log("Event Object Already Exists: %s", eventName);
9257 sprintf(eventName, "NCBevents[0]");
9258 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9259 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9260 afsi_log("Event Object Already Exists: %s", eventName);
9261 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9262 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9263 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9264 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9265 afsi_log("Event Object Already Exists: %s", eventName);
9266 for (i = 0; i < smb_NumServerThreads; i++) {
9267 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9268 NCBreturns[i][0] = retHandle;
9271 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9272 for (i = 0; i < smb_NumServerThreads; i++) {
9273 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9274 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9275 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9276 afsi_log("Event Object Already Exists: %s", eventName);
9277 InitNCBslot((int)(i+1));
9279 numNCBs = smb_NumServerThreads + 1;
9281 /* Initialize dispatch table */
9282 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9283 /* Prepare the table for unknown operations */
9284 for(i=0; i<= SMB_NOPCODES; i++) {
9285 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9287 /* Fill in the ones we do know */
9288 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9289 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9290 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9291 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9292 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9293 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9294 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9295 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9296 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9297 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9298 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9299 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9300 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9301 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9302 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9303 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9304 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9305 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9306 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9307 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9308 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9309 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9310 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9311 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9312 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9313 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9314 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9315 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9316 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9317 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9318 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9319 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9320 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9321 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9322 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9323 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9324 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9325 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9326 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9327 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9328 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9329 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9330 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9331 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9332 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9333 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9334 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9335 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9336 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9337 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9338 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9339 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9340 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9341 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9342 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9343 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9344 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9345 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9346 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9347 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9348 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9349 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9350 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9351 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9352 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9353 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9354 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9355 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9356 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9357 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9358 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9359 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9360 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9361 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9363 /* setup tran 2 dispatch table */
9364 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9365 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9366 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9367 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9368 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9369 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9370 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9371 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9372 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9373 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9374 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9375 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9376 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9377 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9378 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9379 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9380 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9381 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9383 /* setup the rap dispatch table */
9384 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9385 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9386 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9387 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9388 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9392 /* if we are doing SMB authentication we have register outselves as a logon process */
9393 if (smb_authType != SMB_AUTH_NONE) {
9394 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9395 LSA_STRING afsProcessName;
9396 LSA_OPERATIONAL_MODE dummy; /*junk*/
9398 afsProcessName.Buffer = "OpenAFSClientDaemon";
9399 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9400 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9402 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9404 if (nts == STATUS_SUCCESS) {
9405 LSA_STRING packageName;
9406 /* we are registered. Find out the security package id */
9407 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9408 packageName.Length = (USHORT)strlen(packageName.Buffer);
9409 packageName.MaximumLength = packageName.Length + 1;
9410 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9411 if (nts == STATUS_SUCCESS) {
9413 * This code forces Windows to authenticate against the Logon Cache
9414 * first instead of attempting to authenticate against the Domain
9415 * Controller. When the Windows logon cache is enabled this improves
9416 * performance by removing the network access and works around a bug
9417 * seen at sites which are using a MIT Kerberos principal to login
9418 * to machines joined to a non-root domain in a multi-domain forest.
9419 * MsV1_0SetProcessOption was added in Windows XP.
9421 PVOID pResponse = NULL;
9422 ULONG cbResponse = 0;
9423 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9425 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9426 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9427 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9428 OptionsRequest.DisableOptions = FALSE;
9430 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9433 sizeof(OptionsRequest),
9439 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9440 char message[AFSPATHMAX];
9441 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9443 OutputDebugString(message);
9446 OutputDebugString("MsV1_0SetProcessOption success");
9447 afsi_log("MsV1_0SetProcessOption success");
9449 /* END - code from Larry */
9451 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9452 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9453 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9455 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9457 /* something went wrong. We report the error and revert back to no authentication
9458 because we can't perform any auth requests without a successful lsa handle
9459 or sec package id. */
9460 afsi_log("Reverting to NO SMB AUTH");
9461 smb_authType = SMB_AUTH_NONE;
9464 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9466 /* something went wrong. We report the error and revert back to no authentication
9467 because we can't perform any auth requests without a successful lsa handle
9468 or sec package id. */
9469 afsi_log("Reverting to NO SMB AUTH");
9470 smb_authType = SMB_AUTH_NONE;
9474 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9475 * time prevents the failure of authentication when logged into Windows with an
9476 * external Kerberos principal mapped to a local account.
9478 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9479 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9480 * then the only option is NTLMSSP anyway; so just fallback.
9485 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9486 if (secBlobLength == 0) {
9487 smb_authType = SMB_AUTH_NTLM;
9488 afsi_log("Reverting to SMB AUTH NTLM");
9497 /* Now get ourselves a domain name. */
9498 /* For now we are using the local computer name as the domain name.
9499 * It is actually the domain for local logins, and we are acting as
9500 * a local SMB server.
9502 bufsize = lengthof(smb_ServerDomainName) - 1;
9503 GetComputerNameW(smb_ServerDomainName, &bufsize);
9504 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9505 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
9508 /* Start listeners, waiters, servers, and daemons */
9510 smb_StartListeners(1);
9512 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9513 NULL, 0, &lpid, "smb_ClientWaiter");
9514 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9515 thrd_CloseHandle(phandle);
9517 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9518 NULL, 0, &lpid, "smb_ServerWaiter");
9519 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9520 thrd_CloseHandle(phandle);
9522 for (i=0; i<smb_NumServerThreads; i++) {
9523 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9524 (void *) i, 0, &lpid, "smb_Server");
9525 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9526 thrd_CloseHandle(phandle);
9529 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9530 NULL, 0, &lpid, "smb_Daemon");
9531 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9532 thrd_CloseHandle(phandle);
9534 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9535 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9536 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9537 thrd_CloseHandle(phandle);
9539 lock_ReleaseMutex(&smb_StartedLock);
9543 void smb_Shutdown(void)
9550 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9552 /* setup the NCB system */
9555 /* Block new sessions by setting shutdown flag */
9556 smbShutdownFlag = 1;
9558 /* Hang up all sessions */
9559 memset((char *)ncbp, 0, sizeof(NCB));
9560 for (i = 1; i < numSessions; i++)
9562 if (dead_sessions[i])
9565 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9566 ncbp->ncb_command = NCBHANGUP;
9567 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9568 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9569 code = Netbios(ncbp);
9570 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9571 if (code == 0) code = ncbp->ncb_retcode;
9573 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9574 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9578 /* Trigger the shutdown of all SMB threads */
9579 for (i = 0; i < smb_NumServerThreads; i++)
9580 thrd_SetEvent(NCBreturns[i][0]);
9582 thrd_SetEvent(NCBevents[0]);
9583 thrd_SetEvent(SessionEvents[0]);
9584 thrd_SetEvent(NCBavails[0]);
9586 for (i = 0;i < smb_NumServerThreads; i++) {
9587 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9588 if (code == WAIT_OBJECT_0) {
9591 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9592 thrd_SetEvent(NCBreturns[i--][0]);
9596 /* Delete Netbios name */
9597 memset((char *)ncbp, 0, sizeof(NCB));
9598 for (i = 0; i < lana_list.length; i++) {
9599 if (lana_list.lana[i] == LANA_INVALID) continue;
9600 ncbp->ncb_command = NCBDELNAME;
9601 ncbp->ncb_lana_num = lana_list.lana[i];
9602 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9603 code = Netbios(ncbp);
9605 code = ncbp->ncb_retcode;
9607 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9608 ncbp->ncb_lana_num, code);
9613 /* Release the reference counts held by the VCs */
9614 lock_ObtainWrite(&smb_rctLock);
9615 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9620 if (vcp->magic != SMB_VC_MAGIC)
9621 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9622 __FILE__, __LINE__);
9624 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9626 if (fidp->scp != NULL) {
9629 lock_ObtainMutex(&fidp->mx);
9630 if (fidp->scp != NULL) {
9633 lock_ObtainWrite(&scp->rw);
9634 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9635 lock_ReleaseWrite(&scp->rw);
9636 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9637 cm_ReleaseSCache(scp);
9639 lock_ReleaseMutex(&fidp->mx);
9643 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9645 smb_ReleaseVCNoLock(tidp->vcp);
9647 cm_user_t *userp = tidp->userp;
9649 cm_ReleaseUser(userp);
9653 lock_ReleaseWrite(&smb_rctLock);
9655 TlsFree(smb_TlsRequestSlot);
9658 /* Get the UNC \\<servername>\<sharename> prefix. */
9659 char *smb_GetSharename()
9664 /* Make sure we have been properly initialized. */
9665 if (smb_localNamep == NULL)
9668 /* Allocate space for \\<servername>\<sharename>, plus the
9671 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
9673 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
9679 void smb_LogPacket(smb_packet_t *packet)
9683 unsigned length, paramlen, datalen, i, j;
9685 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9687 if (!packet) return;
9689 osi_Log0(smb_logp, "*** SMB packet dump ***");
9691 smbp = (smb_t *) packet->data;
9692 vp = (BYTE *) packet->data;
9694 paramlen = smbp->wct * 2;
9695 datalen = *((WORD *) (smbp->vdata + paramlen));
9696 length = sizeof(*smbp) + paramlen + 1 + datalen;
9698 for (i=0;i < length; i+=16)
9700 memset( buf, ' ', 80 );
9705 buf[strlen(buf)] = ' ';
9707 cp = (BYTE*) buf + 7;
9709 for (j=0;j < 16 && (i+j)<length; j++)
9711 *(cp++) = hex[vp[i+j] >> 4];
9712 *(cp++) = hex[vp[i+j] & 0xf];
9722 for (j=0;j < 16 && (i+j)<length;j++)
9724 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9735 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9738 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9740 #endif /* LOG_PACKET */
9743 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9751 lock_ObtainRead(&smb_rctLock);
9753 sprintf(output, "begin dumping smb_vc_t\r\n");
9754 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9756 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9760 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9761 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9762 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9764 sprintf(output, "begin dumping smb_fid_t\r\n");
9765 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9767 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9769 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",
9770 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9771 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
9772 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
9773 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9776 sprintf(output, "done dumping smb_fid_t\r\n");
9777 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9780 sprintf(output, "done dumping smb_vc_t\r\n");
9781 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9783 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9784 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9786 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9790 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9791 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9792 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9794 sprintf(output, "begin dumping smb_fid_t\r\n");
9795 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9797 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9799 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",
9800 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9801 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
9802 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
9803 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9806 sprintf(output, "done dumping smb_fid_t\r\n");
9807 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9810 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9811 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9814 lock_ReleaseRead(&smb_rctLock);
9818 long smb_IsNetworkStarted(void)
9821 lock_ObtainWrite(&smb_globalLock);
9822 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
9823 lock_ReleaseWrite(&smb_globalLock);