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");
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);
887 LsaFreeReturnBuffer(lsaResp);
890 * This will cause the subsequent authentication to fail but
891 * that is better than us dereferencing a NULL pointer and
894 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
898 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
900 if (numVCs >= CM_SESSION_RESERVED) {
902 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
905 #ifdef DEBUG_SMB_REFCOUNT
907 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
908 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
911 lock_ReleaseWrite(&smb_rctLock);
912 lock_ReleaseWrite(&smb_globalLock);
916 int smb_IsStarMask(clientchar_t *maskp)
921 for(i=0; i<11; i++) {
923 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
929 #ifdef DEBUG_SMB_REFCOUNT
930 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
931 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
933 void smb_ReleaseVCInternal(smb_vc_t *vcp)
939 lock_AssertWrite(&smb_rctLock);
942 if (vcp->refCount == 0) {
943 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
944 #ifdef DEBUG_SMB_REFCOUNT
945 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
946 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
948 /* remove VCP from smb_deadVCsp */
949 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
955 lock_FinalizeMutex(&vcp->mx);
956 memset(vcp,0,sizeof(smb_vc_t));
959 #ifdef DEBUG_SMB_REFCOUNT
960 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
962 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
966 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
967 avcp?"":"not ",vcp, vcp->refCount);
969 /* This is a wrong. However, I suspect that there is an undercount
970 * and I don't want to release 1.4.1 in a state that will allow
971 * smb_vc_t objects to be deallocated while still in the
972 * smb_allVCsp list. The list is supposed to keep a reference
973 * to the smb_vc_t. Put it back.
977 #ifdef DEBUG_SMB_REFCOUNT
978 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
979 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
983 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
984 /* The reference count is non-zero but the VC is dead.
985 * This implies that some FIDs, TIDs, etc on the VC have yet to
986 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
987 * add a reference that will be dropped by
988 * smb_CleanupDeadVC() and try to cleanup the VC again.
989 * Eventually the refCount will drop to zero when all of the
990 * active threads working with the VC end their task.
992 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
993 vcp->refCount++; /* put the refCount back */
994 lock_ReleaseWrite(&smb_rctLock);
995 smb_CleanupDeadVC(vcp);
996 #ifdef DEBUG_SMB_REFCOUNT
997 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
998 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1000 lock_ObtainWrite(&smb_rctLock);
1003 #ifdef DEBUG_SMB_REFCOUNT
1004 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1005 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1010 #ifdef DEBUG_SMB_REFCOUNT
1011 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1013 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1016 lock_AssertWrite(&smb_rctLock);
1017 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1018 smb_ReleaseVCInternal(vcp);
1021 #ifdef DEBUG_SMB_REFCOUNT
1022 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1024 void smb_ReleaseVC(smb_vc_t *vcp)
1027 lock_ObtainWrite(&smb_rctLock);
1028 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1029 smb_ReleaseVCInternal(vcp);
1030 lock_ReleaseWrite(&smb_rctLock);
1033 #ifdef DEBUG_SMB_REFCOUNT
1034 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1036 void smb_HoldVCNoLock(smb_vc_t *vcp)
1039 lock_AssertWrite(&smb_rctLock);
1041 #ifdef DEBUG_SMB_REFCOUNT
1042 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1043 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1045 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1049 #ifdef DEBUG_SMB_REFCOUNT
1050 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1052 void smb_HoldVC(smb_vc_t *vcp)
1055 lock_ObtainWrite(&smb_rctLock);
1057 #ifdef DEBUG_SMB_REFCOUNT
1058 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1059 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1061 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1063 lock_ReleaseWrite(&smb_rctLock);
1066 void smb_CleanupDeadVC(smb_vc_t *vcp)
1068 smb_fid_t *fidpIter;
1069 smb_fid_t *fidpNext;
1071 smb_tid_t *tidpIter;
1072 smb_tid_t *tidpNext;
1074 smb_user_t *uidpIter;
1075 smb_user_t *uidpNext;
1077 afs_uint32 refCount = 0;
1079 lock_ObtainMutex(&vcp->mx);
1080 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1081 lock_ReleaseMutex(&vcp->mx);
1082 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1085 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1086 lock_ReleaseMutex(&vcp->mx);
1087 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1089 lock_ObtainWrite(&smb_rctLock);
1090 /* remove VCP from smb_allVCsp */
1091 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1092 if ((*vcpp)->magic != SMB_VC_MAGIC)
1093 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1094 __FILE__, __LINE__);
1097 vcp->nextp = smb_deadVCsp;
1099 /* Hold onto the reference until we are done with this function */
1104 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1105 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1107 if (fidpIter->deleteOk)
1110 fid = fidpIter->fid;
1111 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1113 smb_HoldFIDNoLock(fidpIter);
1114 lock_ReleaseWrite(&smb_rctLock);
1116 smb_CloseFID(vcp, fidpIter, NULL, 0);
1117 smb_ReleaseFID(fidpIter);
1119 lock_ObtainWrite(&smb_rctLock);
1120 fidpNext = vcp->fidsp;
1123 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1124 tidpNext = tidpIter->nextp;
1125 if (tidpIter->deleteOk)
1127 tidpIter->deleteOk = 1;
1129 tid = tidpIter->tid;
1130 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1132 smb_HoldTIDNoLock(tidpIter);
1133 smb_ReleaseTID(tidpIter, TRUE);
1134 tidpNext = vcp->tidsp;
1137 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1138 uidpNext = uidpIter->nextp;
1139 if (uidpIter->deleteOk)
1141 uidpIter->deleteOk = 1;
1143 /* do not add an additional reference count for the smb_user_t
1144 * as the smb_vc_t already is holding a reference */
1145 lock_ReleaseWrite(&smb_rctLock);
1147 smb_ReleaseUID(uidpIter);
1149 lock_ObtainWrite(&smb_rctLock);
1150 uidpNext = vcp->usersp;
1153 /* The vcp is now on the deadVCsp list. We intentionally drop the
1154 * reference so that the refcount can reach 0 and we can delete it
1156 * If the refCount == 1 going into the ReleaseVCNoLock call
1157 * the object will be freed and it won't be safe to clear
1160 refCount = vcp->refCount;
1161 smb_ReleaseVCNoLock(vcp);
1163 lock_ObtainMutex(&vcp->mx);
1164 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1165 lock_ReleaseMutex(&vcp->mx);
1168 lock_ReleaseWrite(&smb_rctLock);
1169 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1172 #ifdef DEBUG_SMB_REFCOUNT
1173 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1175 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1180 lock_ObtainWrite(&smb_rctLock);
1182 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1183 if (tidp->refCount == 0 && tidp->deleteOk) {
1185 smb_ReleaseTID(tidp, TRUE);
1189 if (tid == tidp->tid) {
1194 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1195 tidp = malloc(sizeof(*tidp));
1196 memset(tidp, 0, sizeof(*tidp));
1197 tidp->nextp = vcp->tidsp;
1200 smb_HoldVCNoLock(vcp);
1202 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1205 #ifdef DEBUG_SMB_REFCOUNT
1207 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1208 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1211 lock_ReleaseWrite(&smb_rctLock);
1215 #ifdef DEBUG_SMB_REFCOUNT
1216 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1218 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1221 lock_AssertWrite(&smb_rctLock);
1223 #ifdef DEBUG_SMB_REFCOUNT
1224 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1225 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1229 #ifdef DEBUG_SMB_REFCOUNT
1230 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1232 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1237 cm_user_t *userp = NULL;
1238 smb_vc_t *vcp = NULL;
1241 lock_ObtainWrite(&smb_rctLock);
1243 lock_AssertWrite(&smb_rctLock);
1245 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1246 #ifdef DEBUG_SMB_REFCOUNT
1247 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1248 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1250 if (tidp->refCount == 0) {
1251 if (tidp->deleteOk) {
1252 ltpp = &tidp->vcp->tidsp;
1253 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1257 osi_assertx(tp != NULL, "null smb_tid_t");
1259 lock_FinalizeMutex(&tidp->mx);
1260 userp = tidp->userp; /* remember to drop ref later */
1268 lock_ReleaseWrite(&smb_rctLock);
1270 cm_ReleaseUser(userp);
1272 smb_ReleaseVCNoLock(vcp);
1275 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1277 smb_user_t *uidp = NULL;
1279 lock_ObtainWrite(&smb_rctLock);
1280 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1281 if (uid == uidp->userID) {
1283 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1285 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1289 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1290 uidp = malloc(sizeof(*uidp));
1291 memset(uidp, 0, sizeof(*uidp));
1292 uidp->nextp = vcp->usersp;
1293 uidp->refCount = 2; /* one for the vcp and one for the caller */
1295 smb_HoldVCNoLock(vcp);
1297 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1299 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1301 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1303 lock_ReleaseWrite(&smb_rctLock);
1307 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1310 smb_username_t *unp= NULL;
1312 lock_ObtainWrite(&smb_rctLock);
1313 for(unp = usernamesp; unp; unp = unp->nextp) {
1314 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1315 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1320 if (!unp && (flags & SMB_FLAG_CREATE)) {
1321 unp = malloc(sizeof(*unp));
1322 memset(unp, 0, sizeof(*unp));
1324 unp->nextp = usernamesp;
1325 unp->name = cm_ClientStrDup(usern);
1326 unp->machine = cm_ClientStrDup(machine);
1328 lock_InitializeMutex(&unp->mx, "username_t mutex");
1329 if (flags & SMB_FLAG_AFSLOGON)
1330 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1333 lock_ReleaseWrite(&smb_rctLock);
1337 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1339 smb_user_t *uidp= NULL;
1341 lock_ObtainWrite(&smb_rctLock);
1342 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1345 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1347 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1348 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1353 lock_ReleaseWrite(&smb_rctLock);
1357 void smb_ReleaseUsername(smb_username_t *unp)
1360 smb_username_t **lupp;
1361 cm_user_t *userp = NULL;
1362 time_t now = osi_Time();
1364 lock_ObtainWrite(&smb_rctLock);
1365 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1366 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1367 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1369 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1373 osi_assertx(up != NULL, "null smb_username_t");
1375 up->nextp = NULL; /* do not remove this */
1376 lock_FinalizeMutex(&unp->mx);
1382 lock_ReleaseWrite(&smb_rctLock);
1384 cm_ReleaseUser(userp);
1387 void smb_HoldUIDNoLock(smb_user_t *uidp)
1389 lock_AssertWrite(&smb_rctLock);
1393 void smb_ReleaseUID(smb_user_t *uidp)
1397 smb_username_t *unp = NULL;
1399 lock_ObtainWrite(&smb_rctLock);
1400 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1401 if (uidp->refCount == 0) {
1402 lupp = &uidp->vcp->usersp;
1403 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1407 osi_assertx(up != NULL, "null smb_user_t");
1409 lock_FinalizeMutex(&uidp->mx);
1411 smb_ReleaseVCNoLock(uidp->vcp);
1415 lock_ReleaseWrite(&smb_rctLock);
1419 cm_ReleaseUserVCRef(unp->userp);
1420 smb_ReleaseUsername(unp);
1424 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1426 cm_user_t *up = NULL;
1431 lock_ObtainMutex(&uidp->mx);
1433 up = uidp->unp->userp;
1436 lock_ReleaseMutex(&uidp->mx);
1442 /* retrieve a held reference to a user structure corresponding to an incoming
1444 * corresponding release function is cm_ReleaseUser.
1446 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1449 cm_user_t *up = NULL;
1452 smbp = (smb_t *) inp;
1453 uidp = smb_FindUID(vcp, smbp->uid, 0);
1457 up = smb_GetUserFromUID(uidp);
1459 smb_ReleaseUID(uidp);
1464 * Return a pointer to a pathname extracted from a TID structure. The
1465 * TID structure is not held; assume it won't go away.
1467 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1472 tidp = smb_FindTID(vcp, tid, 0);
1476 if (tidp->flags & SMB_TIDFLAG_IPC) {
1477 code = CM_ERROR_TIDIPC;
1478 /* tidp->pathname would be NULL, but that's fine */
1480 *treepath = tidp->pathname;
1481 smb_ReleaseTID(tidp, FALSE);
1486 /* check to see if we have a chained fid, that is, a fid that comes from an
1487 * OpenAndX message that ran earlier in this packet. In this case, the fid
1488 * field in a read, for example, request, isn't set, since the value is
1489 * supposed to be inherited from the openAndX call.
1491 int smb_ChainFID(int fid, smb_packet_t *inp)
1493 if (inp->fid == 0 || inp->inCount == 0)
1499 /* are we a priv'd user? What does this mean on NT? */
1500 int smb_SUser(cm_user_t *userp)
1505 /* find a file ID. If we pass in 0 we select an unused File ID.
1506 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1507 * smb_fid_t data structure if desired File ID cannot be found.
1509 #ifdef DEBUG_SMB_REFCOUNT
1510 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1512 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1518 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1521 lock_ObtainWrite(&smb_rctLock);
1522 /* figure out if we need to allocate a new file ID */
1525 fid = vcp->fidCounter;
1529 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1530 if (fidp->refCount == 0 && fidp->deleteOk) {
1532 lock_ReleaseWrite(&smb_rctLock);
1533 smb_ReleaseFID(fidp);
1534 lock_ObtainWrite(&smb_rctLock);
1537 if (fid == fidp->fid) {
1540 if (fid == 0xFFFF) {
1542 "New FID number wraps on vcp 0x%x", vcp);
1552 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1553 char eventName[MAX_PATH];
1555 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1556 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1557 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1558 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1559 thrd_CloseHandle(event);
1561 if (fid == 0xFFFF) {
1562 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1568 fidp = malloc(sizeof(*fidp));
1569 memset(fidp, 0, sizeof(*fidp));
1570 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1573 smb_HoldVCNoLock(vcp);
1574 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1576 fidp->curr_chunk = fidp->prev_chunk = -2;
1577 fidp->raw_write_event = event;
1579 vcp->fidCounter = fid+1;
1580 if (vcp->fidCounter == 0xFFFF) {
1581 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1583 vcp->fidCounter = 1;
1588 #ifdef DEBUG_SMB_REFCOUNT
1590 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1591 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1594 lock_ReleaseWrite(&smb_rctLock);
1598 #ifdef DEBUG_SMB_REFCOUNT
1599 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1601 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1604 smb_fid_t *fidp = NULL;
1610 lock_ObtainWrite(&smb_rctLock);
1611 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1612 if (scp == fidp->scp) {
1617 #ifdef DEBUG_SMB_REFCOUNT
1619 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1620 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1623 lock_ReleaseWrite(&smb_rctLock);
1627 #ifdef DEBUG_SMB_REFCOUNT
1628 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1630 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1633 lock_AssertWrite(&smb_rctLock);
1635 #ifdef DEBUG_SMB_REFCOUNT
1636 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1637 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1642 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1643 /* the sm_fid_t->mx and smb_rctLock must not be held */
1644 #ifdef DEBUG_SMB_REFCOUNT
1645 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1647 void smb_ReleaseFID(smb_fid_t *fidp)
1650 cm_scache_t *scp = NULL;
1651 cm_user_t *userp = NULL;
1652 smb_vc_t *vcp = NULL;
1653 smb_ioctl_t *ioctlp;
1655 lock_ObtainMutex(&fidp->mx);
1656 lock_ObtainWrite(&smb_rctLock);
1657 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1658 #ifdef DEBUG_SMB_REFCOUNT
1659 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1660 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1662 if (fidp->refCount == 0) {
1663 if (fidp->deleteOk) {
1666 scp = fidp->scp; /* release after lock is released */
1668 lock_ObtainWrite(&scp->rw);
1669 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1670 lock_ReleaseWrite(&scp->rw);
1671 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1674 userp = fidp->userp;
1678 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1679 thrd_CloseHandle(fidp->raw_write_event);
1681 /* and see if there is ioctl stuff to free */
1682 ioctlp = fidp->ioctlp;
1685 cm_FreeSpace(ioctlp->prefix);
1686 if (ioctlp->ioctl.inAllocp)
1687 free(ioctlp->ioctl.inAllocp);
1688 if (ioctlp->ioctl.outAllocp)
1689 free(ioctlp->ioctl.outAllocp);
1692 lock_ReleaseMutex(&fidp->mx);
1693 lock_FinalizeMutex(&fidp->mx);
1697 smb_ReleaseVCNoLock(vcp);
1699 lock_ReleaseMutex(&fidp->mx);
1702 lock_ReleaseWrite(&smb_rctLock);
1704 /* now release the scache structure */
1706 cm_ReleaseSCache(scp);
1709 cm_ReleaseUser(userp);
1713 * Case-insensitive search for one string in another;
1714 * used to find variable names in submount pathnames.
1716 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1718 clientchar_t *cursor;
1720 for (cursor = str1; *cursor; cursor++)
1721 if (cm_ClientStrCmpI(cursor, str2) == 0)
1728 * Substitute a variable value for its name in a submount pathname. Variable
1729 * name has been identified by smb_stristr() and is in substr. Variable name
1730 * length (plus one) is in substr_size. Variable value is in newstr.
1732 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1733 unsigned int substr_size, clientchar_t *newstr)
1735 clientchar_t temp[1024];
1737 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1738 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1739 cm_ClientStrCat(str1, cchstr1, temp);
1742 clientchar_t VNUserName[] = _C("%USERNAME%");
1743 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1744 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1745 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1747 typedef struct smb_findShare_rock {
1748 clientchar_t * shareName;
1749 clientchar_t * match;
1751 } smb_findShare_rock_t;
1753 #define SMB_FINDSHARE_EXACT_MATCH 1
1754 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1756 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1760 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1761 normchar_t normName[MAX_PATH];
1763 cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
1765 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1766 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1767 matchType = SMB_FINDSHARE_EXACT_MATCH;
1769 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1770 if(vrock->match) free(vrock->match);
1771 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1772 vrock->matchType = matchType;
1774 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1775 return CM_ERROR_STOPNOW;
1781 /* find a shareName in the table of submounts */
1782 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1783 clientchar_t *shareName,
1784 clientchar_t **pathNamep)
1788 clientchar_t pathName[1024];
1791 clientchar_t *p, *q;
1792 fschar_t *cellname = NULL;
1795 DWORD allSubmount = 1;
1797 /* if allSubmounts == 0, only return the //mountRoot/all share
1798 * if in fact it has been been created in the subMounts table.
1799 * This is to allow sites that want to restrict access to the
1802 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1803 0, KEY_QUERY_VALUE, &parmKey);
1804 if (code == ERROR_SUCCESS) {
1805 cblen = sizeof(allSubmount);
1806 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1807 (BYTE *) &allSubmount, &cblen);
1808 if (code != ERROR_SUCCESS) {
1811 RegCloseKey (parmKey);
1814 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1819 /* In case, the all share is disabled we need to still be able
1820 * to handle ioctl requests
1822 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1823 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1827 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1828 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1829 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1830 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1831 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1837 /* Check for volume references
1839 * They look like <cell>{%,#}<volume>
1841 if (cm_ClientStrChr(shareName, '%') != NULL ||
1842 cm_ClientStrChr(shareName, '#') != NULL) {
1843 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1844 /* make room for '/@vol:' + mountchar + NULL terminator*/
1846 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1847 osi_LogSaveClientString(smb_logp, shareName));
1849 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1850 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1851 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1853 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1855 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1856 cm_ClientStrLwr(*pathNamep);
1857 osi_Log1(smb_logp, " returning pathname [%S]",
1858 osi_LogSaveClientString(smb_logp, *pathNamep));
1866 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1867 0, KEY_QUERY_VALUE, &parmKey);
1868 if (code == ERROR_SUCCESS) {
1869 cblen = sizeof(pathName);
1870 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1871 (BYTE *) pathName, &cblen);
1872 if (code != ERROR_SUCCESS)
1874 RegCloseKey (parmKey);
1878 cchlen = cblen / sizeof(clientchar_t);
1879 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1880 /* We can accept either unix or PC style AFS pathnames. Convert
1881 * Unix-style to PC style here for internal use.
1884 cchlen = lengthof(pathName);
1886 /* within this code block, we maintain, cchlen = writeable
1887 buffer length of p */
1889 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1890 p += cm_mountRootCLen; /* skip mount path */
1891 cchlen -= (DWORD)(p - pathName);
1896 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1902 clientchar_t temp[1024];
1904 if (var = smb_stristr(p, VNUserName)) {
1905 if (uidp && uidp->unp)
1906 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1908 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1910 else if (var = smb_stristr(p, VNLCUserName))
1912 if (uidp && uidp->unp)
1913 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1915 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1916 cm_ClientStrLwr(temp);
1917 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1919 else if (var = smb_stristr(p, VNComputerName))
1921 sizeTemp = lengthof(temp);
1922 GetComputerNameW(temp, &sizeTemp);
1923 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1925 else if (var = smb_stristr(p, VNLCComputerName))
1927 sizeTemp = lengthof(temp);
1928 GetComputerName((LPTSTR)temp, &sizeTemp);
1929 cm_ClientStrLwr(temp);
1930 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1935 *pathNamep = cm_ClientStrDup(p);
1940 /* First lookup shareName in root.afs */
1942 smb_findShare_rock_t vrock;
1944 fschar_t ftemp[1024];
1945 clientchar_t * p = shareName;
1948 /* attempt to locate a partial match in root.afs. This is because
1949 when using the ANSI RAP calls, the share name is limited to 13 chars
1950 and hence is truncated. Of course we prefer exact matches. */
1952 thyper.HighPart = 0;
1955 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1957 vrock.matchType = 0;
1959 cm_HoldSCache(cm_data.rootSCachep);
1960 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1961 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1962 cm_ReleaseSCache(cm_data.rootSCachep);
1964 free(vrock.shareName);
1965 vrock.shareName = NULL;
1967 if (vrock.matchType) {
1968 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1969 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1974 /* if we get here, there was no match for the share in root.afs */
1975 /* so try to create \\<netbiosName>\<cellname> */
1980 /* Get the full name for this cell */
1981 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1982 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1983 #ifdef AFS_AFSDB_ENV
1984 if (code && cm_dnsEnabled) {
1986 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1992 /* construct the path */
1994 clientchar_t temp[1024];
1996 cm_FsStringToClientString(ftemp, (int)cm_FsStrLen(ftemp), temp, 1024);
1997 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1998 rw ? _C("/.%S/") : _C("/%S/"), temp);
1999 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2008 /* Client-side offline caching policy types */
2009 #define CSC_POLICY_MANUAL 0
2010 #define CSC_POLICY_DOCUMENTS 1
2011 #define CSC_POLICY_PROGRAMS 2
2012 #define CSC_POLICY_DISABLE 3
2014 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2017 clientchar_t policy[1024];
2020 int retval = CSC_POLICY_MANUAL;
2022 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2023 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2026 REG_OPTION_NON_VOLATILE,
2032 len = sizeof(policy);
2033 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2035 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2037 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2039 retval = CSC_POLICY_DOCUMENTS;
2041 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2043 retval = CSC_POLICY_PROGRAMS;
2045 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2047 retval = CSC_POLICY_DISABLE;
2050 RegCloseKey(hkCSCPolicy);
2054 /* find a dir search structure by cookie value, and return it held.
2055 * Must be called with smb_globalLock held.
2057 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2059 smb_dirSearch_t *dsp;
2061 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2062 if (dsp->cookie == cookie) {
2063 if (dsp != smb_firstDirSearchp) {
2064 /* move to head of LRU queue, too, if we're not already there */
2065 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2066 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2067 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2068 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2069 if (!smb_lastDirSearchp)
2070 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2072 lock_ObtainMutex(&dsp->mx);
2074 lock_ReleaseMutex(&dsp->mx);
2080 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2081 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2082 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2088 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2090 lock_ObtainWrite(&smb_globalLock);
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);
2105 lock_ReleaseWrite(&smb_globalLock);
2108 /* Must be called with the smb_globalLock held */
2109 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2111 cm_scache_t *scp = NULL;
2113 lock_ObtainMutex(&dsp->mx);
2114 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2115 if (dsp->refCount == 0 && (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);
2128 /* do this now to avoid spurious locking hierarchy creation */
2130 cm_ReleaseSCache(scp);
2133 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2135 lock_ObtainWrite(&smb_globalLock);
2136 smb_ReleaseDirSearchNoLock(dsp);
2137 lock_ReleaseWrite(&smb_globalLock);
2140 /* find a dir search structure by cookie value, and return it held */
2141 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2143 smb_dirSearch_t *dsp;
2145 lock_ObtainWrite(&smb_globalLock);
2146 dsp = smb_FindDirSearchNoLock(cookie);
2147 lock_ReleaseWrite(&smb_globalLock);
2151 /* GC some dir search entries, in the address space expected by the specific protocol.
2152 * Must be called with smb_globalLock held; release the lock temporarily.
2154 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2155 void smb_GCDirSearches(int isV3)
2157 smb_dirSearch_t *prevp;
2158 smb_dirSearch_t *tp;
2159 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2163 victimCount = 0; /* how many have we got so far */
2164 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
2165 /* we'll move tp from queue, so
2168 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
2169 /* if no one is using this guy, and we're either in the new protocol,
2170 * or we're in the old one and this is a small enough ID to be useful
2171 * to the old protocol, GC this guy.
2173 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2174 /* hold and delete */
2175 lock_ObtainMutex(&tp->mx);
2176 tp->flags |= SMB_DIRSEARCH_DELETE;
2177 lock_ReleaseMutex(&tp->mx);
2178 victimsp[victimCount++] = tp;
2182 /* don't do more than this */
2183 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2187 /* now release them */
2188 for (i = 0; i < victimCount; i++) {
2189 smb_ReleaseDirSearchNoLock(victimsp[i]);
2193 /* function for allocating a dir search entry. We need these to remember enough context
2194 * since we don't get passed the path from call to call during a directory search.
2196 * Returns a held dir search structure, and bumps the reference count on the vnode,
2197 * since it saves a pointer to the vnode.
2199 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2201 smb_dirSearch_t *dsp;
2207 lock_ObtainWrite(&smb_globalLock);
2210 /* what's the biggest ID allowed in this version of the protocol */
2211 /* TODO: do we really want a non v3 dir search request to wrap
2212 smb_dirSearchCounter? */
2213 maxAllowed = isV3 ? 65535 : 255;
2214 if (smb_dirSearchCounter > maxAllowed)
2215 smb_dirSearchCounter = 1;
2217 start = smb_dirSearchCounter;
2220 /* twice so we have enough tries to find guys we GC after one pass;
2221 * 10 extra is just in case I mis-counted.
2223 if (++counter > 2*maxAllowed+10)
2224 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2226 if (smb_dirSearchCounter > maxAllowed) {
2227 smb_dirSearchCounter = 1;
2229 if (smb_dirSearchCounter == start) {
2231 smb_GCDirSearches(isV3);
2234 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2236 /* don't need to watch for refcount zero and deleted, since
2237 * we haven't dropped the global lock.
2239 lock_ObtainMutex(&dsp->mx);
2241 lock_ReleaseMutex(&dsp->mx);
2242 ++smb_dirSearchCounter;
2246 dsp = malloc(sizeof(*dsp));
2247 memset(dsp, 0, sizeof(*dsp));
2248 dsp->cookie = smb_dirSearchCounter;
2249 ++smb_dirSearchCounter;
2251 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2252 dsp->lastTime = osi_Time();
2253 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2254 if (!smb_lastDirSearchp)
2255 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2257 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2261 lock_ReleaseWrite(&smb_globalLock);
2265 static smb_packet_t *smb_GetPacket(void)
2269 lock_ObtainWrite(&smb_globalLock);
2270 tbp = smb_packetFreeListp;
2272 smb_packetFreeListp = tbp->nextp;
2273 lock_ReleaseWrite(&smb_globalLock);
2275 tbp = calloc(sizeof(*tbp),1);
2276 tbp->magic = SMB_PACKETMAGIC;
2279 tbp->resumeCode = 0;
2285 tbp->ncb_length = 0;
2288 tbp->stringsp = NULL;
2290 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2295 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2298 tbp = smb_GetPacket();
2299 memcpy(tbp, pkt, sizeof(smb_packet_t));
2300 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2301 tbp->stringsp = NULL;
2303 smb_HoldVC(tbp->vcp);
2307 static NCB *smb_GetNCB(void)
2312 lock_ObtainWrite(&smb_globalLock);
2313 tbp = smb_ncbFreeListp;
2315 smb_ncbFreeListp = tbp->nextp;
2316 lock_ReleaseWrite(&smb_globalLock);
2318 tbp = calloc(sizeof(*tbp),1);
2319 tbp->magic = SMB_NCBMAGIC;
2322 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2324 memset(&tbp->ncb, 0, sizeof(NCB));
2329 static void FreeSMBStrings(smb_packet_t * pkt)
2334 for (s = pkt->stringsp; s; s = ns) {
2338 pkt->stringsp = NULL;
2341 void smb_FreePacket(smb_packet_t *tbp)
2343 smb_vc_t * vcp = NULL;
2344 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2346 lock_ObtainWrite(&smb_globalLock);
2347 tbp->nextp = smb_packetFreeListp;
2348 smb_packetFreeListp = tbp;
2349 tbp->magic = SMB_PACKETMAGIC;
2353 tbp->resumeCode = 0;
2359 tbp->ncb_length = 0;
2361 FreeSMBStrings(tbp);
2362 lock_ReleaseWrite(&smb_globalLock);
2368 static void smb_FreeNCB(NCB *bufferp)
2372 tbp = (smb_ncb_t *) bufferp;
2373 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2375 lock_ObtainWrite(&smb_globalLock);
2376 tbp->nextp = smb_ncbFreeListp;
2377 smb_ncbFreeListp = tbp;
2378 lock_ReleaseWrite(&smb_globalLock);
2381 /* get a ptr to the data part of a packet, and its count */
2382 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2386 unsigned char *afterParmsp;
2388 parmBytes = *smbp->wctp << 1;
2389 afterParmsp = smbp->wctp + parmBytes + 1;
2391 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2392 if (nbytesp) *nbytesp = dataBytes;
2394 /* don't forget to skip the data byte count, since it follows
2395 * the parameters; that's where the "2" comes from below.
2397 return (unsigned char *) (afterParmsp + 2);
2400 /* must set all the returned parameters before playing around with the
2401 * data region, since the data region is located past the end of the
2402 * variable number of parameters.
2404 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2406 unsigned char *afterParmsp;
2408 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2410 *afterParmsp++ = dsize & 0xff;
2411 *afterParmsp = (dsize>>8) & 0xff;
2414 /* return the parm'th parameter in the smbp packet */
2415 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2418 unsigned char *parmDatap;
2420 parmCount = *smbp->wctp;
2422 if (parm >= parmCount) {
2425 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2426 parm, parmCount, smbp->ncb_length);
2427 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2428 parm, parmCount, smbp->ncb_length);
2429 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2430 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2431 osi_panic(s, __FILE__, __LINE__);
2433 parmDatap = smbp->wctp + (2*parm) + 1;
2435 return parmDatap[0] + (parmDatap[1] << 8);
2438 /* return the parm'th parameter in the smbp packet */
2439 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2442 unsigned char *parmDatap;
2444 parmCount = *smbp->wctp;
2446 if (parm >= parmCount) {
2449 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2450 parm, parmCount, smbp->ncb_length);
2451 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2452 parm, parmCount, smbp->ncb_length);
2453 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2454 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2455 osi_panic(s, __FILE__, __LINE__);
2457 parmDatap = smbp->wctp + (2*parm) + 1;
2459 return parmDatap[0];
2462 /* return the parm'th parameter in the smbp packet */
2463 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2466 unsigned char *parmDatap;
2468 parmCount = *smbp->wctp;
2470 if (parm + 1 >= parmCount) {
2473 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2474 parm, parmCount, smbp->ncb_length);
2475 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2476 parm, parmCount, smbp->ncb_length);
2477 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2478 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2479 osi_panic(s, __FILE__, __LINE__);
2481 parmDatap = smbp->wctp + (2*parm) + 1;
2483 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2486 /* return the parm'th parameter in the smbp packet */
2487 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2490 unsigned char *parmDatap;
2492 parmCount = *smbp->wctp;
2494 if (parm * 2 + offset >= parmCount * 2) {
2497 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2498 parm, offset, parmCount, smbp->ncb_length);
2499 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2500 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2501 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2502 parm, offset, parmCount, smbp->ncb_length);
2503 osi_panic(s, __FILE__, __LINE__);
2505 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2507 return parmDatap[0] + (parmDatap[1] << 8);
2510 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2512 unsigned char *parmDatap;
2514 /* make sure we have enough slots */
2515 if (*smbp->wctp <= slot)
2516 *smbp->wctp = slot+1;
2518 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2519 *parmDatap++ = parmValue & 0xff;
2520 *parmDatap = (parmValue>>8) & 0xff;
2523 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2525 unsigned char *parmDatap;
2527 /* make sure we have enough slots */
2528 if (*smbp->wctp <= slot)
2529 *smbp->wctp = slot+2;
2531 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2532 *parmDatap++ = parmValue & 0xff;
2533 *parmDatap++ = (parmValue>>8) & 0xff;
2534 *parmDatap++ = (parmValue>>16) & 0xff;
2535 *parmDatap = (parmValue>>24) & 0xff;
2538 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2540 unsigned char *parmDatap;
2543 /* make sure we have enough slots */
2544 if (*smbp->wctp <= slot)
2545 *smbp->wctp = slot+4;
2547 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2549 *parmDatap++ = *parmValuep++;
2552 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2554 unsigned char *parmDatap;
2556 /* make sure we have enough slots */
2557 if (*smbp->wctp <= slot) {
2558 if (smbp->oddByte) {
2560 *smbp->wctp = slot+1;
2565 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2566 *parmDatap++ = parmValue & 0xff;
2571 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2572 clientchar_t *inPathp)
2574 clientchar_t *lastSlashp;
2576 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2578 *lastComponentp = lastSlashp;
2581 if (inPathp == lastSlashp)
2583 *outPathp++ = *inPathp++;
2592 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2593 char **chainpp, int flags)
2601 if (!WANTS_UNICODE(pktp))
2602 flags |= SMB_STRF_FORCEASCII;
2605 cb = sizeof(pktp->data) - (inp - pktp->data);
2606 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2607 #ifdef DEBUG_UNICODE
2610 cb = sizeof(pktp->data);
2612 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2615 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2616 char ** chainpp, int flags)
2621 if (!WANTS_UNICODE(pktp))
2622 flags |= SMB_STRF_FORCEASCII;
2625 cb = sizeof(pktp->data) - (inp - pktp->data);
2626 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2627 #ifdef DEBUG_UNICODE
2630 cb = sizeof(pktp->data);
2632 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
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)*pcb_max, spacep->wdata, cchdest);
2730 return spacep->wdata;
2736 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2738 size_t * plen, int flags)
2744 /* we are only calculating the required size */
2751 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2753 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2754 if (!(flags & SMB_STRF_IGNORENULL))
2755 *plen += sizeof(wchar_t);
2757 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2767 cch_str = cm_ClientStrLen(str);
2768 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2771 *plen = ((flags & SMB_STRF_IGNORENULL)? cch_dest: cch_dest+1);
2779 /* if outp != NULL ... */
2781 /* Number of bytes left in the buffer.
2783 If outp lies inside the packet data buffer, we assume that the
2784 buffer is the packet data buffer. Otherwise we assume that the
2785 buffer is sizeof(packet->data).
2788 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2789 align = (int)((outp - pktp->data) % 2);
2790 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2792 align = (int)(((size_t) outp) % 2);
2793 buffersize = (int)sizeof(pktp->data);
2798 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2804 if (*str == _C('\0')) {
2806 if (buffersize < sizeof(wchar_t))
2809 *((wchar_t *) outp) = L'\0';
2810 if (plen && !(flags & SMB_STRF_IGNORENULL))
2811 *plen += sizeof(wchar_t);
2812 return outp + sizeof(wchar_t);
2815 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2817 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2818 osi_LogSaveClientString(smb_logp, str),
2824 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1: nchars);
2826 return outp + sizeof(wchar_t) * nchars;
2834 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2837 *plen += ((flags & SMB_STRF_IGNORENULL)? cch_dest - 1: cch_dest);
2839 return outp + cch_dest;
2843 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2849 tlen = inp[0] + (inp[1]<<8);
2850 inp += 2; /* skip length field */
2853 *chainpp = inp + tlen;
2862 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2866 if (*inp++ != 0x1) return NULL;
2867 tlen = inp[0] + (inp[1]<<8);
2868 inp += 2; /* skip length field */
2871 *chainpp = inp + tlen;
2874 if (lengthp) *lengthp = tlen;
2879 /* format a packet as a response */
2880 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2885 outp = (smb_t *) op;
2887 /* zero the basic structure through the smb_wct field, and zero the data
2888 * size field, assuming that wct stays zero; otherwise, you have to
2889 * explicitly set the data size field, too.
2891 inSmbp = (smb_t *) inp;
2892 memset(outp, 0, sizeof(smb_t)+2);
2898 outp->com = inSmbp->com;
2899 outp->tid = inSmbp->tid;
2900 outp->pid = inSmbp->pid;
2901 outp->uid = inSmbp->uid;
2902 outp->mid = inSmbp->mid;
2903 outp->res[0] = inSmbp->res[0];
2904 outp->res[1] = inSmbp->res[1];
2905 op->inCom = inSmbp->com;
2907 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2908 #ifdef SEND_CANONICAL_PATHNAMES
2909 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2911 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2913 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2914 outp->flg2 |= SMB_FLAGS2_UNICODE;
2917 /* copy fields in generic packet area */
2918 op->wctp = &outp->wct;
2921 /* send a (probably response) packet; vcp tells us to whom to send it.
2922 * we compute the length by looking at wct and bcc fields.
2924 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2934 ncbp = smb_GetNCB();
2938 memset((char *)ncbp, 0, sizeof(NCB));
2940 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2941 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2942 extra += tp[0] + (tp[1]<<8);
2943 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2944 extra += 3; /* wct and length fields */
2946 ncbp->ncb_length = extra; /* bytes to send */
2947 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2948 ncbp->ncb_lana_num = vcp->lana;
2949 ncbp->ncb_command = NCBSEND; /* op means send data */
2950 ncbp->ncb_buffer = (char *) inp;/* packet */
2951 code = Netbios(ncbp);
2954 const char * s = ncb_error_string(code);
2955 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2956 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2958 lock_ObtainMutex(&vcp->mx);
2959 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2960 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2962 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2963 lock_ReleaseMutex(&vcp->mx);
2964 lock_ObtainWrite(&smb_globalLock);
2965 dead_sessions[vcp->session] = TRUE;
2966 lock_ReleaseWrite(&smb_globalLock);
2967 smb_CleanupDeadVC(vcp);
2969 lock_ReleaseMutex(&vcp->mx);
2977 void smb_MapNTError(long code, unsigned long *NTStatusp)
2979 unsigned long NTStatus;
2981 /* map CM_ERROR_* errors to NT 32-bit status codes */
2982 /* NT Status codes are listed in ntstatus.h not winerror.h */
2983 if (code == CM_ERROR_NOSUCHCELL) {
2984 NTStatus = 0xC000000FL; /* No such file */
2986 else if (code == CM_ERROR_NOSUCHVOLUME) {
2987 NTStatus = 0xC000000FL; /* No such file */
2989 else if (code == CM_ERROR_TIMEDOUT) {
2991 NTStatus = 0xC00000CFL; /* Sharing Paused */
2993 NTStatus = 0x00000102L; /* Timeout */
2996 else if (code == CM_ERROR_RETRY) {
2997 NTStatus = 0xC000022DL; /* Retry */
2999 else if (code == CM_ERROR_NOACCESS) {
3000 NTStatus = 0xC0000022L; /* Access denied */
3002 else if (code == CM_ERROR_READONLY) {
3003 NTStatus = 0xC00000A2L; /* Write protected */
3005 else if (code == CM_ERROR_NOSUCHFILE ||
3006 code == CM_ERROR_BPLUS_NOMATCH) {
3007 NTStatus = 0xC000000FL; /* No such file */
3009 else if (code == CM_ERROR_NOSUCHPATH) {
3010 NTStatus = 0xC000003AL; /* Object path not found */
3012 else if (code == CM_ERROR_TOOBIG) {
3013 NTStatus = 0xC000007BL; /* Invalid image format */
3015 else if (code == CM_ERROR_INVAL) {
3016 NTStatus = 0xC000000DL; /* Invalid parameter */
3018 else if (code == CM_ERROR_BADFD) {
3019 NTStatus = 0xC0000008L; /* Invalid handle */
3021 else if (code == CM_ERROR_BADFDOP) {
3022 NTStatus = 0xC0000022L; /* Access denied */
3024 else if (code == CM_ERROR_EXISTS) {
3025 NTStatus = 0xC0000035L; /* Object name collision */
3027 else if (code == CM_ERROR_NOTEMPTY) {
3028 NTStatus = 0xC0000101L; /* Directory not empty */
3030 else if (code == CM_ERROR_CROSSDEVLINK) {
3031 NTStatus = 0xC00000D4L; /* Not same device */
3033 else if (code == CM_ERROR_NOTDIR) {
3034 NTStatus = 0xC0000103L; /* Not a directory */
3036 else if (code == CM_ERROR_ISDIR) {
3037 NTStatus = 0xC00000BAL; /* File is a directory */
3039 else if (code == CM_ERROR_BADOP) {
3041 /* I have no idea where this comes from */
3042 NTStatus = 0xC09820FFL; /* SMB no support */
3044 NTStatus = 0xC00000BBL; /* Not supported */
3045 #endif /* COMMENT */
3047 else if (code == CM_ERROR_BADSHARENAME) {
3048 NTStatus = 0xC00000CCL; /* Bad network name */
3050 else if (code == CM_ERROR_NOIPC) {
3052 NTStatus = 0xC0000022L; /* Access Denied */
3054 NTStatus = 0xC000013DL; /* Remote Resources */
3057 else if (code == CM_ERROR_CLOCKSKEW) {
3058 NTStatus = 0xC0000133L; /* Time difference at DC */
3060 else if (code == CM_ERROR_BADTID) {
3061 NTStatus = 0xC0982005L; /* SMB bad TID */
3063 else if (code == CM_ERROR_USESTD) {
3064 NTStatus = 0xC09820FBL; /* SMB use standard */
3066 else if (code == CM_ERROR_QUOTA) {
3067 NTStatus = 0xC0000044L; /* Quota exceeded */
3069 else if (code == CM_ERROR_SPACE) {
3070 NTStatus = 0xC000007FL; /* Disk full */
3072 else if (code == CM_ERROR_ATSYS) {
3073 NTStatus = 0xC0000033L; /* Object name invalid */
3075 else if (code == CM_ERROR_BADNTFILENAME) {
3076 NTStatus = 0xC0000033L; /* Object name invalid */
3078 else if (code == CM_ERROR_WOULDBLOCK) {
3079 NTStatus = 0xC0000055L; /* Lock not granted */
3081 else if (code == CM_ERROR_SHARING_VIOLATION) {
3082 NTStatus = 0xC0000043L; /* Sharing violation */
3084 else if (code == CM_ERROR_LOCK_CONFLICT) {
3085 NTStatus = 0xC0000054L; /* Lock conflict */
3087 else if (code == CM_ERROR_PARTIALWRITE) {
3088 NTStatus = 0xC000007FL; /* Disk full */
3090 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3091 NTStatus = 0xC0000023L; /* Buffer too small */
3093 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3094 NTStatus = 0xC0000035L; /* Object name collision */
3096 else if (code == CM_ERROR_BADPASSWORD) {
3097 NTStatus = 0xC000006DL; /* unknown username or bad password */
3099 else if (code == CM_ERROR_BADLOGONTYPE) {
3100 NTStatus = 0xC000015BL; /* logon type not granted */
3102 else if (code == CM_ERROR_GSSCONTINUE) {
3103 NTStatus = 0xC0000016L; /* more processing required */
3105 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3107 NTStatus = 0xC0000280L; /* reparse point not resolved */
3109 NTStatus = 0xC0000022L; /* Access Denied */
3112 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3113 NTStatus = 0xC0000257L; /* Path Not Covered */
3115 else if (code == CM_ERROR_ALLBUSY) {
3116 NTStatus = 0xC000022DL; /* Retry */
3118 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3119 NTStatus = 0xC00000BEL; /* Bad Network Path */
3121 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3122 NTStatus = 0xC0000322L; /* No Kerberos key */
3124 else if (code == CM_ERROR_BAD_LEVEL) {
3125 NTStatus = 0xC0000148L; /* Invalid Level */
3127 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3128 NTStatus = 0xC000007EL; /* Range Not Locked */
3130 else if (code == CM_ERROR_NOSUCHDEVICE) {
3131 NTStatus = 0xC000000EL; /* No Such Device */
3133 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3134 NTStatus = 0xC0000055L; /* Lock Not Granted */
3136 NTStatus = 0xC0982001L; /* SMB non-specific error */
3139 *NTStatusp = NTStatus;
3140 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3143 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3144 unsigned char *classp)
3146 unsigned char class;
3147 unsigned short error;
3149 /* map CM_ERROR_* errors to SMB errors */
3150 if (code == CM_ERROR_NOSUCHCELL) {
3152 error = 3; /* bad path */
3154 else if (code == CM_ERROR_NOSUCHVOLUME) {
3156 error = 3; /* bad path */
3158 else if (code == CM_ERROR_TIMEDOUT) {
3160 error = 81; /* server is paused */
3162 else if (code == CM_ERROR_RETRY) {
3163 class = 2; /* shouldn't happen */
3166 else if (code == CM_ERROR_NOACCESS) {
3168 error = 4; /* bad access */
3170 else if (code == CM_ERROR_READONLY) {
3172 error = 19; /* read only */
3174 else if (code == CM_ERROR_NOSUCHFILE ||
3175 code == CM_ERROR_BPLUS_NOMATCH) {
3177 error = 2; /* ENOENT! */
3179 else if (code == CM_ERROR_NOSUCHPATH) {
3181 error = 3; /* Bad path */
3183 else if (code == CM_ERROR_TOOBIG) {
3185 error = 11; /* bad format */
3187 else if (code == CM_ERROR_INVAL) {
3188 class = 2; /* server non-specific error code */
3191 else if (code == CM_ERROR_BADFD) {
3193 error = 6; /* invalid file handle */
3195 else if (code == CM_ERROR_BADFDOP) {
3196 class = 1; /* invalid op on FD */
3199 else if (code == CM_ERROR_EXISTS) {
3201 error = 80; /* file already exists */
3203 else if (code == CM_ERROR_NOTEMPTY) {
3205 error = 5; /* delete directory not empty */
3207 else if (code == CM_ERROR_CROSSDEVLINK) {
3209 error = 17; /* EXDEV */
3211 else if (code == CM_ERROR_NOTDIR) {
3212 class = 1; /* bad path */
3215 else if (code == CM_ERROR_ISDIR) {
3216 class = 1; /* access denied; DOS doesn't have a good match */
3219 else if (code == CM_ERROR_BADOP) {
3223 else if (code == CM_ERROR_BADSHARENAME) {
3227 else if (code == CM_ERROR_NOIPC) {
3229 error = 4; /* bad access */
3231 else if (code == CM_ERROR_CLOCKSKEW) {
3232 class = 1; /* invalid function */
3235 else if (code == CM_ERROR_BADTID) {
3239 else if (code == CM_ERROR_USESTD) {
3243 else if (code == CM_ERROR_REMOTECONN) {
3247 else if (code == CM_ERROR_QUOTA) {
3248 if (vcp->flags & SMB_VCFLAG_USEV3) {
3250 error = 39; /* disk full */
3254 error = 5; /* access denied */
3257 else if (code == CM_ERROR_SPACE) {
3258 if (vcp->flags & SMB_VCFLAG_USEV3) {
3260 error = 39; /* disk full */
3264 error = 5; /* access denied */
3267 else if (code == CM_ERROR_PARTIALWRITE) {
3269 error = 39; /* disk full */
3271 else if (code == CM_ERROR_ATSYS) {
3273 error = 2; /* ENOENT */
3275 else if (code == CM_ERROR_WOULDBLOCK) {
3277 error = 33; /* lock conflict */
3279 else if (code == CM_ERROR_LOCK_CONFLICT) {
3281 error = 33; /* lock conflict */
3283 else if (code == CM_ERROR_SHARING_VIOLATION) {
3285 error = 33; /* lock conflict */
3287 else if (code == CM_ERROR_NOFILES) {
3289 error = 18; /* no files in search */
3291 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3293 error = 183; /* Samba uses this */
3295 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3296 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3298 error = 2; /* bad password */
3300 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3302 error = 3; /* bad path */
3311 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3314 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3316 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3317 return CM_ERROR_BADOP;
3321 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3323 unsigned short EchoCount, i;
3324 char *data, *outdata;
3327 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3329 for (i=1; i<=EchoCount; i++) {
3330 data = smb_GetSMBData(inp, &dataSize);
3331 smb_SetSMBParm(outp, 0, i);
3332 smb_SetSMBDataLength(outp, dataSize);
3333 outdata = smb_GetSMBData(outp, NULL);
3334 memcpy(outdata, data, dataSize);
3335 smb_SendPacket(vcp, outp);
3341 /* SMB_COM_READ_RAW */
3342 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3345 long count, minCount, finalCount;
3349 smb_t *smbp = (smb_t*) inp;
3351 cm_user_t *userp = NULL;
3354 char *rawBuf = NULL;
3359 fd = smb_GetSMBParm(inp, 0);
3360 count = smb_GetSMBParm(inp, 3);
3361 minCount = smb_GetSMBParm(inp, 4);
3362 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3364 if (*inp->wctp == 10) {
3365 /* we were sent a request with 64-bit file offsets */
3366 #ifdef AFS_LARGEFILES
3367 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3369 if (LargeIntegerLessThanZero(offset)) {
3370 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3374 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3375 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3378 offset.HighPart = 0;
3382 /* we were sent a request with 32-bit file offsets */
3383 offset.HighPart = 0;
3386 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3387 fd, offset.HighPart, offset.LowPart, count);
3389 fidp = smb_FindFID(vcp, fd, 0);
3393 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3394 smb_CloseFID(vcp, fidp, NULL, 0);
3395 code = CM_ERROR_NOSUCHFILE;
3402 LARGE_INTEGER LOffset, LLength;
3405 key = cm_GenerateKey(vcp->vcID, pid, fd);
3407 LOffset.HighPart = offset.HighPart;
3408 LOffset.LowPart = offset.LowPart;
3409 LLength.HighPart = 0;
3410 LLength.LowPart = count;
3412 lock_ObtainWrite(&fidp->scp->rw);
3413 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3414 lock_ReleaseWrite(&fidp->scp->rw);
3420 lock_ObtainMutex(&smb_RawBufLock);
3422 /* Get a raw buf, from head of list */
3423 rawBuf = smb_RawBufs;
3424 smb_RawBufs = *(char **)smb_RawBufs;
3426 lock_ReleaseMutex(&smb_RawBufLock);
3430 lock_ObtainMutex(&fidp->mx);
3431 if (fidp->flags & SMB_FID_IOCTL)
3433 lock_ReleaseMutex(&fidp->mx);
3434 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3436 /* Give back raw buffer */
3437 lock_ObtainMutex(&smb_RawBufLock);
3438 *((char **) rawBuf) = smb_RawBufs;
3440 smb_RawBufs = rawBuf;
3441 lock_ReleaseMutex(&smb_RawBufLock);
3444 lock_ReleaseMutex(&fidp->mx);
3445 smb_ReleaseFID(fidp);
3448 lock_ReleaseMutex(&fidp->mx);
3450 userp = smb_GetUserFromVCP(vcp, inp);
3452 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3458 cm_ReleaseUser(userp);
3461 smb_ReleaseFID(fidp);
3465 memset((char *)ncbp, 0, sizeof(NCB));
3467 ncbp->ncb_length = (unsigned short) finalCount;
3468 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3469 ncbp->ncb_lana_num = vcp->lana;
3470 ncbp->ncb_command = NCBSEND;
3471 ncbp->ncb_buffer = rawBuf;
3473 code = Netbios(ncbp);
3475 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3478 /* Give back raw buffer */
3479 lock_ObtainMutex(&smb_RawBufLock);
3480 *((char **) rawBuf) = smb_RawBufs;
3482 smb_RawBufs = rawBuf;
3483 lock_ReleaseMutex(&smb_RawBufLock);
3489 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3491 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3496 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3498 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3503 /* SMB_COM_NEGOTIATE */
3504 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3511 int VistaProtoIndex;
3512 int protoIndex; /* index we're using */
3517 char protocol_array[10][1024]; /* protocol signature of the client */
3518 int caps; /* capabilities */
3521 TIME_ZONE_INFORMATION tzi;
3523 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3526 namep = smb_GetSMBData(inp, &dbytes);
3529 coreProtoIndex = -1; /* not found */
3532 VistaProtoIndex = -1;
3533 while(namex < dbytes) {
3534 osi_Log1(smb_logp, "Protocol %s",
3535 osi_LogSaveString(smb_logp, namep+1));
3536 strcpy(protocol_array[tcounter], namep+1);
3538 /* namep points at the first protocol, or really, a 0x02
3539 * byte preceding the null-terminated ASCII name.
3541 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3542 coreProtoIndex = tcounter;
3544 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3545 v3ProtoIndex = tcounter;
3547 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3548 NTProtoIndex = tcounter;
3550 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3551 VistaProtoIndex = tcounter;
3554 /* compute size of protocol entry */
3555 entryLength = (int)strlen(namep+1);
3556 entryLength += 2; /* 0x02 bytes and null termination */
3558 /* advance over this protocol entry */
3559 namex += entryLength;
3560 namep += entryLength;
3561 tcounter++; /* which proto entry we're looking at */
3564 lock_ObtainMutex(&vcp->mx);
3566 if (VistaProtoIndex != -1) {
3567 protoIndex = VistaProtoIndex;
3568 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3571 if (NTProtoIndex != -1) {
3572 protoIndex = NTProtoIndex;
3573 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3575 else if (v3ProtoIndex != -1) {
3576 protoIndex = v3ProtoIndex;
3577 vcp->flags |= SMB_VCFLAG_USEV3;
3579 else if (coreProtoIndex != -1) {
3580 protoIndex = coreProtoIndex;
3581 vcp->flags |= SMB_VCFLAG_USECORE;
3583 else protoIndex = -1;
3584 lock_ReleaseMutex(&vcp->mx);
3586 if (protoIndex == -1)
3587 return CM_ERROR_INVAL;
3588 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3589 smb_SetSMBParm(outp, 0, protoIndex);
3590 if (smb_authType != SMB_AUTH_NONE) {
3591 smb_SetSMBParmByte(outp, 1,
3592 NEGOTIATE_SECURITY_USER_LEVEL |
3593 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3595 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3597 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3598 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3599 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3600 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3601 /* The session key is not a well documented field however most clients
3602 * will echo back the session key to the server. Currently we are using
3603 * the same value for all sessions. We should generate a random value
3604 * and store it into the vcp
3606 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3607 smb_SetSMBParm(outp, 8, 1);
3609 * Tried changing the capabilities to support for W2K - defect 117695
3610 * Maybe something else needs to be changed here?
3614 smb_SetSMBParmLong(outp, 9, 0x43fd);
3616 smb_SetSMBParmLong(outp, 9, 0x251);
3619 * 32-bit error codes *
3625 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3627 NTNEGOTIATE_CAPABILITY_DFS |
3629 #ifdef AFS_LARGEFILES
3630 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3632 NTNEGOTIATE_CAPABILITY_NTFIND |
3633 NTNEGOTIATE_CAPABILITY_RAWMODE |
3634 NTNEGOTIATE_CAPABILITY_NTSMB;
3636 if ( smb_authType == SMB_AUTH_EXTENDED )
3637 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3640 if ( smb_UseUnicode ) {
3641 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3645 smb_SetSMBParmLong(outp, 9, caps);
3647 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3648 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3649 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3651 GetTimeZoneInformation(&tzi);
3652 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3654 if (smb_authType == SMB_AUTH_NTLM) {
3655 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3656 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3657 /* paste in encryption key */
3658 datap = smb_GetSMBData(outp, NULL);
3659 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3660 /* and the faux domain name */
3661 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3662 datap + MSV1_0_CHALLENGE_LENGTH,
3663 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3664 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3668 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3670 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3672 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3674 datap = smb_GetSMBData(outp, NULL);
3675 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3678 datap += sizeof(smb_ServerGUID);
3679 memcpy(datap, secBlob, secBlobLength);
3683 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3684 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3687 else if (v3ProtoIndex != -1) {
3688 smb_SetSMBParm(outp, 0, protoIndex);
3690 /* NOTE: Extended authentication cannot be negotiated with v3
3691 * therefore we fail over to NTLM
3693 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3694 smb_SetSMBParm(outp, 1,
3695 NEGOTIATE_SECURITY_USER_LEVEL |
3696 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3698 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3700 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3701 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3702 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3703 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3704 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3705 smb_SetSMBParm(outp, 7, 1);
3707 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3708 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3709 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3711 GetTimeZoneInformation(&tzi);
3712 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3714 /* NOTE: Extended authentication cannot be negotiated with v3
3715 * therefore we fail over to NTLM
3717 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3718 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3719 smb_SetSMBParm(outp, 12, 0); /* resvd */
3720 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3721 datap = smb_GetSMBData(outp, NULL);
3722 /* paste in a new encryption key */
3723 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3724 /* and the faux domain name */
3725 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3726 datap + MSV1_0_CHALLENGE_LENGTH,
3727 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3729 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3730 smb_SetSMBParm(outp, 12, 0); /* resvd */
3731 smb_SetSMBDataLength(outp, 0);
3734 else if (coreProtoIndex != -1) { /* not really supported anymore */
3735 smb_SetSMBParm(outp, 0, protoIndex);
3736 smb_SetSMBDataLength(outp, 0);
3741 void smb_CheckVCs(void)
3743 smb_vc_t * vcp, *nextp;
3744 smb_packet_t * outp = smb_GetPacket();
3747 lock_ObtainWrite(&smb_rctLock);
3748 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3750 if (vcp->magic != SMB_VC_MAGIC)
3751 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3752 __FILE__, __LINE__);
3756 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3759 smb_HoldVCNoLock(vcp);
3761 smb_HoldVCNoLock(nextp);
3762 smb_FormatResponsePacket(vcp, NULL, outp);
3763 smbp = (smb_t *)outp;
3764 outp->inCom = smbp->com = 0x2b /* Echo */;
3772 smb_SetSMBParm(outp, 0, 0);
3773 smb_SetSMBDataLength(outp, 0);
3774 lock_ReleaseWrite(&smb_rctLock);
3776 smb_SendPacket(vcp, outp);
3778 lock_ObtainWrite(&smb_rctLock);
3779 smb_ReleaseVCNoLock(vcp);
3781 smb_ReleaseVCNoLock(nextp);
3783 lock_ReleaseWrite(&smb_rctLock);
3784 smb_FreePacket(outp);
3787 void smb_Daemon(void *parmp)
3789 afs_uint32 count = 0;
3790 smb_username_t **unpp;
3793 while(smbShutdownFlag == 0) {
3797 if (smbShutdownFlag == 1)
3800 if ((count % 72) == 0) { /* every five minutes */
3802 time_t old_localZero = smb_localZero;
3804 /* Initialize smb_localZero */
3805 myTime.tm_isdst = -1; /* compute whether on DST or not */
3806 myTime.tm_year = 70;
3812 smb_localZero = mktime(&myTime);
3814 #ifndef USE_NUMERIC_TIME_CONV
3815 smb_CalculateNowTZ();
3816 #endif /* USE_NUMERIC_TIME_CONV */
3817 #ifdef AFS_FREELANCE
3818 if ( smb_localZero != old_localZero )
3819 cm_noteLocalMountPointChange();
3825 /* GC smb_username_t objects that will no longer be used */
3827 lock_ObtainWrite(&smb_rctLock);
3828 for ( unpp=&usernamesp; *unpp; ) {
3830 smb_username_t *unp;
3832 lock_ObtainMutex(&(*unpp)->mx);
3833 if ( (*unpp)->refCount > 0 ||
3834 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3835 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3837 else if (!smb_LogoffTokenTransfer ||
3838 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3840 lock_ReleaseMutex(&(*unpp)->mx);
3848 lock_FinalizeMutex(&unp->mx);
3854 cm_ReleaseUser(userp);
3856 unpp = &(*unpp)->nextp;
3859 lock_ReleaseWrite(&smb_rctLock);
3861 /* XXX GC dir search entries */
3865 void smb_WaitingLocksDaemon()
3867 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3868 smb_waitingLock_t *wl, *wlNext;
3871 smb_packet_t *inp, *outp;
3875 while (smbShutdownFlag == 0) {
3876 lock_ObtainWrite(&smb_globalLock);
3877 nwlRequest = smb_allWaitingLocks;
3878 if (nwlRequest == NULL) {
3879 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3884 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3891 lock_ObtainWrite(&smb_globalLock);
3893 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3895 wlRequest = nwlRequest;
3896 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3897 lock_ReleaseWrite(&smb_globalLock);
3901 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3902 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3905 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3906 code = CM_ERROR_LOCK_NOT_GRANTED;
3910 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3912 /* wl->state is either _DONE or _WAITING. _ERROR
3913 would no longer be on the queue. */
3914 code = cm_RetryLock( wl->lockp,
3915 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3918 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3919 } else if (code != CM_ERROR_WOULDBLOCK) {
3920 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3925 if (code == CM_ERROR_WOULDBLOCK) {
3928 if (wlRequest->msTimeout != 0xffffffff
3929 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3941 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3944 scp = wlRequest->scp;
3945 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3949 lock_ObtainWrite(&scp->rw);
3951 for (wl = wlRequest->locks; wl; wl = wlNext) {
3952 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3954 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3955 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3956 wl->LLength, wl->key, NULL, &req);
3958 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3963 lock_ReleaseWrite(&scp->rw);
3967 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3970 for (wl = wlRequest->locks; wl; wl = wlNext) {
3971 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3972 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3977 vcp = wlRequest->vcp;
3978 inp = wlRequest->inp;
3979 outp = wlRequest->outp;
3980 ncbp = smb_GetNCB();
3981 ncbp->ncb_length = inp->ncb_length;
3982 inp->spacep = cm_GetSpace();
3984 /* Remove waitingLock from list */
3985 lock_ObtainWrite(&smb_globalLock);
3986 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3988 lock_ReleaseWrite(&smb_globalLock);
3990 /* Resume packet processing */
3992 smb_SetSMBDataLength(outp, 0);
3993 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3994 outp->resumeCode = code;
3996 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3999 cm_FreeSpace(inp->spacep);
4000 smb_FreePacket(inp);
4001 smb_FreePacket(outp);
4003 cm_ReleaseSCache(wlRequest->scp);
4006 } while (nwlRequest && smbShutdownFlag == 0);
4011 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4013 osi_Log0(smb_logp, "SMB receive get disk attributes");
4015 smb_SetSMBParm(outp, 0, 32000);
4016 smb_SetSMBParm(outp, 1, 64);
4017 smb_SetSMBParm(outp, 2, 1024);
4018 smb_SetSMBParm(outp, 3, 30000);
4019 smb_SetSMBParm(outp, 4, 0);
4020 smb_SetSMBDataLength(outp, 0);
4024 /* SMB_COM_TREE_CONNECT */
4025 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4029 unsigned short newTid;
4030 clientchar_t shareName[AFSPATHMAX];
4031 clientchar_t *sharePath;
4034 clientchar_t *pathp;
4037 osi_Log0(smb_logp, "SMB receive tree connect");
4039 /* parse input parameters */
4042 tbp = smb_GetSMBData(inp, NULL);
4043 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4045 tp = cm_ClientStrRChr(pathp, '\\');
4047 return CM_ERROR_BADSMB;
4048 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4050 lock_ObtainMutex(&vcp->mx);
4051 newTid = vcp->tidCounter++;
4052 lock_ReleaseMutex(&vcp->mx);
4054 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4055 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4056 userp = smb_GetUserFromUID(uidp);
4057 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4059 smb_ReleaseUID(uidp);
4061 smb_ReleaseTID(tidp, FALSE);
4062 return CM_ERROR_BADSHARENAME;
4064 lock_ObtainMutex(&tidp->mx);
4065 tidp->userp = userp;
4066 tidp->pathname = sharePath;
4067 lock_ReleaseMutex(&tidp->mx);
4068 smb_ReleaseTID(tidp, FALSE);
4070 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4071 smb_SetSMBParm(rsp, 1, newTid);
4072 smb_SetSMBDataLength(rsp, 0);
4074 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4078 /* set maskp to the mask part of the incoming path.
4079 * Mask is 11 bytes long (8.3 with the dot elided).
4080 * Returns true if succeeds with a valid name, otherwise it does
4081 * its best, but returns false.
4083 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4091 /* starts off valid */
4094 /* mask starts out all blanks */
4095 memset(maskp, ' ', 11);
4098 /* find last backslash, or use whole thing if there is none */
4099 tp = cm_ClientStrRChr(pathp, '\\');
4103 tp++; /* skip slash */
4107 /* names starting with a dot are illegal */
4115 if (tc == '.' || tc == '"')
4123 /* if we get here, tp point after the dot */
4124 up = maskp+8; /* ext goes here */
4131 if (tc == '.' || tc == '"')
4134 /* copy extension if not too long */
4144 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4146 clientchar_t umask[11];
4154 /* XXX redo this, calling cm_MatchMask with a converted mask */
4156 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4160 /* otherwise, we have a valid 8.3 name; see if we have a match,
4161 * treating '?' as a wildcard in maskp (but not in the file name).
4163 tp1 = umask; /* real name, in mask format */
4164 tp2 = maskp; /* mask, in mask format */
4165 for(i=0; i<11; i++) {
4166 tc1 = *tp1++; /* clientchar_t from real name */
4167 tc2 = *tp2++; /* clientchar_t from mask */
4168 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4169 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4172 if (tc2 == '?' && tc1 != ' ')
4179 /* we got a match */
4183 clientchar_t *smb_FindMask(clientchar_t *pathp)
4187 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4190 return tp+1; /* skip the slash */
4192 return pathp; /* no slash, return the entire path */
4195 /* SMB_COM_SEARCH for a volume label
4197 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4198 dispatch function.) */
4199 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4201 clientchar_t *pathp;
4203 clientchar_t mask[12];
4204 unsigned char *statBlockp;
4205 unsigned char initStatBlock[21];
4208 osi_Log0(smb_logp, "SMB receive search volume");
4210 /* pull pathname and stat block out of request */
4211 tp = smb_GetSMBData(inp, NULL);
4212 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4213 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4214 osi_assertx(pathp != NULL, "null path");
4215 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4216 osi_assertx(statBlockp != NULL, "null statBlock");
4218 statBlockp = initStatBlock;
4222 /* for returning to caller */
4223 smb_Get8Dot3MaskFromPath(mask, pathp);
4225 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4226 tp = smb_GetSMBData(outp, NULL);
4228 *tp++ = 43; /* bytes in a dir entry */
4229 *tp++ = 0; /* high byte in counter */
4231 /* now marshall the dir entry, starting with the search status */
4232 *tp++ = statBlockp[0]; /* Reserved */
4233 memcpy(tp, mask, 11); tp += 11; /* FileName */
4235 /* now pass back server use info, with 1st byte non-zero */
4237 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4239 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4241 *tp++ = 0x8; /* attribute: volume */
4251 /* 4 byte file size */
4257 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4260 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4261 memset(tp, ' ', 13);
4264 /* set the length of the data part of the packet to 43 + 3, for the dir
4265 * entry plus the 5 and the length fields.
4267 smb_SetSMBDataLength(outp, 46);
4272 smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
4273 clientchar_t * tidPathp, clientchar_t * relPathp,
4274 cm_user_t *userp, cm_req_t *reqp)
4282 smb_dirListPatch_t *patchp;
4283 smb_dirListPatch_t *npatchp;
4284 clientchar_t path[AFSPATHMAX];
4286 for (patchp = *dirPatchespp; patchp; patchp =
4287 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4289 dptr = patchp->dptr;
4291 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4292 relPathp ? relPathp : _C(""), patchp->dep->name);
4293 reqp->relPathp = path;
4294 reqp->tidPathp = tidPathp;
4296 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4297 reqp->relPathp = reqp->tidPathp = NULL;
4300 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4301 *dptr++ = SMB_ATTR_HIDDEN;
4304 lock_ObtainWrite(&scp->rw);
4305 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
4306 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4308 lock_ReleaseWrite(&scp->rw);
4309 cm_ReleaseSCache(scp);
4310 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4311 *dptr++ = SMB_ATTR_HIDDEN;
4315 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4317 lock_ConvertWToR(&scp->rw);
4318 attr = smb_Attributes(scp);
4319 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4320 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4321 attr |= SMB_ATTR_HIDDEN;
4325 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4328 shortTemp = (unsigned short) (dosTime & 0xffff);
4329 *((u_short *)dptr) = shortTemp;
4332 /* and copy out date */
4333 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4334 *((u_short *)dptr) = shortTemp;
4337 /* copy out file length */
4338 *((u_long *)dptr) = scp->length.LowPart;
4340 lock_ReleaseRead(&scp->rw);
4341 cm_ReleaseSCache(scp);
4344 /* now free the patches */
4345 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4346 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4350 /* and mark the list as empty */
4351 *dirPatchespp = NULL;
4356 /* SMB_COM_SEARCH */
4357 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4363 clientchar_t *pathp;
4364 cm_dirEntry_t *dep = 0;
4366 smb_dirListPatch_t *dirListPatchesp;
4367 smb_dirListPatch_t *curPatchp;
4371 osi_hyper_t dirLength;
4372 osi_hyper_t bufferOffset;
4373 osi_hyper_t curOffset;
4375 unsigned char *inCookiep;
4376 smb_dirSearch_t *dsp;
4380 unsigned long clientCookie;
4381 cm_pageHeader_t *pageHeaderp;
4382 cm_user_t *userp = NULL;
4384 clientchar_t mask[12];
4386 long nextEntryCookie;
4387 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4388 char resByte; /* reserved byte from the cookie */
4389 char *op; /* output data ptr */
4390 char *origOp; /* original value of op */
4391 cm_space_t *spacep; /* for pathname buffer */
4395 clientchar_t *tidPathp = 0;
4402 maxCount = smb_GetSMBParm(inp, 0);
4404 dirListPatchesp = NULL;
4406 caseFold = CM_FLAG_CASEFOLD;
4408 tp = smb_GetSMBData(inp, NULL);
4409 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4410 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4411 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4413 /* bail out if request looks bad */
4414 if (!tp || !pathp) {
4415 return CM_ERROR_BADSMB;
4418 /* We can handle long names */
4419 if (vcp->flags & SMB_VCFLAG_USENT)
4420 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4422 /* make sure we got a whole search status */
4423 if (dataLength < 21) {
4424 nextCookie = 0; /* start at the beginning of the dir */
4427 attribute = smb_GetSMBParm(inp, 1);
4429 /* handle volume info in another function */
4430 if (attribute & 0x8)
4431 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4433 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4434 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4436 if (*pathp == 0) { /* null pathp, treat as root dir */
4437 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4438 return CM_ERROR_NOFILES;
4442 dsp = smb_NewDirSearch(0);
4443 dsp->attribute = attribute;
4444 smb_Get8Dot3MaskFromPath(mask, pathp);
4445 memcpy(dsp->mask, mask, 12);
4447 /* track if this is likely to match a lot of entries */
4448 if (smb_IsStarMask(mask))
4453 /* pull the next cookie value out of the search status block */
4454 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4455 + (inCookiep[16]<<24);
4456 dsp = smb_FindDirSearch(inCookiep[12]);
4458 /* can't find dir search status; fatal error */
4459 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4460 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4461 return CM_ERROR_BADFD;
4463 attribute = dsp->attribute;
4464 resByte = inCookiep[0];
4466 /* copy out client cookie, in host byte order. Don't bother
4467 * interpreting it, since we're just passing it through, anyway.
4469 memcpy(&clientCookie, &inCookiep[17], 4);
4471 memcpy(mask, dsp->mask, 12);
4473 /* assume we're doing a star match if it has continued for more
4479 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4480 nextCookie, dsp->cookie, attribute);
4482 userp = smb_GetUserFromVCP(vcp, inp);
4484 /* try to get the vnode for the path name next */
4485 lock_ObtainMutex(&dsp->mx);
4488 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4492 spacep = inp->spacep;
4493 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4494 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4496 lock_ReleaseMutex(&dsp->mx);
4497 cm_ReleaseUser(userp);
4498 smb_DeleteDirSearch(dsp);
4499 smb_ReleaseDirSearch(dsp);
4500 return CM_ERROR_NOFILES;
4502 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4503 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4505 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4506 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4509 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4512 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4513 cm_ReleaseSCache(scp);
4514 lock_ReleaseMutex(&dsp->mx);
4515 cm_ReleaseUser(userp);
4516 smb_DeleteDirSearch(dsp);
4517 smb_ReleaseDirSearch(dsp);
4518 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4519 return CM_ERROR_PATH_NOT_COVERED;
4521 return CM_ERROR_BADSHARENAME;
4523 #endif /* DFS_SUPPORT */
4526 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4527 /* we need one hold for the entry we just stored into,
4528 * and one for our own processing. When we're done with this
4529 * function, we'll drop the one for our own processing.
4530 * We held it once from the namei call, and so we do another hold
4534 lock_ObtainWrite(&scp->rw);
4535 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4536 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4537 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4538 dsp->flags |= SMB_DIRSEARCH_BULKST;
4539 dsp->scp->bulkStatProgress = hzero;
4541 lock_ReleaseWrite(&scp->rw);
4544 lock_ReleaseMutex(&dsp->mx);
4546 cm_ReleaseUser(userp);
4547 smb_DeleteDirSearch(dsp);
4548 smb_ReleaseDirSearch(dsp);
4552 /* reserves space for parameter; we'll adjust it again later to the
4553 * real count of the # of entries we returned once we've actually
4554 * assembled the directory listing.
4556 smb_SetSMBParm(outp, 0, 0);
4558 /* get the directory size */
4559 lock_ObtainWrite(&scp->rw);
4560 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4561 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4563 lock_ReleaseWrite(&scp->rw);
4564 cm_ReleaseSCache(scp);
4565 cm_ReleaseUser(userp);
4566 smb_DeleteDirSearch(dsp);
4567 smb_ReleaseDirSearch(dsp);
4571 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4573 dirLength = scp->length;
4575 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4576 curOffset.HighPart = 0;
4577 curOffset.LowPart = nextCookie;
4578 origOp = op = smb_GetSMBData(outp, NULL);
4579 /* and write out the basic header */
4580 *op++ = 5; /* variable block */
4581 op += 2; /* skip vbl block length; we'll fill it in later */
4585 clientchar_t *actualName;
4586 clientchar_t shortName[13];
4587 clientchar_t *shortNameEnd;
4589 /* make sure that curOffset.LowPart doesn't point to the first
4590 * 32 bytes in the 2nd through last dir page, and that it doesn't
4591 * point at the first 13 32-byte chunks in the first dir page,
4592 * since those are dir and page headers, and don't contain useful
4595 temp = curOffset.LowPart & (2048-1);
4596 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4597 /* we're in the first page */
4598 if (temp < 13*32) temp = 13*32;
4601 /* we're in a later dir page */
4602 if (temp < 32) temp = 32;
4605 /* make sure the low order 5 bits are zero */
4608 /* now put temp bits back ito curOffset.LowPart */
4609 curOffset.LowPart &= ~(2048-1);
4610 curOffset.LowPart |= temp;
4612 /* check if we've returned all the names that will fit in the
4615 if (returnedNames >= maxCount) {
4616 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4617 returnedNames, maxCount);
4621 /* check if we've passed the dir's EOF */
4622 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4624 /* see if we can use the bufferp we have now; compute in which page
4625 * the current offset would be, and check whether that's the offset
4626 * of the buffer we have. If not, get the buffer.
4628 thyper.HighPart = curOffset.HighPart;
4629 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4630 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4633 buf_Release(bufferp);
4636 lock_ReleaseWrite(&scp->rw);
4637 code = buf_Get(scp, &thyper, &bufferp);
4638 lock_ObtainMutex(&dsp->mx);
4640 /* now, if we're doing a star match, do bulk fetching of all of
4641 * the status info for files in the dir.
4644 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4645 lock_ObtainWrite(&scp->rw);
4646 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4647 LargeIntegerGreaterThanOrEqualTo(thyper,
4648 scp->bulkStatProgress)) {
4649 /* Don't bulk stat if risking timeout */
4650 int now = GetTickCount();
4651 if (now - req.startTime > RDRtimeout * 1000) {
4652 scp->bulkStatProgress = thyper;
4653 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4654 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4655 dsp->scp->bulkStatProgress = hzero;
4657 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4660 lock_ObtainWrite(&scp->rw);
4662 lock_ReleaseMutex(&dsp->mx);
4664 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4668 bufferOffset = thyper;
4670 /* now get the data in the cache */
4672 code = cm_SyncOp(scp, bufferp, userp, &req,
4674 CM_SCACHESYNC_NEEDCALLBACK |
4675 CM_SCACHESYNC_READ);
4677 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4681 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4683 if (cm_HaveBuffer(scp, bufferp, 0)) {
4684 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4688 /* otherwise, load the buffer and try again */
4689 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4691 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4692 scp, bufferp, code);
4697 buf_Release(bufferp);
4701 } /* if (wrong buffer) ... */
4703 /* now we have the buffer containing the entry we're interested in; copy
4704 * it out if it represents a non-deleted entry.
4706 entryInDir = curOffset.LowPart & (2048-1);
4707 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4709 /* page header will help tell us which entries are free. Page header
4710 * can change more often than once per buffer, since AFS 3 dir page size
4711 * may be less than (but not more than a buffer package buffer.
4713 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4714 temp &= ~(2048 - 1); /* turn off intra-page bits */
4715 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4717 /* now determine which entry we're looking at in the page. If it is
4718 * free (there's a free bitmap at the start of the dir), we should
4719 * skip these 32 bytes.
4721 slotInPage = (entryInDir & 0x7e0) >> 5;
4722 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4723 /* this entry is free */
4724 numDirChunks = 1; /* only skip this guy */
4728 tp = bufferp->datap + entryInBuffer;
4729 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4731 /* while we're here, compute the next entry's location, too,
4732 * since we'll need it when writing out the cookie into the dir
4735 * XXXX Probably should do more sanity checking.
4737 numDirChunks = cm_NameEntries(dep->name, NULL);
4739 /* compute the offset of the cookie representing the next entry */
4740 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4742 /* Compute 8.3 name if necessary */
4743 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4744 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4746 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4747 actualName = shortName;
4750 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
4751 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4752 osi_LogSaveClientString(smb_logp, actualName));
4754 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4755 /* this is one of the entries to use: it is not deleted
4756 * and it matches the star pattern we're looking for.
4759 /* Eliminate entries that don't match requested
4762 /* no hidden files */
4763 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4764 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4768 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4770 /* We have already done the cm_TryBulkStat above */
4771 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4772 fileType = cm_FindFileType(&fid);
4773 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4774 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4776 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4777 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4778 fileType == CM_SCACHETYPE_DFSLINK ||
4779 fileType == CM_SCACHETYPE_INVALID)
4780 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4785 memcpy(op, mask, 11); op += 11;
4786 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
4787 *op++ = (unsigned char)(nextEntryCookie & 0xff);
4788 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
4789 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
4790 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
4791 memcpy(op, &clientCookie, 4); op += 4;
4793 /* now we emit the attribute. This is sort of tricky,
4794 * since we need to really stat the file to find out
4795 * what type of entry we've got. Right now, we're
4796 * copying out data from a buffer, while holding the
4797 * scp locked, so it isn't really convenient to stat
4798 * something now. We'll put in a place holder now,
4799 * and make a second pass before returning this to get
4800 * the real attributes. So, we just skip the data for
4801 * now, and adjust it later. We allocate a patch
4802 * record to make it easy to find this point later.
4803 * The replay will happen at a time when it is safe to
4804 * unlock the directory.
4806 curPatchp = malloc(sizeof(*curPatchp));
4807 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4808 curPatchp->dptr = op;
4809 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4811 /* do hidden attribute here since name won't be around when applying
4815 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4816 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4818 curPatchp->flags = 0;
4820 op += 9; /* skip attr, time, date and size */
4822 /* zero out name area. The spec says to pad with
4823 * spaces, but Samba doesn't, and neither do we.
4827 /* finally, we get to copy out the name; we know that
4828 * it fits in 8.3 or the pattern wouldn't match, but it
4829 * never hurts to be sure.
4831 cm_ClientStringToUtf8(actualName, -1, op, 13);
4832 if (smb_StoreAnsiFilenames)
4834 /* This is a UCHAR field, which is ASCII even if Unicode
4837 /* Uppercase if requested by client */
4838 if (!KNOWS_LONG_NAMES(inp))
4843 /* now, adjust the # of entries copied */
4845 } /* if we're including this name */
4848 /* and adjust curOffset to be where the new cookie is */
4849 thyper.HighPart = 0;
4850 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4851 curOffset = LargeIntegerAdd(thyper, curOffset);
4852 } /* while copying data for dir listing */
4854 /* release the mutex */
4855 lock_ReleaseWrite(&scp->rw);
4857 buf_Release(bufferp);
4861 /* apply and free last set of patches; if not doing a star match, this
4862 * will be empty, but better safe (and freeing everything) than sorry.
4864 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4866 /* special return code for unsuccessful search */
4867 if (code == 0 && dataLength < 21 && returnedNames == 0)
4868 code = CM_ERROR_NOFILES;
4870 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4871 returnedNames, code);
4874 smb_DeleteDirSearch(dsp);
4875 smb_ReleaseDirSearch(dsp);
4876 cm_ReleaseSCache(scp);
4877 cm_ReleaseUser(userp);
4881 /* finalize the output buffer */
4882 smb_SetSMBParm(outp, 0, returnedNames);
4883 temp = (long) (op - origOp);
4884 smb_SetSMBDataLength(outp, temp);
4886 /* the data area is a variable block, which has a 5 (already there)
4887 * followed by the length of the # of data bytes. We now know this to
4888 * be "temp," although that includes the 3 bytes of vbl block header.
4889 * Deduct for them and fill in the length field.
4891 temp -= 3; /* deduct vbl block info */
4892 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4893 origOp[1] = (unsigned char)(temp & 0xff);
4894 origOp[2] = (unsigned char)((temp>>8) & 0xff);
4895 if (returnedNames == 0)
4896 smb_DeleteDirSearch(dsp);
4897 smb_ReleaseDirSearch(dsp);
4898 cm_ReleaseSCache(scp);
4899 cm_ReleaseUser(userp);
4904 /* verify that this is a valid path to a directory. I don't know why they
4905 * don't use the get file attributes call.
4907 * SMB_COM_CHECK_DIRECTORY
4909 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4911 clientchar_t *pathp;
4913 cm_scache_t *rootScp;
4914 cm_scache_t *newScp;
4918 clientchar_t *tidPathp;
4924 pdata = smb_GetSMBData(inp, NULL);
4925 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
4927 return CM_ERROR_BADFD;
4928 osi_Log1(smb_logp, "SMB receive check path %S",
4929 osi_LogSaveClientString(smb_logp, pathp));
4931 rootScp = cm_data.rootSCachep;
4933 userp = smb_GetUserFromVCP(vcp, inp);
4935 caseFold = CM_FLAG_CASEFOLD;
4937 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4939 cm_ReleaseUser(userp);
4940 return CM_ERROR_NOSUCHPATH;
4942 code = cm_NameI(rootScp, pathp,
4943 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4944 userp, tidPathp, &req, &newScp);
4947 cm_ReleaseUser(userp);
4952 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4953 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4954 cm_ReleaseSCache(newScp);
4955 cm_ReleaseUser(userp);
4956 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4957 return CM_ERROR_PATH_NOT_COVERED;
4959 return CM_ERROR_BADSHARENAME;
4961 #endif /* DFS_SUPPORT */
4963 /* now lock the vnode with a callback; returns with newScp locked */
4964 lock_ObtainWrite(&newScp->rw);
4965 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4966 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4968 if (code != CM_ERROR_NOACCESS) {
4969 lock_ReleaseWrite(&newScp->rw);
4970 cm_ReleaseSCache(newScp);
4971 cm_ReleaseUser(userp);
4975 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4978 attrs = smb_Attributes(newScp);
4980 if (!(attrs & SMB_ATTR_DIRECTORY))
4981 code = CM_ERROR_NOTDIR;
4983 lock_ReleaseWrite(&newScp->rw);
4985 cm_ReleaseSCache(newScp);
4986 cm_ReleaseUser(userp);
4990 /* SMB_COM_SET_INFORMATION */
4991 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4993 clientchar_t *pathp;
4995 cm_scache_t *rootScp;
4996 unsigned short attribute;
4998 cm_scache_t *newScp;
5002 clientchar_t *tidPathp;
5008 /* decode basic attributes we're passed */
5009 attribute = smb_GetSMBParm(inp, 0);
5010 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5012 datap = smb_GetSMBData(inp, NULL);
5013 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5015 return CM_ERROR_BADSMB;
5017 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5018 dosTime, attribute);
5020 rootScp = cm_data.rootSCachep;
5022 userp = smb_GetUserFromVCP(vcp, inp);
5024 caseFold = CM_FLAG_CASEFOLD;
5026 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5028 cm_ReleaseUser(userp);
5029 return CM_ERROR_NOSUCHFILE;
5031 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5032 tidPathp, &req, &newScp);
5035 cm_ReleaseUser(userp);
5040 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5041 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5042 cm_ReleaseSCache(newScp);
5043 cm_ReleaseUser(userp);
5044 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5045 return CM_ERROR_PATH_NOT_COVERED;
5047 return CM_ERROR_BADSHARENAME;
5049 #endif /* DFS_SUPPORT */
5051 /* now lock the vnode with a callback; returns with newScp locked; we
5052 * need the current status to determine what the new status is, in some
5055 lock_ObtainWrite(&newScp->rw);
5056 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5057 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5059 lock_ReleaseWrite(&newScp->rw);
5060 cm_ReleaseSCache(newScp);
5061 cm_ReleaseUser(userp);
5065 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5067 /* Check for RO volume */
5068 if (newScp->flags & CM_SCACHEFLAG_RO) {
5069 lock_ReleaseWrite(&newScp->rw);
5070 cm_ReleaseSCache(newScp);
5071 cm_ReleaseUser(userp);
5072 return CM_ERROR_READONLY;
5075 /* prepare for setattr call */
5078 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5079 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5081 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5082 /* we're told to make a writable file read-only */
5083 attr.unixModeBits = newScp->unixModeBits & ~0222;
5084 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5086 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5087 /* we're told to make a read-only file writable */
5088 attr.unixModeBits = newScp->unixModeBits | 0222;
5089 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5091 lock_ReleaseWrite(&newScp->rw);
5093 /* now call setattr */
5095 code = cm_SetAttr(newScp, &attr, userp, &req);
5099 cm_ReleaseSCache(newScp);
5100 cm_ReleaseUser(userp);
5106 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5108 clientchar_t *pathp;
5110 cm_scache_t *rootScp;
5111 cm_scache_t *newScp, *dscp;
5116 clientchar_t *tidPathp;
5118 clientchar_t *lastComp;
5124 datap = smb_GetSMBData(inp, NULL);
5125 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5127 return CM_ERROR_BADSMB;
5129 if (*pathp == 0) /* null path */
5132 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5133 osi_LogSaveClientString(smb_logp, pathp));
5135 rootScp = cm_data.rootSCachep;
5137 userp = smb_GetUserFromVCP(vcp, inp);
5139 /* we shouldn't need this for V3 requests, but we seem to */
5140 caseFold = CM_FLAG_CASEFOLD;
5142 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5144 cm_ReleaseUser(userp);
5145 return CM_ERROR_NOSUCHFILE;
5149 * XXX Strange hack XXX
5151 * As of Patch 5 (16 July 97), we are having the following problem:
5152 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5153 * requests to look up "desktop.ini" in all the subdirectories.
5154 * This can cause zillions of timeouts looking up non-existent cells
5155 * and volumes, especially in the top-level directory.
5157 * We have not found any way to avoid this or work around it except
5158 * to explicitly ignore the requests for mount points that haven't
5159 * yet been evaluated and for directories that haven't yet been
5162 * We should modify this hack to provide a fake desktop.ini file
5163 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5165 spacep = inp->spacep;
5166 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5167 #ifndef SPECIAL_FOLDERS
5168 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5169 code = cm_NameI(rootScp, spacep->wdata,
5170 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5171 userp, tidPathp, &req, &dscp);
5174 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5175 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5177 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5178 return CM_ERROR_PATH_NOT_COVERED;
5180 return CM_ERROR_BADSHARENAME;
5182 #endif /* DFS_SUPPORT */
5183 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5184 code = CM_ERROR_NOSUCHFILE;
5185 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5186 cm_buf_t *bp = buf_Find(dscp, &hzero);
5191 code = CM_ERROR_NOSUCHFILE;
5193 cm_ReleaseSCache(dscp);
5195 cm_ReleaseUser(userp);
5200 #endif /* SPECIAL_FOLDERS */
5202 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5203 tidPathp, &req, &newScp);
5205 cm_ReleaseUser(userp);
5210 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5211 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5212 cm_ReleaseSCache(newScp);
5213 cm_ReleaseUser(userp);
5214 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5215 return CM_ERROR_PATH_NOT_COVERED;
5217 return CM_ERROR_BADSHARENAME;
5219 #endif /* DFS_SUPPORT */
5221 /* now lock the vnode with a callback; returns with newScp locked */
5222 lock_ObtainWrite(&newScp->rw);
5223 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5224 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5226 lock_ReleaseWrite(&newScp->rw);
5227 cm_ReleaseSCache(newScp);
5228 cm_ReleaseUser(userp);
5232 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5235 /* use smb_Attributes instead. Also the fact that a file is
5236 * in a readonly volume doesn't mean it shojuld be marked as RO
5238 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5239 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5240 newScp->fileType == CM_SCACHETYPE_INVALID)
5241 attrs = SMB_ATTR_DIRECTORY;
5244 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
5245 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
5247 attrs = smb_Attributes(newScp);
5250 smb_SetSMBParm(outp, 0, attrs);
5252 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5253 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5254 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5255 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5256 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5257 smb_SetSMBParm(outp, 5, 0);
5258 smb_SetSMBParm(outp, 6, 0);
5259 smb_SetSMBParm(outp, 7, 0);
5260 smb_SetSMBParm(outp, 8, 0);
5261 smb_SetSMBParm(outp, 9, 0);
5262 smb_SetSMBDataLength(outp, 0);
5263 lock_ReleaseWrite(&newScp->rw);
5265 cm_ReleaseSCache(newScp);
5266 cm_ReleaseUser(userp);
5271 /* SMB_COM_TREE_DISCONNECT */
5272 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5276 osi_Log0(smb_logp, "SMB receive tree disconnect");
5278 /* find the tree and free it */
5279 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5281 lock_ObtainWrite(&smb_rctLock);
5283 smb_ReleaseTID(tidp, TRUE);
5284 lock_ReleaseWrite(&smb_rctLock);
5291 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5294 clientchar_t *pathp;
5295 clientchar_t *lastNamep;
5304 clientchar_t *tidPathp;
5310 datap = smb_GetSMBData(inp, NULL);
5311 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5313 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5315 #ifdef DEBUG_VERBOSE
5319 hexpath = osi_HexifyString( pathp );
5320 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5325 share = smb_GetSMBParm(inp, 0);
5326 attribute = smb_GetSMBParm(inp, 1);
5328 spacep = inp->spacep;
5329 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5330 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5331 /* special case magic file name for receiving IOCTL requests
5332 * (since IOCTL calls themselves aren't getting through).
5334 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5335 smb_SetupIoctlFid(fidp, spacep);
5336 smb_SetSMBParm(outp, 0, fidp->fid);
5337 smb_SetSMBParm(outp, 1, 0); /* attrs */
5338 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5339 smb_SetSMBParm(outp, 3, 0);
5340 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5341 smb_SetSMBParm(outp, 5, 0x7fff);
5342 /* pass the open mode back */
5343 smb_SetSMBParm(outp, 6, (share & 0xf));
5344 smb_SetSMBDataLength(outp, 0);
5345 smb_ReleaseFID(fidp);
5349 userp = smb_GetUserFromVCP(vcp, inp);
5351 caseFold = CM_FLAG_CASEFOLD;
5353 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5355 cm_ReleaseUser(userp);
5356 return CM_ERROR_NOSUCHPATH;
5358 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5359 tidPathp, &req, &scp);
5362 cm_ReleaseUser(userp);
5367 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5368 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5369 cm_ReleaseSCache(scp);
5370 cm_ReleaseUser(userp);
5371 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5372 return CM_ERROR_PATH_NOT_COVERED;
5374 return CM_ERROR_BADSHARENAME;
5376 #endif /* DFS_SUPPORT */
5378 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5380 cm_ReleaseSCache(scp);
5381 cm_ReleaseUser(userp);
5385 /* don't need callback to check file type, since file types never
5386 * change, and namei and cm_Lookup all stat the object at least once on
5387 * a successful return.
5389 if (scp->fileType != CM_SCACHETYPE_FILE) {
5390 cm_ReleaseSCache(scp);
5391 cm_ReleaseUser(userp);
5392 return CM_ERROR_ISDIR;
5395 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5396 osi_assertx(fidp, "null smb_fid_t");
5398 /* save a pointer to the vnode */
5400 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5401 lock_ObtainWrite(&scp->rw);
5402 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5403 lock_ReleaseWrite(&scp->rw);
5407 fidp->userp = userp;
5409 lock_ObtainMutex(&fidp->mx);
5410 if ((share & 0xf) == 0)
5411 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5412 else if ((share & 0xf) == 1)
5413 fidp->flags |= SMB_FID_OPENWRITE;
5415 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5416 lock_ReleaseMutex(&fidp->mx);
5418 lock_ObtainRead(&scp->rw);
5419 smb_SetSMBParm(outp, 0, fidp->fid);
5420 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5421 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5422 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5423 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5424 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5425 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5426 /* pass the open mode back; XXXX add access checks */
5427 smb_SetSMBParm(outp, 6, (share & 0xf));
5428 smb_SetSMBDataLength(outp, 0);
5429 lock_ReleaseRead(&scp->rw);
5432 cm_Open(scp, 0, userp);
5434 /* send and free packet */
5435 smb_ReleaseFID(fidp);
5436 cm_ReleaseUser(userp);
5437 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5441 typedef struct smb_unlinkRock {
5446 clientchar_t *maskp; /* pointer to the star pattern */
5449 cm_dirEntryList_t * matches;
5452 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5455 smb_unlinkRock_t *rockp;
5458 normchar_t matchName[MAX_PATH];
5462 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5463 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5464 caseFold |= CM_FLAG_8DOT3;
5466 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5467 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5469 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5470 !cm_Is8Dot3(matchName)) {
5471 cm_Gen8Dot3Name(dep, matchName, NULL);
5472 /* 8.3 matches are always case insensitive */
5473 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5476 osi_Log1(smb_logp, "Found match %S",
5477 osi_LogSaveClientString(smb_logp, matchName));
5479 cm_DirEntryListAdd(dep->name, &rockp->matches);
5483 /* If we made a case sensitive exact match, we might as well quit now. */
5484 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5485 code = CM_ERROR_STOPNOW;
5494 /* SMB_COM_DELETE */
5495 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5499 clientchar_t *pathp;
5503 clientchar_t *lastNamep;
5504 smb_unlinkRock_t rock;
5508 clientchar_t *tidPathp;
5513 attribute = smb_GetSMBParm(inp, 0);
5515 tp = smb_GetSMBData(inp, NULL);
5516 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5518 osi_Log1(smb_logp, "SMB receive unlink %S",
5519 osi_LogSaveClientString(smb_logp, pathp));
5521 spacep = inp->spacep;
5522 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5524 userp = smb_GetUserFromVCP(vcp, inp);
5526 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5528 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5530 cm_ReleaseUser(userp);
5531 return CM_ERROR_NOSUCHPATH;
5533 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5536 cm_ReleaseUser(userp);
5541 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5542 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5543 cm_ReleaseSCache(dscp);
5544 cm_ReleaseUser(userp);
5545 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5546 return CM_ERROR_PATH_NOT_COVERED;
5548 return CM_ERROR_BADSHARENAME;
5550 #endif /* DFS_SUPPORT */
5552 /* otherwise, scp points to the parent directory. */
5559 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5560 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5563 thyper.HighPart = 0;
5568 rock.matches = NULL;
5570 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5571 * match. If that fails, we do a case insensitve match.
5573 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5574 !smb_IsStarMask(rock.maskp)) {
5575 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5578 thyper.HighPart = 0;
5579 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5584 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5586 if (code == CM_ERROR_STOPNOW)
5589 if (code == 0 && rock.matches) {
5590 cm_dirEntryList_t * entry;
5592 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5593 normchar_t normalizedName[MAX_PATH];
5595 /* Note: entry->name is a non-normalized name */
5597 osi_Log1(smb_logp, "Unlinking %s",
5598 osi_LogSaveString(smb_logp, entry->name));
5600 cm_FsStringToNormString(entry->name, -1,
5601 normalizedName, lengthof(normalizedName));
5603 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5605 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5606 smb_NotifyChange(FILE_ACTION_REMOVED,
5607 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5608 dscp, normalizedName, NULL, TRUE);
5612 cm_DirEntryListFree(&rock.matches);
5614 cm_ReleaseUser(userp);
5616 cm_ReleaseSCache(dscp);
5620 if (code == 0 && !rock.any)
5621 code = CM_ERROR_NOSUCHFILE;
5625 typedef struct smb_renameRock {
5626 cm_scache_t *odscp; /* old dir */
5627 cm_scache_t *ndscp; /* new dir */
5628 cm_user_t *userp; /* user */
5629 cm_req_t *reqp; /* request struct */
5630 smb_vc_t *vcp; /* virtual circuit */
5631 normchar_t *maskp; /* pointer to star pattern of old file name */
5632 int flags; /* tilde, casefold, etc */
5633 clientchar_t *newNamep; /* ptr to the new file's name */
5634 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5635 clientchar_t clOldName[MAX_PATH]; /* client name */
5639 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5642 smb_renameRock_t *rockp;
5645 normchar_t matchName[MAX_PATH];
5647 rockp = (smb_renameRock_t *) vrockp;
5649 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5650 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5651 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5652 caseFold |= CM_FLAG_8DOT3;
5654 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5656 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5657 !cm_Is8Dot3(matchName)) {
5658 cm_Gen8Dot3Name(dep, matchName, NULL);
5659 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5664 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5665 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5667 code = CM_ERROR_STOPNOW;
5677 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5680 cm_space_t *spacep = NULL;
5681 smb_renameRock_t rock;
5682 cm_scache_t *oldDscp = NULL;
5683 cm_scache_t *newDscp = NULL;
5684 cm_scache_t *tmpscp= NULL;
5685 cm_scache_t *tmpscp2 = NULL;
5686 clientchar_t *oldLastNamep;
5687 clientchar_t *newLastNamep;
5691 clientchar_t *tidPathp;
5695 userp = smb_GetUserFromVCP(vcp, inp);
5696 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5698 cm_ReleaseUser(userp);
5699 return CM_ERROR_NOSUCHPATH;
5703 spacep = inp->spacep;
5704 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5706 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5707 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5708 userp, tidPathp, &req, &oldDscp);
5710 cm_ReleaseUser(userp);
5715 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5716 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5717 cm_ReleaseSCache(oldDscp);
5718 cm_ReleaseUser(userp);
5719 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5720 return CM_ERROR_PATH_NOT_COVERED;
5722 return CM_ERROR_BADSHARENAME;
5724 #endif /* DFS_SUPPORT */
5726 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5727 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5728 userp, tidPathp, &req, &newDscp);
5731 cm_ReleaseSCache(oldDscp);
5732 cm_ReleaseUser(userp);
5737 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5738 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5739 cm_ReleaseSCache(oldDscp);
5740 cm_ReleaseSCache(newDscp);
5741 cm_ReleaseUser(userp);
5742 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5743 return CM_ERROR_PATH_NOT_COVERED;
5745 return CM_ERROR_BADSHARENAME;
5747 #endif /* DFS_SUPPORT */
5750 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5751 * next, get the component names, and lower case them.
5754 /* handle the old name first */
5756 oldLastNamep = oldPathp;
5760 /* and handle the new name, too */
5762 newLastNamep = newPathp;
5766 /* TODO: The old name could be a wildcard. The new name must not be */
5768 /* do the vnode call */
5769 rock.odscp = oldDscp;
5770 rock.ndscp = newDscp;
5774 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
5775 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5776 rock.newNamep = newLastNamep;
5777 rock.fsOldName[0] = '\0';
5778 rock.clOldName[0] = '\0';
5781 /* Check if the file already exists; if so return error */
5782 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5783 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5784 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5786 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5787 osi_LogSaveClientString(smb_logp, newLastNamep));
5789 /* Check if the old and the new names differ only in case. If so return
5790 * success, else return CM_ERROR_EXISTS
5792 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
5794 /* This would be a success only if the old file is *as same as* the new file */
5795 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5797 if (tmpscp == tmpscp2)
5800 code = CM_ERROR_EXISTS;
5801 cm_ReleaseSCache(tmpscp2);
5804 code = CM_ERROR_NOSUCHFILE;
5807 /* file exist, do not rename, also fixes move */
5808 osi_Log0(smb_logp, "Can't rename. Target already exists");
5809 code = CM_ERROR_EXISTS;
5813 cm_ReleaseSCache(tmpscp);
5814 cm_ReleaseSCache(newDscp);
5815 cm_ReleaseSCache(oldDscp);
5816 cm_ReleaseUser(userp);
5823 /* Now search the directory for the pattern, and do the appropriate rename when found */
5824 thyper.LowPart = 0; /* search dir from here */
5825 thyper.HighPart = 0;
5827 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5828 if (code == 0 && !rock.any) {
5830 thyper.HighPart = 0;
5831 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5832 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5834 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5836 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
5837 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
5838 rock.ndscp, rock.newNamep, rock.userp,
5840 /* if the call worked, stop doing the search now, since we
5841 * really only want to rename one file.
5843 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5844 } else if (code == 0) {
5845 code = CM_ERROR_NOSUCHFILE;
5848 /* Handle Change Notification */
5850 * Being lazy, not distinguishing between files and dirs in this
5851 * filter, since we'd have to do a lookup.
5854 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5855 if (oldDscp == newDscp) {
5856 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5857 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5858 filter, oldDscp, rock.clOldName,
5859 newLastNamep, TRUE);
5861 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5862 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5863 filter, oldDscp, rock.clOldName,
5865 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5866 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5867 filter, newDscp, newLastNamep,
5873 cm_ReleaseSCache(tmpscp);
5874 cm_ReleaseUser(userp);
5875 cm_ReleaseSCache(oldDscp);
5876 cm_ReleaseSCache(newDscp);
5885 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
5888 cm_space_t *spacep = NULL;
5889 cm_scache_t *oldDscp = NULL;
5890 cm_scache_t *newDscp = NULL;
5891 cm_scache_t *tmpscp= NULL;
5892 cm_scache_t *tmpscp2 = NULL;
5893 cm_scache_t *sscp = NULL;
5894 clientchar_t *oldLastNamep;
5895 clientchar_t *newLastNamep;
5898 clientchar_t *tidPathp;
5902 userp = smb_GetUserFromVCP(vcp, inp);
5904 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5906 cm_ReleaseUser(userp);
5907 return CM_ERROR_NOSUCHPATH;
5912 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5914 spacep = inp->spacep;
5915 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5917 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5918 userp, tidPathp, &req, &oldDscp);
5920 cm_ReleaseUser(userp);
5925 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5926 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5927 cm_ReleaseSCache(oldDscp);
5928 cm_ReleaseUser(userp);
5929 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5930 return CM_ERROR_PATH_NOT_COVERED;
5932 return CM_ERROR_BADSHARENAME;
5934 #endif /* DFS_SUPPORT */
5936 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5937 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5938 userp, tidPathp, &req, &newDscp);
5940 cm_ReleaseSCache(oldDscp);
5941 cm_ReleaseUser(userp);
5946 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5947 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5948 cm_ReleaseSCache(newDscp);
5949 cm_ReleaseSCache(oldDscp);
5950 cm_ReleaseUser(userp);
5951 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5952 return CM_ERROR_PATH_NOT_COVERED;
5954 return CM_ERROR_BADSHARENAME;
5956 #endif /* DFS_SUPPORT */
5958 /* Now, although we did two lookups for the two directories (because the same
5959 * directory can be referenced through different paths), we only allow hard links
5960 * within the same directory. */
5961 if (oldDscp != newDscp) {
5962 cm_ReleaseSCache(oldDscp);
5963 cm_ReleaseSCache(newDscp);
5964 cm_ReleaseUser(userp);
5965 return CM_ERROR_CROSSDEVLINK;
5968 /* handle the old name first */
5970 oldLastNamep = oldPathp;
5974 /* and handle the new name, too */
5976 newLastNamep = newPathp;
5980 /* now lookup the old name */
5981 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
5982 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5984 cm_ReleaseSCache(oldDscp);
5985 cm_ReleaseSCache(newDscp);
5986 cm_ReleaseUser(userp);
5990 /* Check if the file already exists; if so return error */
5991 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5992 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5993 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5995 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5996 osi_LogSaveClientString(smb_logp, newLastNamep));
5998 /* if the existing link is to the same file, then we return success */
6000 if(sscp == tmpscp) {
6003 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6004 code = CM_ERROR_EXISTS;
6009 cm_ReleaseSCache(tmpscp);
6010 cm_ReleaseSCache(sscp);
6011 cm_ReleaseSCache(newDscp);
6012 cm_ReleaseSCache(oldDscp);
6013 cm_ReleaseUser(userp);
6017 /* now create the hardlink */
6018 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6019 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6020 osi_Log1(smb_logp," Link returns 0x%x", code);
6022 /* Handle Change Notification */
6024 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6025 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6026 smb_NotifyChange(FILE_ACTION_ADDED,
6027 filter, newDscp, newLastNamep,
6032 cm_ReleaseSCache(tmpscp);
6033 cm_ReleaseUser(userp);
6034 cm_ReleaseSCache(sscp);
6035 cm_ReleaseSCache(oldDscp);
6036 cm_ReleaseSCache(newDscp);
6040 /* SMB_COM_RENAME */
6042 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6044 clientchar_t *oldPathp;
6045 clientchar_t *newPathp;
6049 tp = smb_GetSMBData(inp, NULL);
6050 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6051 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6053 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6054 osi_LogSaveClientString(smb_logp, oldPathp),
6055 osi_LogSaveClientString(smb_logp, newPathp));
6057 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6059 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6065 typedef struct smb_rmdirRock {
6069 normchar_t *maskp; /* pointer to the star pattern */
6072 cm_dirEntryList_t * matches;
6075 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6078 smb_rmdirRock_t *rockp;
6080 normchar_t matchName[MAX_PATH];
6082 rockp = (smb_rmdirRock_t *) vrockp;
6084 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
6085 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6086 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6088 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6090 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6091 !cm_Is8Dot3(matchName)) {
6092 cm_Gen8Dot3Name(dep, matchName, NULL);
6093 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6098 cm_DirEntryListAdd(dep->name, &rockp->matches);
6105 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6108 clientchar_t *pathp;
6112 clientchar_t *lastNamep;
6113 smb_rmdirRock_t rock;
6117 clientchar_t *tidPathp;
6122 tp = smb_GetSMBData(inp, NULL);
6123 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6125 spacep = inp->spacep;
6126 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6128 userp = smb_GetUserFromVCP(vcp, inp);
6130 caseFold = CM_FLAG_CASEFOLD;
6132 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6134 cm_ReleaseUser(userp);
6135 return CM_ERROR_NOSUCHPATH;
6137 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6138 userp, tidPathp, &req, &dscp);
6141 cm_ReleaseUser(userp);
6146 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6147 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6148 cm_ReleaseSCache(dscp);
6149 cm_ReleaseUser(userp);
6150 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6151 return CM_ERROR_PATH_NOT_COVERED;
6153 return CM_ERROR_BADSHARENAME;
6155 #endif /* DFS_SUPPORT */
6157 /* otherwise, scp points to the parent directory. */
6164 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6165 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6168 thyper.HighPart = 0;
6172 rock.matches = NULL;
6174 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6175 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6176 if (code == 0 && !rock.any) {
6178 thyper.HighPart = 0;
6179 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6180 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6183 if (code == 0 && rock.matches) {
6184 cm_dirEntryList_t * entry;
6186 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6187 clientchar_t clientName[MAX_PATH];
6189 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6191 osi_Log1(smb_logp, "Removing directory %s",
6192 osi_LogSaveString(smb_logp, entry->name));
6194 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6196 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6197 smb_NotifyChange(FILE_ACTION_REMOVED,
6198 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6199 dscp, clientName, NULL, TRUE);
6203 cm_DirEntryListFree(&rock.matches);
6205 cm_ReleaseUser(userp);
6207 cm_ReleaseSCache(dscp);
6209 if (code == 0 && !rock.any)
6210 code = CM_ERROR_NOSUCHFILE;
6219 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6229 fid = smb_GetSMBParm(inp, 0);
6231 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6233 fid = smb_ChainFID(fid, inp);
6234 fidp = smb_FindFID(vcp, fid, 0);
6236 return CM_ERROR_BADFD;
6238 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6239 smb_CloseFID(vcp, fidp, NULL, 0);
6240 smb_ReleaseFID(fidp);
6241 return CM_ERROR_NOSUCHFILE;
6244 lock_ObtainMutex(&fidp->mx);
6245 if (fidp->flags & SMB_FID_IOCTL) {
6246 lock_ReleaseMutex(&fidp->mx);
6247 smb_ReleaseFID(fidp);
6248 return CM_ERROR_BADFD;
6250 lock_ReleaseMutex(&fidp->mx);
6252 userp = smb_GetUserFromVCP(vcp, inp);
6254 lock_ObtainMutex(&fidp->mx);
6255 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6256 cm_scache_t * scp = fidp->scp;
6258 lock_ReleaseMutex(&fidp->mx);
6259 code = cm_FSync(scp, userp, &req);
6260 cm_ReleaseSCache(scp);
6263 lock_ReleaseMutex(&fidp->mx);
6266 smb_ReleaseFID(fidp);
6268 cm_ReleaseUser(userp);
6273 struct smb_FullNameRock {
6276 clientchar_t *fullName;
6277 fschar_t *originalName;
6280 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6283 normchar_t matchName[MAX_PATH];
6284 struct smb_FullNameRock *vrockp;
6286 vrockp = (struct smb_FullNameRock *)rockp;
6288 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
6290 if (!cm_Is8Dot3(matchName)) {
6291 clientchar_t shortName[13];
6293 cm_Gen8Dot3Name(dep, shortName, NULL);
6295 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6296 vrockp->fullName = cm_ClientStrDup(matchName);
6297 vrockp->originalName = cm_FsStrDup(dep->name);
6298 return CM_ERROR_STOPNOW;
6301 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6302 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6303 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6304 vrockp->fullName = cm_ClientStrDup(matchName);
6305 vrockp->originalName = cm_FsStrDup(dep->name);
6306 return CM_ERROR_STOPNOW;
6311 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6312 clientchar_t **newPathp, fschar_t ** originalPathp,
6313 cm_user_t *userp, cm_req_t *reqp)
6315 struct smb_FullNameRock rock;
6318 memset(&rock, 0, sizeof(rock));
6322 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6323 if (code == CM_ERROR_STOPNOW) {
6324 *newPathp = rock.fullName;
6325 *originalPathp = rock.originalName;
6327 *newPathp = cm_ClientStrDup(pathp);
6328 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6332 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6333 afs_uint32 dosTime) {
6336 cm_scache_t *dscp = NULL;
6337 clientchar_t *pathp = NULL;
6338 cm_scache_t * scp = NULL;
6339 cm_scache_t *delscp = NULL;
6340 int nullcreator = 0;
6342 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6343 fidp, fidp->fid, scp, vcp);
6346 lock_ObtainMutex(&fidp->mx);
6347 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6348 lock_ReleaseMutex(&fidp->mx);
6349 osi_Log0(smb_logp, " No user specified. Not closing fid");
6350 return CM_ERROR_BADFD;
6353 userp = fidp->userp; /* no hold required since fidp is held
6354 throughout the function */
6355 lock_ReleaseMutex(&fidp->mx);
6360 lock_ObtainWrite(&smb_rctLock);
6361 if (fidp->deleteOk) {
6362 osi_Log0(smb_logp, " Fid already closed.");
6363 lock_ReleaseWrite(&smb_rctLock);
6364 return CM_ERROR_BADFD;
6367 lock_ReleaseWrite(&smb_rctLock);
6369 lock_ObtainMutex(&fidp->mx);
6370 if (fidp->NTopen_dscp) {
6371 dscp = fidp->NTopen_dscp;
6372 cm_HoldSCache(dscp);
6375 if (fidp->NTopen_pathp) {
6376 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6384 /* Don't jump the gun on an async raw write */
6385 while (fidp->raw_writers) {
6386 lock_ReleaseMutex(&fidp->mx);
6387 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6388 lock_ObtainMutex(&fidp->mx);
6391 /* watch for ioctl closes, and read-only opens */
6393 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6394 == SMB_FID_OPENWRITE) {
6395 if (dosTime != 0 && dosTime != -1) {
6396 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6397 /* This fixes defect 10958 */
6398 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6399 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6401 if (smb_AsyncStore != 2) {
6402 lock_ReleaseMutex(&fidp->mx);
6403 code = cm_FSync(scp, userp, &req);
6404 lock_ObtainMutex(&fidp->mx);
6410 /* unlock any pending locks */
6411 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6412 scp->fileType == CM_SCACHETYPE_FILE) {
6416 lock_ReleaseMutex(&fidp->mx);
6418 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6420 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6421 lock_ObtainWrite(&scp->rw);
6423 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6424 CM_SCACHESYNC_NEEDCALLBACK
6425 | CM_SCACHESYNC_GETSTATUS
6426 | CM_SCACHESYNC_LOCK);
6430 "smb CoreClose SyncOp failure code 0x%x", tcode);
6431 goto post_syncopdone;
6434 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6436 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6440 lock_ReleaseWrite(&scp->rw);
6441 lock_ObtainMutex(&fidp->mx);
6444 if (fidp->flags & SMB_FID_DELONCLOSE) {
6445 clientchar_t *fullPathp = NULL;
6446 fschar_t *originalNamep = NULL;
6448 lock_ReleaseMutex(&fidp->mx);
6450 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6455 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6456 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6457 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6459 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6460 smb_NotifyChange(FILE_ACTION_REMOVED,
6461 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6462 dscp, fullPathp, NULL, TRUE);
6465 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6467 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6468 smb_NotifyChange(FILE_ACTION_REMOVED,
6469 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6470 dscp, fullPathp, NULL, TRUE);
6477 free(originalNamep);
6479 lock_ObtainMutex(&fidp->mx);
6480 fidp->flags &= ~SMB_FID_DELONCLOSE;
6483 /* if this was a newly created file, then clear the creator
6484 * in the stat cache entry. */
6485 if (fidp->flags & SMB_FID_CREATED) {
6487 fidp->flags &= ~SMB_FID_CREATED;
6490 if (fidp->flags & SMB_FID_NTOPEN) {
6491 cm_ReleaseSCache(fidp->NTopen_dscp);
6492 fidp->NTopen_dscp = NULL;
6493 free(fidp->NTopen_pathp);
6494 fidp->NTopen_pathp = NULL;
6495 fidp->flags &= ~SMB_FID_NTOPEN;
6497 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6498 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6501 if (fidp->NTopen_wholepathp) {
6502 free(fidp->NTopen_wholepathp);
6503 fidp->NTopen_wholepathp = NULL;
6507 cm_ReleaseSCache(fidp->scp);
6510 lock_ReleaseMutex(&fidp->mx);
6513 cm_ReleaseSCache(dscp);
6516 cm_ReleaseSCache(delscp);
6520 lock_ObtainWrite(&scp->rw);
6521 if (nullcreator && scp->creator == userp)
6522 scp->creator = NULL;
6523 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6524 lock_ReleaseWrite(&scp->rw);
6525 cm_ReleaseSCache(scp);
6535 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6543 fid = smb_GetSMBParm(inp, 0);
6544 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6546 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6548 fid = smb_ChainFID(fid, inp);
6549 fidp = smb_FindFID(vcp, fid, 0);
6551 return CM_ERROR_BADFD;
6554 userp = smb_GetUserFromVCP(vcp, inp);
6556 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6558 smb_ReleaseFID(fidp);
6559 cm_ReleaseUser(userp);
6564 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6566 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6567 cm_user_t *userp, long *readp)
6573 osi_hyper_t fileLength;
6575 osi_hyper_t lastByte;
6576 osi_hyper_t bufferOffset;
6580 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6583 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6584 fidp->fid, offsetp->LowPart, count);
6588 lock_ObtainMutex(&fidp->mx);
6589 /* make sure we have a readable FD */
6590 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6591 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6592 fidp->fid, fidp->flags);
6593 lock_ReleaseMutex(&fidp->mx);
6594 code = CM_ERROR_BADFDOP;
6605 lock_ObtainWrite(&scp->rw);
6607 if (offset.HighPart == 0) {
6608 chunk = offset.LowPart >> cm_logChunkSize;
6609 if (chunk != fidp->curr_chunk) {
6610 fidp->prev_chunk = fidp->curr_chunk;
6611 fidp->curr_chunk = chunk;
6613 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6616 lock_ReleaseMutex(&fidp->mx);
6618 /* start by looking up the file's end */
6619 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6620 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6624 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6626 /* now we have the entry locked, look up the length */
6627 fileLength = scp->length;
6629 /* adjust count down so that it won't go past EOF */
6630 thyper.LowPart = count;
6631 thyper.HighPart = 0;
6632 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6634 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6635 /* we'd read past EOF, so just stop at fileLength bytes.
6636 * Start by computing how many bytes remain in the file.
6638 thyper = LargeIntegerSubtract(fileLength, offset);
6640 /* if we are past EOF, read 0 bytes */
6641 if (LargeIntegerLessThanZero(thyper))
6644 count = thyper.LowPart;
6649 /* now, copy the data one buffer at a time,
6650 * until we've filled the request packet
6653 /* if we've copied all the data requested, we're done */
6654 if (count <= 0) break;
6656 /* otherwise, load up a buffer of data */
6657 thyper.HighPart = offset.HighPart;
6658 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6659 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6662 buf_Release(bufferp);
6665 lock_ReleaseWrite(&scp->rw);
6667 code = buf_Get(scp, &thyper, &bufferp);
6669 lock_ObtainWrite(&scp->rw);
6670 if (code) goto done;
6671 bufferOffset = thyper;
6673 /* now get the data in the cache */
6675 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6676 CM_SCACHESYNC_NEEDCALLBACK |
6677 CM_SCACHESYNC_READ);
6681 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6683 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6685 /* otherwise, load the buffer and try again */
6686 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6690 buf_Release(bufferp);
6694 } /* if (wrong buffer) ... */
6696 /* now we have the right buffer loaded. Copy out the
6697 * data from here to the user's buffer.
6699 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6701 /* and figure out how many bytes we want from this buffer */
6702 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6703 if (nbytes > count) nbytes = count; /* don't go past EOF */
6705 /* now copy the data */
6706 memcpy(op, bufferp->datap + bufIndex, nbytes);
6708 /* adjust counters, pointers, etc. */
6711 thyper.LowPart = nbytes;
6712 thyper.HighPart = 0;
6713 offset = LargeIntegerAdd(thyper, offset);
6717 lock_ReleaseWrite(&scp->rw);
6719 buf_Release(bufferp);
6721 if (code == 0 && sequential)
6722 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6724 cm_ReleaseSCache(scp);
6727 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6728 fidp->fid, code, *readp);
6733 * smb_WriteData -- common code for Write and Raw Write
6735 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6736 cm_user_t *userp, long *writtenp)
6738 osi_hyper_t offset = *offsetp;
6741 cm_scache_t *scp = NULL;
6742 osi_hyper_t fileLength; /* file's length at start of write */
6743 osi_hyper_t minLength; /* don't read past this */
6744 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6745 cm_buf_t *bufferp = NULL;
6746 osi_hyper_t thyper; /* hyper tmp variable */
6747 osi_hyper_t bufferOffset;
6748 afs_uint32 bufIndex; /* index in buffer where our data is */
6749 int doWriteBack = 0;
6750 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6754 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6755 fidp->fid, offsetp->LowPart, count);
6759 lock_ObtainMutex(&fidp->mx);
6760 /* make sure we have a writable FD */
6761 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6762 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6763 fidp->fid, fidp->flags);
6764 lock_ReleaseMutex(&fidp->mx);
6765 code = CM_ERROR_BADFDOP;
6773 lock_ReleaseMutex(&fidp->mx);
6775 lock_ObtainWrite(&scp->rw);
6776 /* start by looking up the file's end */
6777 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6778 CM_SCACHESYNC_NEEDCALLBACK
6779 | CM_SCACHESYNC_SETSTATUS
6780 | CM_SCACHESYNC_GETSTATUS);
6784 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6786 /* now we have the entry locked, look up the length */
6787 fileLength = scp->length;
6788 minLength = fileLength;
6789 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6790 minLength = scp->serverLength;
6792 /* adjust file length if we extend past EOF */
6793 thyper.LowPart = count;
6794 thyper.HighPart = 0;
6795 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6796 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6797 /* we'd write past EOF, so extend the file */
6798 scp->mask |= CM_SCACHEMASK_LENGTH;
6799 scp->length = thyper;
6800 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6802 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6804 /* now, if the new position (thyper) and the old (offset) are in
6805 * different storeback windows, remember to store back the previous
6806 * storeback window when we're done with the write.
6808 * the purpose of this logic is to slow down the CIFS client
6809 * in order to avoid the client disconnecting during the CLOSE
6810 * operation if there are too many dirty buffers left to write
6811 * than can be accomplished during 45 seconds. This used to be
6812 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6813 * so that we can read larger amounts of data at a time.
6815 if (smb_AsyncStore == 1 &&
6816 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
6817 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
6818 /* they're different */
6820 writeBackOffset.HighPart = offset.HighPart;
6821 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
6826 /* now, copy the data one buffer at a time, until we've filled the
6829 /* if we've copied all the data requested, we're done */
6833 /* handle over quota or out of space */
6834 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6835 *writtenp = written;
6836 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6840 /* otherwise, load up a buffer of data */
6841 thyper.HighPart = offset.HighPart;
6842 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6843 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6846 lock_ReleaseMutex(&bufferp->mx);
6847 buf_Release(bufferp);
6850 lock_ReleaseWrite(&scp->rw);
6852 code = buf_Get(scp, &thyper, &bufferp);
6854 lock_ObtainMutex(&bufferp->mx);
6855 lock_ObtainWrite(&scp->rw);
6856 if (code) goto done;
6858 bufferOffset = thyper;
6860 /* now get the data in the cache */
6862 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6863 CM_SCACHESYNC_NEEDCALLBACK
6864 | CM_SCACHESYNC_WRITE
6865 | CM_SCACHESYNC_BUFLOCKED);
6869 cm_SyncOpDone(scp, bufferp,
6870 CM_SCACHESYNC_NEEDCALLBACK
6871 | CM_SCACHESYNC_WRITE
6872 | CM_SCACHESYNC_BUFLOCKED);
6874 /* If we're overwriting the entire buffer, or
6875 * if we're writing at or past EOF, mark the
6876 * buffer as current so we don't call
6877 * cm_GetBuffer. This skips the fetch from the
6878 * server in those cases where we're going to
6879 * obliterate all the data in the buffer anyway,
6880 * or in those cases where there is no useful
6881 * data at the server to start with.
6883 * Use minLength instead of scp->length, since
6884 * the latter has already been updated by this
6887 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6888 || LargeIntegerEqualTo(offset, bufferp->offset)
6889 && (count >= cm_data.buf_blockSize
6890 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6891 ConvertLongToLargeInteger(count)),
6893 if (count < cm_data.buf_blockSize
6894 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
6895 memset(bufferp->datap, 0,
6896 cm_data.buf_blockSize);
6897 bufferp->dataVersion = scp->dataVersion;
6900 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6902 /* otherwise, load the buffer and try again */
6903 lock_ReleaseMutex(&bufferp->mx);
6904 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6906 lock_ReleaseWrite(&scp->rw);
6907 lock_ObtainMutex(&bufferp->mx);
6908 lock_ObtainWrite(&scp->rw);
6912 lock_ReleaseMutex(&bufferp->mx);
6913 buf_Release(bufferp);
6917 } /* if (wrong buffer) ... */
6919 /* now we have the right buffer loaded. Copy out the
6920 * data from here to the user's buffer.
6922 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6924 /* and figure out how many bytes we want from this buffer */
6925 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6927 nbytes = count; /* don't go past end of request */
6929 /* now copy the data */
6930 memcpy(bufferp->datap + bufIndex, op, nbytes);
6931 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
6933 /* adjust counters, pointers, etc. */
6937 thyper.LowPart = nbytes;
6938 thyper.HighPart = 0;
6939 offset = LargeIntegerAdd(thyper, offset);
6943 lock_ReleaseWrite(&scp->rw);
6946 lock_ReleaseMutex(&bufferp->mx);
6947 buf_Release(bufferp);
6950 lock_ObtainMutex(&fidp->mx);
6951 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6952 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6953 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6954 fidp->NTopen_dscp, fidp->NTopen_pathp,
6957 lock_ReleaseMutex(&fidp->mx);
6960 if (smb_AsyncStore > 0) {
6964 lock_ObtainWrite(&scp->rw);
6965 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6967 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6968 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6970 lock_ReleaseWrite(&scp->rw);
6971 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6972 writeBackOffset.HighPart,
6973 smb_AsyncStoreSize, 0, userp);
6974 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6977 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
6981 cm_ReleaseSCache(scp);
6984 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6985 fidp->fid, code, *writtenp);
6990 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6993 unsigned short count;
6995 unsigned short hint;
6996 long written = 0, total_written = 0;
6999 smb_t* smbp = (smb_t*) inp;
7002 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7004 int inDataBlockCount;
7006 fd = smb_GetSMBParm(inp, 0);
7007 count = smb_GetSMBParm(inp, 1);
7008 offset.HighPart = 0; /* too bad */
7009 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7010 hint = smb_GetSMBParm(inp, 4);
7012 op = smb_GetSMBData(inp, NULL);
7013 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7015 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7016 fd, offset.LowPart, count);
7018 fd = smb_ChainFID(fd, inp);
7019 fidp = smb_FindFID(vcp, fd, 0);
7021 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7022 return CM_ERROR_BADFD;
7025 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7026 smb_CloseFID(vcp, fidp, NULL, 0);
7027 smb_ReleaseFID(fidp);
7028 return CM_ERROR_NOSUCHFILE;
7031 lock_ObtainMutex(&fidp->mx);
7032 if (fidp->flags & SMB_FID_IOCTL) {
7033 lock_ReleaseMutex(&fidp->mx);
7034 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7035 smb_ReleaseFID(fidp);
7036 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7039 lock_ReleaseMutex(&fidp->mx);
7040 userp = smb_GetUserFromVCP(vcp, inp);
7044 LARGE_INTEGER LOffset;
7045 LARGE_INTEGER LLength;
7048 key = cm_GenerateKey(vcp->vcID, pid, fd);
7050 LOffset.HighPart = offset.HighPart;
7051 LOffset.LowPart = offset.LowPart;
7052 LLength.HighPart = 0;
7053 LLength.LowPart = count;
7055 lock_ObtainWrite(&fidp->scp->rw);
7056 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7057 lock_ReleaseWrite(&fidp->scp->rw);
7060 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7065 /* special case: 0 bytes transferred means truncate to this position */
7069 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7073 truncAttr.mask = CM_ATTRMASK_LENGTH;
7074 truncAttr.length.LowPart = offset.LowPart;
7075 truncAttr.length.HighPart = 0;
7076 lock_ObtainMutex(&fidp->mx);
7077 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7078 fidp->flags |= SMB_FID_LENGTHSETDONE;
7079 lock_ReleaseMutex(&fidp->mx);
7080 smb_SetSMBParm(outp, 0, 0 /* count */);
7081 smb_SetSMBDataLength(outp, 0);
7086 * Work around bug in NT client
7088 * When copying a file, the NT client should first copy the data,
7089 * then copy the last write time. But sometimes the NT client does
7090 * these in the wrong order, so the data copies would inadvertently
7091 * cause the last write time to be overwritten. We try to detect this,
7092 * and don't set client mod time if we think that would go against the
7095 lock_ObtainMutex(&fidp->mx);
7096 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7097 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7098 fidp->scp->clientModTime = time(NULL);
7100 lock_ReleaseMutex(&fidp->mx);
7103 while ( code == 0 && count > 0 ) {
7104 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7105 if (code == 0 && written == 0)
7106 code = CM_ERROR_PARTIALWRITE;
7108 offset = LargeIntegerAdd(offset,
7109 ConvertLongToLargeInteger(written));
7110 count -= (unsigned short)written;
7111 total_written += written;
7115 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7116 total_written, code);
7118 /* set the packet data length to 3 bytes for the data block header,
7119 * plus the size of the data.
7121 smb_SetSMBParm(outp, 0, total_written);
7122 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7123 smb_SetSMBParm(outp, 3, hint);
7124 smb_SetSMBDataLength(outp, 0);
7127 smb_ReleaseFID(fidp);
7128 cm_ReleaseUser(userp);
7133 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7134 NCB *ncbp, raw_write_cont_t *rwcp)
7143 fd = smb_GetSMBParm(inp, 0);
7144 fidp = smb_FindFID(vcp, fd, 0);
7146 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7147 smb_CloseFID(vcp, fidp, NULL, 0);
7148 smb_ReleaseFID(fidp);
7152 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7153 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7155 userp = smb_GetUserFromVCP(vcp, inp);
7158 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7160 if (rwcp->writeMode & 0x1) { /* synchronous */
7163 smb_FormatResponsePacket(vcp, inp, outp);
7164 op = (smb_t *) outp;
7165 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7166 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7167 smb_SetSMBDataLength(outp, 0);
7168 smb_SendPacket(vcp, outp);
7169 smb_FreePacket(outp);
7171 else { /* asynchronous */
7172 lock_ObtainMutex(&fidp->mx);
7173 fidp->raw_writers--;
7174 if (fidp->raw_writers == 0)
7175 thrd_SetEvent(fidp->raw_write_event);
7176 lock_ReleaseMutex(&fidp->mx);
7179 /* Give back raw buffer */
7180 lock_ObtainMutex(&smb_RawBufLock);
7181 *((char **)rawBuf) = smb_RawBufs;
7182 smb_RawBufs = rawBuf;
7183 lock_ReleaseMutex(&smb_RawBufLock);
7185 smb_ReleaseFID(fidp);
7186 cm_ReleaseUser(userp);
7189 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7194 /* SMB_COM_WRITE_RAW */
7195 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7198 long count, written = 0, total_written = 0;
7202 smb_t *smbp = (smb_t*) inp;
7206 unsigned short writeMode;
7208 fd = smb_GetSMBParm(inp, 0);
7209 totalCount = smb_GetSMBParm(inp, 1);
7210 count = smb_GetSMBParm(inp, 10);
7211 writeMode = smb_GetSMBParm(inp, 7);
7213 op = (char *) inp->data;
7214 op += smb_GetSMBParm(inp, 11);
7216 offset.HighPart = 0;
7217 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7219 if (*inp->wctp == 14) {
7220 /* we received a 64-bit file offset */
7221 #ifdef AFS_LARGEFILES
7222 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7224 if (LargeIntegerLessThanZero(offset)) {
7226 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7227 offset.HighPart, offset.LowPart);
7228 return CM_ERROR_BADSMB;
7231 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7233 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7234 return CM_ERROR_BADSMB;
7237 offset.HighPart = 0;
7240 offset.HighPart = 0; /* 32-bit file offset */
7244 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7245 fd, offset.HighPart, offset.LowPart, count);
7247 " WriteRaw WriteMode 0x%x",
7250 fd = smb_ChainFID(fd, inp);
7251 fidp = smb_FindFID(vcp, fd, 0);
7253 return CM_ERROR_BADFD;
7256 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7257 smb_CloseFID(vcp, fidp, NULL, 0);
7258 smb_ReleaseFID(fidp);
7259 return CM_ERROR_NOSUCHFILE;
7265 LARGE_INTEGER LOffset;
7266 LARGE_INTEGER LLength;
7269 key = cm_GenerateKey(vcp->vcID, pid, fd);
7271 LOffset.HighPart = offset.HighPart;
7272 LOffset.LowPart = offset.LowPart;
7273 LLength.HighPart = 0;
7274 LLength.LowPart = count;
7276 lock_ObtainWrite(&fidp->scp->rw);
7277 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7278 lock_ReleaseWrite(&fidp->scp->rw);
7281 smb_ReleaseFID(fidp);
7286 userp = smb_GetUserFromVCP(vcp, inp);
7289 * Work around bug in NT client
7291 * When copying a file, the NT client should first copy the data,
7292 * then copy the last write time. But sometimes the NT client does
7293 * these in the wrong order, so the data copies would inadvertently
7294 * cause the last write time to be overwritten. We try to detect this,
7295 * and don't set client mod time if we think that would go against the
7298 lock_ObtainMutex(&fidp->mx);
7299 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7300 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7301 fidp->scp->clientModTime = time(NULL);
7303 lock_ReleaseMutex(&fidp->mx);
7306 while ( code == 0 && count > 0 ) {
7307 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7308 if (code == 0 && written == 0)
7309 code = CM_ERROR_PARTIALWRITE;
7311 offset = LargeIntegerAdd(offset,
7312 ConvertLongToLargeInteger(written));
7315 total_written += written;
7319 /* Get a raw buffer */
7322 lock_ObtainMutex(&smb_RawBufLock);
7324 /* Get a raw buf, from head of list */
7325 rawBuf = smb_RawBufs;
7326 smb_RawBufs = *(char **)smb_RawBufs;
7329 code = CM_ERROR_USESTD;
7331 lock_ReleaseMutex(&smb_RawBufLock);
7334 /* Don't allow a premature Close */
7335 if (code == 0 && (writeMode & 1) == 0) {
7336 lock_ObtainMutex(&fidp->mx);
7337 fidp->raw_writers++;
7338 thrd_ResetEvent(fidp->raw_write_event);
7339 lock_ReleaseMutex(&fidp->mx);
7342 smb_ReleaseFID(fidp);
7343 cm_ReleaseUser(userp);
7346 smb_SetSMBParm(outp, 0, total_written);
7347 smb_SetSMBDataLength(outp, 0);
7348 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7353 offset = LargeIntegerAdd(offset,
7354 ConvertLongToLargeInteger(count));
7358 rwcp->offset.HighPart = offset.HighPart;
7359 rwcp->offset.LowPart = offset.LowPart;
7360 rwcp->count = totalCount - count;
7361 rwcp->writeMode = writeMode;
7362 rwcp->alreadyWritten = total_written;
7364 /* set the packet data length to 3 bytes for the data block header,
7365 * plus the size of the data.
7367 smb_SetSMBParm(outp, 0, 0xffff);
7368 smb_SetSMBDataLength(outp, 0);
7374 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7377 long count, finalCount;
7381 smb_t *smbp = (smb_t*) inp;
7386 fd = smb_GetSMBParm(inp, 0);
7387 count = smb_GetSMBParm(inp, 1);
7388 offset.HighPart = 0; /* too bad */
7389 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7391 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7392 fd, offset.LowPart, count);
7394 fd = smb_ChainFID(fd, inp);
7395 fidp = smb_FindFID(vcp, fd, 0);
7397 return CM_ERROR_BADFD;
7399 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7400 smb_CloseFID(vcp, fidp, NULL, 0);
7401 smb_ReleaseFID(fidp);
7402 return CM_ERROR_NOSUCHFILE;
7405 lock_ObtainMutex(&fidp->mx);
7406 if (fidp->flags & SMB_FID_IOCTL) {
7407 lock_ReleaseMutex(&fidp->mx);
7408 code = smb_IoctlRead(fidp, vcp, inp, outp);
7409 smb_ReleaseFID(fidp);
7412 lock_ReleaseMutex(&fidp->mx);
7415 LARGE_INTEGER LOffset, LLength;
7419 key = cm_GenerateKey(vcp->vcID, pid, fd);
7421 LOffset.HighPart = 0;
7422 LOffset.LowPart = offset.LowPart;
7423 LLength.HighPart = 0;
7424 LLength.LowPart = count;
7426 lock_ObtainWrite(&fidp->scp->rw);
7427 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7428 lock_ReleaseWrite(&fidp->scp->rw);
7431 smb_ReleaseFID(fidp);
7435 userp = smb_GetUserFromVCP(vcp, inp);
7437 /* remember this for final results */
7438 smb_SetSMBParm(outp, 0, count);
7439 smb_SetSMBParm(outp, 1, 0);
7440 smb_SetSMBParm(outp, 2, 0);
7441 smb_SetSMBParm(outp, 3, 0);
7442 smb_SetSMBParm(outp, 4, 0);
7444 /* set the packet data length to 3 bytes for the data block header,
7445 * plus the size of the data.
7447 smb_SetSMBDataLength(outp, count+3);
7449 /* get op ptr after putting in the parms, since otherwise we don't
7450 * know where the data really is.
7452 op = smb_GetSMBData(outp, NULL);
7454 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7455 *op++ = 1; /* data block marker */
7456 *op++ = (unsigned char) (count & 0xff);
7457 *op++ = (unsigned char) ((count >> 8) & 0xff);
7459 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7461 /* fix some things up */
7462 smb_SetSMBParm(outp, 0, finalCount);
7463 smb_SetSMBDataLength(outp, finalCount+3);
7465 smb_ReleaseFID(fidp);
7467 cm_ReleaseUser(userp);
7471 /* SMB_COM_CREATE_DIRECTORY */
7472 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7474 clientchar_t *pathp;
7479 cm_scache_t *dscp; /* dir we're dealing with */
7480 cm_scache_t *scp; /* file we're creating */
7482 int initialModeBits;
7483 clientchar_t *lastNamep;
7485 clientchar_t *tidPathp;
7492 /* compute initial mode bits based on read-only flag in attributes */
7493 initialModeBits = 0777;
7495 tp = smb_GetSMBData(inp, NULL);
7496 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7498 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7499 return CM_ERROR_EXISTS;
7501 spacep = inp->spacep;
7502 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7504 userp = smb_GetUserFromVCP(vcp, inp);
7506 caseFold = CM_FLAG_CASEFOLD;
7508 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7510 cm_ReleaseUser(userp);
7511 return CM_ERROR_NOSUCHPATH;
7514 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7515 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7516 userp, tidPathp, &req, &dscp);
7519 cm_ReleaseUser(userp);
7524 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7525 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7526 cm_ReleaseSCache(dscp);
7527 cm_ReleaseUser(userp);
7528 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7529 return CM_ERROR_PATH_NOT_COVERED;
7531 return CM_ERROR_BADSHARENAME;
7533 #endif /* DFS_SUPPORT */
7535 /* otherwise, scp points to the parent directory. Do a lookup, and
7536 * fail if we find it. Otherwise, we do the create.
7542 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7543 if (scp) cm_ReleaseSCache(scp);
7544 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7545 if (code == 0) code = CM_ERROR_EXISTS;
7546 cm_ReleaseSCache(dscp);
7547 cm_ReleaseUser(userp);
7551 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7552 setAttr.clientModTime = time(NULL);
7553 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7554 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7555 smb_NotifyChange(FILE_ACTION_ADDED,
7556 FILE_NOTIFY_CHANGE_DIR_NAME,
7557 dscp, lastNamep, NULL, TRUE);
7559 /* we don't need this any longer */
7560 cm_ReleaseSCache(dscp);
7563 /* something went wrong creating or truncating the file */
7564 cm_ReleaseUser(userp);
7568 /* otherwise we succeeded */
7569 smb_SetSMBDataLength(outp, 0);
7570 cm_ReleaseUser(userp);
7575 BOOL smb_IsLegalFilename(clientchar_t *filename)
7578 * Find the longest substring of filename that does not contain
7579 * any of the chars in illegalChars. If that substring is less
7580 * than the length of the whole string, then one or more of the
7581 * illegal chars is in filename.
7583 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7589 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7590 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7592 clientchar_t *pathp;
7598 cm_scache_t *dscp; /* dir we're dealing with */
7599 cm_scache_t *scp; /* file we're creating */
7601 int initialModeBits;
7604 clientchar_t *lastNamep;
7607 clientchar_t *tidPathp;
7609 int created = 0; /* the file was new */
7614 excl = (inp->inCom == 0x03)? 0 : 1;
7616 attributes = smb_GetSMBParm(inp, 0);
7617 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7619 /* compute initial mode bits based on read-only flag in attributes */
7620 initialModeBits = 0666;
7621 if (attributes & SMB_ATTR_READONLY)
7622 initialModeBits &= ~0222;
7624 tp = smb_GetSMBData(inp, NULL);
7625 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7627 spacep = inp->spacep;
7628 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7630 userp = smb_GetUserFromVCP(vcp, inp);
7632 caseFold = CM_FLAG_CASEFOLD;
7634 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7636 cm_ReleaseUser(userp);
7637 return CM_ERROR_NOSUCHPATH;
7639 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7640 userp, tidPathp, &req, &dscp);
7643 cm_ReleaseUser(userp);
7648 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7649 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7650 cm_ReleaseSCache(dscp);
7651 cm_ReleaseUser(userp);
7652 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7653 return CM_ERROR_PATH_NOT_COVERED;
7655 return CM_ERROR_BADSHARENAME;
7657 #endif /* DFS_SUPPORT */
7659 /* otherwise, scp points to the parent directory. Do a lookup, and
7660 * truncate the file if we find it, otherwise we create the file.
7667 if (!smb_IsLegalFilename(lastNamep))
7668 return CM_ERROR_BADNTFILENAME;
7670 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
7671 #ifdef DEBUG_VERBOSE
7674 hexp = osi_HexifyString( lastNamep );
7675 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7680 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7681 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7682 cm_ReleaseSCache(dscp);
7683 cm_ReleaseUser(userp);
7687 /* if we get here, if code is 0, the file exists and is represented by
7688 * scp. Otherwise, we have to create it.
7692 /* oops, file shouldn't be there */
7693 cm_ReleaseSCache(dscp);
7694 cm_ReleaseSCache(scp);
7695 cm_ReleaseUser(userp);
7696 return CM_ERROR_EXISTS;
7699 setAttr.mask = CM_ATTRMASK_LENGTH;
7700 setAttr.length.LowPart = 0;
7701 setAttr.length.HighPart = 0;
7702 code = cm_SetAttr(scp, &setAttr, userp, &req);
7705 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7706 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7707 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7711 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7712 smb_NotifyChange(FILE_ACTION_ADDED,
7713 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7714 dscp, lastNamep, NULL, TRUE);
7715 } else if (!excl && code == CM_ERROR_EXISTS) {
7716 /* not an exclusive create, and someone else tried
7717 * creating it already, then we open it anyway. We
7718 * don't bother retrying after this, since if this next
7719 * fails, that means that the file was deleted after
7720 * we started this call.
7722 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7725 setAttr.mask = CM_ATTRMASK_LENGTH;
7726 setAttr.length.LowPart = 0;
7727 setAttr.length.HighPart = 0;
7728 code = cm_SetAttr(scp, &setAttr, userp, &req);
7733 /* we don't need this any longer */
7734 cm_ReleaseSCache(dscp);
7737 /* something went wrong creating or truncating the file */
7738 if (scp) cm_ReleaseSCache(scp);
7739 cm_ReleaseUser(userp);
7743 /* make sure we only open files */
7744 if (scp->fileType != CM_SCACHETYPE_FILE) {
7745 cm_ReleaseSCache(scp);
7746 cm_ReleaseUser(userp);
7747 return CM_ERROR_ISDIR;
7750 /* now all we have to do is open the file itself */
7751 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7752 osi_assertx(fidp, "null smb_fid_t");
7756 lock_ObtainMutex(&fidp->mx);
7757 /* always create it open for read/write */
7758 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7760 /* remember that the file was newly created */
7762 fidp->flags |= SMB_FID_CREATED;
7764 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7766 /* save a pointer to the vnode */
7768 lock_ObtainWrite(&scp->rw);
7769 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7770 lock_ReleaseWrite(&scp->rw);
7773 fidp->userp = userp;
7774 lock_ReleaseMutex(&fidp->mx);
7776 smb_SetSMBParm(outp, 0, fidp->fid);
7777 smb_SetSMBDataLength(outp, 0);
7779 cm_Open(scp, 0, userp);
7781 smb_ReleaseFID(fidp);
7782 cm_ReleaseUser(userp);
7783 /* leave scp held since we put it in fidp->scp */
7788 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7791 osi_hyper_t new_offset;
7802 fd = smb_GetSMBParm(inp, 0);
7803 whence = smb_GetSMBParm(inp, 1);
7804 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7806 /* try to find the file descriptor */
7807 fd = smb_ChainFID(fd, inp);
7808 fidp = smb_FindFID(vcp, fd, 0);
7810 return CM_ERROR_BADFD;
7812 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7813 smb_CloseFID(vcp, fidp, NULL, 0);
7814 smb_ReleaseFID(fidp);
7815 return CM_ERROR_NOSUCHFILE;
7818 lock_ObtainMutex(&fidp->mx);
7819 if (fidp->flags & SMB_FID_IOCTL) {
7820 lock_ReleaseMutex(&fidp->mx);
7821 smb_ReleaseFID(fidp);
7822 return CM_ERROR_BADFD;
7824 lock_ReleaseMutex(&fidp->mx);
7826 userp = smb_GetUserFromVCP(vcp, inp);
7828 lock_ObtainMutex(&fidp->mx);
7831 lock_ReleaseMutex(&fidp->mx);
7832 lock_ObtainWrite(&scp->rw);
7833 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7834 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7836 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7838 /* offset from current offset */
7839 new_offset = LargeIntegerAdd(fidp->offset,
7840 ConvertLongToLargeInteger(offset));
7842 else if (whence == 2) {
7843 /* offset from current EOF */
7844 new_offset = LargeIntegerAdd(scp->length,
7845 ConvertLongToLargeInteger(offset));
7847 new_offset = ConvertLongToLargeInteger(offset);
7850 fidp->offset = new_offset;
7851 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7852 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7853 smb_SetSMBDataLength(outp, 0);
7855 lock_ReleaseWrite(&scp->rw);
7856 smb_ReleaseFID(fidp);
7857 cm_ReleaseSCache(scp);
7858 cm_ReleaseUser(userp);
7862 /* dispatch all of the requests received in a packet. Due to chaining, this may
7863 * be more than one request.
7865 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7866 NCB *ncbp, raw_write_cont_t *rwcp)
7870 unsigned long code = 0;
7871 unsigned char *outWctp;
7872 int nparms; /* # of bytes of parameters */
7874 int nbytes; /* bytes of data, excluding count */
7877 unsigned short errCode;
7878 unsigned long NTStatus;
7880 unsigned char errClass;
7881 unsigned int oldGen;
7882 DWORD oldTime, newTime;
7884 /* get easy pointer to the data */
7885 smbp = (smb_t *) inp->data;
7887 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7888 /* setup the basic parms for the initial request in the packet */
7889 inp->inCom = smbp->com;
7890 inp->wctp = &smbp->wct;
7892 inp->ncb_length = ncbp->ncb_length;
7897 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7898 /* log it and discard it */
7899 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7900 __FILE__, __LINE__, ncbp->ncb_length);
7901 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7905 /* We are an ongoing op */
7906 thrd_Increment(&ongoingOps);
7908 /* set up response packet for receiving output */
7909 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7910 smb_FormatResponsePacket(vcp, inp, outp);
7911 outWctp = outp->wctp;
7913 /* Remember session generation number and time */
7914 oldGen = sessionGen;
7915 oldTime = GetTickCount();
7917 while (inp->inCom != 0xff) {
7918 dp = &smb_dispatchTable[inp->inCom];
7920 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7921 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7922 code = outp->resumeCode;
7926 /* process each request in the packet; inCom, wctp and inCount
7927 * are already set up.
7929 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7932 /* now do the dispatch */
7933 /* start by formatting the response record a little, as a default */
7934 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7936 outWctp[1] = 0xff; /* no operation */
7937 outWctp[2] = 0; /* padding */
7942 /* not a chained request, this is a more reasonable default */
7943 outWctp[0] = 0; /* wct of zero */
7944 outWctp[1] = 0; /* and bcc (word) of zero */
7948 /* once set, stays set. Doesn't matter, since we never chain
7949 * "no response" calls.
7951 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7955 /* we have a recognized operation */
7956 char * opName = myCrt_Dispatch(inp->inCom);
7958 if (inp->inCom == 0x1d)
7960 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7962 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
7963 opName,vcp,vcp->lana,vcp->lsn);
7964 code = (*(dp->procp)) (vcp, inp, outp);
7965 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
7966 code,vcp,vcp->lana,vcp->lsn);
7968 if ( code == CM_ERROR_BADSMB ||
7969 code == CM_ERROR_BADOP )
7971 #endif /* LOG_PACKET */
7974 newTime = GetTickCount();
7975 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
7977 if (oldGen != sessionGen) {
7978 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7979 newTime - oldTime, ncbp->ncb_length);
7980 osi_Log3(smb_logp, "Request %s straddled session startup, "
7981 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
7984 FreeSMBStrings(inp);
7986 /* bad opcode, fail the request, after displaying it */
7987 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7990 #endif /* LOG_PACKET */
7993 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7994 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7995 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7996 if (code == IDCANCEL)
7999 code = CM_ERROR_BADOP;
8002 /* catastrophic failure: log as much as possible */
8003 if (code == CM_ERROR_BADSMB) {
8004 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8008 #endif /* LOG_PACKET */
8009 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8012 code = CM_ERROR_INVAL;
8015 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8016 thrd_Decrement(&ongoingOps);
8021 /* now, if we failed, turn the current response into an empty
8022 * one, and fill in the response packet's error code.
8025 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8026 smb_MapNTError(code, &NTStatus);
8027 outWctp = outp->wctp;
8028 smbp = (smb_t *) &outp->data;
8029 if (code != CM_ERROR_PARTIALWRITE
8030 && code != CM_ERROR_BUFFERTOOSMALL
8031 && code != CM_ERROR_GSSCONTINUE) {
8032 /* nuke wct and bcc. For a partial
8033 * write or an in-process authentication handshake,
8034 * assume they're OK.
8040 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8041 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8042 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8043 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8044 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8048 smb_MapCoreError(code, vcp, &errCode, &errClass);
8049 outWctp = outp->wctp;
8050 smbp = (smb_t *) &outp->data;
8051 if (code != CM_ERROR_PARTIALWRITE) {
8052 /* nuke wct and bcc. For a partial
8053 * write, assume they're OK.
8059 smbp->errLow = (unsigned char) (errCode & 0xff);
8060 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8061 smbp->rcls = errClass;
8064 } /* error occurred */
8066 /* if we're here, we've finished one request. Look to see if
8067 * this is a chained opcode. If it is, setup things to process
8068 * the chained request, and setup the output buffer to hold the
8069 * chained response. Start by finding the next input record.
8071 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8072 break; /* not a chained req */
8073 tp = inp->wctp; /* points to start of last request */
8074 /* in a chained request, the first two
8075 * parm fields are required, and are
8076 * AndXCommand/AndXReserved and
8078 if (tp[0] < 2) break;
8079 if (tp[1] == 0xff) break; /* no more chained opcodes */
8081 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8084 /* and now append the next output request to the end of this
8085 * last request. Begin by finding out where the last response
8086 * ends, since that's where we'll put our new response.
8088 outWctp = outp->wctp; /* ptr to out parameters */
8089 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8090 nparms = outWctp[0] << 1;
8091 tp = outWctp + nparms + 1; /* now points to bcc field */
8092 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8093 tp += 2 /* for the count itself */ + nbytes;
8094 /* tp now points to the new output record; go back and patch the
8095 * second parameter (off2) to point to the new record.
8097 temp = (unsigned int)(tp - outp->data);
8098 outWctp[3] = (unsigned char) (temp & 0xff);
8099 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8100 outWctp[2] = 0; /* padding */
8101 outWctp[1] = inp->inCom; /* next opcode */
8103 /* finally, setup for the next iteration */
8106 } /* while loop over all requests in the packet */
8108 /* now send the output packet, and return */
8110 smb_SendPacket(vcp, outp);
8111 thrd_Decrement(&ongoingOps);
8116 /* Wait for Netbios() calls to return, and make the results available to server
8117 * threads. Note that server threads can't wait on the NCBevents array
8118 * themselves, because NCB events are manual-reset, and the servers would race
8119 * each other to reset them.
8121 void smb_ClientWaiter(void *parmp)
8126 while (smbShutdownFlag == 0) {
8127 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8129 if (code == WAIT_OBJECT_0)
8132 /* error checking */
8133 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8135 int abandonIdx = code - WAIT_ABANDONED_0;
8136 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8139 if (code == WAIT_IO_COMPLETION)
8141 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8145 if (code == WAIT_TIMEOUT)
8147 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8150 if (code == WAIT_FAILED)
8152 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8155 idx = code - WAIT_OBJECT_0;
8157 /* check idx range! */
8158 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8160 /* this is fatal - log as much as possible */
8161 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8162 osi_assertx(0, "invalid index");
8165 thrd_ResetEvent(NCBevents[idx]);
8166 thrd_SetEvent(NCBreturns[0][idx]);
8171 * Try to have one NCBRECV request waiting for every live session. Not more
8172 * than one, because if there is more than one, it's hard to handle Write Raw.
8174 void smb_ServerWaiter(void *parmp)
8177 int idx_session, idx_NCB;
8180 while (smbShutdownFlag == 0) {
8182 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8184 if (code == WAIT_OBJECT_0)
8187 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8189 int abandonIdx = code - WAIT_ABANDONED_0;
8190 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8193 if (code == WAIT_IO_COMPLETION)
8195 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8199 if (code == WAIT_TIMEOUT)
8201 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8204 if (code == WAIT_FAILED)
8206 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8209 idx_session = code - WAIT_OBJECT_0;
8211 /* check idx range! */
8212 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8214 /* this is fatal - log as much as possible */
8215 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8216 osi_assertx(0, "invalid index");
8221 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8223 if (code == WAIT_OBJECT_0) {
8224 if (smbShutdownFlag == 1)
8230 /* error checking */
8231 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8233 int abandonIdx = code - WAIT_ABANDONED_0;
8234 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8237 if (code == WAIT_IO_COMPLETION)
8239 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8243 if (code == WAIT_TIMEOUT)
8245 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8248 if (code == WAIT_FAILED)
8250 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8253 idx_NCB = code - WAIT_OBJECT_0;
8255 /* check idx range! */
8256 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8258 /* this is fatal - log as much as possible */
8259 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8260 osi_assertx(0, "invalid index");
8263 /* Link them together */
8264 NCBsessions[idx_NCB] = idx_session;
8267 ncbp = NCBs[idx_NCB];
8268 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8269 ncbp->ncb_command = NCBRECV | ASYNCH;
8270 ncbp->ncb_lana_num = lanas[idx_session];
8271 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8272 ncbp->ncb_event = NCBevents[idx_NCB];
8273 ncbp->ncb_length = SMB_PACKETSIZE;
8279 * The top level loop for handling SMB request messages. Each server thread
8280 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8281 * NCB and buffer for the incoming request are loaned to us.
8283 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8284 * to immediately send a request for the rest of the data. This must come
8285 * before any other traffic for that session, so we delay setting the session
8286 * event until that data has come in.
8288 void smb_Server(VOID *parmp)
8290 INT_PTR myIdx = (INT_PTR) parmp;
8294 smb_packet_t *outbufp;
8296 int idx_NCB, idx_session;
8298 smb_vc_t *vcp = NULL;
8300 extern void rx_StartClientThread(void);
8302 rx_StartClientThread();
8304 outncbp = smb_GetNCB();
8305 outbufp = smb_GetPacket();
8306 outbufp->ncbp = outncbp;
8314 smb_ResetServerPriority();
8316 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8319 /* terminate silently if shutdown flag is set */
8320 if (code == WAIT_OBJECT_0) {
8321 if (smbShutdownFlag == 1) {
8322 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8328 /* error checking */
8329 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8331 int abandonIdx = code - WAIT_ABANDONED_0;
8332 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8335 if (code == WAIT_IO_COMPLETION)
8337 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8341 if (code == WAIT_TIMEOUT)
8343 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8346 if (code == WAIT_FAILED)
8348 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8351 idx_NCB = code - WAIT_OBJECT_0;
8353 /* check idx range! */
8354 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8356 /* this is fatal - log as much as possible */
8357 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8358 osi_assertx(0, "invalid index");
8361 ncbp = NCBs[idx_NCB];
8362 idx_session = NCBsessions[idx_NCB];
8363 rc = ncbp->ncb_retcode;
8365 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8366 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8370 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8374 /* Can this happen? Or is it just my UNIX paranoia? */
8375 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8380 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8383 /* Client closed session */
8384 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8386 lock_ObtainMutex(&vcp->mx);
8387 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8388 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8390 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8391 lock_ReleaseMutex(&vcp->mx);
8392 lock_ObtainWrite(&smb_globalLock);
8393 dead_sessions[vcp->session] = TRUE;
8394 lock_ReleaseWrite(&smb_globalLock);
8396 lock_ReleaseMutex(&vcp->mx);
8398 smb_CleanupDeadVC(vcp);
8405 /* Treat as transient error */
8406 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8409 "dispatch smb recv failed, message incomplete, ncb_length %d",
8412 "SMB message incomplete, "
8413 "length %d", ncbp->ncb_length);
8416 * We used to discard the packet.
8417 * Instead, try handling it normally.
8421 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8425 /* A weird error code. Log it, sleep, and continue. */
8426 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8428 lock_ObtainMutex(&vcp->mx);
8429 if (vcp->errorCount++ > 3) {
8430 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8431 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8432 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8434 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8435 lock_ReleaseMutex(&vcp->mx);
8436 lock_ObtainWrite(&smb_globalLock);
8437 dead_sessions[vcp->session] = TRUE;
8438 lock_ReleaseWrite(&smb_globalLock);
8440 lock_ReleaseMutex(&vcp->mx);
8442 smb_CleanupDeadVC(vcp);
8448 lock_ReleaseMutex(&vcp->mx);
8452 thrd_SetEvent(SessionEvents[idx_session]);
8458 /* Success, so now dispatch on all the data in the packet */
8460 smb_concurrentCalls++;
8461 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8462 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8465 * If at this point vcp is NULL (implies that packet was invalid)
8466 * then we are in big trouble. This means either :
8467 * a) we have the wrong NCB.
8468 * b) Netbios screwed up the call.
8469 * c) The VC was already marked dead before we were able to
8471 * Obviously this implies that
8472 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8473 * lanas[idx_session] != ncbp->ncb_lana_num )
8474 * Either way, we can't do anything with this packet.
8475 * Log, sleep and resume.
8478 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8482 ncbp->ncb_lana_num);
8484 /* Also log in the trace log. */
8485 osi_Log4(smb_logp, "Server: VCP does not exist!"
8486 "LSNs[idx_session]=[%d],"
8487 "lanas[idx_session]=[%d],"
8488 "ncbp->ncb_lsn=[%d],"
8489 "ncbp->ncb_lana_num=[%d]",
8493 ncbp->ncb_lana_num);
8495 /* thrd_Sleep(1000); Don't bother sleeping */
8496 thrd_SetEvent(SessionEvents[idx_session]);
8497 smb_concurrentCalls--;
8501 smb_SetRequestStartTime();
8503 vcp->errorCount = 0;
8504 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8505 smbp = (smb_t *)bufp->data;
8512 if (smbp->com == 0x1d) {
8513 /* Special handling for Write Raw */
8514 raw_write_cont_t rwc;
8515 EVENT_HANDLE rwevent;
8516 char eventName[MAX_PATH];
8518 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8519 if (rwc.code == 0) {
8520 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8521 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8522 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8523 ncbp->ncb_command = NCBRECV | ASYNCH;
8524 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8525 ncbp->ncb_lana_num = vcp->lana;
8526 ncbp->ncb_buffer = rwc.buf;
8527 ncbp->ncb_length = 65535;
8528 ncbp->ncb_event = rwevent;
8530 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8531 thrd_CloseHandle(rwevent);
8533 thrd_SetEvent(SessionEvents[idx_session]);
8535 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8537 else if (smbp->com == 0xa0) {
8539 * Serialize the handling for NT Transact
8542 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8543 thrd_SetEvent(SessionEvents[idx_session]);
8545 thrd_SetEvent(SessionEvents[idx_session]);
8546 /* TODO: what else needs to be serialized? */
8547 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8551 __except( smb_ServerExceptionFilter() ) {
8555 smb_concurrentCalls--;
8558 thrd_SetEvent(NCBavails[idx_NCB]);
8563 smb_FreePacket(outbufp);
8565 smb_FreeNCB(outncbp);
8569 * Exception filter for the server threads. If an exception occurs in the
8570 * dispatch routines, which is where exceptions are most common, then do a
8571 * force trace and give control to upstream exception handlers. Useful for
8574 DWORD smb_ServerExceptionFilter(void) {
8575 /* While this is not the best time to do a trace, if it succeeds, then
8576 * we have a trace (assuming tracing was enabled). Otherwise, this should
8577 * throw a second exception.
8579 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8580 afsd_ForceTrace(TRUE);
8581 buf_ForceTrace(TRUE);
8582 return EXCEPTION_CONTINUE_SEARCH;
8586 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8587 * If the number of server threads is M, and the number of live sessions is
8588 * N, then the number of NCB's in use at any time either waiting for, or
8589 * holding, received messages is M + N, so that is how many NCB's get created.
8591 void InitNCBslot(int idx)
8593 struct smb_packet *bufp;
8594 EVENT_HANDLE retHandle;
8596 char eventName[MAX_PATH];
8598 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8600 NCBs[idx] = smb_GetNCB();
8601 sprintf(eventName,"NCBavails[%d]", idx);
8602 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8603 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8604 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8605 sprintf(eventName,"NCBevents[%d]", idx);
8606 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8607 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8608 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8609 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8610 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8611 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8612 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8613 for (i=0; i<smb_NumServerThreads; i++)
8614 NCBreturns[i][idx] = retHandle;
8615 bufp = smb_GetPacket();
8616 bufp->spacep = cm_GetSpace();
8620 /* listen for new connections */
8621 void smb_Listener(void *parmp)
8627 afs_uint32 session, thread;
8628 smb_vc_t *vcp = NULL;
8630 char rname[NCBNAMSZ+1];
8631 char cname[MAX_COMPUTERNAME_LENGTH+1];
8632 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8633 INT_PTR lana = (INT_PTR) parmp;
8634 char eventName[MAX_PATH];
8636 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
8637 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8638 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8639 thrd_ResetEvent(ListenerShutdown[lana]);
8641 ncbp = smb_GetNCB();
8643 /* retrieve computer name */
8644 GetComputerName(cname, &cnamelen);
8647 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8648 memset(ncbp, 0, sizeof(NCB));
8651 ncbp->ncb_command = NCBLISTEN;
8652 ncbp->ncb_rto = 0; /* No receive timeout */
8653 ncbp->ncb_sto = 0; /* No send timeout */
8655 /* pad out with spaces instead of null termination */
8656 len = (long)strlen(smb_localNamep);
8657 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8658 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8660 strcpy(ncbp->ncb_callname, "*");
8661 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8663 ncbp->ncb_lana_num = (UCHAR)lana;
8665 code = Netbios(ncbp);
8667 if (code == NRC_NAMERR) {
8668 /* An smb shutdown or Vista resume must have taken place */
8670 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8671 ncbp->ncb_lana_num, code);
8673 if (lock_TryMutex(&smb_StartedLock)) {
8674 lana_list.lana[i] = LANA_INVALID;
8675 lock_ReleaseMutex(&smb_StartedLock);
8678 } else if (code == NRC_BRIDGE || code != 0) {
8679 int lanaRemaining = 0;
8681 while (!lock_TryMutex(&smb_StartedLock)) {
8682 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8688 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8689 ncbp->ncb_lana_num, ncb_error_string(code));
8691 for (i = 0; i < lana_list.length; i++) {
8692 if (lana_list.lana[i] == lana) {
8693 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8694 lana_list.lana[i] = LANA_INVALID;
8696 if (lana_list.lana[i] != LANA_INVALID)
8700 if (lanaRemaining == 0) {
8701 cm_VolStatus_Network_Stopped(cm_NetbiosName
8706 smb_ListenerState = SMB_LISTENER_STOPPED;
8707 smb_LANadapter = LANA_INVALID;
8708 lana_list.length = 0;
8710 lock_ReleaseMutex(&smb_StartedLock);
8714 else if (code != 0) {
8715 char tbuffer[AFSPATHMAX];
8717 /* terminate silently if shutdown flag is set */
8718 while (!lock_TryMutex(&smb_StartedLock)) {
8719 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8725 "NCBLISTEN lana=%d failed with code %d [%s]",
8726 ncbp->ncb_lana_num, code, ncb_error_string(code));
8728 "Client exiting due to network failure. Please restart client.\n");
8731 "Client exiting due to network failure. Please restart client.\n"
8732 "NCBLISTEN lana=%d failed with code %d [%s]",
8733 ncbp->ncb_lana_num, code, ncb_error_string(code));
8735 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8736 MB_OK|MB_SERVICE_NOTIFICATION);
8737 osi_panic(tbuffer, __FILE__, __LINE__);
8739 lock_ReleaseMutex(&smb_StartedLock);
8744 /* check for remote conns */
8745 /* first get remote name and insert null terminator */
8746 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8747 for (i=NCBNAMSZ; i>0; i--) {
8748 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8754 /* compare with local name */
8756 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8757 flags |= SMB_VCFLAG_REMOTECONN;
8760 lock_ObtainMutex(&smb_ListenerLock);
8762 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8763 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8765 /* now ncbp->ncb_lsn is the connection ID */
8766 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8767 if (vcp->session == 0) {
8768 /* New generation */
8769 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8772 /* Log session startup */
8774 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8775 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8776 #endif /* NOTSERVICE */
8777 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8778 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8780 if (reportSessionStartups) {
8781 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8784 lock_ObtainMutex(&vcp->mx);
8785 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
8786 vcp->flags |= flags;
8787 lock_ReleaseMutex(&vcp->mx);
8789 /* Allocate slot in session arrays */
8790 /* Re-use dead session if possible, otherwise add one more */
8791 /* But don't look at session[0], it is reserved */
8792 lock_ObtainWrite(&smb_globalLock);
8793 for (session = 1; session < numSessions; session++) {
8794 if (dead_sessions[session]) {
8795 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8796 dead_sessions[session] = FALSE;
8800 lock_ReleaseWrite(&smb_globalLock);
8802 /* We are re-using an existing VC because the lsn and lana
8804 session = vcp->session;
8806 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8808 /* Log session startup */
8810 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8811 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8812 #endif /* NOTSERVICE */
8813 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8814 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8816 if (reportSessionStartups) {
8817 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8821 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8822 unsigned long code = CM_ERROR_ALLBUSY;
8823 smb_packet_t * outp = smb_GetPacket();
8824 unsigned char *outWctp;
8827 smb_FormatResponsePacket(vcp, NULL, outp);
8830 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8831 unsigned long NTStatus;
8832 smb_MapNTError(code, &NTStatus);
8833 outWctp = outp->wctp;
8834 smbp = (smb_t *) &outp->data;
8838 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8839 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8840 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8841 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8842 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8844 unsigned short errCode;
8845 unsigned char errClass;
8846 smb_MapCoreError(code, vcp, &errCode, &errClass);
8847 outWctp = outp->wctp;
8848 smbp = (smb_t *) &outp->data;
8852 smbp->errLow = (unsigned char) (errCode & 0xff);
8853 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8854 smbp->rcls = errClass;
8857 smb_SendPacket(vcp, outp);
8858 smb_FreePacket(outp);
8860 lock_ObtainMutex(&vcp->mx);
8861 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8862 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8864 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8865 lock_ReleaseMutex(&vcp->mx);
8866 lock_ObtainWrite(&smb_globalLock);
8867 dead_sessions[vcp->session] = TRUE;
8868 lock_ReleaseWrite(&smb_globalLock);
8869 smb_CleanupDeadVC(vcp);
8871 lock_ReleaseMutex(&vcp->mx);
8874 /* assert that we do not exceed the maximum number of sessions or NCBs.
8875 * we should probably want to wait for a session to be freed in case
8878 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8879 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8881 lock_ObtainMutex(&vcp->mx);
8882 vcp->session = session;
8883 lock_ReleaseMutex(&vcp->mx);
8884 lock_ObtainWrite(&smb_globalLock);
8885 LSNs[session] = ncbp->ncb_lsn;
8886 lanas[session] = ncbp->ncb_lana_num;
8887 lock_ReleaseWrite(&smb_globalLock);
8889 if (session == numSessions) {
8890 /* Add new NCB for new session */
8891 char eventName[MAX_PATH];
8893 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8895 InitNCBslot(numNCBs);
8896 lock_ObtainWrite(&smb_globalLock);
8898 lock_ReleaseWrite(&smb_globalLock);
8899 thrd_SetEvent(NCBavails[0]);
8900 thrd_SetEvent(NCBevents[0]);
8901 for (thread = 0; thread < smb_NumServerThreads; thread++)
8902 thrd_SetEvent(NCBreturns[thread][0]);
8903 /* Also add new session event */
8904 sprintf(eventName, "SessionEvents[%d]", session);
8905 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8906 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8907 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8908 lock_ObtainWrite(&smb_globalLock);
8910 lock_ReleaseWrite(&smb_globalLock);
8911 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8912 thrd_SetEvent(SessionEvents[0]);
8914 thrd_SetEvent(SessionEvents[session]);
8920 lock_ReleaseMutex(&smb_ListenerLock);
8921 } /* dispatch while loop */
8925 thrd_SetEvent(ListenerShutdown[lana]);
8930 smb_LanAdapterChangeThread(void *param)
8933 * Give the IPAddrDaemon thread a chance
8934 * to block before we trigger.
8937 smb_LanAdapterChange(0);
8940 void smb_SetLanAdapterChangeDetected(void)
8945 lock_ObtainMutex(&smb_StartedLock);
8947 if (!powerStateSuspended) {
8948 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
8949 NULL, 0, &lpid, "smb_LanAdapterChange");
8950 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
8951 thrd_CloseHandle(phandle);
8954 smb_LanAdapterChangeDetected = 1;
8955 lock_ReleaseMutex(&smb_StartedLock);
8958 void smb_LanAdapterChange(int locked) {
8959 lana_number_t lanaNum;
8961 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
8963 LANA_ENUM temp_list;
8968 afsi_log("smb_LanAdapterChange");
8971 lock_ObtainMutex(&smb_StartedLock);
8973 smb_LanAdapterChangeDetected = 0;
8975 if (!powerStateSuspended &&
8976 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
8977 LANA_NETBIOS_NAME_FULL)) &&
8978 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
8979 if ( isGateway != bGateway ||
8980 strcmp(cm_NetbiosName, NetbiosName) ) {
8983 NCB *ncbp = smb_GetNCB();
8984 ncbp->ncb_command = NCBENUM;
8985 ncbp->ncb_buffer = (PUCHAR)&temp_list;
8986 ncbp->ncb_length = sizeof(temp_list);
8987 code = Netbios(ncbp);
8989 if (temp_list.length != lana_list.length)
8992 for (i=0; i<lana_list.length; i++) {
8993 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9005 afsi_log("Lan Adapter Change detected");
9006 smb_StopListeners(1);
9007 smb_RestartListeners(1);
9010 lock_ReleaseMutex(&smb_StartedLock);
9013 /* initialize Netbios */
9014 int smb_NetbiosInit(int locked)
9017 int i, lana, code, l;
9019 int delname_tried=0;
9022 lana_number_t lanaNum;
9025 lock_ObtainMutex(&smb_StartedLock);
9027 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9028 smb_ListenerState != SMB_LISTENER_STOPPED) {
9031 lock_ReleaseMutex(&smb_StartedLock);
9034 /* setup the NCB system */
9035 ncbp = smb_GetNCB();
9037 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9038 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9039 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9041 if (smb_LANadapter != LANA_INVALID)
9042 afsi_log("LAN adapter number %d", smb_LANadapter);
9044 afsi_log("LAN adapter number not determined");
9047 afsi_log("Set for gateway service");
9049 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9051 /* something went horribly wrong. We can't proceed without a netbios name */
9053 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9054 osi_panic(buf, __FILE__, __LINE__);
9057 /* remember the name */
9058 len = (int)strlen(cm_NetbiosName);
9060 free(smb_localNamep);
9061 smb_localNamep = malloc(len+1);
9062 strcpy(smb_localNamep, cm_NetbiosName);
9063 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9065 /* Also copy the value to the client character encoded string */
9066 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9068 if (smb_LANadapter == LANA_INVALID) {
9069 ncbp->ncb_command = NCBENUM;
9070 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9071 ncbp->ncb_length = sizeof(lana_list);
9072 code = Netbios(ncbp);
9074 afsi_log("Netbios NCBENUM error code %d", code);
9075 osi_panic(s, __FILE__, __LINE__);
9079 lana_list.length = 1;
9080 lana_list.lana[0] = smb_LANadapter;
9083 for (i = 0; i < lana_list.length; i++) {
9084 /* reset the adaptor: in Win32, this is required for every process, and
9085 * acts as an init call, not as a real hardware reset.
9087 ncbp->ncb_command = NCBRESET;
9088 ncbp->ncb_callname[0] = 100;
9089 ncbp->ncb_callname[2] = 100;
9090 ncbp->ncb_lana_num = lana_list.lana[i];
9091 code = Netbios(ncbp);
9093 code = ncbp->ncb_retcode;
9095 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9096 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9098 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9102 /* and declare our name so we can receive connections */
9103 memset(ncbp, 0, sizeof(*ncbp));
9104 len=lstrlen(smb_localNamep);
9105 memset(smb_sharename,' ',NCBNAMSZ);
9106 memcpy(smb_sharename,smb_localNamep,len);
9107 afsi_log("lana_list.length %d", lana_list.length);
9109 /* Keep the name so we can unregister it later */
9110 for (l = 0; l < lana_list.length; l++) {
9111 lana = lana_list.lana[l];
9113 ncbp->ncb_command = NCBADDNAME;
9114 ncbp->ncb_lana_num = lana;
9115 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9116 code = Netbios(ncbp);
9118 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9119 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9121 char name[NCBNAMSZ+1];
9123 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9124 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9128 code = ncbp->ncb_retcode;
9131 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9134 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9135 if (code == NRC_BRIDGE) { /* invalid LANA num */
9136 lana_list.lana[l] = LANA_INVALID;
9139 else if (code == NRC_DUPNAME) {
9140 afsi_log("Name already exists; try to delete it");
9141 memset(ncbp, 0, sizeof(*ncbp));
9142 ncbp->ncb_command = NCBDELNAME;
9143 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9144 ncbp->ncb_lana_num = lana;
9145 code = Netbios(ncbp);
9147 code = ncbp->ncb_retcode;
9149 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9151 if (code != 0 || delname_tried) {
9152 lana_list.lana[l] = LANA_INVALID;
9154 else if (code == 0) {
9155 if (!delname_tried) {
9163 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9164 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9168 smb_LANadapter = lana;
9169 lana_found = 1; /* at least one worked */
9173 osi_assertx(lana_list.length >= 0, "empty lana list");
9175 afsi_log("No valid LANA numbers found!");
9176 lana_list.length = 0;
9177 smb_LANadapter = LANA_INVALID;
9178 smb_ListenerState = SMB_LISTENER_STOPPED;
9179 cm_VolStatus_Network_Stopped(cm_NetbiosName
9186 /* we're done with the NCB now */
9189 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9190 if (lana_list.length > 0)
9191 osi_assert(smb_LANadapter != LANA_INVALID);
9194 lock_ReleaseMutex(&smb_StartedLock);
9196 return (lana_list.length > 0 ? 1 : 0);
9199 void smb_StartListeners(int locked)
9206 lock_ObtainMutex(&smb_StartedLock);
9208 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9210 lock_ReleaseMutex(&smb_StartedLock);
9214 afsi_log("smb_StartListeners");
9215 smb_ListenerState = SMB_LISTENER_STARTED;
9216 cm_VolStatus_Network_Started(cm_NetbiosName
9222 for (i = 0; i < lana_list.length; i++) {
9223 if (lana_list.lana[i] == LANA_INVALID)
9225 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9226 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9227 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9228 thrd_CloseHandle(phandle);
9231 lock_ReleaseMutex(&smb_StartedLock);
9234 void smb_RestartListeners(int locked)
9237 lock_ObtainMutex(&smb_StartedLock);
9239 if (powerStateSuspended)
9240 afsi_log("smb_RestartListeners called while suspended");
9242 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9243 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9244 if (smb_NetbiosInit(1))
9245 smb_StartListeners(1);
9246 } else if (smb_LanAdapterChangeDetected) {
9247 smb_LanAdapterChange(1);
9251 lock_ReleaseMutex(&smb_StartedLock);
9254 void smb_StopListener(NCB *ncbp, int lana, int wait)
9258 memset(ncbp, 0, sizeof(*ncbp));
9259 ncbp->ncb_command = NCBDELNAME;
9260 ncbp->ncb_lana_num = lana;
9261 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9262 code = Netbios(ncbp);
9264 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9265 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9267 /* and then reset the LANA; this will cause the listener threads to exit */
9268 ncbp->ncb_command = NCBRESET;
9269 ncbp->ncb_callname[0] = 100;
9270 ncbp->ncb_callname[2] = 100;
9271 ncbp->ncb_lana_num = lana;
9272 code = Netbios(ncbp);
9274 code = ncbp->ncb_retcode;
9276 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
9278 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
9282 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9285 void smb_StopListeners(int locked)
9291 lock_ObtainMutex(&smb_StartedLock);
9293 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9295 lock_ReleaseMutex(&smb_StartedLock);
9299 afsi_log("smb_StopListeners");
9300 smb_ListenerState = SMB_LISTENER_STOPPED;
9301 cm_VolStatus_Network_Stopped(cm_NetbiosName
9307 ncbp = smb_GetNCB();
9309 /* Unregister the SMB name */
9310 for (l = 0; l < lana_list.length; l++) {
9311 lana = lana_list.lana[l];
9313 if (lana != LANA_INVALID) {
9314 smb_StopListener(ncbp, lana, TRUE);
9316 /* mark the adapter invalid */
9317 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9321 /* force a re-evaluation of the network adapters */
9322 lana_list.length = 0;
9323 smb_LANadapter = LANA_INVALID;
9326 lock_ReleaseMutex(&smb_StartedLock);
9329 void smb_Init(osi_log_t *logp, int useV3,
9339 EVENT_HANDLE retHandle;
9340 char eventName[MAX_PATH];
9341 int startListeners = 0;
9343 smb_TlsRequestSlot = TlsAlloc();
9345 smb_MBfunc = aMBfunc;
9349 /* Initialize smb_localZero */
9350 myTime.tm_isdst = -1; /* compute whether on DST or not */
9351 myTime.tm_year = 70;
9357 smb_localZero = mktime(&myTime);
9359 #ifndef USE_NUMERIC_TIME_CONV
9360 /* Initialize kludge-GMT */
9361 smb_CalculateNowTZ();
9362 #endif /* USE_NUMERIC_TIME_CONV */
9363 #ifdef AFS_FREELANCE_CLIENT
9364 /* Make sure the root.afs volume has the correct time */
9365 cm_noteLocalMountPointChange();
9368 /* initialize the remote debugging log */
9371 /* and the global lock */
9372 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
9373 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
9375 /* Raw I/O data structures */
9376 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
9378 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
9379 lock_InitializeMutex(&smb_StartedLock, "smb started lock");
9381 /* 4 Raw I/O buffers */
9382 smb_RawBufs = calloc(65536,1);
9383 *((char **)smb_RawBufs) = NULL;
9384 for (i=0; i<3; i++) {
9385 char *rawBuf = calloc(65536,1);
9386 *((char **)rawBuf) = smb_RawBufs;
9387 smb_RawBufs = rawBuf;
9390 /* global free lists */
9391 smb_ncbFreeListp = NULL;
9392 smb_packetFreeListp = NULL;
9394 lock_ObtainMutex(&smb_StartedLock);
9395 startListeners = smb_NetbiosInit(1);
9397 /* Initialize listener and server structures */
9399 memset(dead_sessions, 0, sizeof(dead_sessions));
9400 sprintf(eventName, "SessionEvents[0]");
9401 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9402 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9403 afsi_log("Event Object Already Exists: %s", eventName);
9405 smb_NumServerThreads = nThreads;
9406 sprintf(eventName, "NCBavails[0]");
9407 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9408 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9409 afsi_log("Event Object Already Exists: %s", eventName);
9410 sprintf(eventName, "NCBevents[0]");
9411 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9412 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9413 afsi_log("Event Object Already Exists: %s", eventName);
9414 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9415 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9416 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9417 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9418 afsi_log("Event Object Already Exists: %s", eventName);
9419 for (i = 0; i < smb_NumServerThreads; i++) {
9420 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9421 NCBreturns[i][0] = retHandle;
9424 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9425 for (i = 0; i < smb_NumServerThreads; i++) {
9426 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9427 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9428 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9429 afsi_log("Event Object Already Exists: %s", eventName);
9430 InitNCBslot((int)(i+1));
9432 numNCBs = smb_NumServerThreads + 1;
9434 /* Initialize dispatch table */
9435 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9436 /* Prepare the table for unknown operations */
9437 for(i=0; i<= SMB_NOPCODES; i++) {
9438 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9440 /* Fill in the ones we do know */
9441 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9442 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9443 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9444 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9445 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9446 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9447 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9448 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9449 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9450 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9451 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9452 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9453 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9454 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9455 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9456 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9457 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9458 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9459 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9460 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9461 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9462 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9463 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9464 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9465 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9466 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9467 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9468 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9469 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9470 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9471 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9472 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9473 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9474 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9475 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9476 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9477 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9478 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9479 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9480 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9481 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9482 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9483 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9484 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9485 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9486 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9487 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9488 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9489 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9490 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9491 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9492 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9493 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9494 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9495 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9496 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9497 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9498 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9499 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9500 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9501 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9502 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9503 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9504 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9505 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9506 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9507 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9508 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9509 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9510 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9511 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9512 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9513 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9514 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9516 /* setup tran 2 dispatch table */
9517 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9518 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9519 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9520 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9521 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9522 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9523 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9524 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9525 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9526 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9527 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9528 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9529 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9530 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9531 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9532 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9533 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9534 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9536 /* setup the rap dispatch table */
9537 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9538 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9539 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9540 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9541 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9545 /* if we are doing SMB authentication we have register outselves as a logon process */
9546 if (smb_authType != SMB_AUTH_NONE) {
9547 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9548 LSA_STRING afsProcessName;
9549 LSA_OPERATIONAL_MODE dummy; /*junk*/
9551 afsProcessName.Buffer = "OpenAFSClientDaemon";
9552 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9553 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9555 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9557 if (nts == STATUS_SUCCESS) {
9558 LSA_STRING packageName;
9559 /* we are registered. Find out the security package id */
9560 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9561 packageName.Length = (USHORT)strlen(packageName.Buffer);
9562 packageName.MaximumLength = packageName.Length + 1;
9563 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9564 if (nts == STATUS_SUCCESS) {
9566 * This code forces Windows to authenticate against the Logon Cache
9567 * first instead of attempting to authenticate against the Domain
9568 * Controller. When the Windows logon cache is enabled this improves
9569 * performance by removing the network access and works around a bug
9570 * seen at sites which are using a MIT Kerberos principal to login
9571 * to machines joined to a non-root domain in a multi-domain forest.
9572 * MsV1_0SetProcessOption was added in Windows XP.
9574 PVOID pResponse = NULL;
9575 ULONG cbResponse = 0;
9576 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9578 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9579 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9580 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9581 OptionsRequest.DisableOptions = FALSE;
9583 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9586 sizeof(OptionsRequest),
9592 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9593 char message[AFSPATHMAX];
9594 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9596 OutputDebugString(message);
9599 OutputDebugString("MsV1_0SetProcessOption success");
9600 afsi_log("MsV1_0SetProcessOption success");
9602 /* END - code from Larry */
9604 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9605 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9606 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9608 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9610 /* something went wrong. We report the error and revert back to no authentication
9611 because we can't perform any auth requests without a successful lsa handle
9612 or sec package id. */
9613 afsi_log("Reverting to NO SMB AUTH");
9614 smb_authType = SMB_AUTH_NONE;
9617 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9619 /* something went wrong. We report the error and revert back to no authentication
9620 because we can't perform any auth requests without a successful lsa handle
9621 or sec package id. */
9622 afsi_log("Reverting to NO SMB AUTH");
9623 smb_authType = SMB_AUTH_NONE;
9627 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9628 * time prevents the failure of authentication when logged into Windows with an
9629 * external Kerberos principal mapped to a local account.
9631 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9632 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9633 * then the only option is NTLMSSP anyway; so just fallback.
9638 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9639 if (secBlobLength == 0) {
9640 smb_authType = SMB_AUTH_NTLM;
9641 afsi_log("Reverting to SMB AUTH NTLM");
9650 /* Now get ourselves a domain name. */
9651 /* For now we are using the local computer name as the domain name.
9652 * It is actually the domain for local logins, and we are acting as
9653 * a local SMB server.
9655 bufsize = lengthof(smb_ServerDomainName) - 1;
9656 GetComputerNameW(smb_ServerDomainName, &bufsize);
9657 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9658 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
9661 /* Start listeners, waiters, servers, and daemons */
9663 smb_StartListeners(1);
9665 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9666 NULL, 0, &lpid, "smb_ClientWaiter");
9667 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9668 thrd_CloseHandle(phandle);
9670 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9671 NULL, 0, &lpid, "smb_ServerWaiter");
9672 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9673 thrd_CloseHandle(phandle);
9675 for (i=0; i<smb_NumServerThreads; i++) {
9676 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9677 (void *) i, 0, &lpid, "smb_Server");
9678 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9679 thrd_CloseHandle(phandle);
9682 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9683 NULL, 0, &lpid, "smb_Daemon");
9684 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9685 thrd_CloseHandle(phandle);
9687 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9688 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9689 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9690 thrd_CloseHandle(phandle);
9692 lock_ReleaseMutex(&smb_StartedLock);
9696 void smb_Shutdown(void)
9703 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9705 /* setup the NCB system */
9706 ncbp = smb_GetNCB();
9708 /* Block new sessions by setting shutdown flag */
9709 smbShutdownFlag = 1;
9711 /* Hang up all sessions */
9712 memset((char *)ncbp, 0, sizeof(NCB));
9713 for (i = 1; i < numSessions; i++)
9715 if (dead_sessions[i])
9718 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9719 ncbp->ncb_command = NCBHANGUP;
9720 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9721 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9722 code = Netbios(ncbp);
9723 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9724 if (code == 0) code = ncbp->ncb_retcode;
9726 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9727 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9731 /* Trigger the shutdown of all SMB threads */
9732 for (i = 0; i < smb_NumServerThreads; i++)
9733 thrd_SetEvent(NCBreturns[i][0]);
9735 thrd_SetEvent(NCBevents[0]);
9736 thrd_SetEvent(SessionEvents[0]);
9737 thrd_SetEvent(NCBavails[0]);
9739 for (i = 0;i < smb_NumServerThreads; i++) {
9740 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9741 if (code == WAIT_OBJECT_0) {
9744 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9745 thrd_SetEvent(NCBreturns[i--][0]);
9749 /* Delete Netbios name */
9750 memset((char *)ncbp, 0, sizeof(NCB));
9751 for (i = 0; i < lana_list.length; i++) {
9752 if (lana_list.lana[i] == LANA_INVALID) continue;
9753 ncbp->ncb_command = NCBDELNAME;
9754 ncbp->ncb_lana_num = lana_list.lana[i];
9755 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9756 code = Netbios(ncbp);
9758 code = ncbp->ncb_retcode;
9760 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9761 ncbp->ncb_lana_num, code);
9766 /* Release the reference counts held by the VCs */
9767 lock_ObtainWrite(&smb_rctLock);
9768 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9773 if (vcp->magic != SMB_VC_MAGIC)
9774 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9775 __FILE__, __LINE__);
9777 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9779 if (fidp->scp != NULL) {
9782 lock_ObtainMutex(&fidp->mx);
9783 if (fidp->scp != NULL) {
9786 lock_ObtainWrite(&scp->rw);
9787 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9788 lock_ReleaseWrite(&scp->rw);
9789 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9790 cm_ReleaseSCache(scp);
9792 lock_ReleaseMutex(&fidp->mx);
9796 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9798 smb_ReleaseVCNoLock(tidp->vcp);
9800 cm_user_t *userp = tidp->userp;
9802 cm_ReleaseUser(userp);
9806 lock_ReleaseWrite(&smb_rctLock);
9808 TlsFree(smb_TlsRequestSlot);
9811 /* Get the UNC \\<servername>\<sharename> prefix. */
9812 char *smb_GetSharename()
9817 /* Make sure we have been properly initialized. */
9818 if (smb_localNamep == NULL)
9821 /* Allocate space for \\<servername>\<sharename>, plus the
9824 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
9826 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
9832 void smb_LogPacket(smb_packet_t *packet)
9836 unsigned length, paramlen, datalen, i, j;
9838 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9840 if (!packet) return;
9842 osi_Log0(smb_logp, "*** SMB packet dump ***");
9844 smbp = (smb_t *) packet->data;
9845 vp = (BYTE *) packet->data;
9847 paramlen = smbp->wct * 2;
9848 datalen = *((WORD *) (smbp->vdata + paramlen));
9849 length = sizeof(*smbp) + paramlen + 1 + datalen;
9851 for (i=0;i < length; i+=16)
9853 memset( buf, ' ', 80 );
9858 buf[strlen(buf)] = ' ';
9860 cp = (BYTE*) buf + 7;
9862 for (j=0;j < 16 && (i+j)<length; j++)
9864 *(cp++) = hex[vp[i+j] >> 4];
9865 *(cp++) = hex[vp[i+j] & 0xf];
9875 for (j=0;j < 16 && (i+j)<length;j++)
9877 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9888 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9891 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9893 #endif /* LOG_PACKET */
9896 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9904 lock_ObtainRead(&smb_rctLock);
9906 sprintf(output, "begin dumping smb_vc_t\r\n");
9907 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9909 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9913 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9914 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9915 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9917 sprintf(output, "begin dumping smb_fid_t\r\n");
9918 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9920 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9922 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n",
9923 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9924 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
9925 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
9926 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9929 sprintf(output, "done dumping smb_fid_t\r\n");
9930 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9933 sprintf(output, "done dumping smb_vc_t\r\n");
9934 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9936 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9937 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9939 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9943 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9944 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9945 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9947 sprintf(output, "begin dumping smb_fid_t\r\n");
9948 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9950 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9952 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n",
9953 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9954 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
9955 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
9956 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9959 sprintf(output, "done dumping smb_fid_t\r\n");
9960 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9963 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9964 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9967 lock_ReleaseRead(&smb_rctLock);
9971 long smb_IsNetworkStarted(void)
9974 lock_ObtainWrite(&smb_globalLock);
9975 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
9976 lock_ReleaseWrite(&smb_globalLock);