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_InitReq(cm_req_t *reqp)
196 reqp->flags |= CM_REQ_SOURCE_SMB;
199 void smb_ResetServerPriority()
201 void * p = TlsGetValue(smb_TlsRequestSlot);
204 TlsSetValue(smb_TlsRequestSlot, NULL);
205 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
209 void smb_SetRequestStartTime()
211 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
213 tp = malloc(sizeof(time_t));
217 if (!TlsSetValue(smb_TlsRequestSlot, tp))
222 void smb_UpdateServerPriority()
224 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
227 time_t now = osi_Time();
229 /* Give one priority boost for each 15 seconds */
230 SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
235 const char * ncb_error_string(int code)
239 case 0x01: s = "llegal buffer length"; break;
240 case 0x03: s = "illegal command"; break;
241 case 0x05: s = "command timed out"; break;
242 case 0x06: s = "message incomplete, issue another command"; break;
243 case 0x07: s = "illegal buffer address"; break;
244 case 0x08: s = "session number out of range"; break;
245 case 0x09: s = "no resource available"; break;
246 case 0x0a: s = "session closed"; break;
247 case 0x0b: s = "command cancelled"; break;
248 case 0x0d: s = "duplicate name"; break;
249 case 0x0e: s = "name table full"; break;
250 case 0x0f: s = "no deletions, name has active sessions"; break;
251 case 0x11: s = "local session table full"; break;
252 case 0x12: s = "remote session table full"; break;
253 case 0x13: s = "illegal name number"; break;
254 case 0x14: s = "no callname"; break;
255 case 0x15: s = "cannot put * in NCB_NAME"; break;
256 case 0x16: s = "name in use on remote adapter"; break;
257 case 0x17: s = "name deleted"; break;
258 case 0x18: s = "session ended abnormally"; break;
259 case 0x19: s = "name conflict detected"; break;
260 case 0x21: s = "interface busy, IRET before retrying"; break;
261 case 0x22: s = "too many commands outstanding, retry later";break;
262 case 0x23: s = "ncb_lana_num field invalid"; break;
263 case 0x24: s = "command completed while cancel occurring "; break;
264 case 0x26: s = "command not valid to cancel"; break;
265 case 0x30: s = "name defined by anther local process"; break;
266 case 0x34: s = "environment undefined. RESET required"; break;
267 case 0x35: s = "required OS resources exhausted"; break;
268 case 0x36: s = "max number of applications exceeded"; break;
269 case 0x37: s = "no saps available for netbios"; break;
270 case 0x38: s = "requested resources are not available"; break;
271 case 0x39: s = "invalid ncb address or length > segment"; break;
272 case 0x3B: s = "invalid NCB DDID"; break;
273 case 0x3C: s = "lock of user area failed"; break;
274 case 0x3f: s = "NETBIOS not loaded"; break;
275 case 0x40: s = "system error"; break;
276 default: s = "unknown error";
282 char * myCrt_Dispatch(int i)
287 return "(00)ReceiveCoreMakeDir";
289 return "(01)ReceiveCoreRemoveDir";
291 return "(02)ReceiveCoreOpen";
293 return "(03)ReceiveCoreCreate";
295 return "(04)ReceiveCoreClose";
297 return "(05)ReceiveCoreFlush";
299 return "(06)ReceiveCoreUnlink";
301 return "(07)ReceiveCoreRename";
303 return "(08)ReceiveCoreGetFileAttributes";
305 return "(09)ReceiveCoreSetFileAttributes";
307 return "(0a)ReceiveCoreRead";
309 return "(0b)ReceiveCoreWrite";
311 return "(0c)ReceiveCoreLockRecord";
313 return "(0d)ReceiveCoreUnlockRecord";
315 return "(0e)SendCoreBadOp";
317 return "(0f)ReceiveCoreCreate";
319 return "(10)ReceiveCoreCheckPath";
321 return "(11)SendCoreBadOp";
323 return "(12)ReceiveCoreSeek";
325 return "(1a)ReceiveCoreReadRaw";
327 return "(1d)ReceiveCoreWriteRawDummy";
329 return "(22)ReceiveV3SetAttributes";
331 return "(23)ReceiveV3GetAttributes";
333 return "(24)ReceiveV3LockingX";
335 return "(25)ReceiveV3Trans";
337 return "(26)ReceiveV3Trans[aux]";
339 return "(29)SendCoreBadOp";
341 return "(2b)ReceiveCoreEcho";
343 return "(2d)ReceiveV3OpenX";
345 return "(2e)ReceiveV3ReadX";
347 return "(2f)ReceiveV3WriteX";
349 return "(32)ReceiveV3Tran2A";
351 return "(33)ReceiveV3Tran2A[aux]";
353 return "(34)ReceiveV3FindClose";
355 return "(35)ReceiveV3FindNotifyClose";
357 return "(70)ReceiveCoreTreeConnect";
359 return "(71)ReceiveCoreTreeDisconnect";
361 return "(72)ReceiveNegotiate";
363 return "(73)ReceiveV3SessionSetupX";
365 return "(74)ReceiveV3UserLogoffX";
367 return "(75)ReceiveV3TreeConnectX";
369 return "(80)ReceiveCoreGetDiskAttributes";
371 return "(81)ReceiveCoreSearchDir";
375 return "(83)FindUnique";
377 return "(84)FindClose";
379 return "(A0)ReceiveNTTransact";
381 return "(A2)ReceiveNTCreateX";
383 return "(A4)ReceiveNTCancel";
385 return "(A5)ReceiveNTRename";
387 return "(C0)OpenPrintFile";
389 return "(C1)WritePrintFile";
391 return "(C2)ClosePrintFile";
393 return "(C3)GetPrintQueue";
395 return "(D8)ReadBulk";
397 return "(D9)WriteBulk";
399 return "(DA)WriteBulkData";
401 return "unknown SMB op";
405 char * myCrt_2Dispatch(int i)
410 return "unknown SMB op-2";
412 return "S(00)CreateFile_ReceiveTran2Open";
414 return "S(01)FindFirst_ReceiveTran2SearchDir";
416 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
418 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
420 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
422 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
424 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
426 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
428 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
430 return "S(09)_ReceiveTran2FSCTL";
432 return "S(0a)_ReceiveTran2IOCTL";
434 return "S(0b)_ReceiveTran2FindNotifyFirst";
436 return "S(0c)_ReceiveTran2FindNotifyNext";
438 return "S(0d)_ReceiveTran2CreateDirectory";
440 return "S(0e)_ReceiveTran2SessionSetup";
442 return "S(0f)_QueryFileSystemInformationFid";
444 return "S(10)_ReceiveTran2GetDfsReferral";
446 return "S(11)_ReceiveTran2ReportDfsInconsistency";
450 char * myCrt_RapDispatch(int i)
455 return "unknown RAP OP";
457 return "RAP(0)NetShareEnum";
459 return "RAP(1)NetShareGetInfo";
461 return "RAP(13)NetServerGetInfo";
463 return "RAP(63)NetWkStaGetInfo";
467 /* scache must be locked */
468 unsigned int smb_Attributes(cm_scache_t *scp)
472 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
473 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
474 scp->fileType == CM_SCACHETYPE_INVALID)
476 attrs = SMB_ATTR_DIRECTORY;
477 #ifdef SPECIAL_FOLDERS
478 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
479 #endif /* SPECIAL_FOLDERS */
480 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
481 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
486 * We used to mark a file RO if it was in an RO volume, but that
487 * turns out to be impolitic in NT. See defect 10007.
490 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
491 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
493 if ((scp->unixModeBits & 0222) == 0)
494 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
500 /* Check if the named file/dir is a dotfile/dotdir */
501 /* String pointed to by lastComp can have leading slashes, but otherwise should have
502 no other patch components */
503 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
507 /* skip over slashes */
508 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
513 /* nulls, curdir and parent dir doesn't count */
519 if(*(s+1) == _C('.') && !*(s + 2))
526 static int ExtractBits(WORD bits, short start, short len)
533 num = bits << (16 - end);
534 num = num >> ((16 - end) + start);
539 void ShowUnixTime(char *FuncName, time_t unixTime)
544 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
546 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
547 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
549 int day, month, year, sec, min, hour;
552 day = ExtractBits(wDate, 0, 5);
553 month = ExtractBits(wDate, 5, 4);
554 year = ExtractBits(wDate, 9, 7) + 1980;
556 sec = ExtractBits(wTime, 0, 5);
557 min = ExtractBits(wTime, 5, 6);
558 hour = ExtractBits(wTime, 11, 5);
560 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
561 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
565 /* Determine if we are observing daylight savings time */
566 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
568 TIME_ZONE_INFORMATION timeZoneInformation;
569 SYSTEMTIME utc, local, localDST;
571 /* Get the time zone info. NT uses this to calc if we are in DST. */
572 GetTimeZoneInformation(&timeZoneInformation);
574 /* Return the daylight bias */
575 *pDstBias = timeZoneInformation.DaylightBias;
577 /* Return the bias */
578 *pBias = timeZoneInformation.Bias;
580 /* Now determine if DST is being observed */
582 /* Get the UTC (GMT) time */
585 /* Convert UTC time to local time using the time zone info. If we are
586 observing DST, the calculated local time will include this.
588 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
590 /* Set the daylight bias to 0. The daylight bias is the amount of change
591 * in time that we use for daylight savings time. By setting this to 0
592 * we cause there to be no change in time during daylight savings time.
594 timeZoneInformation.DaylightBias = 0;
596 /* Convert the utc time to local time again, but this time without any
597 adjustment for daylight savings time.
599 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
601 /* If the two times are different, then it means that the localDST that
602 we calculated includes the daylight bias, and therefore we are
603 observing daylight savings time.
605 *pDST = localDST.wHour != local.wHour;
609 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
611 BOOL dst; /* Will be TRUE if observing DST */
612 LONG dstBias; /* Offset from local time if observing DST */
613 LONG bias; /* Offset from GMT for local time */
616 * This function will adjust the last write time to compensate
617 * for two bugs in the smb client:
619 * 1) During Daylight Savings Time, the LastWriteTime is ahead
620 * in time by the DaylightBias (ignoring the sign - the
621 * DaylightBias is always stored as a negative number). If
622 * the DaylightBias is -60, then the LastWriteTime will be
623 * ahead by 60 minutes.
625 * 2) If the local time zone is a positive offset from GMT, then
626 * the LastWriteTime will be the correct local time plus the
627 * Bias (ignoring the sign - a positive offset from GMT is
628 * always stored as a negative Bias). If the Bias is -120,
629 * then the LastWriteTime will be ahead by 120 minutes.
631 * These bugs can occur at the same time.
634 GetTimeZoneInfo(&dst, &dstBias, &bias);
636 /* First adjust for DST */
638 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
640 /* Now adjust for a positive offset from GMT (a negative bias). */
642 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
645 #ifndef USE_NUMERIC_TIME_CONV
647 * Calculate the difference (in seconds) between local time and GMT.
648 * This enables us to convert file times to kludge-GMT.
654 struct tm gmt_tm, local_tm;
655 int days, hours, minutes, seconds;
658 gmt_tm = *(gmtime(&t));
659 local_tm = *(localtime(&t));
661 days = local_tm.tm_yday - gmt_tm.tm_yday;
662 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
663 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
664 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
668 #endif /* USE_NUMERIC_TIME_CONV */
670 #ifdef USE_NUMERIC_TIME_CONV
671 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
673 // Note that LONGLONG is a 64-bit value
676 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
677 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
678 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
681 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
686 time_t ersatz_unixTime;
689 * Must use kludge-GMT instead of real GMT.
690 * kludge-GMT is computed by adding time zone difference to localtime.
693 * ltp = gmtime(&unixTime);
695 ersatz_unixTime = unixTime - smb_NowTZ;
696 ltp = localtime(&ersatz_unixTime);
698 /* if we fail, make up something */
701 localJunk.tm_year = 89 - 20;
702 localJunk.tm_mon = 4;
703 localJunk.tm_mday = 12;
704 localJunk.tm_hour = 0;
705 localJunk.tm_min = 0;
706 localJunk.tm_sec = 0;
709 stm.wYear = ltp->tm_year + 1900;
710 stm.wMonth = ltp->tm_mon + 1;
711 stm.wDayOfWeek = ltp->tm_wday;
712 stm.wDay = ltp->tm_mday;
713 stm.wHour = ltp->tm_hour;
714 stm.wMinute = ltp->tm_min;
715 stm.wSecond = ltp->tm_sec;
716 stm.wMilliseconds = 0;
718 SystemTimeToFileTime(&stm, largeTimep);
720 #endif /* USE_NUMERIC_TIME_CONV */
722 #ifdef USE_NUMERIC_TIME_CONV
723 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
725 // Note that LONGLONG is a 64-bit value
728 ll = largeTimep->dwHighDateTime;
730 ll += largeTimep->dwLowDateTime;
732 ll -= 116444736000000000;
735 *unixTimep = (DWORD)ll;
737 #else /* USE_NUMERIC_TIME_CONV */
738 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
744 FileTimeToSystemTime(largeTimep, &stm);
746 lt.tm_year = stm.wYear - 1900;
747 lt.tm_mon = stm.wMonth - 1;
748 lt.tm_wday = stm.wDayOfWeek;
749 lt.tm_mday = stm.wDay;
750 lt.tm_hour = stm.wHour;
751 lt.tm_min = stm.wMinute;
752 lt.tm_sec = stm.wSecond;
755 save_timezone = _timezone;
756 _timezone += smb_NowTZ;
757 *unixTimep = mktime(<);
758 _timezone = save_timezone;
760 #endif /* USE_NUMERIC_TIME_CONV */
762 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
772 /* if we fail, make up something */
775 localJunk.tm_year = 89 - 20;
776 localJunk.tm_mon = 4;
777 localJunk.tm_mday = 12;
778 localJunk.tm_hour = 0;
779 localJunk.tm_min = 0;
780 localJunk.tm_sec = 0;
783 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
784 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
785 *searchTimep = (dosDate<<16) | dosTime;
788 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
790 unsigned short dosDate;
791 unsigned short dosTime;
794 dosDate = (unsigned short) (searchTime & 0xffff);
795 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
797 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
798 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
799 localTm.tm_mday = (dosDate) & 0x1f;
800 localTm.tm_hour = (dosTime>>11) & 0x1f;
801 localTm.tm_min = (dosTime >> 5) & 0x3f;
802 localTm.tm_sec = (dosTime & 0x1f) * 2;
803 localTm.tm_isdst = -1; /* compute whether DST in effect */
805 *unixTimep = mktime(&localTm);
808 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
810 time_t diff_t = unixTime - smb_localZero;
811 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
812 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
814 *dosUTimep = (afs_uint32)diff_t;
817 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
819 *unixTimep = dosTime + smb_localZero;
822 #ifdef DEBUG_SMB_REFCOUNT
823 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
825 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
830 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
831 lock_ObtainWrite(&smb_rctLock);
832 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
833 if (vcp->magic != SMB_VC_MAGIC)
834 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
837 if (lsn == vcp->lsn && lana == vcp->lana &&
838 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
839 smb_HoldVCNoLock(vcp);
843 if (!vcp && (flags & SMB_FLAG_CREATE)) {
844 vcp = malloc(sizeof(*vcp));
845 memset(vcp, 0, sizeof(*vcp));
846 vcp->vcID = ++numVCs;
847 vcp->magic = SMB_VC_MAGIC;
848 vcp->refCount = 2; /* smb_allVCsp and caller */
851 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
852 vcp->nextp = smb_allVCsp;
854 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
859 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
860 /* We must obtain a challenge for extended auth
861 * in case the client negotiates smb v3
863 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
864 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
865 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
866 ULONG lsaRespSize = 0;
868 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
870 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
877 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
878 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
879 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
880 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
881 nts, ntsEx, lsaRespSize);
883 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
885 if (ntsEx == STATUS_SUCCESS) {
886 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
889 * This will cause the subsequent authentication to fail but
890 * that is better than us dereferencing a NULL pointer and
893 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
896 LsaFreeReturnBuffer(lsaResp);
899 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
901 if (numVCs >= CM_SESSION_RESERVED) {
903 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
906 #ifdef DEBUG_SMB_REFCOUNT
908 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
909 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
912 lock_ReleaseWrite(&smb_rctLock);
913 lock_ReleaseWrite(&smb_globalLock);
917 int smb_IsStarMask(clientchar_t *maskp)
922 for(i=0; i<11; i++) {
924 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
930 #ifdef DEBUG_SMB_REFCOUNT
931 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
932 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
934 void smb_ReleaseVCInternal(smb_vc_t *vcp)
940 lock_AssertWrite(&smb_rctLock);
943 if (vcp->refCount == 0) {
944 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
945 #ifdef DEBUG_SMB_REFCOUNT
946 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
947 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
949 /* remove VCP from smb_deadVCsp */
950 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
956 lock_FinalizeMutex(&vcp->mx);
957 memset(vcp,0,sizeof(smb_vc_t));
960 #ifdef DEBUG_SMB_REFCOUNT
961 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
963 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
967 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
968 avcp?"":"not ",vcp, vcp->refCount);
970 /* This is a wrong. However, I suspect that there is an undercount
971 * and I don't want to release 1.4.1 in a state that will allow
972 * smb_vc_t objects to be deallocated while still in the
973 * smb_allVCsp list. The list is supposed to keep a reference
974 * to the smb_vc_t. Put it back.
978 #ifdef DEBUG_SMB_REFCOUNT
979 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
980 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
984 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
985 /* The reference count is non-zero but the VC is dead.
986 * This implies that some FIDs, TIDs, etc on the VC have yet to
987 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
988 * add a reference that will be dropped by
989 * smb_CleanupDeadVC() and try to cleanup the VC again.
990 * Eventually the refCount will drop to zero when all of the
991 * active threads working with the VC end their task.
993 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
994 vcp->refCount++; /* put the refCount back */
995 lock_ReleaseWrite(&smb_rctLock);
996 smb_CleanupDeadVC(vcp);
997 #ifdef DEBUG_SMB_REFCOUNT
998 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
999 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1001 lock_ObtainWrite(&smb_rctLock);
1004 #ifdef DEBUG_SMB_REFCOUNT
1005 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1006 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1011 #ifdef DEBUG_SMB_REFCOUNT
1012 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1014 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1017 lock_AssertWrite(&smb_rctLock);
1018 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1019 smb_ReleaseVCInternal(vcp);
1022 #ifdef DEBUG_SMB_REFCOUNT
1023 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1025 void smb_ReleaseVC(smb_vc_t *vcp)
1028 lock_ObtainWrite(&smb_rctLock);
1029 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1030 smb_ReleaseVCInternal(vcp);
1031 lock_ReleaseWrite(&smb_rctLock);
1034 #ifdef DEBUG_SMB_REFCOUNT
1035 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1037 void smb_HoldVCNoLock(smb_vc_t *vcp)
1040 lock_AssertWrite(&smb_rctLock);
1042 #ifdef DEBUG_SMB_REFCOUNT
1043 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1044 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1046 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1050 #ifdef DEBUG_SMB_REFCOUNT
1051 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1053 void smb_HoldVC(smb_vc_t *vcp)
1056 lock_ObtainWrite(&smb_rctLock);
1058 #ifdef DEBUG_SMB_REFCOUNT
1059 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1060 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1062 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1064 lock_ReleaseWrite(&smb_rctLock);
1067 void smb_CleanupDeadVC(smb_vc_t *vcp)
1069 smb_fid_t *fidpIter;
1070 smb_fid_t *fidpNext;
1072 smb_tid_t *tidpIter;
1073 smb_tid_t *tidpNext;
1075 smb_user_t *uidpIter;
1076 smb_user_t *uidpNext;
1078 afs_uint32 refCount = 0;
1080 lock_ObtainMutex(&vcp->mx);
1081 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1082 lock_ReleaseMutex(&vcp->mx);
1083 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1086 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1087 lock_ReleaseMutex(&vcp->mx);
1088 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1090 lock_ObtainWrite(&smb_rctLock);
1091 /* remove VCP from smb_allVCsp */
1092 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1093 if ((*vcpp)->magic != SMB_VC_MAGIC)
1094 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1095 __FILE__, __LINE__);
1098 vcp->nextp = smb_deadVCsp;
1100 /* Hold onto the reference until we are done with this function */
1105 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1106 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1108 if (fidpIter->deleteOk)
1111 fid = fidpIter->fid;
1112 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1114 smb_HoldFIDNoLock(fidpIter);
1115 lock_ReleaseWrite(&smb_rctLock);
1117 smb_CloseFID(vcp, fidpIter, NULL, 0);
1118 smb_ReleaseFID(fidpIter);
1120 lock_ObtainWrite(&smb_rctLock);
1121 fidpNext = vcp->fidsp;
1124 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1125 tidpNext = tidpIter->nextp;
1126 if (tidpIter->deleteOk)
1128 tidpIter->deleteOk = 1;
1130 tid = tidpIter->tid;
1131 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1133 smb_HoldTIDNoLock(tidpIter);
1134 smb_ReleaseTID(tidpIter, TRUE);
1135 tidpNext = vcp->tidsp;
1138 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1139 uidpNext = uidpIter->nextp;
1140 if (uidpIter->deleteOk)
1142 uidpIter->deleteOk = 1;
1144 /* do not add an additional reference count for the smb_user_t
1145 * as the smb_vc_t already is holding a reference */
1146 lock_ReleaseWrite(&smb_rctLock);
1148 smb_ReleaseUID(uidpIter);
1150 lock_ObtainWrite(&smb_rctLock);
1151 uidpNext = vcp->usersp;
1154 /* The vcp is now on the deadVCsp list. We intentionally drop the
1155 * reference so that the refcount can reach 0 and we can delete it
1157 * If the refCount == 1 going into the ReleaseVCNoLock call
1158 * the object will be freed and it won't be safe to clear
1161 refCount = vcp->refCount;
1162 smb_ReleaseVCNoLock(vcp);
1164 lock_ObtainMutex(&vcp->mx);
1165 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1166 lock_ReleaseMutex(&vcp->mx);
1169 lock_ReleaseWrite(&smb_rctLock);
1170 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1173 #ifdef DEBUG_SMB_REFCOUNT
1174 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1176 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1181 lock_ObtainWrite(&smb_rctLock);
1183 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1184 if (tidp->refCount == 0 && tidp->deleteOk) {
1186 smb_ReleaseTID(tidp, TRUE);
1190 if (tid == tidp->tid) {
1195 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1196 tidp = malloc(sizeof(*tidp));
1197 memset(tidp, 0, sizeof(*tidp));
1198 tidp->nextp = vcp->tidsp;
1201 smb_HoldVCNoLock(vcp);
1203 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1206 #ifdef DEBUG_SMB_REFCOUNT
1208 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1209 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1212 lock_ReleaseWrite(&smb_rctLock);
1216 #ifdef DEBUG_SMB_REFCOUNT
1217 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1219 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1222 lock_AssertWrite(&smb_rctLock);
1224 #ifdef DEBUG_SMB_REFCOUNT
1225 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1226 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1230 #ifdef DEBUG_SMB_REFCOUNT
1231 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1233 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1238 cm_user_t *userp = NULL;
1239 smb_vc_t *vcp = NULL;
1242 lock_ObtainWrite(&smb_rctLock);
1244 lock_AssertWrite(&smb_rctLock);
1246 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1247 #ifdef DEBUG_SMB_REFCOUNT
1248 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1249 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1251 if (tidp->refCount == 0) {
1252 if (tidp->deleteOk) {
1253 ltpp = &tidp->vcp->tidsp;
1254 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1258 osi_assertx(tp != NULL, "null smb_tid_t");
1260 lock_FinalizeMutex(&tidp->mx);
1261 userp = tidp->userp; /* remember to drop ref later */
1269 lock_ReleaseWrite(&smb_rctLock);
1271 cm_ReleaseUser(userp);
1273 smb_ReleaseVCNoLock(vcp);
1276 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1278 smb_user_t *uidp = NULL;
1280 lock_ObtainWrite(&smb_rctLock);
1281 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1282 if (uid == uidp->userID) {
1284 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1286 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1290 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1291 uidp = malloc(sizeof(*uidp));
1292 memset(uidp, 0, sizeof(*uidp));
1293 uidp->nextp = vcp->usersp;
1294 uidp->refCount = 2; /* one for the vcp and one for the caller */
1296 smb_HoldVCNoLock(vcp);
1298 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1300 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1302 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1304 lock_ReleaseWrite(&smb_rctLock);
1308 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1311 smb_username_t *unp= NULL;
1313 lock_ObtainWrite(&smb_rctLock);
1314 for(unp = usernamesp; unp; unp = unp->nextp) {
1315 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1316 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1321 if (!unp && (flags & SMB_FLAG_CREATE)) {
1322 unp = malloc(sizeof(*unp));
1323 memset(unp, 0, sizeof(*unp));
1325 unp->nextp = usernamesp;
1326 unp->name = cm_ClientStrDup(usern);
1327 unp->machine = cm_ClientStrDup(machine);
1329 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1330 if (flags & SMB_FLAG_AFSLOGON)
1331 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1334 lock_ReleaseWrite(&smb_rctLock);
1338 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1340 smb_user_t *uidp= NULL;
1342 lock_ObtainWrite(&smb_rctLock);
1343 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1346 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1348 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1349 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1354 lock_ReleaseWrite(&smb_rctLock);
1358 void smb_ReleaseUsername(smb_username_t *unp)
1361 smb_username_t **lupp;
1362 cm_user_t *userp = NULL;
1363 time_t now = osi_Time();
1365 lock_ObtainWrite(&smb_rctLock);
1366 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1367 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1368 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1370 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1374 osi_assertx(up != NULL, "null smb_username_t");
1376 up->nextp = NULL; /* do not remove this */
1377 lock_FinalizeMutex(&unp->mx);
1383 lock_ReleaseWrite(&smb_rctLock);
1385 cm_ReleaseUser(userp);
1388 void smb_HoldUIDNoLock(smb_user_t *uidp)
1390 lock_AssertWrite(&smb_rctLock);
1394 void smb_ReleaseUID(smb_user_t *uidp)
1398 smb_username_t *unp = NULL;
1400 lock_ObtainWrite(&smb_rctLock);
1401 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1402 if (uidp->refCount == 0) {
1403 lupp = &uidp->vcp->usersp;
1404 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1408 osi_assertx(up != NULL, "null smb_user_t");
1410 lock_FinalizeMutex(&uidp->mx);
1412 smb_ReleaseVCNoLock(uidp->vcp);
1416 lock_ReleaseWrite(&smb_rctLock);
1420 cm_ReleaseUserVCRef(unp->userp);
1421 smb_ReleaseUsername(unp);
1425 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1427 cm_user_t *up = NULL;
1432 lock_ObtainMutex(&uidp->mx);
1434 up = uidp->unp->userp;
1437 lock_ReleaseMutex(&uidp->mx);
1443 /* retrieve a held reference to a user structure corresponding to an incoming
1445 * corresponding release function is cm_ReleaseUser.
1447 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1450 cm_user_t *up = NULL;
1453 smbp = (smb_t *) inp;
1454 uidp = smb_FindUID(vcp, smbp->uid, 0);
1458 up = smb_GetUserFromUID(uidp);
1460 smb_ReleaseUID(uidp);
1465 * Return a pointer to a pathname extracted from a TID structure. The
1466 * TID structure is not held; assume it won't go away.
1468 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1473 tidp = smb_FindTID(vcp, tid, 0);
1477 if (tidp->flags & SMB_TIDFLAG_IPC) {
1478 code = CM_ERROR_TIDIPC;
1479 /* tidp->pathname would be NULL, but that's fine */
1481 *treepath = tidp->pathname;
1482 smb_ReleaseTID(tidp, FALSE);
1487 /* check to see if we have a chained fid, that is, a fid that comes from an
1488 * OpenAndX message that ran earlier in this packet. In this case, the fid
1489 * field in a read, for example, request, isn't set, since the value is
1490 * supposed to be inherited from the openAndX call.
1492 int smb_ChainFID(int fid, smb_packet_t *inp)
1494 if (inp->fid == 0 || inp->inCount == 0)
1500 /* are we a priv'd user? What does this mean on NT? */
1501 int smb_SUser(cm_user_t *userp)
1506 /* find a file ID. If we pass in 0 we select an unused File ID.
1507 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1508 * smb_fid_t data structure if desired File ID cannot be found.
1510 #ifdef DEBUG_SMB_REFCOUNT
1511 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1513 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1519 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1522 lock_ObtainWrite(&smb_rctLock);
1523 /* figure out if we need to allocate a new file ID */
1526 fid = vcp->fidCounter;
1530 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1531 if (fidp->refCount == 0 && fidp->deleteOk) {
1533 lock_ReleaseWrite(&smb_rctLock);
1534 smb_ReleaseFID(fidp);
1535 lock_ObtainWrite(&smb_rctLock);
1538 if (fid == fidp->fid) {
1541 if (fid == 0xFFFF) {
1543 "New FID number wraps on vcp 0x%x", vcp);
1553 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1554 char eventName[MAX_PATH];
1556 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1557 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1558 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1559 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1560 thrd_CloseHandle(event);
1562 if (fid == 0xFFFF) {
1563 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1569 fidp = malloc(sizeof(*fidp));
1570 memset(fidp, 0, sizeof(*fidp));
1571 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1574 smb_HoldVCNoLock(vcp);
1575 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1577 fidp->curr_chunk = fidp->prev_chunk = -2;
1578 fidp->raw_write_event = event;
1580 vcp->fidCounter = fid+1;
1581 if (vcp->fidCounter == 0xFFFF) {
1582 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1584 vcp->fidCounter = 1;
1589 #ifdef DEBUG_SMB_REFCOUNT
1591 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1592 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 lock_ReleaseWrite(&smb_rctLock);
1599 #ifdef DEBUG_SMB_REFCOUNT
1600 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1602 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1605 smb_fid_t *fidp = NULL;
1611 lock_ObtainWrite(&smb_rctLock);
1612 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1613 if (scp == fidp->scp) {
1618 #ifdef DEBUG_SMB_REFCOUNT
1620 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1621 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1624 lock_ReleaseWrite(&smb_rctLock);
1628 #ifdef DEBUG_SMB_REFCOUNT
1629 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1631 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1634 lock_AssertWrite(&smb_rctLock);
1636 #ifdef DEBUG_SMB_REFCOUNT
1637 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1638 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1643 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1644 /* the sm_fid_t->mx and smb_rctLock must not be held */
1645 #ifdef DEBUG_SMB_REFCOUNT
1646 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1648 void smb_ReleaseFID(smb_fid_t *fidp)
1651 cm_scache_t *scp = NULL;
1652 cm_user_t *userp = NULL;
1653 smb_vc_t *vcp = NULL;
1654 smb_ioctl_t *ioctlp;
1656 lock_ObtainMutex(&fidp->mx);
1657 lock_ObtainWrite(&smb_rctLock);
1658 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1659 #ifdef DEBUG_SMB_REFCOUNT
1660 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1661 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1663 if (fidp->refCount == 0) {
1664 if (fidp->deleteOk) {
1667 scp = fidp->scp; /* release after lock is released */
1669 lock_ObtainWrite(&scp->rw);
1670 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1671 lock_ReleaseWrite(&scp->rw);
1672 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1675 userp = fidp->userp;
1679 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1680 thrd_CloseHandle(fidp->raw_write_event);
1682 /* and see if there is ioctl stuff to free */
1683 ioctlp = fidp->ioctlp;
1686 cm_FreeSpace(ioctlp->prefix);
1687 if (ioctlp->ioctl.inAllocp)
1688 free(ioctlp->ioctl.inAllocp);
1689 if (ioctlp->ioctl.outAllocp)
1690 free(ioctlp->ioctl.outAllocp);
1693 lock_ReleaseMutex(&fidp->mx);
1694 lock_FinalizeMutex(&fidp->mx);
1699 smb_ReleaseVCNoLock(vcp);
1703 lock_ReleaseMutex(&fidp->mx);
1705 lock_ReleaseWrite(&smb_rctLock);
1707 /* now release the scache structure */
1709 cm_ReleaseSCache(scp);
1712 cm_ReleaseUser(userp);
1716 * Case-insensitive search for one string in another;
1717 * used to find variable names in submount pathnames.
1719 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1721 clientchar_t *cursor;
1723 for (cursor = str1; *cursor; cursor++)
1724 if (cm_ClientStrCmpI(cursor, str2) == 0)
1731 * Substitute a variable value for its name in a submount pathname. Variable
1732 * name has been identified by smb_stristr() and is in substr. Variable name
1733 * length (plus one) is in substr_size. Variable value is in newstr.
1735 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1736 unsigned int substr_size, clientchar_t *newstr)
1738 clientchar_t temp[1024];
1740 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1741 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1742 cm_ClientStrCat(str1, cchstr1, temp);
1745 clientchar_t VNUserName[] = _C("%USERNAME%");
1746 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1747 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1748 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1750 typedef struct smb_findShare_rock {
1751 clientchar_t * shareName;
1752 clientchar_t * match;
1754 } smb_findShare_rock_t;
1756 #define SMB_FINDSHARE_EXACT_MATCH 1
1757 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1759 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1763 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1764 normchar_t normName[MAX_PATH];
1766 cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
1768 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1769 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1770 matchType = SMB_FINDSHARE_EXACT_MATCH;
1772 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1773 if(vrock->match) free(vrock->match);
1774 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1775 vrock->matchType = matchType;
1777 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1778 return CM_ERROR_STOPNOW;
1784 /* find a shareName in the table of submounts */
1785 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1786 clientchar_t *shareName,
1787 clientchar_t **pathNamep)
1791 clientchar_t pathName[1024];
1794 clientchar_t *p, *q;
1795 fschar_t *cellname = NULL;
1798 DWORD allSubmount = 1;
1800 /* if allSubmounts == 0, only return the //mountRoot/all share
1801 * if in fact it has been been created in the subMounts table.
1802 * This is to allow sites that want to restrict access to the
1805 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1806 0, KEY_QUERY_VALUE, &parmKey);
1807 if (code == ERROR_SUCCESS) {
1808 cblen = sizeof(allSubmount);
1809 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1810 (BYTE *) &allSubmount, &cblen);
1811 if (code != ERROR_SUCCESS) {
1814 RegCloseKey (parmKey);
1817 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1822 /* In case, the all share is disabled we need to still be able
1823 * to handle ioctl requests
1825 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1826 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1830 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1831 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1832 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1833 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1834 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1840 /* Check for volume references
1842 * They look like <cell>{%,#}<volume>
1844 if (cm_ClientStrChr(shareName, '%') != NULL ||
1845 cm_ClientStrChr(shareName, '#') != NULL) {
1846 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1847 /* make room for '/@vol:' + mountchar + NULL terminator*/
1849 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1850 osi_LogSaveClientString(smb_logp, shareName));
1852 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1853 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1854 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1856 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1858 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1859 cm_ClientStrLwr(*pathNamep);
1860 osi_Log1(smb_logp, " returning pathname [%S]",
1861 osi_LogSaveClientString(smb_logp, *pathNamep));
1869 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1870 0, KEY_QUERY_VALUE, &parmKey);
1871 if (code == ERROR_SUCCESS) {
1872 cblen = sizeof(pathName);
1873 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1874 (BYTE *) pathName, &cblen);
1875 if (code != ERROR_SUCCESS)
1877 RegCloseKey (parmKey);
1881 cchlen = cblen / sizeof(clientchar_t);
1882 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1883 /* We can accept either unix or PC style AFS pathnames. Convert
1884 * Unix-style to PC style here for internal use.
1887 cchlen = lengthof(pathName);
1889 /* within this code block, we maintain, cchlen = writeable
1890 buffer length of p */
1892 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1893 p += cm_mountRootCLen; /* skip mount path */
1894 cchlen -= (DWORD)(p - pathName);
1899 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1905 clientchar_t temp[1024];
1907 if (var = smb_stristr(p, VNUserName)) {
1908 if (uidp && uidp->unp)
1909 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1911 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1913 else if (var = smb_stristr(p, VNLCUserName))
1915 if (uidp && uidp->unp)
1916 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1918 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1919 cm_ClientStrLwr(temp);
1920 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1922 else if (var = smb_stristr(p, VNComputerName))
1924 sizeTemp = lengthof(temp);
1925 GetComputerNameW(temp, &sizeTemp);
1926 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1928 else if (var = smb_stristr(p, VNLCComputerName))
1930 sizeTemp = lengthof(temp);
1931 GetComputerName((LPTSTR)temp, &sizeTemp);
1932 cm_ClientStrLwr(temp);
1933 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1938 *pathNamep = cm_ClientStrDup(p);
1943 /* First lookup shareName in root.afs */
1945 smb_findShare_rock_t vrock;
1947 fschar_t ftemp[1024];
1948 clientchar_t * p = shareName;
1951 /* attempt to locate a partial match in root.afs. This is because
1952 when using the ANSI RAP calls, the share name is limited to 13 chars
1953 and hence is truncated. Of course we prefer exact matches. */
1955 thyper.HighPart = 0;
1958 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1960 vrock.matchType = 0;
1962 cm_HoldSCache(cm_data.rootSCachep);
1963 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1964 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1965 cm_ReleaseSCache(cm_data.rootSCachep);
1967 free(vrock.shareName);
1968 vrock.shareName = NULL;
1970 if (vrock.matchType) {
1971 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1972 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1977 /* if we get here, there was no match for the share in root.afs */
1978 /* so try to create \\<netbiosName>\<cellname> */
1983 /* Get the full name for this cell */
1984 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1985 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1986 #ifdef AFS_AFSDB_ENV
1987 if (code && cm_dnsEnabled) {
1989 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1995 /* construct the path */
1997 clientchar_t temp[1024];
1999 cm_FsStringToClientString(ftemp, -1, temp, 1024);
2000 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2001 rw ? _C("/.%S/") : _C("/%S/"), temp);
2002 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2011 /* Client-side offline caching policy types */
2012 #define CSC_POLICY_MANUAL 0
2013 #define CSC_POLICY_DOCUMENTS 1
2014 #define CSC_POLICY_PROGRAMS 2
2015 #define CSC_POLICY_DISABLE 3
2017 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2020 clientchar_t policy[1024];
2023 int retval = CSC_POLICY_MANUAL;
2025 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2026 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2029 REG_OPTION_NON_VOLATILE,
2035 len = sizeof(policy);
2036 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2038 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2040 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2042 retval = CSC_POLICY_DOCUMENTS;
2044 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2046 retval = CSC_POLICY_PROGRAMS;
2048 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2050 retval = CSC_POLICY_DISABLE;
2053 RegCloseKey(hkCSCPolicy);
2057 /* find a dir search structure by cookie value, and return it held.
2058 * Must be called with smb_globalLock held.
2060 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2062 smb_dirSearch_t *dsp;
2064 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2065 if (dsp->cookie == cookie) {
2066 if (dsp != smb_firstDirSearchp) {
2067 /* move to head of LRU queue, too, if we're not already there */
2068 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2069 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2070 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2071 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2072 if (!smb_lastDirSearchp)
2073 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2081 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2082 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2083 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2089 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2091 lock_ObtainMutex(&dsp->mx);
2092 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2093 dsp->cookie, dsp, dsp->scp);
2094 dsp->flags |= SMB_DIRSEARCH_DELETE;
2095 if (dsp->scp != NULL) {
2096 lock_ObtainWrite(&dsp->scp->rw);
2097 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2098 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2099 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2100 dsp->scp->bulkStatProgress = hzero;
2102 lock_ReleaseWrite(&dsp->scp->rw);
2104 lock_ReleaseMutex(&dsp->mx);
2107 /* Must be called with the smb_globalLock held */
2108 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2110 cm_scache_t *scp = NULL;
2112 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2113 if (dsp->refCount == 0) {
2114 lock_ObtainMutex(&dsp->mx);
2115 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2116 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2117 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2118 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2119 lock_ReleaseMutex(&dsp->mx);
2120 lock_FinalizeMutex(&dsp->mx);
2122 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2123 dsp->cookie, dsp, scp);
2126 lock_ReleaseMutex(&dsp->mx);
2129 /* do this now to avoid spurious locking hierarchy creation */
2131 cm_ReleaseSCache(scp);
2134 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2136 lock_ObtainWrite(&smb_globalLock);
2137 smb_ReleaseDirSearchNoLock(dsp);
2138 lock_ReleaseWrite(&smb_globalLock);
2141 /* find a dir search structure by cookie value, and return it held */
2142 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2144 smb_dirSearch_t *dsp;
2146 lock_ObtainWrite(&smb_globalLock);
2147 dsp = smb_FindDirSearchNoLock(cookie);
2148 lock_ReleaseWrite(&smb_globalLock);
2152 /* GC some dir search entries, in the address space expected by the specific protocol.
2153 * Must be called with smb_globalLock held; release the lock temporarily.
2155 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2156 void smb_GCDirSearches(int isV3)
2158 smb_dirSearch_t *prevp;
2159 smb_dirSearch_t *dsp;
2160 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2164 victimCount = 0; /* how many have we got so far */
2165 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2166 /* we'll move tp from queue, so
2169 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2170 /* if no one is using this guy, and we're either in the new protocol,
2171 * or we're in the old one and this is a small enough ID to be useful
2172 * to the old protocol, GC this guy.
2174 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2175 /* hold and delete */
2176 lock_ObtainMutex(&dsp->mx);
2177 dsp->flags |= SMB_DIRSEARCH_DELETE;
2178 lock_ReleaseMutex(&dsp->mx);
2179 victimsp[victimCount++] = dsp;
2183 /* don't do more than this */
2184 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2188 /* now release them */
2189 for (i = 0; i < victimCount; i++) {
2190 smb_ReleaseDirSearchNoLock(victimsp[i]);
2194 /* function for allocating a dir search entry. We need these to remember enough context
2195 * since we don't get passed the path from call to call during a directory search.
2197 * Returns a held dir search structure, and bumps the reference count on the vnode,
2198 * since it saves a pointer to the vnode.
2200 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2202 smb_dirSearch_t *dsp;
2208 lock_ObtainWrite(&smb_globalLock);
2211 /* what's the biggest ID allowed in this version of the protocol */
2212 /* TODO: do we really want a non v3 dir search request to wrap
2213 smb_dirSearchCounter? */
2214 maxAllowed = isV3 ? 65535 : 255;
2215 if (smb_dirSearchCounter > maxAllowed)
2216 smb_dirSearchCounter = 1;
2218 start = smb_dirSearchCounter;
2221 /* twice so we have enough tries to find guys we GC after one pass;
2222 * 10 extra is just in case I mis-counted.
2224 if (++counter > 2*maxAllowed+10)
2225 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2227 if (smb_dirSearchCounter > maxAllowed) {
2228 smb_dirSearchCounter = 1;
2230 if (smb_dirSearchCounter == start) {
2232 smb_GCDirSearches(isV3);
2235 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2237 /* don't need to watch for refcount zero and deleted, since
2238 * we haven't dropped the global lock.
2241 ++smb_dirSearchCounter;
2245 dsp = malloc(sizeof(*dsp));
2246 memset(dsp, 0, sizeof(*dsp));
2247 dsp->cookie = smb_dirSearchCounter;
2248 ++smb_dirSearchCounter;
2250 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2251 dsp->lastTime = osi_Time();
2252 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2253 if (!smb_lastDirSearchp)
2254 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2256 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2260 lock_ReleaseWrite(&smb_globalLock);
2264 static smb_packet_t *smb_GetPacket(void)
2268 lock_ObtainWrite(&smb_globalLock);
2269 tbp = smb_packetFreeListp;
2271 smb_packetFreeListp = tbp->nextp;
2272 lock_ReleaseWrite(&smb_globalLock);
2274 tbp = calloc(sizeof(*tbp),1);
2275 tbp->magic = SMB_PACKETMAGIC;
2278 tbp->resumeCode = 0;
2284 tbp->ncb_length = 0;
2287 tbp->stringsp = NULL;
2289 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2294 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2297 tbp = smb_GetPacket();
2298 memcpy(tbp, pkt, sizeof(smb_packet_t));
2299 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2300 tbp->stringsp = NULL;
2302 smb_HoldVC(tbp->vcp);
2306 static NCB *smb_GetNCB(void)
2311 lock_ObtainWrite(&smb_globalLock);
2312 tbp = smb_ncbFreeListp;
2314 smb_ncbFreeListp = tbp->nextp;
2315 lock_ReleaseWrite(&smb_globalLock);
2317 tbp = calloc(sizeof(*tbp),1);
2318 tbp->magic = SMB_NCBMAGIC;
2321 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2323 memset(&tbp->ncb, 0, sizeof(NCB));
2328 static void FreeSMBStrings(smb_packet_t * pkt)
2333 for (s = pkt->stringsp; s; s = ns) {
2337 pkt->stringsp = NULL;
2340 void smb_FreePacket(smb_packet_t *tbp)
2342 smb_vc_t * vcp = NULL;
2343 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2345 lock_ObtainWrite(&smb_globalLock);
2346 tbp->nextp = smb_packetFreeListp;
2347 smb_packetFreeListp = tbp;
2348 tbp->magic = SMB_PACKETMAGIC;
2352 tbp->resumeCode = 0;
2358 tbp->ncb_length = 0;
2360 FreeSMBStrings(tbp);
2361 lock_ReleaseWrite(&smb_globalLock);
2367 static void smb_FreeNCB(NCB *bufferp)
2371 tbp = (smb_ncb_t *) bufferp;
2372 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2374 lock_ObtainWrite(&smb_globalLock);
2375 tbp->nextp = smb_ncbFreeListp;
2376 smb_ncbFreeListp = tbp;
2377 lock_ReleaseWrite(&smb_globalLock);
2380 /* get a ptr to the data part of a packet, and its count */
2381 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2385 unsigned char *afterParmsp;
2387 parmBytes = *smbp->wctp << 1;
2388 afterParmsp = smbp->wctp + parmBytes + 1;
2390 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2391 if (nbytesp) *nbytesp = dataBytes;
2393 /* don't forget to skip the data byte count, since it follows
2394 * the parameters; that's where the "2" comes from below.
2396 return (unsigned char *) (afterParmsp + 2);
2399 /* must set all the returned parameters before playing around with the
2400 * data region, since the data region is located past the end of the
2401 * variable number of parameters.
2403 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2405 unsigned char *afterParmsp;
2407 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2409 *afterParmsp++ = dsize & 0xff;
2410 *afterParmsp = (dsize>>8) & 0xff;
2413 /* return the parm'th parameter in the smbp packet */
2414 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2417 unsigned char *parmDatap;
2419 parmCount = *smbp->wctp;
2421 if (parm >= parmCount) {
2424 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2425 parm, parmCount, smbp->ncb_length);
2426 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2427 parm, parmCount, smbp->ncb_length);
2428 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2429 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2430 osi_panic(s, __FILE__, __LINE__);
2432 parmDatap = smbp->wctp + (2*parm) + 1;
2434 return parmDatap[0] + (parmDatap[1] << 8);
2437 /* return the parm'th parameter in the smbp packet */
2438 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2441 unsigned char *parmDatap;
2443 parmCount = *smbp->wctp;
2445 if (parm >= parmCount) {
2448 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2449 parm, parmCount, smbp->ncb_length);
2450 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2451 parm, parmCount, smbp->ncb_length);
2452 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2453 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2454 osi_panic(s, __FILE__, __LINE__);
2456 parmDatap = smbp->wctp + (2*parm) + 1;
2458 return parmDatap[0];
2461 /* return the parm'th parameter in the smbp packet */
2462 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2465 unsigned char *parmDatap;
2467 parmCount = *smbp->wctp;
2469 if (parm + 1 >= parmCount) {
2472 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2473 parm, parmCount, smbp->ncb_length);
2474 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2475 parm, parmCount, smbp->ncb_length);
2476 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2477 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2478 osi_panic(s, __FILE__, __LINE__);
2480 parmDatap = smbp->wctp + (2*parm) + 1;
2482 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2485 /* return the parm'th parameter in the smbp packet */
2486 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2489 unsigned char *parmDatap;
2491 parmCount = *smbp->wctp;
2493 if (parm * 2 + offset >= parmCount * 2) {
2496 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2497 parm, offset, parmCount, smbp->ncb_length);
2498 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2499 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2500 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2501 parm, offset, parmCount, smbp->ncb_length);
2502 osi_panic(s, __FILE__, __LINE__);
2504 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2506 return parmDatap[0] + (parmDatap[1] << 8);
2509 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2511 unsigned char *parmDatap;
2513 /* make sure we have enough slots */
2514 if (*smbp->wctp <= slot)
2515 *smbp->wctp = slot+1;
2517 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2518 *parmDatap++ = parmValue & 0xff;
2519 *parmDatap = (parmValue>>8) & 0xff;
2522 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2524 unsigned char *parmDatap;
2526 /* make sure we have enough slots */
2527 if (*smbp->wctp <= slot)
2528 *smbp->wctp = slot+2;
2530 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2531 *parmDatap++ = parmValue & 0xff;
2532 *parmDatap++ = (parmValue>>8) & 0xff;
2533 *parmDatap++ = (parmValue>>16) & 0xff;
2534 *parmDatap = (parmValue>>24) & 0xff;
2537 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2539 unsigned char *parmDatap;
2542 /* make sure we have enough slots */
2543 if (*smbp->wctp <= slot)
2544 *smbp->wctp = slot+4;
2546 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2548 *parmDatap++ = *parmValuep++;
2551 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2553 unsigned char *parmDatap;
2555 /* make sure we have enough slots */
2556 if (*smbp->wctp <= slot) {
2557 if (smbp->oddByte) {
2559 *smbp->wctp = slot+1;
2564 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2565 *parmDatap++ = parmValue & 0xff;
2570 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2571 clientchar_t *inPathp)
2573 clientchar_t *lastSlashp;
2575 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2577 *lastComponentp = lastSlashp;
2580 if (inPathp == lastSlashp)
2582 *outPathp++ = *inPathp++;
2591 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2592 char **chainpp, int flags)
2600 if (!WANTS_UNICODE(pktp))
2601 flags |= SMB_STRF_FORCEASCII;
2604 cb = sizeof(pktp->data) - (inp - pktp->data);
2605 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2606 #ifdef DEBUG_UNICODE
2609 cb = sizeof(pktp->data);
2611 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2614 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2615 char ** chainpp, int flags)
2620 if (!WANTS_UNICODE(pktp))
2621 flags |= SMB_STRF_FORCEASCII;
2624 cb = sizeof(pktp->data) - (inp - pktp->data);
2625 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2626 #ifdef DEBUG_UNICODE
2629 cb = sizeof(pktp->data);
2631 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2632 flags | SMB_STRF_SRCNULTERM);
2635 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2636 size_t cb, char ** chainpp, int flags)
2639 if (!WANTS_UNICODE(pktp))
2640 flags |= SMB_STRF_FORCEASCII;
2643 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2646 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2647 size_t cch, char ** chainpp, int flags)
2652 if (!WANTS_UNICODE(pktp))
2653 flags |= SMB_STRF_FORCEASCII;
2655 cb = cch * sizeof(wchar_t);
2658 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2662 smb_ParseStringBuf(const unsigned char * bufbase,
2663 cm_space_t ** stringspp,
2664 unsigned char *inp, size_t *pcb_max,
2665 char **chainpp, int flags)
2668 if (!(flags & SMB_STRF_FORCEASCII)) {
2670 cm_space_t * spacep;
2673 if (bufbase && ((inp - bufbase) % 2) != 0) {
2674 inp++; /* unicode strings are always word aligned */
2678 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2680 cch_src = *pcb_max / sizeof(wchar_t);
2684 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2691 spacep = cm_GetSpace();
2692 spacep->nextp = *stringspp;
2693 *stringspp = spacep;
2697 *chainpp = inp + sizeof(wchar_t);
2700 *(spacep->wdata) = 0;
2701 return spacep->wdata;
2704 StringCchCopyNW(spacep->wdata,
2705 lengthof(spacep->wdata),
2706 (const clientchar_t *) inp, cch_src);
2709 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2711 return spacep->wdata;
2715 cm_space_t * spacep;
2718 /* Not using Unicode */
2720 *chainpp = inp + strlen(inp) + 1;
2723 spacep = cm_GetSpace();
2724 spacep->nextp = *stringspp;
2725 *stringspp = spacep;
2727 cchdest = lengthof(spacep->wdata);
2728 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2729 spacep->wdata, cchdest);
2731 return spacep->wdata;
2737 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2739 size_t * plen, int flags)
2745 /* we are only calculating the required size */
2752 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2754 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2755 if (!(flags & SMB_STRF_IGNORENUL))
2756 *plen += sizeof(wchar_t);
2758 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2768 cch_str = cm_ClientStrLen(str);
2769 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2772 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2780 /* if outp != NULL ... */
2782 /* Number of bytes left in the buffer.
2784 If outp lies inside the packet data buffer, we assume that the
2785 buffer is the packet data buffer. Otherwise we assume that the
2786 buffer is sizeof(packet->data).
2789 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2790 align = (int)((outp - pktp->data) % 2);
2791 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2793 align = (int)(((size_t) outp) % 2);
2794 buffersize = (int)sizeof(pktp->data);
2799 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2805 if (*str == _C('\0')) {
2807 if (buffersize < sizeof(wchar_t))
2810 *((wchar_t *) outp) = L'\0';
2811 if (plen && !(flags & SMB_STRF_IGNORENUL))
2812 *plen += sizeof(wchar_t);
2813 return outp + sizeof(wchar_t);
2816 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2818 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2819 osi_LogSaveClientString(smb_logp, str),
2825 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2827 return outp + sizeof(wchar_t) * nchars;
2835 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2838 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2840 return outp + cch_dest;
2844 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2850 tlen = inp[0] + (inp[1]<<8);
2851 inp += 2; /* skip length field */
2854 *chainpp = inp + tlen;
2863 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2867 if (*inp++ != 0x1) return NULL;
2868 tlen = inp[0] + (inp[1]<<8);
2869 inp += 2; /* skip length field */
2872 *chainpp = inp + tlen;
2875 if (lengthp) *lengthp = tlen;
2880 /* format a packet as a response */
2881 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2886 outp = (smb_t *) op;
2888 /* zero the basic structure through the smb_wct field, and zero the data
2889 * size field, assuming that wct stays zero; otherwise, you have to
2890 * explicitly set the data size field, too.
2892 inSmbp = (smb_t *) inp;
2893 memset(outp, 0, sizeof(smb_t)+2);
2899 outp->com = inSmbp->com;
2900 outp->tid = inSmbp->tid;
2901 outp->pid = inSmbp->pid;
2902 outp->uid = inSmbp->uid;
2903 outp->mid = inSmbp->mid;
2904 outp->res[0] = inSmbp->res[0];
2905 outp->res[1] = inSmbp->res[1];
2906 op->inCom = inSmbp->com;
2908 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2909 #ifdef SEND_CANONICAL_PATHNAMES
2910 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2912 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2914 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2915 outp->flg2 |= SMB_FLAGS2_UNICODE;
2918 /* copy fields in generic packet area */
2919 op->wctp = &outp->wct;
2922 /* send a (probably response) packet; vcp tells us to whom to send it.
2923 * we compute the length by looking at wct and bcc fields.
2925 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2935 ncbp = smb_GetNCB();
2939 memset((char *)ncbp, 0, sizeof(NCB));
2941 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2942 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2943 extra += tp[0] + (tp[1]<<8);
2944 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2945 extra += 3; /* wct and length fields */
2947 ncbp->ncb_length = extra; /* bytes to send */
2948 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2949 ncbp->ncb_lana_num = vcp->lana;
2950 ncbp->ncb_command = NCBSEND; /* op means send data */
2951 ncbp->ncb_buffer = (char *) inp;/* packet */
2952 code = Netbios(ncbp);
2955 const char * s = ncb_error_string(code);
2956 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2957 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2959 lock_ObtainMutex(&vcp->mx);
2960 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2961 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2963 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2964 lock_ReleaseMutex(&vcp->mx);
2965 lock_ObtainWrite(&smb_globalLock);
2966 dead_sessions[vcp->session] = TRUE;
2967 lock_ReleaseWrite(&smb_globalLock);
2968 smb_CleanupDeadVC(vcp);
2970 lock_ReleaseMutex(&vcp->mx);
2978 void smb_MapNTError(long code, unsigned long *NTStatusp)
2980 unsigned long NTStatus;
2982 /* map CM_ERROR_* errors to NT 32-bit status codes */
2983 /* NT Status codes are listed in ntstatus.h not winerror.h */
2984 if (code == CM_ERROR_NOSUCHCELL) {
2985 NTStatus = 0xC000000FL; /* No such file */
2987 else if (code == CM_ERROR_NOSUCHVOLUME) {
2988 NTStatus = 0xC000000FL; /* No such file */
2990 else if (code == CM_ERROR_TIMEDOUT) {
2992 NTStatus = 0xC00000CFL; /* Sharing Paused */
2994 NTStatus = 0x00000102L; /* Timeout */
2997 else if (code == CM_ERROR_RETRY) {
2998 NTStatus = 0xC000022DL; /* Retry */
3000 else if (code == CM_ERROR_NOACCESS) {
3001 NTStatus = 0xC0000022L; /* Access denied */
3003 else if (code == CM_ERROR_READONLY) {
3004 NTStatus = 0xC00000A2L; /* Write protected */
3006 else if (code == CM_ERROR_NOSUCHFILE ||
3007 code == CM_ERROR_BPLUS_NOMATCH) {
3008 NTStatus = 0xC000000FL; /* No such file */
3010 else if (code == CM_ERROR_NOSUCHPATH) {
3011 NTStatus = 0xC000003AL; /* Object path not found */
3013 else if (code == CM_ERROR_TOOBIG) {
3014 NTStatus = 0xC000007BL; /* Invalid image format */
3016 else if (code == CM_ERROR_INVAL) {
3017 NTStatus = 0xC000000DL; /* Invalid parameter */
3019 else if (code == CM_ERROR_BADFD) {
3020 NTStatus = 0xC0000008L; /* Invalid handle */
3022 else if (code == CM_ERROR_BADFDOP) {
3023 NTStatus = 0xC0000022L; /* Access denied */
3025 else if (code == CM_ERROR_EXISTS) {
3026 NTStatus = 0xC0000035L; /* Object name collision */
3028 else if (code == CM_ERROR_NOTEMPTY) {
3029 NTStatus = 0xC0000101L; /* Directory not empty */
3031 else if (code == CM_ERROR_CROSSDEVLINK) {
3032 NTStatus = 0xC00000D4L; /* Not same device */
3034 else if (code == CM_ERROR_NOTDIR) {
3035 NTStatus = 0xC0000103L; /* Not a directory */
3037 else if (code == CM_ERROR_ISDIR) {
3038 NTStatus = 0xC00000BAL; /* File is a directory */
3040 else if (code == CM_ERROR_BADOP) {
3042 /* I have no idea where this comes from */
3043 NTStatus = 0xC09820FFL; /* SMB no support */
3045 NTStatus = 0xC00000BBL; /* Not supported */
3046 #endif /* COMMENT */
3048 else if (code == CM_ERROR_BADSHARENAME) {
3049 NTStatus = 0xC00000CCL; /* Bad network name */
3051 else if (code == CM_ERROR_NOIPC) {
3053 NTStatus = 0xC0000022L; /* Access Denied */
3055 NTStatus = 0xC000013DL; /* Remote Resources */
3058 else if (code == CM_ERROR_CLOCKSKEW) {
3059 NTStatus = 0xC0000133L; /* Time difference at DC */
3061 else if (code == CM_ERROR_BADTID) {
3062 NTStatus = 0xC0982005L; /* SMB bad TID */
3064 else if (code == CM_ERROR_USESTD) {
3065 NTStatus = 0xC09820FBL; /* SMB use standard */
3067 else if (code == CM_ERROR_QUOTA) {
3068 NTStatus = 0xC0000044L; /* Quota exceeded */
3070 else if (code == CM_ERROR_SPACE) {
3071 NTStatus = 0xC000007FL; /* Disk full */
3073 else if (code == CM_ERROR_ATSYS) {
3074 NTStatus = 0xC0000033L; /* Object name invalid */
3076 else if (code == CM_ERROR_BADNTFILENAME) {
3077 NTStatus = 0xC0000033L; /* Object name invalid */
3079 else if (code == CM_ERROR_WOULDBLOCK) {
3080 NTStatus = 0xC0000055L; /* Lock not granted */
3082 else if (code == CM_ERROR_SHARING_VIOLATION) {
3083 NTStatus = 0xC0000043L; /* Sharing violation */
3085 else if (code == CM_ERROR_LOCK_CONFLICT) {
3086 NTStatus = 0xC0000054L; /* Lock conflict */
3088 else if (code == CM_ERROR_PARTIALWRITE) {
3089 NTStatus = 0xC000007FL; /* Disk full */
3091 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3092 NTStatus = 0xC0000023L; /* Buffer too small */
3094 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3095 NTStatus = 0xC0000035L; /* Object name collision */
3097 else if (code == CM_ERROR_BADPASSWORD) {
3098 NTStatus = 0xC000006DL; /* unknown username or bad password */
3100 else if (code == CM_ERROR_BADLOGONTYPE) {
3101 NTStatus = 0xC000015BL; /* logon type not granted */
3103 else if (code == CM_ERROR_GSSCONTINUE) {
3104 NTStatus = 0xC0000016L; /* more processing required */
3106 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3108 NTStatus = 0xC0000280L; /* reparse point not resolved */
3110 NTStatus = 0xC0000022L; /* Access Denied */
3113 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3114 NTStatus = 0xC0000257L; /* Path Not Covered */
3116 else if (code == CM_ERROR_ALLBUSY) {
3117 NTStatus = 0xC000022DL; /* Retry */
3119 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3120 NTStatus = 0xC00000BEL; /* Bad Network Path */
3122 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3123 NTStatus = 0xC0000322L; /* No Kerberos key */
3125 else if (code == CM_ERROR_BAD_LEVEL) {
3126 NTStatus = 0xC0000148L; /* Invalid Level */
3128 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3129 NTStatus = 0xC000007EL; /* Range Not Locked */
3131 else if (code == CM_ERROR_NOSUCHDEVICE) {
3132 NTStatus = 0xC000000EL; /* No Such Device */
3134 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3135 NTStatus = 0xC0000055L; /* Lock Not Granted */
3137 NTStatus = 0xC0982001L; /* SMB non-specific error */
3140 *NTStatusp = NTStatus;
3141 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3144 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3145 unsigned char *classp)
3147 unsigned char class;
3148 unsigned short error;
3150 /* map CM_ERROR_* errors to SMB errors */
3151 if (code == CM_ERROR_NOSUCHCELL) {
3153 error = 3; /* bad path */
3155 else if (code == CM_ERROR_NOSUCHVOLUME) {
3157 error = 3; /* bad path */
3159 else if (code == CM_ERROR_TIMEDOUT) {
3161 error = 81; /* server is paused */
3163 else if (code == CM_ERROR_RETRY) {
3164 class = 2; /* shouldn't happen */
3167 else if (code == CM_ERROR_NOACCESS) {
3169 error = 4; /* bad access */
3171 else if (code == CM_ERROR_READONLY) {
3173 error = 19; /* read only */
3175 else if (code == CM_ERROR_NOSUCHFILE ||
3176 code == CM_ERROR_BPLUS_NOMATCH) {
3178 error = 2; /* ENOENT! */
3180 else if (code == CM_ERROR_NOSUCHPATH) {
3182 error = 3; /* Bad path */
3184 else if (code == CM_ERROR_TOOBIG) {
3186 error = 11; /* bad format */
3188 else if (code == CM_ERROR_INVAL) {
3189 class = 2; /* server non-specific error code */
3192 else if (code == CM_ERROR_BADFD) {
3194 error = 6; /* invalid file handle */
3196 else if (code == CM_ERROR_BADFDOP) {
3197 class = 1; /* invalid op on FD */
3200 else if (code == CM_ERROR_EXISTS) {
3202 error = 80; /* file already exists */
3204 else if (code == CM_ERROR_NOTEMPTY) {
3206 error = 5; /* delete directory not empty */
3208 else if (code == CM_ERROR_CROSSDEVLINK) {
3210 error = 17; /* EXDEV */
3212 else if (code == CM_ERROR_NOTDIR) {
3213 class = 1; /* bad path */
3216 else if (code == CM_ERROR_ISDIR) {
3217 class = 1; /* access denied; DOS doesn't have a good match */
3220 else if (code == CM_ERROR_BADOP) {
3224 else if (code == CM_ERROR_BADSHARENAME) {
3228 else if (code == CM_ERROR_NOIPC) {
3230 error = 4; /* bad access */
3232 else if (code == CM_ERROR_CLOCKSKEW) {
3233 class = 1; /* invalid function */
3236 else if (code == CM_ERROR_BADTID) {
3240 else if (code == CM_ERROR_USESTD) {
3244 else if (code == CM_ERROR_REMOTECONN) {
3248 else if (code == CM_ERROR_QUOTA) {
3249 if (vcp->flags & SMB_VCFLAG_USEV3) {
3251 error = 39; /* disk full */
3255 error = 5; /* access denied */
3258 else if (code == CM_ERROR_SPACE) {
3259 if (vcp->flags & SMB_VCFLAG_USEV3) {
3261 error = 39; /* disk full */
3265 error = 5; /* access denied */
3268 else if (code == CM_ERROR_PARTIALWRITE) {
3270 error = 39; /* disk full */
3272 else if (code == CM_ERROR_ATSYS) {
3274 error = 2; /* ENOENT */
3276 else if (code == CM_ERROR_WOULDBLOCK) {
3278 error = 33; /* lock conflict */
3280 else if (code == CM_ERROR_LOCK_CONFLICT) {
3282 error = 33; /* lock conflict */
3284 else if (code == CM_ERROR_SHARING_VIOLATION) {
3286 error = 33; /* lock conflict */
3288 else if (code == CM_ERROR_NOFILES) {
3290 error = 18; /* no files in search */
3292 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3294 error = 183; /* Samba uses this */
3296 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3297 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3299 error = 2; /* bad password */
3301 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3303 error = 3; /* bad path */
3312 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3315 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3317 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3318 return CM_ERROR_BADOP;
3322 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3324 unsigned short EchoCount, i;
3325 char *data, *outdata;
3328 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3330 for (i=1; i<=EchoCount; i++) {
3331 data = smb_GetSMBData(inp, &dataSize);
3332 smb_SetSMBParm(outp, 0, i);
3333 smb_SetSMBDataLength(outp, dataSize);
3334 outdata = smb_GetSMBData(outp, NULL);
3335 memcpy(outdata, data, dataSize);
3336 smb_SendPacket(vcp, outp);
3342 /* SMB_COM_READ_RAW */
3343 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3346 long count, minCount, finalCount;
3350 smb_t *smbp = (smb_t*) inp;
3352 cm_user_t *userp = NULL;
3355 char *rawBuf = NULL;
3360 fd = smb_GetSMBParm(inp, 0);
3361 count = smb_GetSMBParm(inp, 3);
3362 minCount = smb_GetSMBParm(inp, 4);
3363 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3365 if (*inp->wctp == 10) {
3366 /* we were sent a request with 64-bit file offsets */
3367 #ifdef AFS_LARGEFILES
3368 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3370 if (LargeIntegerLessThanZero(offset)) {
3371 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3375 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3376 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3379 offset.HighPart = 0;
3383 /* we were sent a request with 32-bit file offsets */
3384 offset.HighPart = 0;
3387 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3388 fd, offset.HighPart, offset.LowPart, count);
3390 fidp = smb_FindFID(vcp, fd, 0);
3394 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3395 smb_CloseFID(vcp, fidp, NULL, 0);
3396 code = CM_ERROR_NOSUCHFILE;
3403 LARGE_INTEGER LOffset, LLength;
3406 key = cm_GenerateKey(vcp->vcID, pid, fd);
3408 LOffset.HighPart = offset.HighPart;
3409 LOffset.LowPart = offset.LowPart;
3410 LLength.HighPart = 0;
3411 LLength.LowPart = count;
3413 lock_ObtainWrite(&fidp->scp->rw);
3414 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3415 lock_ReleaseWrite(&fidp->scp->rw);
3421 lock_ObtainMutex(&smb_RawBufLock);
3423 /* Get a raw buf, from head of list */
3424 rawBuf = smb_RawBufs;
3425 smb_RawBufs = *(char **)smb_RawBufs;
3427 lock_ReleaseMutex(&smb_RawBufLock);
3431 lock_ObtainMutex(&fidp->mx);
3432 if (fidp->flags & SMB_FID_IOCTL)
3434 lock_ReleaseMutex(&fidp->mx);
3435 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3437 /* Give back raw buffer */
3438 lock_ObtainMutex(&smb_RawBufLock);
3439 *((char **) rawBuf) = smb_RawBufs;
3441 smb_RawBufs = rawBuf;
3442 lock_ReleaseMutex(&smb_RawBufLock);
3445 lock_ReleaseMutex(&fidp->mx);
3446 smb_ReleaseFID(fidp);
3449 lock_ReleaseMutex(&fidp->mx);
3451 userp = smb_GetUserFromVCP(vcp, inp);
3453 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3459 cm_ReleaseUser(userp);
3462 smb_ReleaseFID(fidp);
3466 memset((char *)ncbp, 0, sizeof(NCB));
3468 ncbp->ncb_length = (unsigned short) finalCount;
3469 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3470 ncbp->ncb_lana_num = vcp->lana;
3471 ncbp->ncb_command = NCBSEND;
3472 ncbp->ncb_buffer = rawBuf;
3474 code = Netbios(ncbp);
3476 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3479 /* Give back raw buffer */
3480 lock_ObtainMutex(&smb_RawBufLock);
3481 *((char **) rawBuf) = smb_RawBufs;
3483 smb_RawBufs = rawBuf;
3484 lock_ReleaseMutex(&smb_RawBufLock);
3490 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3492 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3497 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3499 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3504 /* SMB_COM_NEGOTIATE */
3505 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3512 int VistaProtoIndex;
3513 int protoIndex; /* index we're using */
3518 char protocol_array[10][1024]; /* protocol signature of the client */
3519 int caps; /* capabilities */
3522 TIME_ZONE_INFORMATION tzi;
3524 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3527 namep = smb_GetSMBData(inp, &dbytes);
3530 coreProtoIndex = -1; /* not found */
3533 VistaProtoIndex = -1;
3534 while(namex < dbytes) {
3535 osi_Log1(smb_logp, "Protocol %s",
3536 osi_LogSaveString(smb_logp, namep+1));
3537 strcpy(protocol_array[tcounter], namep+1);
3539 /* namep points at the first protocol, or really, a 0x02
3540 * byte preceding the null-terminated ASCII name.
3542 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3543 coreProtoIndex = tcounter;
3545 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3546 v3ProtoIndex = tcounter;
3548 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3549 NTProtoIndex = tcounter;
3551 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3552 VistaProtoIndex = tcounter;
3555 /* compute size of protocol entry */
3556 entryLength = (int)strlen(namep+1);
3557 entryLength += 2; /* 0x02 bytes and null termination */
3559 /* advance over this protocol entry */
3560 namex += entryLength;
3561 namep += entryLength;
3562 tcounter++; /* which proto entry we're looking at */
3565 lock_ObtainMutex(&vcp->mx);
3567 if (VistaProtoIndex != -1) {
3568 protoIndex = VistaProtoIndex;
3569 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3572 if (NTProtoIndex != -1) {
3573 protoIndex = NTProtoIndex;
3574 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3576 else if (v3ProtoIndex != -1) {
3577 protoIndex = v3ProtoIndex;
3578 vcp->flags |= SMB_VCFLAG_USEV3;
3580 else if (coreProtoIndex != -1) {
3581 protoIndex = coreProtoIndex;
3582 vcp->flags |= SMB_VCFLAG_USECORE;
3584 else protoIndex = -1;
3585 lock_ReleaseMutex(&vcp->mx);
3587 if (protoIndex == -1)
3588 return CM_ERROR_INVAL;
3589 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3590 smb_SetSMBParm(outp, 0, protoIndex);
3591 if (smb_authType != SMB_AUTH_NONE) {
3592 smb_SetSMBParmByte(outp, 1,
3593 NEGOTIATE_SECURITY_USER_LEVEL |
3594 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3596 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3598 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3599 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3600 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3601 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3602 /* The session key is not a well documented field however most clients
3603 * will echo back the session key to the server. Currently we are using
3604 * the same value for all sessions. We should generate a random value
3605 * and store it into the vcp
3607 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3608 smb_SetSMBParm(outp, 8, 1);
3610 * Tried changing the capabilities to support for W2K - defect 117695
3611 * Maybe something else needs to be changed here?
3615 smb_SetSMBParmLong(outp, 9, 0x43fd);
3617 smb_SetSMBParmLong(outp, 9, 0x251);
3620 * 32-bit error codes *
3626 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3628 NTNEGOTIATE_CAPABILITY_DFS |
3630 #ifdef AFS_LARGEFILES
3631 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3633 NTNEGOTIATE_CAPABILITY_NTFIND |
3634 NTNEGOTIATE_CAPABILITY_RAWMODE |
3635 NTNEGOTIATE_CAPABILITY_NTSMB;
3637 if ( smb_authType == SMB_AUTH_EXTENDED )
3638 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3641 if ( smb_UseUnicode ) {
3642 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3646 smb_SetSMBParmLong(outp, 9, caps);
3648 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3649 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3650 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3652 GetTimeZoneInformation(&tzi);
3653 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3655 if (smb_authType == SMB_AUTH_NTLM) {
3656 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3657 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3658 /* paste in encryption key */
3659 datap = smb_GetSMBData(outp, NULL);
3660 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3661 /* and the faux domain name */
3662 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3663 datap + MSV1_0_CHALLENGE_LENGTH,
3664 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3665 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3669 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3671 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3673 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3675 datap = smb_GetSMBData(outp, NULL);
3676 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3679 datap += sizeof(smb_ServerGUID);
3680 memcpy(datap, secBlob, secBlobLength);
3684 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3685 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3688 else if (v3ProtoIndex != -1) {
3689 smb_SetSMBParm(outp, 0, protoIndex);
3691 /* NOTE: Extended authentication cannot be negotiated with v3
3692 * therefore we fail over to NTLM
3694 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3695 smb_SetSMBParm(outp, 1,
3696 NEGOTIATE_SECURITY_USER_LEVEL |
3697 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3699 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3701 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3702 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3703 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3704 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3705 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3706 smb_SetSMBParm(outp, 7, 1);
3708 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3709 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3710 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3712 GetTimeZoneInformation(&tzi);
3713 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3715 /* NOTE: Extended authentication cannot be negotiated with v3
3716 * therefore we fail over to NTLM
3718 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3719 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3720 smb_SetSMBParm(outp, 12, 0); /* resvd */
3721 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3722 datap = smb_GetSMBData(outp, NULL);
3723 /* paste in a new encryption key */
3724 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3725 /* and the faux domain name */
3726 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3727 datap + MSV1_0_CHALLENGE_LENGTH,
3728 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3730 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3731 smb_SetSMBParm(outp, 12, 0); /* resvd */
3732 smb_SetSMBDataLength(outp, 0);
3735 else if (coreProtoIndex != -1) { /* not really supported anymore */
3736 smb_SetSMBParm(outp, 0, protoIndex);
3737 smb_SetSMBDataLength(outp, 0);
3742 void smb_CheckVCs(void)
3744 smb_vc_t * vcp, *nextp;
3745 smb_packet_t * outp = smb_GetPacket();
3748 lock_ObtainWrite(&smb_rctLock);
3749 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3751 if (vcp->magic != SMB_VC_MAGIC)
3752 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3753 __FILE__, __LINE__);
3757 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3760 smb_HoldVCNoLock(vcp);
3762 smb_HoldVCNoLock(nextp);
3763 smb_FormatResponsePacket(vcp, NULL, outp);
3764 smbp = (smb_t *)outp;
3765 outp->inCom = smbp->com = 0x2b /* Echo */;
3773 smb_SetSMBParm(outp, 0, 0);
3774 smb_SetSMBDataLength(outp, 0);
3775 lock_ReleaseWrite(&smb_rctLock);
3777 smb_SendPacket(vcp, outp);
3779 lock_ObtainWrite(&smb_rctLock);
3780 smb_ReleaseVCNoLock(vcp);
3782 smb_ReleaseVCNoLock(nextp);
3784 lock_ReleaseWrite(&smb_rctLock);
3785 smb_FreePacket(outp);
3788 void smb_Daemon(void *parmp)
3790 afs_uint32 count = 0;
3791 smb_username_t **unpp;
3794 while(smbShutdownFlag == 0) {
3798 if (smbShutdownFlag == 1)
3801 if ((count % 72) == 0) { /* every five minutes */
3803 time_t old_localZero = smb_localZero;
3805 /* Initialize smb_localZero */
3806 myTime.tm_isdst = -1; /* compute whether on DST or not */
3807 myTime.tm_year = 70;
3813 smb_localZero = mktime(&myTime);
3815 #ifndef USE_NUMERIC_TIME_CONV
3816 smb_CalculateNowTZ();
3817 #endif /* USE_NUMERIC_TIME_CONV */
3818 #ifdef AFS_FREELANCE
3819 if ( smb_localZero != old_localZero )
3820 cm_noteLocalMountPointChange();
3826 /* GC smb_username_t objects that will no longer be used */
3828 lock_ObtainWrite(&smb_rctLock);
3829 for ( unpp=&usernamesp; *unpp; ) {
3831 smb_username_t *unp;
3833 lock_ObtainMutex(&(*unpp)->mx);
3834 if ( (*unpp)->refCount > 0 ||
3835 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3836 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3838 else if (!smb_LogoffTokenTransfer ||
3839 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3841 lock_ReleaseMutex(&(*unpp)->mx);
3849 lock_FinalizeMutex(&unp->mx);
3855 cm_ReleaseUser(userp);
3857 unpp = &(*unpp)->nextp;
3860 lock_ReleaseWrite(&smb_rctLock);
3862 /* XXX GC dir search entries */
3866 void smb_WaitingLocksDaemon()
3868 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3869 smb_waitingLock_t *wl, *wlNext;
3872 smb_packet_t *inp, *outp;
3876 while (smbShutdownFlag == 0) {
3877 lock_ObtainWrite(&smb_globalLock);
3878 nwlRequest = smb_allWaitingLocks;
3879 if (nwlRequest == NULL) {
3880 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3885 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3892 lock_ObtainWrite(&smb_globalLock);
3894 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3896 wlRequest = nwlRequest;
3897 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3898 lock_ReleaseWrite(&smb_globalLock);
3902 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3903 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3906 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3907 code = CM_ERROR_LOCK_NOT_GRANTED;
3911 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3913 /* wl->state is either _DONE or _WAITING. _ERROR
3914 would no longer be on the queue. */
3915 code = cm_RetryLock( wl->lockp,
3916 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3919 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3920 } else if (code != CM_ERROR_WOULDBLOCK) {
3921 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3926 if (code == CM_ERROR_WOULDBLOCK) {
3929 if (wlRequest->msTimeout != 0xffffffff
3930 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3942 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3945 scp = wlRequest->scp;
3946 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3950 lock_ObtainWrite(&scp->rw);
3952 for (wl = wlRequest->locks; wl; wl = wlNext) {
3953 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3955 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3956 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3957 wl->LLength, wl->key, NULL, &req);
3959 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3964 lock_ReleaseWrite(&scp->rw);
3968 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3971 for (wl = wlRequest->locks; wl; wl = wlNext) {
3972 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3973 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3978 vcp = wlRequest->vcp;
3979 inp = wlRequest->inp;
3980 outp = wlRequest->outp;
3981 ncbp = smb_GetNCB();
3982 ncbp->ncb_length = inp->ncb_length;
3983 inp->spacep = cm_GetSpace();
3985 /* Remove waitingLock from list */
3986 lock_ObtainWrite(&smb_globalLock);
3987 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3989 lock_ReleaseWrite(&smb_globalLock);
3991 /* Resume packet processing */
3993 smb_SetSMBDataLength(outp, 0);
3994 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3995 outp->resumeCode = code;
3997 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4000 cm_FreeSpace(inp->spacep);
4001 smb_FreePacket(inp);
4002 smb_FreePacket(outp);
4004 cm_ReleaseSCache(wlRequest->scp);
4007 } while (nwlRequest && smbShutdownFlag == 0);
4012 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4014 osi_Log0(smb_logp, "SMB receive get disk attributes");
4016 smb_SetSMBParm(outp, 0, 32000);
4017 smb_SetSMBParm(outp, 1, 64);
4018 smb_SetSMBParm(outp, 2, 1024);
4019 smb_SetSMBParm(outp, 3, 30000);
4020 smb_SetSMBParm(outp, 4, 0);
4021 smb_SetSMBDataLength(outp, 0);
4025 /* SMB_COM_TREE_CONNECT */
4026 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4030 unsigned short newTid;
4031 clientchar_t shareName[AFSPATHMAX];
4032 clientchar_t *sharePath;
4035 clientchar_t *pathp;
4038 osi_Log0(smb_logp, "SMB receive tree connect");
4040 /* parse input parameters */
4043 tbp = smb_GetSMBData(inp, NULL);
4044 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4046 tp = cm_ClientStrRChr(pathp, '\\');
4048 return CM_ERROR_BADSMB;
4049 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4051 lock_ObtainMutex(&vcp->mx);
4052 newTid = vcp->tidCounter++;
4053 lock_ReleaseMutex(&vcp->mx);
4055 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4056 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4057 userp = smb_GetUserFromUID(uidp);
4058 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4060 smb_ReleaseUID(uidp);
4062 smb_ReleaseTID(tidp, FALSE);
4063 return CM_ERROR_BADSHARENAME;
4065 lock_ObtainMutex(&tidp->mx);
4066 tidp->userp = userp;
4067 tidp->pathname = sharePath;
4068 lock_ReleaseMutex(&tidp->mx);
4069 smb_ReleaseTID(tidp, FALSE);
4071 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4072 smb_SetSMBParm(rsp, 1, newTid);
4073 smb_SetSMBDataLength(rsp, 0);
4075 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4079 /* set maskp to the mask part of the incoming path.
4080 * Mask is 11 bytes long (8.3 with the dot elided).
4081 * Returns true if succeeds with a valid name, otherwise it does
4082 * its best, but returns false.
4084 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4092 /* starts off valid */
4095 /* mask starts out all blanks */
4096 memset(maskp, ' ', 11);
4099 /* find last backslash, or use whole thing if there is none */
4100 tp = cm_ClientStrRChr(pathp, '\\');
4104 tp++; /* skip slash */
4108 /* names starting with a dot are illegal */
4116 if (tc == '.' || tc == '"')
4124 /* if we get here, tp point after the dot */
4125 up = maskp+8; /* ext goes here */
4132 if (tc == '.' || tc == '"')
4135 /* copy extension if not too long */
4145 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4147 clientchar_t umask[11];
4155 /* XXX redo this, calling cm_MatchMask with a converted mask */
4157 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4161 /* otherwise, we have a valid 8.3 name; see if we have a match,
4162 * treating '?' as a wildcard in maskp (but not in the file name).
4164 tp1 = umask; /* real name, in mask format */
4165 tp2 = maskp; /* mask, in mask format */
4166 for(i=0; i<11; i++) {
4167 tc1 = *tp1++; /* clientchar_t from real name */
4168 tc2 = *tp2++; /* clientchar_t from mask */
4169 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4170 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4173 if (tc2 == '?' && tc1 != ' ')
4180 /* we got a match */
4184 clientchar_t *smb_FindMask(clientchar_t *pathp)
4188 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4191 return tp+1; /* skip the slash */
4193 return pathp; /* no slash, return the entire path */
4196 /* SMB_COM_SEARCH for a volume label
4198 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4199 dispatch function.) */
4200 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4202 clientchar_t *pathp;
4204 clientchar_t mask[12];
4205 unsigned char *statBlockp;
4206 unsigned char initStatBlock[21];
4209 osi_Log0(smb_logp, "SMB receive search volume");
4211 /* pull pathname and stat block out of request */
4212 tp = smb_GetSMBData(inp, NULL);
4213 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4214 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4215 osi_assertx(pathp != NULL, "null path");
4216 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4217 osi_assertx(statBlockp != NULL, "null statBlock");
4219 statBlockp = initStatBlock;
4223 /* for returning to caller */
4224 smb_Get8Dot3MaskFromPath(mask, pathp);
4226 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4227 tp = smb_GetSMBData(outp, NULL);
4229 *tp++ = 43; /* bytes in a dir entry */
4230 *tp++ = 0; /* high byte in counter */
4232 /* now marshall the dir entry, starting with the search status */
4233 *tp++ = statBlockp[0]; /* Reserved */
4234 memcpy(tp, mask, 11); tp += 11; /* FileName */
4236 /* now pass back server use info, with 1st byte non-zero */
4238 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4240 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4242 *tp++ = 0x8; /* attribute: volume */
4252 /* 4 byte file size */
4258 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4261 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4262 memset(tp, ' ', 13);
4265 /* set the length of the data part of the packet to 43 + 3, for the dir
4266 * entry plus the 5 and the length fields.
4268 smb_SetSMBDataLength(outp, 46);
4273 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4274 clientchar_t * tidPathp, clientchar_t * relPathp,
4275 cm_user_t *userp, cm_req_t *reqp)
4283 smb_dirListPatch_t *patchp;
4284 smb_dirListPatch_t *npatchp;
4285 clientchar_t path[AFSPATHMAX];
4287 afs_int32 mustFake = 0;
4289 code = cm_FindACLCache(dscp, userp, &rights);
4291 lock_ObtainWrite(&dscp->rw);
4292 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4293 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4294 lock_ReleaseWrite(&dscp->rw);
4295 if (code == CM_ERROR_NOACCESS) {
4303 if (!mustFake) { /* Bulk Stat */
4305 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4307 memset(bsp, 0, sizeof(cm_bulkStat_t));
4309 for (patchp = *dirPatchespp, count=0;
4311 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4312 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4316 if (lock_TryWrite(&tscp->rw)) {
4317 /* we have an entry that we can look at */
4318 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4319 /* we have a callback on it. Don't bother
4320 * fetching this stat entry, since we're happy
4321 * with the info we have.
4323 lock_ReleaseWrite(&tscp->rw);
4324 cm_ReleaseSCache(tscp);
4327 lock_ReleaseWrite(&tscp->rw);
4329 cm_ReleaseSCache(tscp);
4333 bsp->fids[i].Volume = patchp->fid.volume;
4334 bsp->fids[i].Vnode = patchp->fid.vnode;
4335 bsp->fids[i].Unique = patchp->fid.unique;
4337 if (bsp->counter == AFSCBMAX) {
4338 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4339 memset(bsp, 0, sizeof(cm_bulkStat_t));
4343 if (bsp->counter > 0)
4344 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4349 for (patchp = *dirPatchespp; patchp; patchp =
4350 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4352 dptr = patchp->dptr;
4354 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4355 relPathp ? relPathp : _C(""), patchp->dep->name);
4356 reqp->relPathp = path;
4357 reqp->tidPathp = tidPathp;
4359 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4360 reqp->relPathp = reqp->tidPathp = NULL;
4363 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4364 *dptr++ = SMB_ATTR_HIDDEN;
4367 lock_ObtainWrite(&scp->rw);
4368 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4369 lock_ReleaseWrite(&scp->rw);
4371 /* set the attribute */
4372 switch (scp->fileType) {
4373 case CM_SCACHETYPE_DIRECTORY:
4374 case CM_SCACHETYPE_MOUNTPOINT:
4375 case CM_SCACHETYPE_SYMLINK:
4376 case CM_SCACHETYPE_INVALID:
4377 attr = SMB_ATTR_DIRECTORY;
4380 /* if we get here we either have a normal file
4381 * or we have a file for which we have never
4382 * received status info. In this case, we can
4383 * check the even/odd value of the entry's vnode.
4384 * even means it is to be treated as a directory
4385 * and odd means it is to be treated as a file.
4387 if (mustFake && (scp->fid.vnode & 0x1))
4388 attr = SMB_ATTR_DIRECTORY;
4390 attr = SMB_ATTR_NORMAL;
4394 /* 1969-12-31 23:59:58 +00*/
4395 dosTime = 0xEBBFBF7D;
4398 shortTemp = (unsigned short) (dosTime & 0xffff);
4399 *((u_short *)dptr) = shortTemp;
4402 /* and copy out date */
4403 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4404 *((u_short *)dptr) = shortTemp;
4407 /* copy out file length */
4408 *((u_long *)dptr) = 0;
4411 lock_ConvertWToR(&scp->rw);
4412 attr = smb_Attributes(scp);
4413 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4414 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4415 attr |= SMB_ATTR_HIDDEN;
4419 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4422 shortTemp = (unsigned short) (dosTime & 0xffff);
4423 *((u_short *)dptr) = shortTemp;
4426 /* and copy out date */
4427 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4428 *((u_short *)dptr) = shortTemp;
4431 /* copy out file length */
4432 *((u_long *)dptr) = scp->length.LowPart;
4434 lock_ReleaseRead(&scp->rw);
4436 cm_ReleaseSCache(scp);
4439 /* now free the patches */
4440 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4441 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4445 /* and mark the list as empty */
4446 *dirPatchespp = NULL;
4452 /* SMB_COM_SEARCH */
4453 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4459 clientchar_t *pathp;
4460 cm_dirEntry_t *dep = 0;
4462 smb_dirListPatch_t *dirListPatchesp;
4463 smb_dirListPatch_t *curPatchp;
4467 osi_hyper_t dirLength;
4468 osi_hyper_t bufferOffset;
4469 osi_hyper_t curOffset;
4471 unsigned char *inCookiep;
4472 smb_dirSearch_t *dsp;
4476 unsigned long clientCookie;
4477 cm_pageHeader_t *pageHeaderp;
4478 cm_user_t *userp = NULL;
4480 clientchar_t mask[12];
4482 long nextEntryCookie;
4483 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4484 char resByte; /* reserved byte from the cookie */
4485 char *op; /* output data ptr */
4486 char *origOp; /* original value of op */
4487 cm_space_t *spacep; /* for pathname buffer */
4491 clientchar_t *tidPathp = 0;
4498 maxCount = smb_GetSMBParm(inp, 0);
4500 dirListPatchesp = NULL;
4502 caseFold = CM_FLAG_CASEFOLD;
4504 tp = smb_GetSMBData(inp, NULL);
4505 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4506 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4507 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4509 /* bail out if request looks bad */
4510 if (!tp || !pathp) {
4511 return CM_ERROR_BADSMB;
4514 /* We can handle long names */
4515 if (vcp->flags & SMB_VCFLAG_USENT)
4516 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4518 /* make sure we got a whole search status */
4519 if (dataLength < 21) {
4520 nextCookie = 0; /* start at the beginning of the dir */
4523 attribute = smb_GetSMBParm(inp, 1);
4525 /* handle volume info in another function */
4526 if (attribute & 0x8)
4527 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4529 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4530 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4532 if (*pathp == 0) { /* null pathp, treat as root dir */
4533 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4534 return CM_ERROR_NOFILES;
4538 dsp = smb_NewDirSearch(0);
4539 dsp->attribute = attribute;
4540 smb_Get8Dot3MaskFromPath(mask, pathp);
4541 memcpy(dsp->mask, mask, 12);
4543 /* track if this is likely to match a lot of entries */
4544 if (smb_IsStarMask(mask))
4549 /* pull the next cookie value out of the search status block */
4550 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4551 + (inCookiep[16]<<24);
4552 dsp = smb_FindDirSearch(inCookiep[12]);
4554 /* can't find dir search status; fatal error */
4555 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4556 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4557 return CM_ERROR_BADFD;
4559 attribute = dsp->attribute;
4560 resByte = inCookiep[0];
4562 /* copy out client cookie, in host byte order. Don't bother
4563 * interpreting it, since we're just passing it through, anyway.
4565 memcpy(&clientCookie, &inCookiep[17], 4);
4567 memcpy(mask, dsp->mask, 12);
4569 /* assume we're doing a star match if it has continued for more
4575 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4576 nextCookie, dsp->cookie, attribute);
4578 userp = smb_GetUserFromVCP(vcp, inp);
4580 /* try to get the vnode for the path name next */
4581 lock_ObtainMutex(&dsp->mx);
4584 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4588 spacep = inp->spacep;
4589 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4590 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4592 lock_ReleaseMutex(&dsp->mx);
4593 cm_ReleaseUser(userp);
4594 smb_DeleteDirSearch(dsp);
4595 smb_ReleaseDirSearch(dsp);
4596 return CM_ERROR_NOFILES;
4598 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4599 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4601 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4602 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4605 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4608 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4609 cm_ReleaseSCache(scp);
4610 lock_ReleaseMutex(&dsp->mx);
4611 cm_ReleaseUser(userp);
4612 smb_DeleteDirSearch(dsp);
4613 smb_ReleaseDirSearch(dsp);
4614 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4615 return CM_ERROR_PATH_NOT_COVERED;
4617 return CM_ERROR_BADSHARENAME;
4619 #endif /* DFS_SUPPORT */
4622 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4623 /* we need one hold for the entry we just stored into,
4624 * and one for our own processing. When we're done with this
4625 * function, we'll drop the one for our own processing.
4626 * We held it once from the namei call, and so we do another hold
4630 lock_ObtainWrite(&scp->rw);
4631 dsp->flags |= SMB_DIRSEARCH_BULKST;
4632 lock_ReleaseWrite(&scp->rw);
4635 lock_ReleaseMutex(&dsp->mx);
4637 cm_ReleaseUser(userp);
4638 smb_DeleteDirSearch(dsp);
4639 smb_ReleaseDirSearch(dsp);
4643 /* reserves space for parameter; we'll adjust it again later to the
4644 * real count of the # of entries we returned once we've actually
4645 * assembled the directory listing.
4647 smb_SetSMBParm(outp, 0, 0);
4649 /* get the directory size */
4650 lock_ObtainWrite(&scp->rw);
4651 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4652 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4654 lock_ReleaseWrite(&scp->rw);
4655 cm_ReleaseSCache(scp);
4656 cm_ReleaseUser(userp);
4657 smb_DeleteDirSearch(dsp);
4658 smb_ReleaseDirSearch(dsp);
4662 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4664 dirLength = scp->length;
4666 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4667 curOffset.HighPart = 0;
4668 curOffset.LowPart = nextCookie;
4669 origOp = op = smb_GetSMBData(outp, NULL);
4670 /* and write out the basic header */
4671 *op++ = 5; /* variable block */
4672 op += 2; /* skip vbl block length; we'll fill it in later */
4676 clientchar_t *actualName;
4677 clientchar_t shortName[13];
4678 clientchar_t *shortNameEnd;
4680 /* make sure that curOffset.LowPart doesn't point to the first
4681 * 32 bytes in the 2nd through last dir page, and that it doesn't
4682 * point at the first 13 32-byte chunks in the first dir page,
4683 * since those are dir and page headers, and don't contain useful
4686 temp = curOffset.LowPart & (2048-1);
4687 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4688 /* we're in the first page */
4689 if (temp < 13*32) temp = 13*32;
4692 /* we're in a later dir page */
4693 if (temp < 32) temp = 32;
4696 /* make sure the low order 5 bits are zero */
4699 /* now put temp bits back ito curOffset.LowPart */
4700 curOffset.LowPart &= ~(2048-1);
4701 curOffset.LowPart |= temp;
4703 /* check if we've returned all the names that will fit in the
4706 if (returnedNames >= maxCount) {
4707 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4708 returnedNames, maxCount);
4712 /* check if we've passed the dir's EOF */
4713 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4715 /* see if we can use the bufferp we have now; compute in which page
4716 * the current offset would be, and check whether that's the offset
4717 * of the buffer we have. If not, get the buffer.
4719 thyper.HighPart = curOffset.HighPart;
4720 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4721 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4724 buf_Release(bufferp);
4727 lock_ReleaseWrite(&scp->rw);
4728 code = buf_Get(scp, &thyper, &bufferp);
4729 lock_ObtainMutex(&dsp->mx);
4731 /* now, if we're doing a star match, do bulk fetching of all of
4732 * the status info for files in the dir.
4735 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4737 lock_ObtainWrite(&scp->rw);
4738 lock_ReleaseMutex(&dsp->mx);
4740 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4744 bufferOffset = thyper;
4746 /* now get the data in the cache */
4748 code = cm_SyncOp(scp, bufferp, userp, &req,
4750 CM_SCACHESYNC_NEEDCALLBACK |
4751 CM_SCACHESYNC_READ);
4753 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4757 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4759 if (cm_HaveBuffer(scp, bufferp, 0)) {
4760 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4764 /* otherwise, load the buffer and try again */
4765 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4767 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4768 scp, bufferp, code);
4773 buf_Release(bufferp);
4777 } /* if (wrong buffer) ... */
4779 /* now we have the buffer containing the entry we're interested in; copy
4780 * it out if it represents a non-deleted entry.
4782 entryInDir = curOffset.LowPart & (2048-1);
4783 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4785 /* page header will help tell us which entries are free. Page header
4786 * can change more often than once per buffer, since AFS 3 dir page size
4787 * may be less than (but not more than a buffer package buffer.
4789 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4790 temp &= ~(2048 - 1); /* turn off intra-page bits */
4791 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4793 /* now determine which entry we're looking at in the page. If it is
4794 * free (there's a free bitmap at the start of the dir), we should
4795 * skip these 32 bytes.
4797 slotInPage = (entryInDir & 0x7e0) >> 5;
4798 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4799 /* this entry is free */
4800 numDirChunks = 1; /* only skip this guy */
4804 tp = bufferp->datap + entryInBuffer;
4805 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4807 /* while we're here, compute the next entry's location, too,
4808 * since we'll need it when writing out the cookie into the dir
4811 * XXXX Probably should do more sanity checking.
4813 numDirChunks = cm_NameEntries(dep->name, NULL);
4815 /* compute the offset of the cookie representing the next entry */
4816 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4818 /* Compute 8.3 name if necessary */
4819 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4820 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4822 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4823 actualName = shortName;
4826 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
4827 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4828 osi_LogSaveClientString(smb_logp, actualName));
4830 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4831 /* this is one of the entries to use: it is not deleted
4832 * and it matches the star pattern we're looking for.
4835 /* Eliminate entries that don't match requested
4838 /* no hidden files */
4839 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4840 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4844 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4846 /* We have already done the cm_TryBulkStat above */
4847 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4848 fileType = cm_FindFileType(&fid);
4849 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4850 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4852 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4853 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4854 fileType == CM_SCACHETYPE_DFSLINK ||
4855 fileType == CM_SCACHETYPE_INVALID)
4856 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4861 memcpy(op, mask, 11); op += 11;
4862 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
4863 *op++ = (unsigned char)(nextEntryCookie & 0xff);
4864 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
4865 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
4866 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
4867 memcpy(op, &clientCookie, 4); op += 4;
4869 /* now we emit the attribute. This is sort of tricky,
4870 * since we need to really stat the file to find out
4871 * what type of entry we've got. Right now, we're
4872 * copying out data from a buffer, while holding the
4873 * scp locked, so it isn't really convenient to stat
4874 * something now. We'll put in a place holder now,
4875 * and make a second pass before returning this to get
4876 * the real attributes. So, we just skip the data for
4877 * now, and adjust it later. We allocate a patch
4878 * record to make it easy to find this point later.
4879 * The replay will happen at a time when it is safe to
4880 * unlock the directory.
4882 curPatchp = malloc(sizeof(*curPatchp));
4883 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4884 curPatchp->dptr = op;
4885 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4887 /* do hidden attribute here since name won't be around when applying
4891 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4892 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4894 curPatchp->flags = 0;
4896 op += 9; /* skip attr, time, date and size */
4898 /* zero out name area. The spec says to pad with
4899 * spaces, but Samba doesn't, and neither do we.
4903 /* finally, we get to copy out the name; we know that
4904 * it fits in 8.3 or the pattern wouldn't match, but it
4905 * never hurts to be sure.
4907 cm_ClientStringToUtf8(actualName, -1, op, 13);
4908 if (smb_StoreAnsiFilenames)
4910 /* This is a UCHAR field, which is ASCII even if Unicode
4913 /* Uppercase if requested by client */
4914 if (!KNOWS_LONG_NAMES(inp))
4919 /* now, adjust the # of entries copied */
4921 } /* if we're including this name */
4924 /* and adjust curOffset to be where the new cookie is */
4925 thyper.HighPart = 0;
4926 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4927 curOffset = LargeIntegerAdd(thyper, curOffset);
4928 } /* while copying data for dir listing */
4930 /* release the mutex */
4931 lock_ReleaseWrite(&scp->rw);
4933 buf_Release(bufferp);
4937 /* apply and free last set of patches; if not doing a star match, this
4938 * will be empty, but better safe (and freeing everything) than sorry.
4940 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4942 /* special return code for unsuccessful search */
4943 if (code == 0 && dataLength < 21 && returnedNames == 0)
4944 code = CM_ERROR_NOFILES;
4946 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4947 returnedNames, code);
4950 smb_DeleteDirSearch(dsp);
4951 smb_ReleaseDirSearch(dsp);
4952 cm_ReleaseSCache(scp);
4953 cm_ReleaseUser(userp);
4957 /* finalize the output buffer */
4958 smb_SetSMBParm(outp, 0, returnedNames);
4959 temp = (long) (op - origOp);
4960 smb_SetSMBDataLength(outp, temp);
4962 /* the data area is a variable block, which has a 5 (already there)
4963 * followed by the length of the # of data bytes. We now know this to
4964 * be "temp," although that includes the 3 bytes of vbl block header.
4965 * Deduct for them and fill in the length field.
4967 temp -= 3; /* deduct vbl block info */
4968 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4969 origOp[1] = (unsigned char)(temp & 0xff);
4970 origOp[2] = (unsigned char)((temp>>8) & 0xff);
4971 if (returnedNames == 0)
4972 smb_DeleteDirSearch(dsp);
4973 smb_ReleaseDirSearch(dsp);
4974 cm_ReleaseSCache(scp);
4975 cm_ReleaseUser(userp);
4980 /* verify that this is a valid path to a directory. I don't know why they
4981 * don't use the get file attributes call.
4983 * SMB_COM_CHECK_DIRECTORY
4985 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4987 clientchar_t *pathp;
4989 cm_scache_t *rootScp;
4990 cm_scache_t *newScp;
4994 clientchar_t *tidPathp;
5000 pdata = smb_GetSMBData(inp, NULL);
5001 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5003 return CM_ERROR_BADFD;
5004 osi_Log1(smb_logp, "SMB receive check path %S",
5005 osi_LogSaveClientString(smb_logp, pathp));
5007 rootScp = cm_data.rootSCachep;
5009 userp = smb_GetUserFromVCP(vcp, inp);
5011 caseFold = CM_FLAG_CASEFOLD;
5013 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5015 cm_ReleaseUser(userp);
5016 return CM_ERROR_NOSUCHPATH;
5018 code = cm_NameI(rootScp, pathp,
5019 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5020 userp, tidPathp, &req, &newScp);
5023 cm_ReleaseUser(userp);
5028 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5029 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5030 cm_ReleaseSCache(newScp);
5031 cm_ReleaseUser(userp);
5032 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5033 return CM_ERROR_PATH_NOT_COVERED;
5035 return CM_ERROR_BADSHARENAME;
5037 #endif /* DFS_SUPPORT */
5039 /* now lock the vnode with a callback; returns with newScp locked */
5040 lock_ObtainWrite(&newScp->rw);
5041 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5042 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5044 if (code != CM_ERROR_NOACCESS) {
5045 lock_ReleaseWrite(&newScp->rw);
5046 cm_ReleaseSCache(newScp);
5047 cm_ReleaseUser(userp);
5051 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5054 attrs = smb_Attributes(newScp);
5056 if (!(attrs & SMB_ATTR_DIRECTORY))
5057 code = CM_ERROR_NOTDIR;
5059 lock_ReleaseWrite(&newScp->rw);
5061 cm_ReleaseSCache(newScp);
5062 cm_ReleaseUser(userp);
5066 /* SMB_COM_SET_INFORMATION */
5067 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5069 clientchar_t *pathp;
5071 cm_scache_t *rootScp;
5072 unsigned short attribute;
5074 cm_scache_t *newScp;
5078 clientchar_t *tidPathp;
5084 /* decode basic attributes we're passed */
5085 attribute = smb_GetSMBParm(inp, 0);
5086 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5088 datap = smb_GetSMBData(inp, NULL);
5089 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5091 return CM_ERROR_BADSMB;
5093 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5094 dosTime, attribute);
5096 rootScp = cm_data.rootSCachep;
5098 userp = smb_GetUserFromVCP(vcp, inp);
5100 caseFold = CM_FLAG_CASEFOLD;
5102 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5104 cm_ReleaseUser(userp);
5105 return CM_ERROR_NOSUCHFILE;
5107 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5108 tidPathp, &req, &newScp);
5111 cm_ReleaseUser(userp);
5116 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5117 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5118 cm_ReleaseSCache(newScp);
5119 cm_ReleaseUser(userp);
5120 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5121 return CM_ERROR_PATH_NOT_COVERED;
5123 return CM_ERROR_BADSHARENAME;
5125 #endif /* DFS_SUPPORT */
5127 /* now lock the vnode with a callback; returns with newScp locked; we
5128 * need the current status to determine what the new status is, in some
5131 lock_ObtainWrite(&newScp->rw);
5132 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5133 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5135 lock_ReleaseWrite(&newScp->rw);
5136 cm_ReleaseSCache(newScp);
5137 cm_ReleaseUser(userp);
5141 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5143 /* Check for RO volume */
5144 if (newScp->flags & CM_SCACHEFLAG_RO) {
5145 lock_ReleaseWrite(&newScp->rw);
5146 cm_ReleaseSCache(newScp);
5147 cm_ReleaseUser(userp);
5148 return CM_ERROR_READONLY;
5151 /* prepare for setattr call */
5154 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5155 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5157 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5158 /* we're told to make a writable file read-only */
5159 attr.unixModeBits = newScp->unixModeBits & ~0222;
5160 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5162 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5163 /* we're told to make a read-only file writable */
5164 attr.unixModeBits = newScp->unixModeBits | 0222;
5165 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5167 lock_ReleaseWrite(&newScp->rw);
5169 /* now call setattr */
5171 code = cm_SetAttr(newScp, &attr, userp, &req);
5175 cm_ReleaseSCache(newScp);
5176 cm_ReleaseUser(userp);
5182 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5184 clientchar_t *pathp;
5186 cm_scache_t *rootScp;
5187 cm_scache_t *newScp, *dscp;
5192 clientchar_t *tidPathp;
5194 clientchar_t *lastComp;
5200 datap = smb_GetSMBData(inp, NULL);
5201 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5203 return CM_ERROR_BADSMB;
5205 if (*pathp == 0) /* null path */
5208 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5209 osi_LogSaveClientString(smb_logp, pathp));
5211 rootScp = cm_data.rootSCachep;
5213 userp = smb_GetUserFromVCP(vcp, inp);
5215 /* we shouldn't need this for V3 requests, but we seem to */
5216 caseFold = CM_FLAG_CASEFOLD;
5218 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5220 cm_ReleaseUser(userp);
5221 return CM_ERROR_NOSUCHFILE;
5225 * XXX Strange hack XXX
5227 * As of Patch 5 (16 July 97), we are having the following problem:
5228 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5229 * requests to look up "desktop.ini" in all the subdirectories.
5230 * This can cause zillions of timeouts looking up non-existent cells
5231 * and volumes, especially in the top-level directory.
5233 * We have not found any way to avoid this or work around it except
5234 * to explicitly ignore the requests for mount points that haven't
5235 * yet been evaluated and for directories that haven't yet been
5238 * We should modify this hack to provide a fake desktop.ini file
5239 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5241 spacep = inp->spacep;
5242 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5243 #ifndef SPECIAL_FOLDERS
5244 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5245 code = cm_NameI(rootScp, spacep->wdata,
5246 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5247 userp, tidPathp, &req, &dscp);
5250 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5251 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5253 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5254 return CM_ERROR_PATH_NOT_COVERED;
5256 return CM_ERROR_BADSHARENAME;
5258 #endif /* DFS_SUPPORT */
5259 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5260 code = CM_ERROR_NOSUCHFILE;
5261 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5262 cm_buf_t *bp = buf_Find(dscp, &hzero);
5267 code = CM_ERROR_NOSUCHFILE;
5269 cm_ReleaseSCache(dscp);
5271 cm_ReleaseUser(userp);
5276 #endif /* SPECIAL_FOLDERS */
5278 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5279 tidPathp, &req, &newScp);
5281 cm_ReleaseUser(userp);
5286 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5287 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5288 cm_ReleaseSCache(newScp);
5289 cm_ReleaseUser(userp);
5290 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5291 return CM_ERROR_PATH_NOT_COVERED;
5293 return CM_ERROR_BADSHARENAME;
5295 #endif /* DFS_SUPPORT */
5297 /* now lock the vnode with a callback; returns with newScp locked */
5298 lock_ObtainWrite(&newScp->rw);
5299 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5300 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5302 lock_ReleaseWrite(&newScp->rw);
5303 cm_ReleaseSCache(newScp);
5304 cm_ReleaseUser(userp);
5308 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5311 /* use smb_Attributes instead. Also the fact that a file is
5312 * in a readonly volume doesn't mean it shojuld be marked as RO
5314 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5315 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5316 newScp->fileType == CM_SCACHETYPE_INVALID)
5317 attrs = SMB_ATTR_DIRECTORY;
5320 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
5321 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
5323 attrs = smb_Attributes(newScp);
5326 smb_SetSMBParm(outp, 0, attrs);
5328 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5329 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5330 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5331 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5332 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5333 smb_SetSMBParm(outp, 5, 0);
5334 smb_SetSMBParm(outp, 6, 0);
5335 smb_SetSMBParm(outp, 7, 0);
5336 smb_SetSMBParm(outp, 8, 0);
5337 smb_SetSMBParm(outp, 9, 0);
5338 smb_SetSMBDataLength(outp, 0);
5339 lock_ReleaseWrite(&newScp->rw);
5341 cm_ReleaseSCache(newScp);
5342 cm_ReleaseUser(userp);
5347 /* SMB_COM_TREE_DISCONNECT */
5348 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5352 osi_Log0(smb_logp, "SMB receive tree disconnect");
5354 /* find the tree and free it */
5355 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5357 lock_ObtainWrite(&smb_rctLock);
5359 smb_ReleaseTID(tidp, TRUE);
5360 lock_ReleaseWrite(&smb_rctLock);
5367 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5370 clientchar_t *pathp;
5371 clientchar_t *lastNamep;
5380 clientchar_t *tidPathp;
5386 datap = smb_GetSMBData(inp, NULL);
5387 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5389 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5391 #ifdef DEBUG_VERBOSE
5395 hexpath = osi_HexifyString( pathp );
5396 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5401 share = smb_GetSMBParm(inp, 0);
5402 attribute = smb_GetSMBParm(inp, 1);
5404 spacep = inp->spacep;
5405 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5406 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5407 /* special case magic file name for receiving IOCTL requests
5408 * (since IOCTL calls themselves aren't getting through).
5410 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5411 smb_SetupIoctlFid(fidp, spacep);
5412 smb_SetSMBParm(outp, 0, fidp->fid);
5413 smb_SetSMBParm(outp, 1, 0); /* attrs */
5414 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5415 smb_SetSMBParm(outp, 3, 0);
5416 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5417 smb_SetSMBParm(outp, 5, 0x7fff);
5418 /* pass the open mode back */
5419 smb_SetSMBParm(outp, 6, (share & 0xf));
5420 smb_SetSMBDataLength(outp, 0);
5421 smb_ReleaseFID(fidp);
5425 userp = smb_GetUserFromVCP(vcp, inp);
5427 caseFold = CM_FLAG_CASEFOLD;
5429 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5431 cm_ReleaseUser(userp);
5432 return CM_ERROR_NOSUCHPATH;
5434 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5435 tidPathp, &req, &scp);
5438 cm_ReleaseUser(userp);
5443 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5444 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5445 cm_ReleaseSCache(scp);
5446 cm_ReleaseUser(userp);
5447 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5448 return CM_ERROR_PATH_NOT_COVERED;
5450 return CM_ERROR_BADSHARENAME;
5452 #endif /* DFS_SUPPORT */
5454 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5456 cm_ReleaseSCache(scp);
5457 cm_ReleaseUser(userp);
5461 /* don't need callback to check file type, since file types never
5462 * change, and namei and cm_Lookup all stat the object at least once on
5463 * a successful return.
5465 if (scp->fileType != CM_SCACHETYPE_FILE) {
5466 cm_ReleaseSCache(scp);
5467 cm_ReleaseUser(userp);
5468 return CM_ERROR_ISDIR;
5471 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5472 osi_assertx(fidp, "null smb_fid_t");
5474 /* save a pointer to the vnode */
5476 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5477 lock_ObtainWrite(&scp->rw);
5478 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5479 lock_ReleaseWrite(&scp->rw);
5483 fidp->userp = userp;
5485 lock_ObtainMutex(&fidp->mx);
5486 if ((share & 0xf) == 0)
5487 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5488 else if ((share & 0xf) == 1)
5489 fidp->flags |= SMB_FID_OPENWRITE;
5491 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5492 lock_ReleaseMutex(&fidp->mx);
5494 lock_ObtainRead(&scp->rw);
5495 smb_SetSMBParm(outp, 0, fidp->fid);
5496 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5497 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5498 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5499 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5500 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5501 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5502 /* pass the open mode back; XXXX add access checks */
5503 smb_SetSMBParm(outp, 6, (share & 0xf));
5504 smb_SetSMBDataLength(outp, 0);
5505 lock_ReleaseRead(&scp->rw);
5508 cm_Open(scp, 0, userp);
5510 /* send and free packet */
5511 smb_ReleaseFID(fidp);
5512 cm_ReleaseUser(userp);
5513 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5517 typedef struct smb_unlinkRock {
5522 clientchar_t *maskp; /* pointer to the star pattern */
5525 cm_dirEntryList_t * matches;
5528 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5531 smb_unlinkRock_t *rockp;
5534 normchar_t matchName[MAX_PATH];
5538 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5539 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5540 caseFold |= CM_FLAG_8DOT3;
5542 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5543 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5545 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5546 !cm_Is8Dot3(matchName)) {
5547 cm_Gen8Dot3Name(dep, matchName, NULL);
5548 /* 8.3 matches are always case insensitive */
5549 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5552 osi_Log1(smb_logp, "Found match %S",
5553 osi_LogSaveClientString(smb_logp, matchName));
5555 cm_DirEntryListAdd(dep->name, &rockp->matches);
5559 /* If we made a case sensitive exact match, we might as well quit now. */
5560 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5561 code = CM_ERROR_STOPNOW;
5570 /* SMB_COM_DELETE */
5571 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5575 clientchar_t *pathp;
5579 clientchar_t *lastNamep;
5580 smb_unlinkRock_t rock;
5584 clientchar_t *tidPathp;
5589 attribute = smb_GetSMBParm(inp, 0);
5591 tp = smb_GetSMBData(inp, NULL);
5592 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5594 osi_Log1(smb_logp, "SMB receive unlink %S",
5595 osi_LogSaveClientString(smb_logp, pathp));
5597 spacep = inp->spacep;
5598 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5600 userp = smb_GetUserFromVCP(vcp, inp);
5602 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5604 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5606 cm_ReleaseUser(userp);
5607 return CM_ERROR_NOSUCHPATH;
5609 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5612 cm_ReleaseUser(userp);
5617 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5618 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5619 cm_ReleaseSCache(dscp);
5620 cm_ReleaseUser(userp);
5621 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5622 return CM_ERROR_PATH_NOT_COVERED;
5624 return CM_ERROR_BADSHARENAME;
5626 #endif /* DFS_SUPPORT */
5628 /* otherwise, scp points to the parent directory. */
5635 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5636 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5639 thyper.HighPart = 0;
5644 rock.matches = NULL;
5646 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5647 * match. If that fails, we do a case insensitve match.
5649 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5650 !smb_IsStarMask(rock.maskp)) {
5651 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5654 thyper.HighPart = 0;
5655 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5660 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5662 if (code == CM_ERROR_STOPNOW)
5665 if (code == 0 && rock.matches) {
5666 cm_dirEntryList_t * entry;
5668 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5669 normchar_t normalizedName[MAX_PATH];
5671 /* Note: entry->name is a non-normalized name */
5673 osi_Log1(smb_logp, "Unlinking %s",
5674 osi_LogSaveString(smb_logp, entry->name));
5676 cm_FsStringToNormString(entry->name, -1,
5677 normalizedName, lengthof(normalizedName));
5679 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5681 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5682 smb_NotifyChange(FILE_ACTION_REMOVED,
5683 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5684 dscp, normalizedName, NULL, TRUE);
5688 cm_DirEntryListFree(&rock.matches);
5690 cm_ReleaseUser(userp);
5692 cm_ReleaseSCache(dscp);
5696 if (code == 0 && !rock.any)
5697 code = CM_ERROR_NOSUCHFILE;
5701 typedef struct smb_renameRock {
5702 cm_scache_t *odscp; /* old dir */
5703 cm_scache_t *ndscp; /* new dir */
5704 cm_user_t *userp; /* user */
5705 cm_req_t *reqp; /* request struct */
5706 smb_vc_t *vcp; /* virtual circuit */
5707 normchar_t *maskp; /* pointer to star pattern of old file name */
5708 int flags; /* tilde, casefold, etc */
5709 clientchar_t *newNamep; /* ptr to the new file's name */
5710 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5711 clientchar_t clOldName[MAX_PATH]; /* client name */
5715 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5718 smb_renameRock_t *rockp;
5721 normchar_t matchName[MAX_PATH];
5723 rockp = (smb_renameRock_t *) vrockp;
5725 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5726 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5727 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5728 caseFold |= CM_FLAG_8DOT3;
5730 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5732 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5733 !cm_Is8Dot3(matchName)) {
5734 cm_Gen8Dot3Name(dep, matchName, NULL);
5735 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5740 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5741 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5743 code = CM_ERROR_STOPNOW;
5753 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5756 cm_space_t *spacep = NULL;
5757 smb_renameRock_t rock;
5758 cm_scache_t *oldDscp = NULL;
5759 cm_scache_t *newDscp = NULL;
5760 cm_scache_t *tmpscp= NULL;
5761 cm_scache_t *tmpscp2 = NULL;
5762 clientchar_t *oldLastNamep;
5763 clientchar_t *newLastNamep;
5767 clientchar_t *tidPathp;
5771 userp = smb_GetUserFromVCP(vcp, inp);
5772 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5774 cm_ReleaseUser(userp);
5775 return CM_ERROR_NOSUCHPATH;
5779 spacep = inp->spacep;
5780 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5782 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5783 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5784 userp, tidPathp, &req, &oldDscp);
5786 cm_ReleaseUser(userp);
5791 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5792 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5793 cm_ReleaseSCache(oldDscp);
5794 cm_ReleaseUser(userp);
5795 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5796 return CM_ERROR_PATH_NOT_COVERED;
5798 return CM_ERROR_BADSHARENAME;
5800 #endif /* DFS_SUPPORT */
5802 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5803 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5804 userp, tidPathp, &req, &newDscp);
5807 cm_ReleaseSCache(oldDscp);
5808 cm_ReleaseUser(userp);
5813 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5814 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5815 cm_ReleaseSCache(oldDscp);
5816 cm_ReleaseSCache(newDscp);
5817 cm_ReleaseUser(userp);
5818 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5819 return CM_ERROR_PATH_NOT_COVERED;
5821 return CM_ERROR_BADSHARENAME;
5823 #endif /* DFS_SUPPORT */
5826 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5827 * next, get the component names, and lower case them.
5830 /* handle the old name first */
5832 oldLastNamep = oldPathp;
5836 /* and handle the new name, too */
5838 newLastNamep = newPathp;
5842 /* TODO: The old name could be a wildcard. The new name must not be */
5844 /* do the vnode call */
5845 rock.odscp = oldDscp;
5846 rock.ndscp = newDscp;
5850 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
5851 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5852 rock.newNamep = newLastNamep;
5853 rock.fsOldName[0] = '\0';
5854 rock.clOldName[0] = '\0';
5857 /* Check if the file already exists; if so return error */
5858 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5859 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5860 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5862 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5863 osi_LogSaveClientString(smb_logp, newLastNamep));
5865 /* Check if the old and the new names differ only in case. If so return
5866 * success, else return CM_ERROR_EXISTS
5868 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
5870 /* This would be a success only if the old file is *as same as* the new file */
5871 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5873 if (tmpscp == tmpscp2)
5876 code = CM_ERROR_EXISTS;
5877 cm_ReleaseSCache(tmpscp2);
5880 code = CM_ERROR_NOSUCHFILE;
5883 /* file exist, do not rename, also fixes move */
5884 osi_Log0(smb_logp, "Can't rename. Target already exists");
5885 code = CM_ERROR_EXISTS;
5889 cm_ReleaseSCache(tmpscp);
5890 cm_ReleaseSCache(newDscp);
5891 cm_ReleaseSCache(oldDscp);
5892 cm_ReleaseUser(userp);
5899 /* Now search the directory for the pattern, and do the appropriate rename when found */
5900 thyper.LowPart = 0; /* search dir from here */
5901 thyper.HighPart = 0;
5903 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5904 if (code == 0 && !rock.any) {
5906 thyper.HighPart = 0;
5907 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5908 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5910 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5912 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
5913 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
5914 rock.ndscp, rock.newNamep, rock.userp,
5916 /* if the call worked, stop doing the search now, since we
5917 * really only want to rename one file.
5920 osi_Log0(smb_logp, "cm_Rename failure");
5921 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5922 } else if (code == 0) {
5923 code = CM_ERROR_NOSUCHFILE;
5926 /* Handle Change Notification */
5928 * Being lazy, not distinguishing between files and dirs in this
5929 * filter, since we'd have to do a lookup.
5932 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5933 if (oldDscp == newDscp) {
5934 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5935 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5936 filter, oldDscp, rock.clOldName,
5937 newLastNamep, TRUE);
5939 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5940 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5941 filter, oldDscp, rock.clOldName,
5943 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5944 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5945 filter, newDscp, newLastNamep,
5951 cm_ReleaseSCache(tmpscp);
5952 cm_ReleaseUser(userp);
5953 cm_ReleaseSCache(oldDscp);
5954 cm_ReleaseSCache(newDscp);
5963 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
5966 cm_space_t *spacep = NULL;
5967 cm_scache_t *oldDscp = NULL;
5968 cm_scache_t *newDscp = NULL;
5969 cm_scache_t *tmpscp= NULL;
5970 cm_scache_t *tmpscp2 = NULL;
5971 cm_scache_t *sscp = NULL;
5972 clientchar_t *oldLastNamep;
5973 clientchar_t *newLastNamep;
5976 clientchar_t *tidPathp;
5980 userp = smb_GetUserFromVCP(vcp, inp);
5982 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5984 cm_ReleaseUser(userp);
5985 return CM_ERROR_NOSUCHPATH;
5990 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5992 spacep = inp->spacep;
5993 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5995 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5996 userp, tidPathp, &req, &oldDscp);
5998 cm_ReleaseUser(userp);
6003 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6004 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6005 cm_ReleaseSCache(oldDscp);
6006 cm_ReleaseUser(userp);
6007 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6008 return CM_ERROR_PATH_NOT_COVERED;
6010 return CM_ERROR_BADSHARENAME;
6012 #endif /* DFS_SUPPORT */
6014 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6015 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6016 userp, tidPathp, &req, &newDscp);
6018 cm_ReleaseSCache(oldDscp);
6019 cm_ReleaseUser(userp);
6024 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6025 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6026 cm_ReleaseSCache(newDscp);
6027 cm_ReleaseSCache(oldDscp);
6028 cm_ReleaseUser(userp);
6029 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6030 return CM_ERROR_PATH_NOT_COVERED;
6032 return CM_ERROR_BADSHARENAME;
6034 #endif /* DFS_SUPPORT */
6036 /* Now, although we did two lookups for the two directories (because the same
6037 * directory can be referenced through different paths), we only allow hard links
6038 * within the same directory. */
6039 if (oldDscp != newDscp) {
6040 cm_ReleaseSCache(oldDscp);
6041 cm_ReleaseSCache(newDscp);
6042 cm_ReleaseUser(userp);
6043 return CM_ERROR_CROSSDEVLINK;
6046 /* handle the old name first */
6048 oldLastNamep = oldPathp;
6052 /* and handle the new name, too */
6054 newLastNamep = newPathp;
6058 /* now lookup the old name */
6059 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6060 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6062 cm_ReleaseSCache(oldDscp);
6063 cm_ReleaseSCache(newDscp);
6064 cm_ReleaseUser(userp);
6068 /* Check if the file already exists; if so return error */
6069 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6070 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6071 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6073 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6074 osi_LogSaveClientString(smb_logp, newLastNamep));
6076 /* if the existing link is to the same file, then we return success */
6078 if(sscp == tmpscp) {
6081 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6082 code = CM_ERROR_EXISTS;
6087 cm_ReleaseSCache(tmpscp);
6088 cm_ReleaseSCache(sscp);
6089 cm_ReleaseSCache(newDscp);
6090 cm_ReleaseSCache(oldDscp);
6091 cm_ReleaseUser(userp);
6095 /* now create the hardlink */
6096 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6097 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6098 osi_Log1(smb_logp," Link returns 0x%x", code);
6100 /* Handle Change Notification */
6102 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6103 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6104 smb_NotifyChange(FILE_ACTION_ADDED,
6105 filter, newDscp, newLastNamep,
6110 cm_ReleaseSCache(tmpscp);
6111 cm_ReleaseUser(userp);
6112 cm_ReleaseSCache(sscp);
6113 cm_ReleaseSCache(oldDscp);
6114 cm_ReleaseSCache(newDscp);
6118 /* SMB_COM_RENAME */
6120 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6122 clientchar_t *oldPathp;
6123 clientchar_t *newPathp;
6127 tp = smb_GetSMBData(inp, NULL);
6128 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6129 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6131 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6132 osi_LogSaveClientString(smb_logp, oldPathp),
6133 osi_LogSaveClientString(smb_logp, newPathp));
6135 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6137 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6143 typedef struct smb_rmdirRock {
6147 normchar_t *maskp; /* pointer to the star pattern */
6150 cm_dirEntryList_t * matches;
6153 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6156 smb_rmdirRock_t *rockp;
6158 normchar_t matchName[MAX_PATH];
6160 rockp = (smb_rmdirRock_t *) vrockp;
6162 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
6163 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6164 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6166 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6168 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6169 !cm_Is8Dot3(matchName)) {
6170 cm_Gen8Dot3Name(dep, matchName, NULL);
6171 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6176 cm_DirEntryListAdd(dep->name, &rockp->matches);
6183 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6186 clientchar_t *pathp;
6190 clientchar_t *lastNamep;
6191 smb_rmdirRock_t rock;
6195 clientchar_t *tidPathp;
6200 tp = smb_GetSMBData(inp, NULL);
6201 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6203 spacep = inp->spacep;
6204 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6206 userp = smb_GetUserFromVCP(vcp, inp);
6208 caseFold = CM_FLAG_CASEFOLD;
6210 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6212 cm_ReleaseUser(userp);
6213 return CM_ERROR_NOSUCHPATH;
6215 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6216 userp, tidPathp, &req, &dscp);
6219 cm_ReleaseUser(userp);
6224 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6225 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6226 cm_ReleaseSCache(dscp);
6227 cm_ReleaseUser(userp);
6228 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6229 return CM_ERROR_PATH_NOT_COVERED;
6231 return CM_ERROR_BADSHARENAME;
6233 #endif /* DFS_SUPPORT */
6235 /* otherwise, scp points to the parent directory. */
6242 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6243 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6246 thyper.HighPart = 0;
6250 rock.matches = NULL;
6252 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6253 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6254 if (code == 0 && !rock.any) {
6256 thyper.HighPart = 0;
6257 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6258 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6261 if (code == 0 && rock.matches) {
6262 cm_dirEntryList_t * entry;
6264 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6265 clientchar_t clientName[MAX_PATH];
6267 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6269 osi_Log1(smb_logp, "Removing directory %s",
6270 osi_LogSaveString(smb_logp, entry->name));
6272 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6274 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6275 smb_NotifyChange(FILE_ACTION_REMOVED,
6276 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6277 dscp, clientName, NULL, TRUE);
6281 cm_DirEntryListFree(&rock.matches);
6283 cm_ReleaseUser(userp);
6285 cm_ReleaseSCache(dscp);
6287 if (code == 0 && !rock.any)
6288 code = CM_ERROR_NOSUCHFILE;
6297 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6307 fid = smb_GetSMBParm(inp, 0);
6309 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6311 fid = smb_ChainFID(fid, inp);
6312 fidp = smb_FindFID(vcp, fid, 0);
6314 return CM_ERROR_BADFD;
6316 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6317 smb_CloseFID(vcp, fidp, NULL, 0);
6318 smb_ReleaseFID(fidp);
6319 return CM_ERROR_NOSUCHFILE;
6322 lock_ObtainMutex(&fidp->mx);
6323 if (fidp->flags & SMB_FID_IOCTL) {
6324 lock_ReleaseMutex(&fidp->mx);
6325 smb_ReleaseFID(fidp);
6326 return CM_ERROR_BADFD;
6328 lock_ReleaseMutex(&fidp->mx);
6330 userp = smb_GetUserFromVCP(vcp, inp);
6332 lock_ObtainMutex(&fidp->mx);
6333 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6334 cm_scache_t * scp = fidp->scp;
6336 lock_ReleaseMutex(&fidp->mx);
6337 code = cm_FSync(scp, userp, &req);
6338 cm_ReleaseSCache(scp);
6341 lock_ReleaseMutex(&fidp->mx);
6344 smb_ReleaseFID(fidp);
6346 cm_ReleaseUser(userp);
6351 struct smb_FullNameRock {
6354 clientchar_t *fullName;
6355 fschar_t *originalName;
6358 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6361 normchar_t matchName[MAX_PATH];
6362 struct smb_FullNameRock *vrockp;
6364 vrockp = (struct smb_FullNameRock *)rockp;
6366 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
6368 if (!cm_Is8Dot3(matchName)) {
6369 clientchar_t shortName[13];
6371 cm_Gen8Dot3Name(dep, shortName, NULL);
6373 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6374 vrockp->fullName = cm_ClientStrDup(matchName);
6375 vrockp->originalName = cm_FsStrDup(dep->name);
6376 return CM_ERROR_STOPNOW;
6379 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6380 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6381 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6382 vrockp->fullName = cm_ClientStrDup(matchName);
6383 vrockp->originalName = cm_FsStrDup(dep->name);
6384 return CM_ERROR_STOPNOW;
6389 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6390 clientchar_t **newPathp, fschar_t ** originalPathp,
6391 cm_user_t *userp, cm_req_t *reqp)
6393 struct smb_FullNameRock rock;
6396 memset(&rock, 0, sizeof(rock));
6400 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6401 if (code == CM_ERROR_STOPNOW) {
6402 *newPathp = rock.fullName;
6403 *originalPathp = rock.originalName;
6405 *newPathp = cm_ClientStrDup(pathp);
6406 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6410 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6411 afs_uint32 dosTime) {
6414 cm_scache_t *dscp = NULL;
6415 clientchar_t *pathp = NULL;
6416 cm_scache_t * scp = NULL;
6417 cm_scache_t *delscp = NULL;
6418 int nullcreator = 0;
6420 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6421 fidp, fidp->fid, scp, vcp);
6424 lock_ObtainMutex(&fidp->mx);
6425 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6426 lock_ReleaseMutex(&fidp->mx);
6427 osi_Log0(smb_logp, " No user specified. Not closing fid");
6428 return CM_ERROR_BADFD;
6431 userp = fidp->userp; /* no hold required since fidp is held
6432 throughout the function */
6433 lock_ReleaseMutex(&fidp->mx);
6438 lock_ObtainWrite(&smb_rctLock);
6439 if (fidp->deleteOk) {
6440 osi_Log0(smb_logp, " Fid already closed.");
6441 lock_ReleaseWrite(&smb_rctLock);
6442 return CM_ERROR_BADFD;
6445 lock_ReleaseWrite(&smb_rctLock);
6447 lock_ObtainMutex(&fidp->mx);
6448 if (fidp->NTopen_dscp) {
6449 dscp = fidp->NTopen_dscp;
6450 cm_HoldSCache(dscp);
6453 if (fidp->NTopen_pathp) {
6454 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6462 /* Don't jump the gun on an async raw write */
6463 while (fidp->raw_writers) {
6464 lock_ReleaseMutex(&fidp->mx);
6465 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6466 lock_ObtainMutex(&fidp->mx);
6469 /* watch for ioctl closes, and read-only opens */
6471 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6472 == SMB_FID_OPENWRITE) {
6473 if (dosTime != 0 && dosTime != -1) {
6474 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6475 /* This fixes defect 10958 */
6476 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6477 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6479 if (smb_AsyncStore != 2) {
6480 lock_ReleaseMutex(&fidp->mx);
6481 code = cm_FSync(scp, userp, &req);
6482 lock_ObtainMutex(&fidp->mx);
6488 /* unlock any pending locks */
6489 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6490 scp->fileType == CM_SCACHETYPE_FILE) {
6494 lock_ReleaseMutex(&fidp->mx);
6496 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6498 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6499 lock_ObtainWrite(&scp->rw);
6501 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6502 CM_SCACHESYNC_NEEDCALLBACK
6503 | CM_SCACHESYNC_GETSTATUS
6504 | CM_SCACHESYNC_LOCK);
6508 "smb CoreClose SyncOp failure code 0x%x", tcode);
6509 goto post_syncopdone;
6512 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6514 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6518 lock_ReleaseWrite(&scp->rw);
6519 lock_ObtainMutex(&fidp->mx);
6522 if (fidp->flags & SMB_FID_DELONCLOSE) {
6523 clientchar_t *fullPathp = NULL;
6524 fschar_t *originalNamep = NULL;
6526 lock_ReleaseMutex(&fidp->mx);
6528 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6533 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6534 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6535 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6537 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6538 smb_NotifyChange(FILE_ACTION_REMOVED,
6539 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6540 dscp, fullPathp, NULL, TRUE);
6543 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6545 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6546 smb_NotifyChange(FILE_ACTION_REMOVED,
6547 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6548 dscp, fullPathp, NULL, TRUE);
6555 free(originalNamep);
6557 lock_ObtainMutex(&fidp->mx);
6558 fidp->flags &= ~SMB_FID_DELONCLOSE;
6561 /* if this was a newly created file, then clear the creator
6562 * in the stat cache entry. */
6563 if (fidp->flags & SMB_FID_CREATED) {
6565 fidp->flags &= ~SMB_FID_CREATED;
6568 if (fidp->flags & SMB_FID_NTOPEN) {
6569 cm_ReleaseSCache(fidp->NTopen_dscp);
6570 fidp->NTopen_dscp = NULL;
6571 free(fidp->NTopen_pathp);
6572 fidp->NTopen_pathp = NULL;
6573 fidp->flags &= ~SMB_FID_NTOPEN;
6575 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6576 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6579 if (fidp->NTopen_wholepathp) {
6580 free(fidp->NTopen_wholepathp);
6581 fidp->NTopen_wholepathp = NULL;
6585 cm_ReleaseSCache(fidp->scp);
6588 lock_ReleaseMutex(&fidp->mx);
6591 cm_ReleaseSCache(dscp);
6594 cm_ReleaseSCache(delscp);
6598 lock_ObtainWrite(&scp->rw);
6599 if (nullcreator && scp->creator == userp)
6600 scp->creator = NULL;
6601 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6602 lock_ReleaseWrite(&scp->rw);
6603 cm_ReleaseSCache(scp);
6613 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6621 fid = smb_GetSMBParm(inp, 0);
6622 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6624 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6626 fid = smb_ChainFID(fid, inp);
6627 fidp = smb_FindFID(vcp, fid, 0);
6629 return CM_ERROR_BADFD;
6632 userp = smb_GetUserFromVCP(vcp, inp);
6634 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6636 smb_ReleaseFID(fidp);
6637 cm_ReleaseUser(userp);
6642 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6644 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6645 cm_user_t *userp, long *readp)
6651 osi_hyper_t fileLength;
6653 osi_hyper_t lastByte;
6654 osi_hyper_t bufferOffset;
6658 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6661 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6662 fidp->fid, offsetp->LowPart, count);
6666 lock_ObtainMutex(&fidp->mx);
6667 /* make sure we have a readable FD */
6668 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6669 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6670 fidp->fid, fidp->flags);
6671 lock_ReleaseMutex(&fidp->mx);
6672 code = CM_ERROR_BADFDOP;
6683 lock_ObtainWrite(&scp->rw);
6685 if (offset.HighPart == 0) {
6686 chunk = offset.LowPart >> cm_logChunkSize;
6687 if (chunk != fidp->curr_chunk) {
6688 fidp->prev_chunk = fidp->curr_chunk;
6689 fidp->curr_chunk = chunk;
6691 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6694 lock_ReleaseMutex(&fidp->mx);
6696 /* start by looking up the file's end */
6697 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6698 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6702 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6704 /* now we have the entry locked, look up the length */
6705 fileLength = scp->length;
6707 /* adjust count down so that it won't go past EOF */
6708 thyper.LowPart = count;
6709 thyper.HighPart = 0;
6710 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6712 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6713 /* we'd read past EOF, so just stop at fileLength bytes.
6714 * Start by computing how many bytes remain in the file.
6716 thyper = LargeIntegerSubtract(fileLength, offset);
6718 /* if we are past EOF, read 0 bytes */
6719 if (LargeIntegerLessThanZero(thyper))
6722 count = thyper.LowPart;
6727 /* now, copy the data one buffer at a time,
6728 * until we've filled the request packet
6731 /* if we've copied all the data requested, we're done */
6732 if (count <= 0) break;
6734 /* otherwise, load up a buffer of data */
6735 thyper.HighPart = offset.HighPart;
6736 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6737 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6740 buf_Release(bufferp);
6743 lock_ReleaseWrite(&scp->rw);
6745 code = buf_Get(scp, &thyper, &bufferp);
6747 lock_ObtainWrite(&scp->rw);
6748 if (code) goto done;
6749 bufferOffset = thyper;
6751 /* now get the data in the cache */
6753 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6754 CM_SCACHESYNC_NEEDCALLBACK |
6755 CM_SCACHESYNC_READ);
6759 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6761 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6763 /* otherwise, load the buffer and try again */
6764 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6768 buf_Release(bufferp);
6772 } /* if (wrong buffer) ... */
6774 /* now we have the right buffer loaded. Copy out the
6775 * data from here to the user's buffer.
6777 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6779 /* and figure out how many bytes we want from this buffer */
6780 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6781 if (nbytes > count) nbytes = count; /* don't go past EOF */
6783 /* now copy the data */
6784 memcpy(op, bufferp->datap + bufIndex, nbytes);
6786 /* adjust counters, pointers, etc. */
6789 thyper.LowPart = nbytes;
6790 thyper.HighPart = 0;
6791 offset = LargeIntegerAdd(thyper, offset);
6795 lock_ReleaseWrite(&scp->rw);
6797 buf_Release(bufferp);
6799 if (code == 0 && sequential)
6800 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6802 cm_ReleaseSCache(scp);
6805 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6806 fidp->fid, code, *readp);
6811 * smb_WriteData -- common code for Write and Raw Write
6813 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6814 cm_user_t *userp, long *writtenp)
6816 osi_hyper_t offset = *offsetp;
6819 cm_scache_t *scp = NULL;
6820 osi_hyper_t fileLength; /* file's length at start of write */
6821 osi_hyper_t minLength; /* don't read past this */
6822 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6823 cm_buf_t *bufferp = NULL;
6824 osi_hyper_t thyper; /* hyper tmp variable */
6825 osi_hyper_t bufferOffset;
6826 afs_uint32 bufIndex; /* index in buffer where our data is */
6827 int doWriteBack = 0;
6828 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6832 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6833 fidp->fid, offsetp->LowPart, count);
6837 lock_ObtainMutex(&fidp->mx);
6838 /* make sure we have a writable FD */
6839 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6840 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6841 fidp->fid, fidp->flags);
6842 lock_ReleaseMutex(&fidp->mx);
6843 code = CM_ERROR_BADFDOP;
6851 lock_ReleaseMutex(&fidp->mx);
6853 lock_ObtainWrite(&scp->rw);
6854 /* start by looking up the file's end */
6855 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6856 CM_SCACHESYNC_NEEDCALLBACK
6857 | CM_SCACHESYNC_SETSTATUS
6858 | CM_SCACHESYNC_GETSTATUS);
6862 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6864 /* now we have the entry locked, look up the length */
6865 fileLength = scp->length;
6866 minLength = fileLength;
6867 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6868 minLength = scp->serverLength;
6870 /* adjust file length if we extend past EOF */
6871 thyper.LowPart = count;
6872 thyper.HighPart = 0;
6873 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6874 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6875 /* we'd write past EOF, so extend the file */
6876 scp->mask |= CM_SCACHEMASK_LENGTH;
6877 scp->length = thyper;
6878 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6880 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6882 /* now, if the new position (thyper) and the old (offset) are in
6883 * different storeback windows, remember to store back the previous
6884 * storeback window when we're done with the write.
6886 * the purpose of this logic is to slow down the CIFS client
6887 * in order to avoid the client disconnecting during the CLOSE
6888 * operation if there are too many dirty buffers left to write
6889 * than can be accomplished during 45 seconds. This used to be
6890 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6891 * so that we can read larger amounts of data at a time.
6893 if (smb_AsyncStore == 1 &&
6894 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
6895 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
6896 /* they're different */
6898 writeBackOffset.HighPart = offset.HighPart;
6899 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
6904 /* now, copy the data one buffer at a time, until we've filled the
6907 /* if we've copied all the data requested, we're done */
6911 /* handle over quota or out of space */
6912 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6913 *writtenp = written;
6914 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6918 /* otherwise, load up a buffer of data */
6919 thyper.HighPart = offset.HighPart;
6920 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6921 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6924 lock_ReleaseMutex(&bufferp->mx);
6925 buf_Release(bufferp);
6928 lock_ReleaseWrite(&scp->rw);
6930 code = buf_Get(scp, &thyper, &bufferp);
6932 lock_ObtainMutex(&bufferp->mx);
6933 lock_ObtainWrite(&scp->rw);
6934 if (code) goto done;
6936 bufferOffset = thyper;
6938 /* now get the data in the cache */
6940 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6941 CM_SCACHESYNC_NEEDCALLBACK
6942 | CM_SCACHESYNC_WRITE
6943 | CM_SCACHESYNC_BUFLOCKED);
6947 cm_SyncOpDone(scp, bufferp,
6948 CM_SCACHESYNC_NEEDCALLBACK
6949 | CM_SCACHESYNC_WRITE
6950 | CM_SCACHESYNC_BUFLOCKED);
6952 /* If we're overwriting the entire buffer, or
6953 * if we're writing at or past EOF, mark the
6954 * buffer as current so we don't call
6955 * cm_GetBuffer. This skips the fetch from the
6956 * server in those cases where we're going to
6957 * obliterate all the data in the buffer anyway,
6958 * or in those cases where there is no useful
6959 * data at the server to start with.
6961 * Use minLength instead of scp->length, since
6962 * the latter has already been updated by this
6965 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6966 || LargeIntegerEqualTo(offset, bufferp->offset)
6967 && (count >= cm_data.buf_blockSize
6968 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6969 ConvertLongToLargeInteger(count)),
6971 if (count < cm_data.buf_blockSize
6972 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
6973 memset(bufferp->datap, 0,
6974 cm_data.buf_blockSize);
6975 bufferp->dataVersion = scp->dataVersion;
6978 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6980 /* otherwise, load the buffer and try again */
6981 lock_ReleaseMutex(&bufferp->mx);
6982 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6984 lock_ReleaseWrite(&scp->rw);
6985 lock_ObtainMutex(&bufferp->mx);
6986 lock_ObtainWrite(&scp->rw);
6990 lock_ReleaseMutex(&bufferp->mx);
6991 buf_Release(bufferp);
6995 } /* if (wrong buffer) ... */
6997 /* now we have the right buffer loaded. Copy out the
6998 * data from here to the user's buffer.
7000 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7002 /* and figure out how many bytes we want from this buffer */
7003 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7005 nbytes = count; /* don't go past end of request */
7007 /* now copy the data */
7008 memcpy(bufferp->datap + bufIndex, op, nbytes);
7009 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7011 /* adjust counters, pointers, etc. */
7015 thyper.LowPart = nbytes;
7016 thyper.HighPart = 0;
7017 offset = LargeIntegerAdd(thyper, offset);
7021 lock_ReleaseWrite(&scp->rw);
7024 lock_ReleaseMutex(&bufferp->mx);
7025 buf_Release(bufferp);
7028 lock_ObtainMutex(&fidp->mx);
7029 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7030 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7032 lock_ReleaseMutex(&fidp->mx);
7033 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7034 fidp->NTopen_dscp, fidp->NTopen_pathp,
7037 lock_ReleaseMutex(&fidp->mx);
7041 if (smb_AsyncStore > 0) {
7045 lock_ObtainWrite(&scp->rw);
7046 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7048 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7049 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7051 lock_ReleaseWrite(&scp->rw);
7052 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7053 writeBackOffset.HighPart,
7054 smb_AsyncStoreSize, 0, userp);
7055 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7058 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7062 cm_ReleaseSCache(scp);
7065 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7066 fidp->fid, code, *writtenp);
7071 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7074 unsigned short count;
7076 unsigned short hint;
7077 long written = 0, total_written = 0;
7080 smb_t* smbp = (smb_t*) inp;
7083 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7085 int inDataBlockCount;
7087 fd = smb_GetSMBParm(inp, 0);
7088 count = smb_GetSMBParm(inp, 1);
7089 offset.HighPart = 0; /* too bad */
7090 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7091 hint = smb_GetSMBParm(inp, 4);
7093 op = smb_GetSMBData(inp, NULL);
7094 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7096 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7097 fd, offset.LowPart, count);
7099 fd = smb_ChainFID(fd, inp);
7100 fidp = smb_FindFID(vcp, fd, 0);
7102 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7103 return CM_ERROR_BADFD;
7106 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7107 smb_CloseFID(vcp, fidp, NULL, 0);
7108 smb_ReleaseFID(fidp);
7109 return CM_ERROR_NOSUCHFILE;
7112 lock_ObtainMutex(&fidp->mx);
7113 if (fidp->flags & SMB_FID_IOCTL) {
7114 lock_ReleaseMutex(&fidp->mx);
7115 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7116 smb_ReleaseFID(fidp);
7117 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7120 lock_ReleaseMutex(&fidp->mx);
7121 userp = smb_GetUserFromVCP(vcp, inp);
7125 LARGE_INTEGER LOffset;
7126 LARGE_INTEGER LLength;
7129 key = cm_GenerateKey(vcp->vcID, pid, fd);
7131 LOffset.HighPart = offset.HighPart;
7132 LOffset.LowPart = offset.LowPart;
7133 LLength.HighPart = 0;
7134 LLength.LowPart = count;
7136 lock_ObtainWrite(&fidp->scp->rw);
7137 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7138 lock_ReleaseWrite(&fidp->scp->rw);
7141 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7146 /* special case: 0 bytes transferred means truncate to this position */
7150 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7154 truncAttr.mask = CM_ATTRMASK_LENGTH;
7155 truncAttr.length.LowPart = offset.LowPart;
7156 truncAttr.length.HighPart = 0;
7157 lock_ObtainMutex(&fidp->mx);
7158 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7159 fidp->flags |= SMB_FID_LENGTHSETDONE;
7160 lock_ReleaseMutex(&fidp->mx);
7161 smb_SetSMBParm(outp, 0, 0 /* count */);
7162 smb_SetSMBDataLength(outp, 0);
7167 * Work around bug in NT client
7169 * When copying a file, the NT client should first copy the data,
7170 * then copy the last write time. But sometimes the NT client does
7171 * these in the wrong order, so the data copies would inadvertently
7172 * cause the last write time to be overwritten. We try to detect this,
7173 * and don't set client mod time if we think that would go against the
7176 lock_ObtainMutex(&fidp->mx);
7177 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7178 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7179 fidp->scp->clientModTime = time(NULL);
7181 lock_ReleaseMutex(&fidp->mx);
7184 while ( code == 0 && count > 0 ) {
7185 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7186 if (code == 0 && written == 0)
7187 code = CM_ERROR_PARTIALWRITE;
7189 offset = LargeIntegerAdd(offset,
7190 ConvertLongToLargeInteger(written));
7191 count -= (unsigned short)written;
7192 total_written += written;
7196 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7197 total_written, code);
7199 /* set the packet data length to 3 bytes for the data block header,
7200 * plus the size of the data.
7202 smb_SetSMBParm(outp, 0, total_written);
7203 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7204 smb_SetSMBParm(outp, 3, hint);
7205 smb_SetSMBDataLength(outp, 0);
7208 smb_ReleaseFID(fidp);
7209 cm_ReleaseUser(userp);
7214 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7215 NCB *ncbp, raw_write_cont_t *rwcp)
7224 fd = smb_GetSMBParm(inp, 0);
7225 fidp = smb_FindFID(vcp, fd, 0);
7227 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7228 smb_CloseFID(vcp, fidp, NULL, 0);
7229 smb_ReleaseFID(fidp);
7233 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7234 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7236 userp = smb_GetUserFromVCP(vcp, inp);
7239 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7241 if (rwcp->writeMode & 0x1) { /* synchronous */
7244 smb_FormatResponsePacket(vcp, inp, outp);
7245 op = (smb_t *) outp;
7246 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7247 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7248 smb_SetSMBDataLength(outp, 0);
7249 smb_SendPacket(vcp, outp);
7250 smb_FreePacket(outp);
7252 else { /* asynchronous */
7253 lock_ObtainMutex(&fidp->mx);
7254 fidp->raw_writers--;
7255 if (fidp->raw_writers == 0)
7256 thrd_SetEvent(fidp->raw_write_event);
7257 lock_ReleaseMutex(&fidp->mx);
7260 /* Give back raw buffer */
7261 lock_ObtainMutex(&smb_RawBufLock);
7262 *((char **)rawBuf) = smb_RawBufs;
7263 smb_RawBufs = rawBuf;
7264 lock_ReleaseMutex(&smb_RawBufLock);
7266 smb_ReleaseFID(fidp);
7267 cm_ReleaseUser(userp);
7270 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7275 /* SMB_COM_WRITE_RAW */
7276 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7279 long count, written = 0, total_written = 0;
7283 smb_t *smbp = (smb_t*) inp;
7287 unsigned short writeMode;
7289 fd = smb_GetSMBParm(inp, 0);
7290 totalCount = smb_GetSMBParm(inp, 1);
7291 count = smb_GetSMBParm(inp, 10);
7292 writeMode = smb_GetSMBParm(inp, 7);
7294 op = (char *) inp->data;
7295 op += smb_GetSMBParm(inp, 11);
7297 offset.HighPart = 0;
7298 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7300 if (*inp->wctp == 14) {
7301 /* we received a 64-bit file offset */
7302 #ifdef AFS_LARGEFILES
7303 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7305 if (LargeIntegerLessThanZero(offset)) {
7307 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7308 offset.HighPart, offset.LowPart);
7309 return CM_ERROR_BADSMB;
7312 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7314 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7315 return CM_ERROR_BADSMB;
7318 offset.HighPart = 0;
7321 offset.HighPart = 0; /* 32-bit file offset */
7325 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7326 fd, offset.HighPart, offset.LowPart, count);
7328 " WriteRaw WriteMode 0x%x",
7331 fd = smb_ChainFID(fd, inp);
7332 fidp = smb_FindFID(vcp, fd, 0);
7334 return CM_ERROR_BADFD;
7337 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7338 smb_CloseFID(vcp, fidp, NULL, 0);
7339 smb_ReleaseFID(fidp);
7340 return CM_ERROR_NOSUCHFILE;
7346 LARGE_INTEGER LOffset;
7347 LARGE_INTEGER LLength;
7350 key = cm_GenerateKey(vcp->vcID, pid, fd);
7352 LOffset.HighPart = offset.HighPart;
7353 LOffset.LowPart = offset.LowPart;
7354 LLength.HighPart = 0;
7355 LLength.LowPart = count;
7357 lock_ObtainWrite(&fidp->scp->rw);
7358 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7359 lock_ReleaseWrite(&fidp->scp->rw);
7362 smb_ReleaseFID(fidp);
7367 userp = smb_GetUserFromVCP(vcp, inp);
7370 * Work around bug in NT client
7372 * When copying a file, the NT client should first copy the data,
7373 * then copy the last write time. But sometimes the NT client does
7374 * these in the wrong order, so the data copies would inadvertently
7375 * cause the last write time to be overwritten. We try to detect this,
7376 * and don't set client mod time if we think that would go against the
7379 lock_ObtainMutex(&fidp->mx);
7380 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7381 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7382 fidp->scp->clientModTime = time(NULL);
7384 lock_ReleaseMutex(&fidp->mx);
7387 while ( code == 0 && count > 0 ) {
7388 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7389 if (code == 0 && written == 0)
7390 code = CM_ERROR_PARTIALWRITE;
7392 offset = LargeIntegerAdd(offset,
7393 ConvertLongToLargeInteger(written));
7396 total_written += written;
7400 /* Get a raw buffer */
7403 lock_ObtainMutex(&smb_RawBufLock);
7405 /* Get a raw buf, from head of list */
7406 rawBuf = smb_RawBufs;
7407 smb_RawBufs = *(char **)smb_RawBufs;
7410 code = CM_ERROR_USESTD;
7412 lock_ReleaseMutex(&smb_RawBufLock);
7415 /* Don't allow a premature Close */
7416 if (code == 0 && (writeMode & 1) == 0) {
7417 lock_ObtainMutex(&fidp->mx);
7418 fidp->raw_writers++;
7419 thrd_ResetEvent(fidp->raw_write_event);
7420 lock_ReleaseMutex(&fidp->mx);
7423 smb_ReleaseFID(fidp);
7424 cm_ReleaseUser(userp);
7427 smb_SetSMBParm(outp, 0, total_written);
7428 smb_SetSMBDataLength(outp, 0);
7429 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7434 offset = LargeIntegerAdd(offset,
7435 ConvertLongToLargeInteger(count));
7439 rwcp->offset.HighPart = offset.HighPart;
7440 rwcp->offset.LowPart = offset.LowPart;
7441 rwcp->count = totalCount - count;
7442 rwcp->writeMode = writeMode;
7443 rwcp->alreadyWritten = total_written;
7445 /* set the packet data length to 3 bytes for the data block header,
7446 * plus the size of the data.
7448 smb_SetSMBParm(outp, 0, 0xffff);
7449 smb_SetSMBDataLength(outp, 0);
7455 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7458 long count, finalCount;
7462 smb_t *smbp = (smb_t*) inp;
7467 fd = smb_GetSMBParm(inp, 0);
7468 count = smb_GetSMBParm(inp, 1);
7469 offset.HighPart = 0; /* too bad */
7470 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7472 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7473 fd, offset.LowPart, count);
7475 fd = smb_ChainFID(fd, inp);
7476 fidp = smb_FindFID(vcp, fd, 0);
7478 return CM_ERROR_BADFD;
7480 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7481 smb_CloseFID(vcp, fidp, NULL, 0);
7482 smb_ReleaseFID(fidp);
7483 return CM_ERROR_NOSUCHFILE;
7486 lock_ObtainMutex(&fidp->mx);
7487 if (fidp->flags & SMB_FID_IOCTL) {
7488 lock_ReleaseMutex(&fidp->mx);
7489 code = smb_IoctlRead(fidp, vcp, inp, outp);
7490 smb_ReleaseFID(fidp);
7493 lock_ReleaseMutex(&fidp->mx);
7496 LARGE_INTEGER LOffset, LLength;
7500 key = cm_GenerateKey(vcp->vcID, pid, fd);
7502 LOffset.HighPart = 0;
7503 LOffset.LowPart = offset.LowPart;
7504 LLength.HighPart = 0;
7505 LLength.LowPart = count;
7507 lock_ObtainWrite(&fidp->scp->rw);
7508 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7509 lock_ReleaseWrite(&fidp->scp->rw);
7512 smb_ReleaseFID(fidp);
7516 userp = smb_GetUserFromVCP(vcp, inp);
7518 /* remember this for final results */
7519 smb_SetSMBParm(outp, 0, count);
7520 smb_SetSMBParm(outp, 1, 0);
7521 smb_SetSMBParm(outp, 2, 0);
7522 smb_SetSMBParm(outp, 3, 0);
7523 smb_SetSMBParm(outp, 4, 0);
7525 /* set the packet data length to 3 bytes for the data block header,
7526 * plus the size of the data.
7528 smb_SetSMBDataLength(outp, count+3);
7530 /* get op ptr after putting in the parms, since otherwise we don't
7531 * know where the data really is.
7533 op = smb_GetSMBData(outp, NULL);
7535 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7536 *op++ = 1; /* data block marker */
7537 *op++ = (unsigned char) (count & 0xff);
7538 *op++ = (unsigned char) ((count >> 8) & 0xff);
7540 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7542 /* fix some things up */
7543 smb_SetSMBParm(outp, 0, finalCount);
7544 smb_SetSMBDataLength(outp, finalCount+3);
7546 smb_ReleaseFID(fidp);
7548 cm_ReleaseUser(userp);
7552 /* SMB_COM_CREATE_DIRECTORY */
7553 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7555 clientchar_t *pathp;
7560 cm_scache_t *dscp; /* dir we're dealing with */
7561 cm_scache_t *scp; /* file we're creating */
7563 int initialModeBits;
7564 clientchar_t *lastNamep;
7566 clientchar_t *tidPathp;
7573 /* compute initial mode bits based on read-only flag in attributes */
7574 initialModeBits = 0777;
7576 tp = smb_GetSMBData(inp, NULL);
7577 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7579 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7580 return CM_ERROR_EXISTS;
7582 spacep = inp->spacep;
7583 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7585 userp = smb_GetUserFromVCP(vcp, inp);
7587 caseFold = CM_FLAG_CASEFOLD;
7589 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7591 cm_ReleaseUser(userp);
7592 return CM_ERROR_NOSUCHPATH;
7595 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7596 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7597 userp, tidPathp, &req, &dscp);
7600 cm_ReleaseUser(userp);
7605 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7606 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7607 cm_ReleaseSCache(dscp);
7608 cm_ReleaseUser(userp);
7609 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7610 return CM_ERROR_PATH_NOT_COVERED;
7612 return CM_ERROR_BADSHARENAME;
7614 #endif /* DFS_SUPPORT */
7616 /* otherwise, scp points to the parent directory. Do a lookup, and
7617 * fail if we find it. Otherwise, we do the create.
7623 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7624 if (scp) cm_ReleaseSCache(scp);
7625 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7626 if (code == 0) code = CM_ERROR_EXISTS;
7627 cm_ReleaseSCache(dscp);
7628 cm_ReleaseUser(userp);
7632 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7633 setAttr.clientModTime = time(NULL);
7634 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7635 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7636 smb_NotifyChange(FILE_ACTION_ADDED,
7637 FILE_NOTIFY_CHANGE_DIR_NAME,
7638 dscp, lastNamep, NULL, TRUE);
7640 /* we don't need this any longer */
7641 cm_ReleaseSCache(dscp);
7644 /* something went wrong creating or truncating the file */
7645 cm_ReleaseUser(userp);
7649 /* otherwise we succeeded */
7650 smb_SetSMBDataLength(outp, 0);
7651 cm_ReleaseUser(userp);
7656 BOOL smb_IsLegalFilename(clientchar_t *filename)
7659 * Find the longest substring of filename that does not contain
7660 * any of the chars in illegalChars. If that substring is less
7661 * than the length of the whole string, then one or more of the
7662 * illegal chars is in filename.
7664 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7670 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7671 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7673 clientchar_t *pathp;
7679 cm_scache_t *dscp; /* dir we're dealing with */
7680 cm_scache_t *scp; /* file we're creating */
7682 int initialModeBits;
7685 clientchar_t *lastNamep;
7688 clientchar_t *tidPathp;
7690 int created = 0; /* the file was new */
7695 excl = (inp->inCom == 0x03)? 0 : 1;
7697 attributes = smb_GetSMBParm(inp, 0);
7698 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7700 /* compute initial mode bits based on read-only flag in attributes */
7701 initialModeBits = 0666;
7702 if (attributes & SMB_ATTR_READONLY)
7703 initialModeBits &= ~0222;
7705 tp = smb_GetSMBData(inp, NULL);
7706 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7708 spacep = inp->spacep;
7709 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7711 userp = smb_GetUserFromVCP(vcp, inp);
7713 caseFold = CM_FLAG_CASEFOLD;
7715 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7717 cm_ReleaseUser(userp);
7718 return CM_ERROR_NOSUCHPATH;
7720 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7721 userp, tidPathp, &req, &dscp);
7724 cm_ReleaseUser(userp);
7729 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7730 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7731 cm_ReleaseSCache(dscp);
7732 cm_ReleaseUser(userp);
7733 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7734 return CM_ERROR_PATH_NOT_COVERED;
7736 return CM_ERROR_BADSHARENAME;
7738 #endif /* DFS_SUPPORT */
7740 /* otherwise, scp points to the parent directory. Do a lookup, and
7741 * truncate the file if we find it, otherwise we create the file.
7748 if (!smb_IsLegalFilename(lastNamep))
7749 return CM_ERROR_BADNTFILENAME;
7751 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
7752 #ifdef DEBUG_VERBOSE
7755 hexp = osi_HexifyString( lastNamep );
7756 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7761 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7762 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7763 cm_ReleaseSCache(dscp);
7764 cm_ReleaseUser(userp);
7768 /* if we get here, if code is 0, the file exists and is represented by
7769 * scp. Otherwise, we have to create it.
7773 /* oops, file shouldn't be there */
7774 cm_ReleaseSCache(dscp);
7775 cm_ReleaseSCache(scp);
7776 cm_ReleaseUser(userp);
7777 return CM_ERROR_EXISTS;
7780 setAttr.mask = CM_ATTRMASK_LENGTH;
7781 setAttr.length.LowPart = 0;
7782 setAttr.length.HighPart = 0;
7783 code = cm_SetAttr(scp, &setAttr, userp, &req);
7786 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7787 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7788 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7792 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7793 smb_NotifyChange(FILE_ACTION_ADDED,
7794 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7795 dscp, lastNamep, NULL, TRUE);
7796 } else if (!excl && code == CM_ERROR_EXISTS) {
7797 /* not an exclusive create, and someone else tried
7798 * creating it already, then we open it anyway. We
7799 * don't bother retrying after this, since if this next
7800 * fails, that means that the file was deleted after
7801 * we started this call.
7803 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7806 setAttr.mask = CM_ATTRMASK_LENGTH;
7807 setAttr.length.LowPart = 0;
7808 setAttr.length.HighPart = 0;
7809 code = cm_SetAttr(scp, &setAttr, userp, &req);
7814 /* we don't need this any longer */
7815 cm_ReleaseSCache(dscp);
7818 /* something went wrong creating or truncating the file */
7819 if (scp) cm_ReleaseSCache(scp);
7820 cm_ReleaseUser(userp);
7824 /* make sure we only open files */
7825 if (scp->fileType != CM_SCACHETYPE_FILE) {
7826 cm_ReleaseSCache(scp);
7827 cm_ReleaseUser(userp);
7828 return CM_ERROR_ISDIR;
7831 /* now all we have to do is open the file itself */
7832 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7833 osi_assertx(fidp, "null smb_fid_t");
7837 lock_ObtainMutex(&fidp->mx);
7838 /* always create it open for read/write */
7839 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7841 /* remember that the file was newly created */
7843 fidp->flags |= SMB_FID_CREATED;
7845 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7847 /* save a pointer to the vnode */
7849 lock_ObtainWrite(&scp->rw);
7850 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7851 lock_ReleaseWrite(&scp->rw);
7854 fidp->userp = userp;
7855 lock_ReleaseMutex(&fidp->mx);
7857 smb_SetSMBParm(outp, 0, fidp->fid);
7858 smb_SetSMBDataLength(outp, 0);
7860 cm_Open(scp, 0, userp);
7862 smb_ReleaseFID(fidp);
7863 cm_ReleaseUser(userp);
7864 /* leave scp held since we put it in fidp->scp */
7869 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7872 osi_hyper_t new_offset;
7883 fd = smb_GetSMBParm(inp, 0);
7884 whence = smb_GetSMBParm(inp, 1);
7885 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7887 /* try to find the file descriptor */
7888 fd = smb_ChainFID(fd, inp);
7889 fidp = smb_FindFID(vcp, fd, 0);
7891 return CM_ERROR_BADFD;
7893 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7894 smb_CloseFID(vcp, fidp, NULL, 0);
7895 smb_ReleaseFID(fidp);
7896 return CM_ERROR_NOSUCHFILE;
7899 lock_ObtainMutex(&fidp->mx);
7900 if (fidp->flags & SMB_FID_IOCTL) {
7901 lock_ReleaseMutex(&fidp->mx);
7902 smb_ReleaseFID(fidp);
7903 return CM_ERROR_BADFD;
7905 lock_ReleaseMutex(&fidp->mx);
7907 userp = smb_GetUserFromVCP(vcp, inp);
7909 lock_ObtainMutex(&fidp->mx);
7912 lock_ReleaseMutex(&fidp->mx);
7913 lock_ObtainWrite(&scp->rw);
7914 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7915 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7917 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7919 /* offset from current offset */
7920 new_offset = LargeIntegerAdd(fidp->offset,
7921 ConvertLongToLargeInteger(offset));
7923 else if (whence == 2) {
7924 /* offset from current EOF */
7925 new_offset = LargeIntegerAdd(scp->length,
7926 ConvertLongToLargeInteger(offset));
7928 new_offset = ConvertLongToLargeInteger(offset);
7931 fidp->offset = new_offset;
7932 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7933 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7934 smb_SetSMBDataLength(outp, 0);
7936 lock_ReleaseWrite(&scp->rw);
7937 smb_ReleaseFID(fidp);
7938 cm_ReleaseSCache(scp);
7939 cm_ReleaseUser(userp);
7943 /* dispatch all of the requests received in a packet. Due to chaining, this may
7944 * be more than one request.
7946 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7947 NCB *ncbp, raw_write_cont_t *rwcp)
7951 unsigned long code = 0;
7952 unsigned char *outWctp;
7953 int nparms; /* # of bytes of parameters */
7955 int nbytes; /* bytes of data, excluding count */
7958 unsigned short errCode;
7959 unsigned long NTStatus;
7961 unsigned char errClass;
7962 unsigned int oldGen;
7963 DWORD oldTime, newTime;
7965 /* get easy pointer to the data */
7966 smbp = (smb_t *) inp->data;
7968 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7969 /* setup the basic parms for the initial request in the packet */
7970 inp->inCom = smbp->com;
7971 inp->wctp = &smbp->wct;
7973 inp->ncb_length = ncbp->ncb_length;
7978 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7979 /* log it and discard it */
7980 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7981 __FILE__, __LINE__, ncbp->ncb_length);
7982 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7986 /* We are an ongoing op */
7987 thrd_Increment(&ongoingOps);
7989 /* set up response packet for receiving output */
7990 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7991 smb_FormatResponsePacket(vcp, inp, outp);
7992 outWctp = outp->wctp;
7994 /* Remember session generation number and time */
7995 oldGen = sessionGen;
7996 oldTime = GetTickCount();
7998 while (inp->inCom != 0xff) {
7999 dp = &smb_dispatchTable[inp->inCom];
8001 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8002 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8003 code = outp->resumeCode;
8007 /* process each request in the packet; inCom, wctp and inCount
8008 * are already set up.
8010 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8013 /* now do the dispatch */
8014 /* start by formatting the response record a little, as a default */
8015 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8017 outWctp[1] = 0xff; /* no operation */
8018 outWctp[2] = 0; /* padding */
8023 /* not a chained request, this is a more reasonable default */
8024 outWctp[0] = 0; /* wct of zero */
8025 outWctp[1] = 0; /* and bcc (word) of zero */
8029 /* once set, stays set. Doesn't matter, since we never chain
8030 * "no response" calls.
8032 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8036 /* we have a recognized operation */
8037 char * opName = myCrt_Dispatch(inp->inCom);
8039 if (inp->inCom == 0x1d)
8041 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8043 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
8044 opName,vcp,vcp->lana,vcp->lsn);
8045 code = (*(dp->procp)) (vcp, inp, outp);
8046 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
8047 code,vcp,vcp->lana,vcp->lsn);
8049 if ( code == CM_ERROR_BADSMB ||
8050 code == CM_ERROR_BADOP )
8052 #endif /* LOG_PACKET */
8055 newTime = GetTickCount();
8056 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
8058 if (oldGen != sessionGen) {
8059 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8060 newTime - oldTime, ncbp->ncb_length);
8061 osi_Log3(smb_logp, "Request %s straddled session startup, "
8062 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8065 FreeSMBStrings(inp);
8067 /* bad opcode, fail the request, after displaying it */
8068 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8071 #endif /* LOG_PACKET */
8074 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8075 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8076 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8077 if (code == IDCANCEL)
8080 code = CM_ERROR_BADOP;
8083 /* catastrophic failure: log as much as possible */
8084 if (code == CM_ERROR_BADSMB) {
8085 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8089 #endif /* LOG_PACKET */
8090 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8093 code = CM_ERROR_INVAL;
8096 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8097 thrd_Decrement(&ongoingOps);
8102 /* now, if we failed, turn the current response into an empty
8103 * one, and fill in the response packet's error code.
8106 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8107 smb_MapNTError(code, &NTStatus);
8108 outWctp = outp->wctp;
8109 smbp = (smb_t *) &outp->data;
8110 if (code != CM_ERROR_PARTIALWRITE
8111 && code != CM_ERROR_BUFFERTOOSMALL
8112 && code != CM_ERROR_GSSCONTINUE) {
8113 /* nuke wct and bcc. For a partial
8114 * write or an in-process authentication handshake,
8115 * assume they're OK.
8121 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8122 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8123 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8124 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8125 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8129 smb_MapCoreError(code, vcp, &errCode, &errClass);
8130 outWctp = outp->wctp;
8131 smbp = (smb_t *) &outp->data;
8132 if (code != CM_ERROR_PARTIALWRITE) {
8133 /* nuke wct and bcc. For a partial
8134 * write, assume they're OK.
8140 smbp->errLow = (unsigned char) (errCode & 0xff);
8141 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8142 smbp->rcls = errClass;
8145 } /* error occurred */
8147 /* if we're here, we've finished one request. Look to see if
8148 * this is a chained opcode. If it is, setup things to process
8149 * the chained request, and setup the output buffer to hold the
8150 * chained response. Start by finding the next input record.
8152 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8153 break; /* not a chained req */
8154 tp = inp->wctp; /* points to start of last request */
8155 /* in a chained request, the first two
8156 * parm fields are required, and are
8157 * AndXCommand/AndXReserved and
8159 if (tp[0] < 2) break;
8160 if (tp[1] == 0xff) break; /* no more chained opcodes */
8162 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8165 /* and now append the next output request to the end of this
8166 * last request. Begin by finding out where the last response
8167 * ends, since that's where we'll put our new response.
8169 outWctp = outp->wctp; /* ptr to out parameters */
8170 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8171 nparms = outWctp[0] << 1;
8172 tp = outWctp + nparms + 1; /* now points to bcc field */
8173 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8174 tp += 2 /* for the count itself */ + nbytes;
8175 /* tp now points to the new output record; go back and patch the
8176 * second parameter (off2) to point to the new record.
8178 temp = (unsigned int)(tp - outp->data);
8179 outWctp[3] = (unsigned char) (temp & 0xff);
8180 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8181 outWctp[2] = 0; /* padding */
8182 outWctp[1] = inp->inCom; /* next opcode */
8184 /* finally, setup for the next iteration */
8187 } /* while loop over all requests in the packet */
8189 /* now send the output packet, and return */
8191 smb_SendPacket(vcp, outp);
8192 thrd_Decrement(&ongoingOps);
8197 /* Wait for Netbios() calls to return, and make the results available to server
8198 * threads. Note that server threads can't wait on the NCBevents array
8199 * themselves, because NCB events are manual-reset, and the servers would race
8200 * each other to reset them.
8202 void smb_ClientWaiter(void *parmp)
8207 while (smbShutdownFlag == 0) {
8208 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8210 if (code == WAIT_OBJECT_0)
8213 /* error checking */
8214 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8216 int abandonIdx = code - WAIT_ABANDONED_0;
8217 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8220 if (code == WAIT_IO_COMPLETION)
8222 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8226 if (code == WAIT_TIMEOUT)
8228 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8231 if (code == WAIT_FAILED)
8233 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8236 idx = code - WAIT_OBJECT_0;
8238 /* check idx range! */
8239 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8241 /* this is fatal - log as much as possible */
8242 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8243 osi_assertx(0, "invalid index");
8246 thrd_ResetEvent(NCBevents[idx]);
8247 thrd_SetEvent(NCBreturns[0][idx]);
8252 * Try to have one NCBRECV request waiting for every live session. Not more
8253 * than one, because if there is more than one, it's hard to handle Write Raw.
8255 void smb_ServerWaiter(void *parmp)
8258 int idx_session, idx_NCB;
8261 while (smbShutdownFlag == 0) {
8263 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8265 if (code == WAIT_OBJECT_0)
8268 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8270 int abandonIdx = code - WAIT_ABANDONED_0;
8271 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8274 if (code == WAIT_IO_COMPLETION)
8276 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8280 if (code == WAIT_TIMEOUT)
8282 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8285 if (code == WAIT_FAILED)
8287 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8290 idx_session = code - WAIT_OBJECT_0;
8292 /* check idx range! */
8293 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8295 /* this is fatal - log as much as possible */
8296 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8297 osi_assertx(0, "invalid index");
8302 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8304 if (code == WAIT_OBJECT_0) {
8305 if (smbShutdownFlag == 1)
8311 /* error checking */
8312 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8314 int abandonIdx = code - WAIT_ABANDONED_0;
8315 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8318 if (code == WAIT_IO_COMPLETION)
8320 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8324 if (code == WAIT_TIMEOUT)
8326 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8329 if (code == WAIT_FAILED)
8331 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8334 idx_NCB = code - WAIT_OBJECT_0;
8336 /* check idx range! */
8337 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8339 /* this is fatal - log as much as possible */
8340 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8341 osi_assertx(0, "invalid index");
8344 /* Link them together */
8345 NCBsessions[idx_NCB] = idx_session;
8348 ncbp = NCBs[idx_NCB];
8349 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8350 ncbp->ncb_command = NCBRECV | ASYNCH;
8351 ncbp->ncb_lana_num = lanas[idx_session];
8352 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8353 ncbp->ncb_event = NCBevents[idx_NCB];
8354 ncbp->ncb_length = SMB_PACKETSIZE;
8360 * The top level loop for handling SMB request messages. Each server thread
8361 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8362 * NCB and buffer for the incoming request are loaned to us.
8364 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8365 * to immediately send a request for the rest of the data. This must come
8366 * before any other traffic for that session, so we delay setting the session
8367 * event until that data has come in.
8369 void smb_Server(VOID *parmp)
8371 INT_PTR myIdx = (INT_PTR) parmp;
8375 smb_packet_t *outbufp;
8377 int idx_NCB, idx_session;
8379 smb_vc_t *vcp = NULL;
8381 extern void rx_StartClientThread(void);
8383 rx_StartClientThread();
8385 outncbp = smb_GetNCB();
8386 outbufp = smb_GetPacket();
8387 outbufp->ncbp = outncbp;
8395 smb_ResetServerPriority();
8397 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8400 /* terminate silently if shutdown flag is set */
8401 if (code == WAIT_OBJECT_0) {
8402 if (smbShutdownFlag == 1) {
8403 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8409 /* error checking */
8410 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8412 int abandonIdx = code - WAIT_ABANDONED_0;
8413 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8416 if (code == WAIT_IO_COMPLETION)
8418 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8422 if (code == WAIT_TIMEOUT)
8424 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8427 if (code == WAIT_FAILED)
8429 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8432 idx_NCB = code - WAIT_OBJECT_0;
8434 /* check idx range! */
8435 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8437 /* this is fatal - log as much as possible */
8438 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8439 osi_assertx(0, "invalid index");
8442 ncbp = NCBs[idx_NCB];
8443 idx_session = NCBsessions[idx_NCB];
8444 rc = ncbp->ncb_retcode;
8446 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8447 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8451 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8455 /* Can this happen? Or is it just my UNIX paranoia? */
8456 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8461 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8464 /* Client closed session */
8465 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8467 lock_ObtainMutex(&vcp->mx);
8468 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8469 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8471 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8472 lock_ReleaseMutex(&vcp->mx);
8473 lock_ObtainWrite(&smb_globalLock);
8474 dead_sessions[vcp->session] = TRUE;
8475 lock_ReleaseWrite(&smb_globalLock);
8477 lock_ReleaseMutex(&vcp->mx);
8479 smb_CleanupDeadVC(vcp);
8486 /* Treat as transient error */
8487 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8490 "dispatch smb recv failed, message incomplete, ncb_length %d",
8493 "SMB message incomplete, "
8494 "length %d", ncbp->ncb_length);
8497 * We used to discard the packet.
8498 * Instead, try handling it normally.
8502 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8506 /* A weird error code. Log it, sleep, and continue. */
8507 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8509 lock_ObtainMutex(&vcp->mx);
8510 if (vcp->errorCount++ > 3) {
8511 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8512 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8513 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8515 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8516 lock_ReleaseMutex(&vcp->mx);
8517 lock_ObtainWrite(&smb_globalLock);
8518 dead_sessions[vcp->session] = TRUE;
8519 lock_ReleaseWrite(&smb_globalLock);
8521 lock_ReleaseMutex(&vcp->mx);
8523 smb_CleanupDeadVC(vcp);
8529 lock_ReleaseMutex(&vcp->mx);
8533 thrd_SetEvent(SessionEvents[idx_session]);
8539 /* Success, so now dispatch on all the data in the packet */
8541 smb_concurrentCalls++;
8542 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8543 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8546 * If at this point vcp is NULL (implies that packet was invalid)
8547 * then we are in big trouble. This means either :
8548 * a) we have the wrong NCB.
8549 * b) Netbios screwed up the call.
8550 * c) The VC was already marked dead before we were able to
8552 * Obviously this implies that
8553 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8554 * lanas[idx_session] != ncbp->ncb_lana_num )
8555 * Either way, we can't do anything with this packet.
8556 * Log, sleep and resume.
8559 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8563 ncbp->ncb_lana_num);
8565 /* Also log in the trace log. */
8566 osi_Log4(smb_logp, "Server: VCP does not exist!"
8567 "LSNs[idx_session]=[%d],"
8568 "lanas[idx_session]=[%d],"
8569 "ncbp->ncb_lsn=[%d],"
8570 "ncbp->ncb_lana_num=[%d]",
8574 ncbp->ncb_lana_num);
8576 /* thrd_Sleep(1000); Don't bother sleeping */
8577 thrd_SetEvent(SessionEvents[idx_session]);
8578 smb_concurrentCalls--;
8582 smb_SetRequestStartTime();
8584 vcp->errorCount = 0;
8585 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8586 smbp = (smb_t *)bufp->data;
8593 if (smbp->com == 0x1d) {
8594 /* Special handling for Write Raw */
8595 raw_write_cont_t rwc;
8596 EVENT_HANDLE rwevent;
8597 char eventName[MAX_PATH];
8599 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8600 if (rwc.code == 0) {
8601 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8602 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8603 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8604 ncbp->ncb_command = NCBRECV | ASYNCH;
8605 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8606 ncbp->ncb_lana_num = vcp->lana;
8607 ncbp->ncb_buffer = rwc.buf;
8608 ncbp->ncb_length = 65535;
8609 ncbp->ncb_event = rwevent;
8611 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8612 thrd_CloseHandle(rwevent);
8614 thrd_SetEvent(SessionEvents[idx_session]);
8616 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8618 else if (smbp->com == 0xa0) {
8620 * Serialize the handling for NT Transact
8623 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8624 thrd_SetEvent(SessionEvents[idx_session]);
8626 thrd_SetEvent(SessionEvents[idx_session]);
8627 /* TODO: what else needs to be serialized? */
8628 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8632 __except( smb_ServerExceptionFilter() ) {
8636 smb_concurrentCalls--;
8639 thrd_SetEvent(NCBavails[idx_NCB]);
8644 smb_FreePacket(outbufp);
8646 smb_FreeNCB(outncbp);
8650 * Exception filter for the server threads. If an exception occurs in the
8651 * dispatch routines, which is where exceptions are most common, then do a
8652 * force trace and give control to upstream exception handlers. Useful for
8655 DWORD smb_ServerExceptionFilter(void) {
8656 /* While this is not the best time to do a trace, if it succeeds, then
8657 * we have a trace (assuming tracing was enabled). Otherwise, this should
8658 * throw a second exception.
8660 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8661 afsd_ForceTrace(TRUE);
8662 buf_ForceTrace(TRUE);
8663 return EXCEPTION_CONTINUE_SEARCH;
8667 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8668 * If the number of server threads is M, and the number of live sessions is
8669 * N, then the number of NCB's in use at any time either waiting for, or
8670 * holding, received messages is M + N, so that is how many NCB's get created.
8672 void InitNCBslot(int idx)
8674 struct smb_packet *bufp;
8675 EVENT_HANDLE retHandle;
8677 char eventName[MAX_PATH];
8679 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8681 NCBs[idx] = smb_GetNCB();
8682 sprintf(eventName,"NCBavails[%d]", idx);
8683 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8684 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8685 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8686 sprintf(eventName,"NCBevents[%d]", idx);
8687 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8688 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8689 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8690 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8691 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8692 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8693 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8694 for (i=0; i<smb_NumServerThreads; i++)
8695 NCBreturns[i][idx] = retHandle;
8696 bufp = smb_GetPacket();
8697 bufp->spacep = cm_GetSpace();
8701 /* listen for new connections */
8702 void smb_Listener(void *parmp)
8708 afs_uint32 session, thread;
8709 smb_vc_t *vcp = NULL;
8711 char rname[NCBNAMSZ+1];
8712 char cname[MAX_COMPUTERNAME_LENGTH+1];
8713 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8714 INT_PTR lana = (INT_PTR) parmp;
8715 char eventName[MAX_PATH];
8717 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
8718 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8719 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8720 thrd_ResetEvent(ListenerShutdown[lana]);
8722 ncbp = smb_GetNCB();
8724 /* retrieve computer name */
8725 GetComputerName(cname, &cnamelen);
8728 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8729 memset(ncbp, 0, sizeof(NCB));
8732 ncbp->ncb_command = NCBLISTEN;
8733 ncbp->ncb_rto = 0; /* No receive timeout */
8734 ncbp->ncb_sto = 0; /* No send timeout */
8736 /* pad out with spaces instead of null termination */
8737 len = (long)strlen(smb_localNamep);
8738 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8739 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8741 strcpy(ncbp->ncb_callname, "*");
8742 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8744 ncbp->ncb_lana_num = (UCHAR)lana;
8746 code = Netbios(ncbp);
8748 if (code == NRC_NAMERR) {
8749 /* An smb shutdown or Vista resume must have taken place */
8751 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8752 ncbp->ncb_lana_num, code);
8754 if (lock_TryMutex(&smb_StartedLock)) {
8755 lana_list.lana[i] = LANA_INVALID;
8756 lock_ReleaseMutex(&smb_StartedLock);
8759 } else if (code == NRC_BRIDGE || code != 0) {
8760 int lanaRemaining = 0;
8762 while (!lock_TryMutex(&smb_StartedLock)) {
8763 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8769 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8770 ncbp->ncb_lana_num, ncb_error_string(code));
8772 for (i = 0; i < lana_list.length; i++) {
8773 if (lana_list.lana[i] == lana) {
8774 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8775 lana_list.lana[i] = LANA_INVALID;
8777 if (lana_list.lana[i] != LANA_INVALID)
8781 if (lanaRemaining == 0) {
8782 cm_VolStatus_Network_Stopped(cm_NetbiosName
8787 smb_ListenerState = SMB_LISTENER_STOPPED;
8788 smb_LANadapter = LANA_INVALID;
8789 lana_list.length = 0;
8791 lock_ReleaseMutex(&smb_StartedLock);
8795 else if (code != 0) {
8796 char tbuffer[AFSPATHMAX];
8798 /* terminate silently if shutdown flag is set */
8799 while (!lock_TryMutex(&smb_StartedLock)) {
8800 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8806 "NCBLISTEN lana=%d failed with code %d [%s]",
8807 ncbp->ncb_lana_num, code, ncb_error_string(code));
8809 "Client exiting due to network failure. Please restart client.\n");
8812 "Client exiting due to network failure. Please restart client.\n"
8813 "NCBLISTEN lana=%d failed with code %d [%s]",
8814 ncbp->ncb_lana_num, code, ncb_error_string(code));
8816 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8817 MB_OK|MB_SERVICE_NOTIFICATION);
8818 osi_panic(tbuffer, __FILE__, __LINE__);
8820 lock_ReleaseMutex(&smb_StartedLock);
8825 /* check for remote conns */
8826 /* first get remote name and insert null terminator */
8827 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8828 for (i=NCBNAMSZ; i>0; i--) {
8829 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8835 /* compare with local name */
8837 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8838 flags |= SMB_VCFLAG_REMOTECONN;
8841 lock_ObtainMutex(&smb_ListenerLock);
8843 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8844 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8846 /* now ncbp->ncb_lsn is the connection ID */
8847 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8848 if (vcp->session == 0) {
8849 /* New generation */
8850 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8853 /* Log session startup */
8855 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8856 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8857 #endif /* NOTSERVICE */
8858 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8859 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8861 if (reportSessionStartups) {
8862 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8865 lock_ObtainMutex(&vcp->mx);
8866 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
8867 vcp->flags |= flags;
8868 lock_ReleaseMutex(&vcp->mx);
8870 /* Allocate slot in session arrays */
8871 /* Re-use dead session if possible, otherwise add one more */
8872 /* But don't look at session[0], it is reserved */
8873 lock_ObtainWrite(&smb_globalLock);
8874 for (session = 1; session < numSessions; session++) {
8875 if (dead_sessions[session]) {
8876 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8877 dead_sessions[session] = FALSE;
8881 lock_ReleaseWrite(&smb_globalLock);
8883 /* We are re-using an existing VC because the lsn and lana
8885 session = vcp->session;
8887 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8889 /* Log session startup */
8891 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8892 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8893 #endif /* NOTSERVICE */
8894 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8895 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8897 if (reportSessionStartups) {
8898 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8902 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8903 unsigned long code = CM_ERROR_ALLBUSY;
8904 smb_packet_t * outp = smb_GetPacket();
8905 unsigned char *outWctp;
8908 smb_FormatResponsePacket(vcp, NULL, outp);
8911 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8912 unsigned long NTStatus;
8913 smb_MapNTError(code, &NTStatus);
8914 outWctp = outp->wctp;
8915 smbp = (smb_t *) &outp->data;
8919 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8920 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8921 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8922 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8923 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8925 unsigned short errCode;
8926 unsigned char errClass;
8927 smb_MapCoreError(code, vcp, &errCode, &errClass);
8928 outWctp = outp->wctp;
8929 smbp = (smb_t *) &outp->data;
8933 smbp->errLow = (unsigned char) (errCode & 0xff);
8934 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8935 smbp->rcls = errClass;
8938 smb_SendPacket(vcp, outp);
8939 smb_FreePacket(outp);
8941 lock_ObtainMutex(&vcp->mx);
8942 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8943 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8945 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8946 lock_ReleaseMutex(&vcp->mx);
8947 lock_ObtainWrite(&smb_globalLock);
8948 dead_sessions[vcp->session] = TRUE;
8949 lock_ReleaseWrite(&smb_globalLock);
8950 smb_CleanupDeadVC(vcp);
8952 lock_ReleaseMutex(&vcp->mx);
8955 /* assert that we do not exceed the maximum number of sessions or NCBs.
8956 * we should probably want to wait for a session to be freed in case
8959 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8960 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8962 lock_ObtainMutex(&vcp->mx);
8963 vcp->session = session;
8964 lock_ReleaseMutex(&vcp->mx);
8965 lock_ObtainWrite(&smb_globalLock);
8966 LSNs[session] = ncbp->ncb_lsn;
8967 lanas[session] = ncbp->ncb_lana_num;
8968 lock_ReleaseWrite(&smb_globalLock);
8970 if (session == numSessions) {
8971 /* Add new NCB for new session */
8972 char eventName[MAX_PATH];
8974 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8976 InitNCBslot(numNCBs);
8977 lock_ObtainWrite(&smb_globalLock);
8979 lock_ReleaseWrite(&smb_globalLock);
8980 thrd_SetEvent(NCBavails[0]);
8981 thrd_SetEvent(NCBevents[0]);
8982 for (thread = 0; thread < smb_NumServerThreads; thread++)
8983 thrd_SetEvent(NCBreturns[thread][0]);
8984 /* Also add new session event */
8985 sprintf(eventName, "SessionEvents[%d]", session);
8986 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8987 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8988 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8989 lock_ObtainWrite(&smb_globalLock);
8991 lock_ReleaseWrite(&smb_globalLock);
8992 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8993 thrd_SetEvent(SessionEvents[0]);
8995 thrd_SetEvent(SessionEvents[session]);
9001 lock_ReleaseMutex(&smb_ListenerLock);
9002 } /* dispatch while loop */
9006 thrd_SetEvent(ListenerShutdown[lana]);
9011 smb_LanAdapterChangeThread(void *param)
9014 * Give the IPAddrDaemon thread a chance
9015 * to block before we trigger.
9018 smb_LanAdapterChange(0);
9021 void smb_SetLanAdapterChangeDetected(void)
9026 lock_ObtainMutex(&smb_StartedLock);
9028 if (!powerStateSuspended) {
9029 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9030 NULL, 0, &lpid, "smb_LanAdapterChange");
9031 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9032 thrd_CloseHandle(phandle);
9035 smb_LanAdapterChangeDetected = 1;
9036 lock_ReleaseMutex(&smb_StartedLock);
9039 void smb_LanAdapterChange(int locked) {
9040 lana_number_t lanaNum;
9042 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9044 LANA_ENUM temp_list;
9049 afsi_log("smb_LanAdapterChange");
9052 lock_ObtainMutex(&smb_StartedLock);
9054 smb_LanAdapterChangeDetected = 0;
9056 if (!powerStateSuspended &&
9057 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9058 LANA_NETBIOS_NAME_FULL)) &&
9059 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9060 if ( isGateway != bGateway ||
9061 strcmp(cm_NetbiosName, NetbiosName) ) {
9064 NCB *ncbp = smb_GetNCB();
9065 ncbp->ncb_command = NCBENUM;
9066 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9067 ncbp->ncb_length = sizeof(temp_list);
9068 code = Netbios(ncbp);
9070 if (temp_list.length != lana_list.length)
9073 for (i=0; i<lana_list.length; i++) {
9074 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9086 afsi_log("Lan Adapter Change detected");
9087 smb_StopListeners(1);
9088 smb_RestartListeners(1);
9091 lock_ReleaseMutex(&smb_StartedLock);
9094 /* initialize Netbios */
9095 int smb_NetbiosInit(int locked)
9098 int i, lana, code, l;
9100 int delname_tried=0;
9103 lana_number_t lanaNum;
9106 lock_ObtainMutex(&smb_StartedLock);
9108 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9109 smb_ListenerState != SMB_LISTENER_STOPPED) {
9112 lock_ReleaseMutex(&smb_StartedLock);
9115 /* setup the NCB system */
9116 ncbp = smb_GetNCB();
9118 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9119 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9120 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9122 if (smb_LANadapter != LANA_INVALID)
9123 afsi_log("LAN adapter number %d", smb_LANadapter);
9125 afsi_log("LAN adapter number not determined");
9128 afsi_log("Set for gateway service");
9130 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9132 /* something went horribly wrong. We can't proceed without a netbios name */
9134 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9135 osi_panic(buf, __FILE__, __LINE__);
9138 /* remember the name */
9139 len = (int)strlen(cm_NetbiosName);
9141 free(smb_localNamep);
9142 smb_localNamep = malloc(len+1);
9143 strcpy(smb_localNamep, cm_NetbiosName);
9144 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9146 /* Also copy the value to the client character encoded string */
9147 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9149 if (smb_LANadapter == LANA_INVALID) {
9150 ncbp->ncb_command = NCBENUM;
9151 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9152 ncbp->ncb_length = sizeof(lana_list);
9153 code = Netbios(ncbp);
9155 afsi_log("Netbios NCBENUM error code %d", code);
9156 osi_panic(s, __FILE__, __LINE__);
9160 lana_list.length = 1;
9161 lana_list.lana[0] = smb_LANadapter;
9164 for (i = 0; i < lana_list.length; i++) {
9165 /* reset the adaptor: in Win32, this is required for every process, and
9166 * acts as an init call, not as a real hardware reset.
9168 ncbp->ncb_command = NCBRESET;
9169 ncbp->ncb_callname[0] = 100;
9170 ncbp->ncb_callname[2] = 100;
9171 ncbp->ncb_lana_num = lana_list.lana[i];
9172 code = Netbios(ncbp);
9174 code = ncbp->ncb_retcode;
9176 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9177 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9179 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9183 /* and declare our name so we can receive connections */
9184 memset(ncbp, 0, sizeof(*ncbp));
9185 len=lstrlen(smb_localNamep);
9186 memset(smb_sharename,' ',NCBNAMSZ);
9187 memcpy(smb_sharename,smb_localNamep,len);
9188 afsi_log("lana_list.length %d", lana_list.length);
9190 /* Keep the name so we can unregister it later */
9191 for (l = 0; l < lana_list.length; l++) {
9192 lana = lana_list.lana[l];
9194 ncbp->ncb_command = NCBADDNAME;
9195 ncbp->ncb_lana_num = lana;
9196 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9197 code = Netbios(ncbp);
9199 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9200 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9202 char name[NCBNAMSZ+1];
9204 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9205 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9209 code = ncbp->ncb_retcode;
9212 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9215 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9216 if (code == NRC_BRIDGE) { /* invalid LANA num */
9217 lana_list.lana[l] = LANA_INVALID;
9220 else if (code == NRC_DUPNAME) {
9221 afsi_log("Name already exists; try to delete it");
9222 memset(ncbp, 0, sizeof(*ncbp));
9223 ncbp->ncb_command = NCBDELNAME;
9224 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9225 ncbp->ncb_lana_num = lana;
9226 code = Netbios(ncbp);
9228 code = ncbp->ncb_retcode;
9230 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9232 if (code != 0 || delname_tried) {
9233 lana_list.lana[l] = LANA_INVALID;
9235 else if (code == 0) {
9236 if (!delname_tried) {
9244 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9245 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9249 smb_LANadapter = lana;
9250 lana_found = 1; /* at least one worked */
9254 osi_assertx(lana_list.length >= 0, "empty lana list");
9256 afsi_log("No valid LANA numbers found!");
9257 lana_list.length = 0;
9258 smb_LANadapter = LANA_INVALID;
9259 smb_ListenerState = SMB_LISTENER_STOPPED;
9260 cm_VolStatus_Network_Stopped(cm_NetbiosName
9267 /* we're done with the NCB now */
9270 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9271 if (lana_list.length > 0)
9272 osi_assert(smb_LANadapter != LANA_INVALID);
9275 lock_ReleaseMutex(&smb_StartedLock);
9277 return (lana_list.length > 0 ? 1 : 0);
9280 void smb_StartListeners(int locked)
9287 lock_ObtainMutex(&smb_StartedLock);
9289 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9291 lock_ReleaseMutex(&smb_StartedLock);
9295 afsi_log("smb_StartListeners");
9296 smb_ListenerState = SMB_LISTENER_STARTED;
9297 cm_VolStatus_Network_Started(cm_NetbiosName
9303 for (i = 0; i < lana_list.length; i++) {
9304 if (lana_list.lana[i] == LANA_INVALID)
9306 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9307 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9308 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9309 thrd_CloseHandle(phandle);
9312 lock_ReleaseMutex(&smb_StartedLock);
9315 void smb_RestartListeners(int locked)
9318 lock_ObtainMutex(&smb_StartedLock);
9320 if (powerStateSuspended)
9321 afsi_log("smb_RestartListeners called while suspended");
9323 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9324 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9325 if (smb_NetbiosInit(1))
9326 smb_StartListeners(1);
9327 } else if (smb_LanAdapterChangeDetected) {
9328 smb_LanAdapterChange(1);
9332 lock_ReleaseMutex(&smb_StartedLock);
9335 void smb_StopListener(NCB *ncbp, int lana, int wait)
9339 memset(ncbp, 0, sizeof(*ncbp));
9340 ncbp->ncb_command = NCBDELNAME;
9341 ncbp->ncb_lana_num = lana;
9342 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9343 code = Netbios(ncbp);
9345 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9346 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9348 /* and then reset the LANA; this will cause the listener threads to exit */
9349 ncbp->ncb_command = NCBRESET;
9350 ncbp->ncb_callname[0] = 100;
9351 ncbp->ncb_callname[2] = 100;
9352 ncbp->ncb_lana_num = lana;
9353 code = Netbios(ncbp);
9355 code = ncbp->ncb_retcode;
9357 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
9359 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
9363 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9366 void smb_StopListeners(int locked)
9372 lock_ObtainMutex(&smb_StartedLock);
9374 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9376 lock_ReleaseMutex(&smb_StartedLock);
9380 afsi_log("smb_StopListeners");
9381 smb_ListenerState = SMB_LISTENER_STOPPED;
9382 cm_VolStatus_Network_Stopped(cm_NetbiosName
9388 ncbp = smb_GetNCB();
9390 /* Unregister the SMB name */
9391 for (l = 0; l < lana_list.length; l++) {
9392 lana = lana_list.lana[l];
9394 if (lana != LANA_INVALID) {
9395 smb_StopListener(ncbp, lana, TRUE);
9397 /* mark the adapter invalid */
9398 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9402 /* force a re-evaluation of the network adapters */
9403 lana_list.length = 0;
9404 smb_LANadapter = LANA_INVALID;
9407 lock_ReleaseMutex(&smb_StartedLock);
9410 void smb_Init(osi_log_t *logp, int useV3,
9420 EVENT_HANDLE retHandle;
9421 char eventName[MAX_PATH];
9422 int startListeners = 0;
9424 smb_TlsRequestSlot = TlsAlloc();
9426 smb_MBfunc = aMBfunc;
9430 /* Initialize smb_localZero */
9431 myTime.tm_isdst = -1; /* compute whether on DST or not */
9432 myTime.tm_year = 70;
9438 smb_localZero = mktime(&myTime);
9440 #ifndef USE_NUMERIC_TIME_CONV
9441 /* Initialize kludge-GMT */
9442 smb_CalculateNowTZ();
9443 #endif /* USE_NUMERIC_TIME_CONV */
9444 #ifdef AFS_FREELANCE_CLIENT
9445 /* Make sure the root.afs volume has the correct time */
9446 cm_noteLocalMountPointChange();
9449 /* initialize the remote debugging log */
9452 /* and the global lock */
9453 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
9454 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
9456 /* Raw I/O data structures */
9457 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
9459 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
9460 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
9462 /* 4 Raw I/O buffers */
9463 smb_RawBufs = calloc(65536,1);
9464 *((char **)smb_RawBufs) = NULL;
9465 for (i=0; i<3; i++) {
9466 char *rawBuf = calloc(65536,1);
9467 *((char **)rawBuf) = smb_RawBufs;
9468 smb_RawBufs = rawBuf;
9471 /* global free lists */
9472 smb_ncbFreeListp = NULL;
9473 smb_packetFreeListp = NULL;
9475 lock_ObtainMutex(&smb_StartedLock);
9476 startListeners = smb_NetbiosInit(1);
9478 /* Initialize listener and server structures */
9480 memset(dead_sessions, 0, sizeof(dead_sessions));
9481 sprintf(eventName, "SessionEvents[0]");
9482 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9483 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9484 afsi_log("Event Object Already Exists: %s", eventName);
9486 smb_NumServerThreads = nThreads;
9487 sprintf(eventName, "NCBavails[0]");
9488 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9489 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9490 afsi_log("Event Object Already Exists: %s", eventName);
9491 sprintf(eventName, "NCBevents[0]");
9492 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9493 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9494 afsi_log("Event Object Already Exists: %s", eventName);
9495 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9496 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9497 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9498 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9499 afsi_log("Event Object Already Exists: %s", eventName);
9500 for (i = 0; i < smb_NumServerThreads; i++) {
9501 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9502 NCBreturns[i][0] = retHandle;
9505 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9506 for (i = 0; i < smb_NumServerThreads; i++) {
9507 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9508 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9509 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9510 afsi_log("Event Object Already Exists: %s", eventName);
9511 InitNCBslot((int)(i+1));
9513 numNCBs = smb_NumServerThreads + 1;
9515 /* Initialize dispatch table */
9516 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9517 /* Prepare the table for unknown operations */
9518 for(i=0; i<= SMB_NOPCODES; i++) {
9519 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9521 /* Fill in the ones we do know */
9522 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9523 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9524 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9525 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9526 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9527 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9528 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9529 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9530 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9531 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9532 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9533 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9534 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9535 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9536 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9537 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9538 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9539 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9540 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9541 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9542 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9543 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9544 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9545 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9546 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9547 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9548 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9549 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9550 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9551 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9552 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9553 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9554 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9555 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9556 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9557 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9558 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9559 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9560 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9561 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9562 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9563 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9564 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9565 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9566 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9567 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9568 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9569 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9570 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9571 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9572 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9573 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9574 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9575 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9576 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9577 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9578 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9579 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9580 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9581 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9582 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9583 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9584 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9585 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9586 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9587 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9588 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9589 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9590 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9591 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9592 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9593 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9594 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9595 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9597 /* setup tran 2 dispatch table */
9598 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9599 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9600 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9601 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9602 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9603 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9604 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9605 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9606 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9607 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9608 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9609 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9610 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9611 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9612 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9613 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9614 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9615 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9617 /* setup the rap dispatch table */
9618 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9619 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9620 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9621 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9622 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9626 /* if we are doing SMB authentication we have register outselves as a logon process */
9627 if (smb_authType != SMB_AUTH_NONE) {
9628 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9629 LSA_STRING afsProcessName;
9630 LSA_OPERATIONAL_MODE dummy; /*junk*/
9632 afsProcessName.Buffer = "OpenAFSClientDaemon";
9633 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9634 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9636 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9638 if (nts == STATUS_SUCCESS) {
9639 LSA_STRING packageName;
9640 /* we are registered. Find out the security package id */
9641 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9642 packageName.Length = (USHORT)strlen(packageName.Buffer);
9643 packageName.MaximumLength = packageName.Length + 1;
9644 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9645 if (nts == STATUS_SUCCESS) {
9647 * This code forces Windows to authenticate against the Logon Cache
9648 * first instead of attempting to authenticate against the Domain
9649 * Controller. When the Windows logon cache is enabled this improves
9650 * performance by removing the network access and works around a bug
9651 * seen at sites which are using a MIT Kerberos principal to login
9652 * to machines joined to a non-root domain in a multi-domain forest.
9653 * MsV1_0SetProcessOption was added in Windows XP.
9655 PVOID pResponse = NULL;
9656 ULONG cbResponse = 0;
9657 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9659 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9660 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9661 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9662 OptionsRequest.DisableOptions = FALSE;
9664 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9667 sizeof(OptionsRequest),
9673 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9674 char message[AFSPATHMAX];
9675 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9677 OutputDebugString(message);
9680 OutputDebugString("MsV1_0SetProcessOption success");
9681 afsi_log("MsV1_0SetProcessOption success");
9683 /* END - code from Larry */
9685 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9686 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9687 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9689 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9691 /* something went wrong. We report the error and revert back to no authentication
9692 because we can't perform any auth requests without a successful lsa handle
9693 or sec package id. */
9694 afsi_log("Reverting to NO SMB AUTH");
9695 smb_authType = SMB_AUTH_NONE;
9698 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9700 /* something went wrong. We report the error and revert back to no authentication
9701 because we can't perform any auth requests without a successful lsa handle
9702 or sec package id. */
9703 afsi_log("Reverting to NO SMB AUTH");
9704 smb_authType = SMB_AUTH_NONE;
9708 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9709 * time prevents the failure of authentication when logged into Windows with an
9710 * external Kerberos principal mapped to a local account.
9712 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9713 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9714 * then the only option is NTLMSSP anyway; so just fallback.
9719 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9720 if (secBlobLength == 0) {
9721 smb_authType = SMB_AUTH_NTLM;
9722 afsi_log("Reverting to SMB AUTH NTLM");
9731 /* Now get ourselves a domain name. */
9732 /* For now we are using the local computer name as the domain name.
9733 * It is actually the domain for local logins, and we are acting as
9734 * a local SMB server.
9736 bufsize = lengthof(smb_ServerDomainName) - 1;
9737 GetComputerNameW(smb_ServerDomainName, &bufsize);
9738 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9739 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
9742 /* Start listeners, waiters, servers, and daemons */
9744 smb_StartListeners(1);
9746 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9747 NULL, 0, &lpid, "smb_ClientWaiter");
9748 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9749 thrd_CloseHandle(phandle);
9751 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9752 NULL, 0, &lpid, "smb_ServerWaiter");
9753 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9754 thrd_CloseHandle(phandle);
9756 for (i=0; i<smb_NumServerThreads; i++) {
9757 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9758 (void *) i, 0, &lpid, "smb_Server");
9759 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9760 thrd_CloseHandle(phandle);
9763 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9764 NULL, 0, &lpid, "smb_Daemon");
9765 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9766 thrd_CloseHandle(phandle);
9768 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9769 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9770 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9771 thrd_CloseHandle(phandle);
9773 lock_ReleaseMutex(&smb_StartedLock);
9777 void smb_Shutdown(void)
9784 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9786 /* setup the NCB system */
9787 ncbp = smb_GetNCB();
9789 /* Block new sessions by setting shutdown flag */
9790 smbShutdownFlag = 1;
9792 /* Hang up all sessions */
9793 memset((char *)ncbp, 0, sizeof(NCB));
9794 for (i = 1; i < numSessions; i++)
9796 if (dead_sessions[i])
9799 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9800 ncbp->ncb_command = NCBHANGUP;
9801 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9802 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9803 code = Netbios(ncbp);
9804 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9805 if (code == 0) code = ncbp->ncb_retcode;
9807 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9808 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9812 /* Trigger the shutdown of all SMB threads */
9813 for (i = 0; i < smb_NumServerThreads; i++)
9814 thrd_SetEvent(NCBreturns[i][0]);
9816 thrd_SetEvent(NCBevents[0]);
9817 thrd_SetEvent(SessionEvents[0]);
9818 thrd_SetEvent(NCBavails[0]);
9820 for (i = 0;i < smb_NumServerThreads; i++) {
9821 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9822 if (code == WAIT_OBJECT_0) {
9825 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9826 thrd_SetEvent(NCBreturns[i--][0]);
9830 /* Delete Netbios name */
9831 memset((char *)ncbp, 0, sizeof(NCB));
9832 for (i = 0; i < lana_list.length; i++) {
9833 if (lana_list.lana[i] == LANA_INVALID) continue;
9834 ncbp->ncb_command = NCBDELNAME;
9835 ncbp->ncb_lana_num = lana_list.lana[i];
9836 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9837 code = Netbios(ncbp);
9839 code = ncbp->ncb_retcode;
9841 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9842 ncbp->ncb_lana_num, code);
9847 /* Release the reference counts held by the VCs */
9848 lock_ObtainWrite(&smb_rctLock);
9849 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9854 if (vcp->magic != SMB_VC_MAGIC)
9855 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9856 __FILE__, __LINE__);
9858 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9860 if (fidp->scp != NULL) {
9863 lock_ObtainMutex(&fidp->mx);
9864 if (fidp->scp != NULL) {
9867 lock_ObtainWrite(&scp->rw);
9868 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9869 lock_ReleaseWrite(&scp->rw);
9870 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9871 cm_ReleaseSCache(scp);
9873 lock_ReleaseMutex(&fidp->mx);
9877 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9879 smb_ReleaseVCNoLock(tidp->vcp);
9881 cm_user_t *userp = tidp->userp;
9883 cm_ReleaseUser(userp);
9887 lock_ReleaseWrite(&smb_rctLock);
9889 TlsFree(smb_TlsRequestSlot);
9892 /* Get the UNC \\<servername>\<sharename> prefix. */
9893 char *smb_GetSharename()
9898 /* Make sure we have been properly initialized. */
9899 if (smb_localNamep == NULL)
9902 /* Allocate space for \\<servername>\<sharename>, plus the
9905 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
9907 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
9913 void smb_LogPacket(smb_packet_t *packet)
9917 unsigned length, paramlen, datalen, i, j;
9919 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9921 if (!packet) return;
9923 osi_Log0(smb_logp, "*** SMB packet dump ***");
9925 smbp = (smb_t *) packet->data;
9926 vp = (BYTE *) packet->data;
9928 paramlen = smbp->wct * 2;
9929 datalen = *((WORD *) (smbp->vdata + paramlen));
9930 length = sizeof(*smbp) + paramlen + 1 + datalen;
9932 for (i=0;i < length; i+=16)
9934 memset( buf, ' ', 80 );
9939 buf[strlen(buf)] = ' ';
9941 cp = (BYTE*) buf + 7;
9943 for (j=0;j < 16 && (i+j)<length; j++)
9945 *(cp++) = hex[vp[i+j] >> 4];
9946 *(cp++) = hex[vp[i+j] & 0xf];
9956 for (j=0;j < 16 && (i+j)<length;j++)
9958 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9969 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9972 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9974 #endif /* LOG_PACKET */
9977 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9983 smb_username_t *unp;
9984 smb_waitingLockRequest_t *wlrp;
9987 lock_ObtainRead(&smb_rctLock);
9989 sprintf(output, "begin dumping smb_username_t\r\n");
9990 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9991 for (unp = usernamesp; unp; unp=unp->nextp)
9995 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
9996 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
9997 unp->name ? unp->name : _C("NULL"),
9998 unp->machine ? unp->machine : _C("NULL"));
9999 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10001 sprintf(output, " begin dumping cm_ucell_t\r\n");
10002 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10004 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10005 sprintf(output, " %s -- ucellp=0x%p, cellp=0x%p, flags=0x%x, tktLen=%04u, kvno=%03u, expires=%I64u, gen=%d, name=%s, cellname=%s\r\n",
10006 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10007 ucellp->expirationTime, ucellp->gen,
10009 ucellp->cellp->name);
10010 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10013 sprintf(output, " done dumping cm_ucell_t\r\n");
10014 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10017 sprintf(output, "done dumping smb_username_t\r\n");
10018 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10021 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10022 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10025 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10026 smb_waitingLock_t *lockp;
10028 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10029 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10030 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10032 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10033 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10034 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10035 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10036 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10037 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10039 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10040 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10043 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10044 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10046 sprintf(output, "begin dumping smb_vc_t\r\n");
10047 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10049 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10055 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10056 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10057 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10059 sprintf(output, " begin dumping smb_user_t\r\n");
10060 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10061 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10062 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10063 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10064 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10066 sprintf(output, " done dumping smb_user_t\r\n");
10067 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10069 sprintf(output, " begin dumping smb_tid_t\r\n");
10070 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10071 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10072 sprintf(output, " %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
10073 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10074 tidp->pathname ? tidp->pathname : _C("NULL"));
10075 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10077 sprintf(output, " done dumping smb_tid_t\r\n");
10078 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10080 sprintf(output, " begin dumping smb_fid_t\r\n");
10081 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10083 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10085 sprintf(output, " %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
10086 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10087 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10088 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10089 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10092 sprintf(output, " done dumping smb_fid_t\r\n");
10093 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10096 sprintf(output, "done dumping smb_vc_t\r\n");
10097 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10099 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10100 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10102 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10108 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10109 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10110 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10112 sprintf(output, " begin dumping smb_user_t\r\n");
10113 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10114 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10115 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10116 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10117 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10119 sprintf(output, " done dumping smb_user_t\r\n");
10120 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10122 sprintf(output, " begin dumping smb_tid_t\r\n");
10123 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10124 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10125 sprintf(output, " %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
10126 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10127 tidp->pathname ? tidp->pathname : _C("NULL"));
10128 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10130 sprintf(output, " done dumping smb_tid_t\r\n");
10131 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10133 sprintf(output, " begin dumping smb_fid_t\r\n");
10134 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10136 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10138 sprintf(output, " %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
10139 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10140 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10141 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10142 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10145 sprintf(output, " done dumping smb_fid_t\r\n");
10146 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10149 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10150 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10153 lock_ReleaseRead(&smb_rctLock);
10157 long smb_IsNetworkStarted(void)
10160 lock_ObtainWrite(&smb_globalLock);
10161 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10162 lock_ReleaseWrite(&smb_globalLock);