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);
1698 smb_ReleaseVCNoLock(vcp);
1702 lock_ReleaseMutex(&fidp->mx);
1704 lock_ReleaseWrite(&smb_rctLock);
1706 /* now release the scache structure */
1708 cm_ReleaseSCache(scp);
1711 cm_ReleaseUser(userp);
1715 * Case-insensitive search for one string in another;
1716 * used to find variable names in submount pathnames.
1718 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1720 clientchar_t *cursor;
1722 for (cursor = str1; *cursor; cursor++)
1723 if (cm_ClientStrCmpI(cursor, str2) == 0)
1730 * Substitute a variable value for its name in a submount pathname. Variable
1731 * name has been identified by smb_stristr() and is in substr. Variable name
1732 * length (plus one) is in substr_size. Variable value is in newstr.
1734 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1735 unsigned int substr_size, clientchar_t *newstr)
1737 clientchar_t temp[1024];
1739 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1740 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1741 cm_ClientStrCat(str1, cchstr1, temp);
1744 clientchar_t VNUserName[] = _C("%USERNAME%");
1745 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1746 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1747 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1749 typedef struct smb_findShare_rock {
1750 clientchar_t * shareName;
1751 clientchar_t * match;
1753 } smb_findShare_rock_t;
1755 #define SMB_FINDSHARE_EXACT_MATCH 1
1756 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1758 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1762 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1763 normchar_t normName[MAX_PATH];
1765 cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
1767 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1768 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1769 matchType = SMB_FINDSHARE_EXACT_MATCH;
1771 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1772 if(vrock->match) free(vrock->match);
1773 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1774 vrock->matchType = matchType;
1776 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1777 return CM_ERROR_STOPNOW;
1783 /* find a shareName in the table of submounts */
1784 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1785 clientchar_t *shareName,
1786 clientchar_t **pathNamep)
1790 clientchar_t pathName[1024];
1793 clientchar_t *p, *q;
1794 fschar_t *cellname = NULL;
1797 DWORD allSubmount = 1;
1799 /* if allSubmounts == 0, only return the //mountRoot/all share
1800 * if in fact it has been been created in the subMounts table.
1801 * This is to allow sites that want to restrict access to the
1804 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1805 0, KEY_QUERY_VALUE, &parmKey);
1806 if (code == ERROR_SUCCESS) {
1807 cblen = sizeof(allSubmount);
1808 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1809 (BYTE *) &allSubmount, &cblen);
1810 if (code != ERROR_SUCCESS) {
1813 RegCloseKey (parmKey);
1816 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1821 /* In case, the all share is disabled we need to still be able
1822 * to handle ioctl requests
1824 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1825 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1829 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1830 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1831 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1832 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1833 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1839 /* Check for volume references
1841 * They look like <cell>{%,#}<volume>
1843 if (cm_ClientStrChr(shareName, '%') != NULL ||
1844 cm_ClientStrChr(shareName, '#') != NULL) {
1845 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1846 /* make room for '/@vol:' + mountchar + NULL terminator*/
1848 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1849 osi_LogSaveClientString(smb_logp, shareName));
1851 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1852 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1853 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1855 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1857 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1858 cm_ClientStrLwr(*pathNamep);
1859 osi_Log1(smb_logp, " returning pathname [%S]",
1860 osi_LogSaveClientString(smb_logp, *pathNamep));
1868 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1869 0, KEY_QUERY_VALUE, &parmKey);
1870 if (code == ERROR_SUCCESS) {
1871 cblen = sizeof(pathName);
1872 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1873 (BYTE *) pathName, &cblen);
1874 if (code != ERROR_SUCCESS)
1876 RegCloseKey (parmKey);
1880 cchlen = cblen / sizeof(clientchar_t);
1881 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1882 /* We can accept either unix or PC style AFS pathnames. Convert
1883 * Unix-style to PC style here for internal use.
1886 cchlen = lengthof(pathName);
1888 /* within this code block, we maintain, cchlen = writeable
1889 buffer length of p */
1891 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1892 p += cm_mountRootCLen; /* skip mount path */
1893 cchlen -= (DWORD)(p - pathName);
1898 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1904 clientchar_t temp[1024];
1906 if (var = smb_stristr(p, VNUserName)) {
1907 if (uidp && uidp->unp)
1908 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1910 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1912 else if (var = smb_stristr(p, VNLCUserName))
1914 if (uidp && uidp->unp)
1915 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1917 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1918 cm_ClientStrLwr(temp);
1919 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1921 else if (var = smb_stristr(p, VNComputerName))
1923 sizeTemp = lengthof(temp);
1924 GetComputerNameW(temp, &sizeTemp);
1925 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1927 else if (var = smb_stristr(p, VNLCComputerName))
1929 sizeTemp = lengthof(temp);
1930 GetComputerName((LPTSTR)temp, &sizeTemp);
1931 cm_ClientStrLwr(temp);
1932 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1937 *pathNamep = cm_ClientStrDup(p);
1942 /* First lookup shareName in root.afs */
1944 smb_findShare_rock_t vrock;
1946 fschar_t ftemp[1024];
1947 clientchar_t * p = shareName;
1950 /* attempt to locate a partial match in root.afs. This is because
1951 when using the ANSI RAP calls, the share name is limited to 13 chars
1952 and hence is truncated. Of course we prefer exact matches. */
1954 thyper.HighPart = 0;
1957 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1959 vrock.matchType = 0;
1961 cm_HoldSCache(cm_data.rootSCachep);
1962 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1963 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1964 cm_ReleaseSCache(cm_data.rootSCachep);
1966 free(vrock.shareName);
1967 vrock.shareName = NULL;
1969 if (vrock.matchType) {
1970 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1971 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1976 /* if we get here, there was no match for the share in root.afs */
1977 /* so try to create \\<netbiosName>\<cellname> */
1982 /* Get the full name for this cell */
1983 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1984 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1985 #ifdef AFS_AFSDB_ENV
1986 if (code && cm_dnsEnabled) {
1988 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1994 /* construct the path */
1996 clientchar_t temp[1024];
1998 cm_FsStringToClientString(ftemp, (int)cm_FsStrLen(ftemp), temp, 1024);
1999 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2000 rw ? _C("/.%S/") : _C("/%S/"), temp);
2001 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2010 /* Client-side offline caching policy types */
2011 #define CSC_POLICY_MANUAL 0
2012 #define CSC_POLICY_DOCUMENTS 1
2013 #define CSC_POLICY_PROGRAMS 2
2014 #define CSC_POLICY_DISABLE 3
2016 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2019 clientchar_t policy[1024];
2022 int retval = CSC_POLICY_MANUAL;
2024 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2025 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2028 REG_OPTION_NON_VOLATILE,
2034 len = sizeof(policy);
2035 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2037 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2039 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2041 retval = CSC_POLICY_DOCUMENTS;
2043 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2045 retval = CSC_POLICY_PROGRAMS;
2047 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2049 retval = CSC_POLICY_DISABLE;
2052 RegCloseKey(hkCSCPolicy);
2056 /* find a dir search structure by cookie value, and return it held.
2057 * Must be called with smb_globalLock held.
2059 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2061 smb_dirSearch_t *dsp;
2063 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2064 if (dsp->cookie == cookie) {
2065 if (dsp != smb_firstDirSearchp) {
2066 /* move to head of LRU queue, too, if we're not already there */
2067 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2068 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2069 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2070 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2071 if (!smb_lastDirSearchp)
2072 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2074 lock_ObtainMutex(&dsp->mx);
2076 lock_ReleaseMutex(&dsp->mx);
2082 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2083 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2084 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2090 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2092 lock_ObtainWrite(&smb_globalLock);
2093 lock_ObtainMutex(&dsp->mx);
2094 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2095 dsp->cookie, dsp, dsp->scp);
2096 dsp->flags |= SMB_DIRSEARCH_DELETE;
2097 if (dsp->scp != NULL) {
2098 lock_ObtainWrite(&dsp->scp->rw);
2099 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2100 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2101 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2102 dsp->scp->bulkStatProgress = hzero;
2104 lock_ReleaseWrite(&dsp->scp->rw);
2106 lock_ReleaseMutex(&dsp->mx);
2107 lock_ReleaseWrite(&smb_globalLock);
2110 /* Must be called with the smb_globalLock held */
2111 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2113 cm_scache_t *scp = NULL;
2115 lock_ObtainMutex(&dsp->mx);
2116 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2117 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
2118 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2119 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2120 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2121 lock_ReleaseMutex(&dsp->mx);
2122 lock_FinalizeMutex(&dsp->mx);
2124 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2125 dsp->cookie, dsp, scp);
2128 lock_ReleaseMutex(&dsp->mx);
2130 /* do this now to avoid spurious locking hierarchy creation */
2132 cm_ReleaseSCache(scp);
2135 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2137 lock_ObtainWrite(&smb_globalLock);
2138 smb_ReleaseDirSearchNoLock(dsp);
2139 lock_ReleaseWrite(&smb_globalLock);
2142 /* find a dir search structure by cookie value, and return it held */
2143 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2145 smb_dirSearch_t *dsp;
2147 lock_ObtainWrite(&smb_globalLock);
2148 dsp = smb_FindDirSearchNoLock(cookie);
2149 lock_ReleaseWrite(&smb_globalLock);
2153 /* GC some dir search entries, in the address space expected by the specific protocol.
2154 * Must be called with smb_globalLock held; release the lock temporarily.
2156 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2157 void smb_GCDirSearches(int isV3)
2159 smb_dirSearch_t *prevp;
2160 smb_dirSearch_t *tp;
2161 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2165 victimCount = 0; /* how many have we got so far */
2166 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
2167 /* we'll move tp from queue, so
2170 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
2171 /* if no one is using this guy, and we're either in the new protocol,
2172 * or we're in the old one and this is a small enough ID to be useful
2173 * to the old protocol, GC this guy.
2175 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2176 /* hold and delete */
2177 lock_ObtainMutex(&tp->mx);
2178 tp->flags |= SMB_DIRSEARCH_DELETE;
2179 lock_ReleaseMutex(&tp->mx);
2180 victimsp[victimCount++] = tp;
2184 /* don't do more than this */
2185 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2189 /* now release them */
2190 for (i = 0; i < victimCount; i++) {
2191 smb_ReleaseDirSearchNoLock(victimsp[i]);
2195 /* function for allocating a dir search entry. We need these to remember enough context
2196 * since we don't get passed the path from call to call during a directory search.
2198 * Returns a held dir search structure, and bumps the reference count on the vnode,
2199 * since it saves a pointer to the vnode.
2201 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2203 smb_dirSearch_t *dsp;
2209 lock_ObtainWrite(&smb_globalLock);
2212 /* what's the biggest ID allowed in this version of the protocol */
2213 /* TODO: do we really want a non v3 dir search request to wrap
2214 smb_dirSearchCounter? */
2215 maxAllowed = isV3 ? 65535 : 255;
2216 if (smb_dirSearchCounter > maxAllowed)
2217 smb_dirSearchCounter = 1;
2219 start = smb_dirSearchCounter;
2222 /* twice so we have enough tries to find guys we GC after one pass;
2223 * 10 extra is just in case I mis-counted.
2225 if (++counter > 2*maxAllowed+10)
2226 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2228 if (smb_dirSearchCounter > maxAllowed) {
2229 smb_dirSearchCounter = 1;
2231 if (smb_dirSearchCounter == start) {
2233 smb_GCDirSearches(isV3);
2236 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2238 /* don't need to watch for refcount zero and deleted, since
2239 * we haven't dropped the global lock.
2241 lock_ObtainMutex(&dsp->mx);
2243 lock_ReleaseMutex(&dsp->mx);
2244 ++smb_dirSearchCounter;
2248 dsp = malloc(sizeof(*dsp));
2249 memset(dsp, 0, sizeof(*dsp));
2250 dsp->cookie = smb_dirSearchCounter;
2251 ++smb_dirSearchCounter;
2253 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2254 dsp->lastTime = osi_Time();
2255 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2256 if (!smb_lastDirSearchp)
2257 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2259 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2263 lock_ReleaseWrite(&smb_globalLock);
2267 static smb_packet_t *smb_GetPacket(void)
2271 lock_ObtainWrite(&smb_globalLock);
2272 tbp = smb_packetFreeListp;
2274 smb_packetFreeListp = tbp->nextp;
2275 lock_ReleaseWrite(&smb_globalLock);
2277 tbp = calloc(sizeof(*tbp),1);
2278 tbp->magic = SMB_PACKETMAGIC;
2281 tbp->resumeCode = 0;
2287 tbp->ncb_length = 0;
2290 tbp->stringsp = NULL;
2292 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2297 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2300 tbp = smb_GetPacket();
2301 memcpy(tbp, pkt, sizeof(smb_packet_t));
2302 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2303 tbp->stringsp = NULL;
2305 smb_HoldVC(tbp->vcp);
2309 static NCB *smb_GetNCB(void)
2314 lock_ObtainWrite(&smb_globalLock);
2315 tbp = smb_ncbFreeListp;
2317 smb_ncbFreeListp = tbp->nextp;
2318 lock_ReleaseWrite(&smb_globalLock);
2320 tbp = calloc(sizeof(*tbp),1);
2321 tbp->magic = SMB_NCBMAGIC;
2324 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2326 memset(&tbp->ncb, 0, sizeof(NCB));
2331 static void FreeSMBStrings(smb_packet_t * pkt)
2336 for (s = pkt->stringsp; s; s = ns) {
2340 pkt->stringsp = NULL;
2343 void smb_FreePacket(smb_packet_t *tbp)
2345 smb_vc_t * vcp = NULL;
2346 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2348 lock_ObtainWrite(&smb_globalLock);
2349 tbp->nextp = smb_packetFreeListp;
2350 smb_packetFreeListp = tbp;
2351 tbp->magic = SMB_PACKETMAGIC;
2355 tbp->resumeCode = 0;
2361 tbp->ncb_length = 0;
2363 FreeSMBStrings(tbp);
2364 lock_ReleaseWrite(&smb_globalLock);
2370 static void smb_FreeNCB(NCB *bufferp)
2374 tbp = (smb_ncb_t *) bufferp;
2375 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2377 lock_ObtainWrite(&smb_globalLock);
2378 tbp->nextp = smb_ncbFreeListp;
2379 smb_ncbFreeListp = tbp;
2380 lock_ReleaseWrite(&smb_globalLock);
2383 /* get a ptr to the data part of a packet, and its count */
2384 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2388 unsigned char *afterParmsp;
2390 parmBytes = *smbp->wctp << 1;
2391 afterParmsp = smbp->wctp + parmBytes + 1;
2393 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2394 if (nbytesp) *nbytesp = dataBytes;
2396 /* don't forget to skip the data byte count, since it follows
2397 * the parameters; that's where the "2" comes from below.
2399 return (unsigned char *) (afterParmsp + 2);
2402 /* must set all the returned parameters before playing around with the
2403 * data region, since the data region is located past the end of the
2404 * variable number of parameters.
2406 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2408 unsigned char *afterParmsp;
2410 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2412 *afterParmsp++ = dsize & 0xff;
2413 *afterParmsp = (dsize>>8) & 0xff;
2416 /* return the parm'th parameter in the smbp packet */
2417 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2420 unsigned char *parmDatap;
2422 parmCount = *smbp->wctp;
2424 if (parm >= parmCount) {
2427 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2428 parm, parmCount, smbp->ncb_length);
2429 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2430 parm, parmCount, smbp->ncb_length);
2431 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2432 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2433 osi_panic(s, __FILE__, __LINE__);
2435 parmDatap = smbp->wctp + (2*parm) + 1;
2437 return parmDatap[0] + (parmDatap[1] << 8);
2440 /* return the parm'th parameter in the smbp packet */
2441 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2444 unsigned char *parmDatap;
2446 parmCount = *smbp->wctp;
2448 if (parm >= parmCount) {
2451 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2452 parm, parmCount, smbp->ncb_length);
2453 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2454 parm, parmCount, smbp->ncb_length);
2455 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2456 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2457 osi_panic(s, __FILE__, __LINE__);
2459 parmDatap = smbp->wctp + (2*parm) + 1;
2461 return parmDatap[0];
2464 /* return the parm'th parameter in the smbp packet */
2465 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2468 unsigned char *parmDatap;
2470 parmCount = *smbp->wctp;
2472 if (parm + 1 >= parmCount) {
2475 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2476 parm, parmCount, smbp->ncb_length);
2477 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2478 parm, parmCount, smbp->ncb_length);
2479 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2480 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2481 osi_panic(s, __FILE__, __LINE__);
2483 parmDatap = smbp->wctp + (2*parm) + 1;
2485 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2488 /* return the parm'th parameter in the smbp packet */
2489 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2492 unsigned char *parmDatap;
2494 parmCount = *smbp->wctp;
2496 if (parm * 2 + offset >= parmCount * 2) {
2499 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2500 parm, offset, parmCount, smbp->ncb_length);
2501 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2502 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2503 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2504 parm, offset, parmCount, smbp->ncb_length);
2505 osi_panic(s, __FILE__, __LINE__);
2507 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2509 return parmDatap[0] + (parmDatap[1] << 8);
2512 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2514 unsigned char *parmDatap;
2516 /* make sure we have enough slots */
2517 if (*smbp->wctp <= slot)
2518 *smbp->wctp = slot+1;
2520 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2521 *parmDatap++ = parmValue & 0xff;
2522 *parmDatap = (parmValue>>8) & 0xff;
2525 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2527 unsigned char *parmDatap;
2529 /* make sure we have enough slots */
2530 if (*smbp->wctp <= slot)
2531 *smbp->wctp = slot+2;
2533 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2534 *parmDatap++ = parmValue & 0xff;
2535 *parmDatap++ = (parmValue>>8) & 0xff;
2536 *parmDatap++ = (parmValue>>16) & 0xff;
2537 *parmDatap = (parmValue>>24) & 0xff;
2540 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2542 unsigned char *parmDatap;
2545 /* make sure we have enough slots */
2546 if (*smbp->wctp <= slot)
2547 *smbp->wctp = slot+4;
2549 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2551 *parmDatap++ = *parmValuep++;
2554 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2556 unsigned char *parmDatap;
2558 /* make sure we have enough slots */
2559 if (*smbp->wctp <= slot) {
2560 if (smbp->oddByte) {
2562 *smbp->wctp = slot+1;
2567 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2568 *parmDatap++ = parmValue & 0xff;
2573 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2574 clientchar_t *inPathp)
2576 clientchar_t *lastSlashp;
2578 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2580 *lastComponentp = lastSlashp;
2583 if (inPathp == lastSlashp)
2585 *outPathp++ = *inPathp++;
2594 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2595 char **chainpp, int flags)
2603 if (!WANTS_UNICODE(pktp))
2604 flags |= SMB_STRF_FORCEASCII;
2607 cb = sizeof(pktp->data) - (inp - pktp->data);
2608 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2609 #ifdef DEBUG_UNICODE
2612 cb = sizeof(pktp->data);
2614 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2617 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2618 char ** chainpp, int flags)
2623 if (!WANTS_UNICODE(pktp))
2624 flags |= SMB_STRF_FORCEASCII;
2627 cb = sizeof(pktp->data) - (inp - pktp->data);
2628 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2629 #ifdef DEBUG_UNICODE
2632 cb = sizeof(pktp->data);
2634 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2637 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2638 size_t cb, char ** chainpp, int flags)
2641 if (!WANTS_UNICODE(pktp))
2642 flags |= SMB_STRF_FORCEASCII;
2645 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2648 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2649 size_t cch, char ** chainpp, int flags)
2654 if (!WANTS_UNICODE(pktp))
2655 flags |= SMB_STRF_FORCEASCII;
2657 cb = cch * sizeof(wchar_t);
2660 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2664 smb_ParseStringBuf(const unsigned char * bufbase,
2665 cm_space_t ** stringspp,
2666 unsigned char *inp, size_t *pcb_max,
2667 char **chainpp, int flags)
2670 if (!(flags & SMB_STRF_FORCEASCII)) {
2672 cm_space_t * spacep;
2675 if (bufbase && ((inp - bufbase) % 2) != 0) {
2676 inp++; /* unicode strings are always word aligned */
2680 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2682 cch_src = *pcb_max / sizeof(wchar_t);
2686 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2693 spacep = cm_GetSpace();
2694 spacep->nextp = *stringspp;
2695 *stringspp = spacep;
2699 *chainpp = inp + sizeof(wchar_t);
2702 *(spacep->wdata) = 0;
2703 return spacep->wdata;
2706 StringCchCopyNW(spacep->wdata,
2707 lengthof(spacep->wdata),
2708 (const clientchar_t *) inp, cch_src);
2711 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2713 return spacep->wdata;
2717 cm_space_t * spacep;
2720 /* Not using Unicode */
2722 *chainpp = inp + strlen(inp) + 1;
2725 spacep = cm_GetSpace();
2726 spacep->nextp = *stringspp;
2727 *stringspp = spacep;
2729 cchdest = lengthof(spacep->wdata);
2730 cm_Utf8ToUtf16(inp, (int)*pcb_max, spacep->wdata, cchdest);
2732 return spacep->wdata;
2738 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2740 size_t * plen, int flags)
2746 /* we are only calculating the required size */
2753 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2755 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2756 if (!(flags & SMB_STRF_IGNORENUL))
2757 *plen += sizeof(wchar_t);
2759 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2769 cch_str = cm_ClientStrLen(str);
2770 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2773 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2781 /* if outp != NULL ... */
2783 /* Number of bytes left in the buffer.
2785 If outp lies inside the packet data buffer, we assume that the
2786 buffer is the packet data buffer. Otherwise we assume that the
2787 buffer is sizeof(packet->data).
2790 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2791 align = (int)((outp - pktp->data) % 2);
2792 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2794 align = (int)(((size_t) outp) % 2);
2795 buffersize = (int)sizeof(pktp->data);
2800 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2806 if (*str == _C('\0')) {
2808 if (buffersize < sizeof(wchar_t))
2811 *((wchar_t *) outp) = L'\0';
2812 if (plen && !(flags & SMB_STRF_IGNORENUL))
2813 *plen += sizeof(wchar_t);
2814 return outp + sizeof(wchar_t);
2817 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2819 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2820 osi_LogSaveClientString(smb_logp, str),
2826 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2828 return outp + sizeof(wchar_t) * nchars;
2836 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2839 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2841 return outp + cch_dest;
2845 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2851 tlen = inp[0] + (inp[1]<<8);
2852 inp += 2; /* skip length field */
2855 *chainpp = inp + tlen;
2864 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2868 if (*inp++ != 0x1) return NULL;
2869 tlen = inp[0] + (inp[1]<<8);
2870 inp += 2; /* skip length field */
2873 *chainpp = inp + tlen;
2876 if (lengthp) *lengthp = tlen;
2881 /* format a packet as a response */
2882 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2887 outp = (smb_t *) op;
2889 /* zero the basic structure through the smb_wct field, and zero the data
2890 * size field, assuming that wct stays zero; otherwise, you have to
2891 * explicitly set the data size field, too.
2893 inSmbp = (smb_t *) inp;
2894 memset(outp, 0, sizeof(smb_t)+2);
2900 outp->com = inSmbp->com;
2901 outp->tid = inSmbp->tid;
2902 outp->pid = inSmbp->pid;
2903 outp->uid = inSmbp->uid;
2904 outp->mid = inSmbp->mid;
2905 outp->res[0] = inSmbp->res[0];
2906 outp->res[1] = inSmbp->res[1];
2907 op->inCom = inSmbp->com;
2909 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2910 #ifdef SEND_CANONICAL_PATHNAMES
2911 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2913 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2915 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2916 outp->flg2 |= SMB_FLAGS2_UNICODE;
2919 /* copy fields in generic packet area */
2920 op->wctp = &outp->wct;
2923 /* send a (probably response) packet; vcp tells us to whom to send it.
2924 * we compute the length by looking at wct and bcc fields.
2926 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2936 ncbp = smb_GetNCB();
2940 memset((char *)ncbp, 0, sizeof(NCB));
2942 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2943 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2944 extra += tp[0] + (tp[1]<<8);
2945 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2946 extra += 3; /* wct and length fields */
2948 ncbp->ncb_length = extra; /* bytes to send */
2949 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2950 ncbp->ncb_lana_num = vcp->lana;
2951 ncbp->ncb_command = NCBSEND; /* op means send data */
2952 ncbp->ncb_buffer = (char *) inp;/* packet */
2953 code = Netbios(ncbp);
2956 const char * s = ncb_error_string(code);
2957 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2958 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2960 lock_ObtainMutex(&vcp->mx);
2961 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2962 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2964 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2965 lock_ReleaseMutex(&vcp->mx);
2966 lock_ObtainWrite(&smb_globalLock);
2967 dead_sessions[vcp->session] = TRUE;
2968 lock_ReleaseWrite(&smb_globalLock);
2969 smb_CleanupDeadVC(vcp);
2971 lock_ReleaseMutex(&vcp->mx);
2979 void smb_MapNTError(long code, unsigned long *NTStatusp)
2981 unsigned long NTStatus;
2983 /* map CM_ERROR_* errors to NT 32-bit status codes */
2984 /* NT Status codes are listed in ntstatus.h not winerror.h */
2985 if (code == CM_ERROR_NOSUCHCELL) {
2986 NTStatus = 0xC000000FL; /* No such file */
2988 else if (code == CM_ERROR_NOSUCHVOLUME) {
2989 NTStatus = 0xC000000FL; /* No such file */
2991 else if (code == CM_ERROR_TIMEDOUT) {
2993 NTStatus = 0xC00000CFL; /* Sharing Paused */
2995 NTStatus = 0x00000102L; /* Timeout */
2998 else if (code == CM_ERROR_RETRY) {
2999 NTStatus = 0xC000022DL; /* Retry */
3001 else if (code == CM_ERROR_NOACCESS) {
3002 NTStatus = 0xC0000022L; /* Access denied */
3004 else if (code == CM_ERROR_READONLY) {
3005 NTStatus = 0xC00000A2L; /* Write protected */
3007 else if (code == CM_ERROR_NOSUCHFILE ||
3008 code == CM_ERROR_BPLUS_NOMATCH) {
3009 NTStatus = 0xC000000FL; /* No such file */
3011 else if (code == CM_ERROR_NOSUCHPATH) {
3012 NTStatus = 0xC000003AL; /* Object path not found */
3014 else if (code == CM_ERROR_TOOBIG) {
3015 NTStatus = 0xC000007BL; /* Invalid image format */
3017 else if (code == CM_ERROR_INVAL) {
3018 NTStatus = 0xC000000DL; /* Invalid parameter */
3020 else if (code == CM_ERROR_BADFD) {
3021 NTStatus = 0xC0000008L; /* Invalid handle */
3023 else if (code == CM_ERROR_BADFDOP) {
3024 NTStatus = 0xC0000022L; /* Access denied */
3026 else if (code == CM_ERROR_EXISTS) {
3027 NTStatus = 0xC0000035L; /* Object name collision */
3029 else if (code == CM_ERROR_NOTEMPTY) {
3030 NTStatus = 0xC0000101L; /* Directory not empty */
3032 else if (code == CM_ERROR_CROSSDEVLINK) {
3033 NTStatus = 0xC00000D4L; /* Not same device */
3035 else if (code == CM_ERROR_NOTDIR) {
3036 NTStatus = 0xC0000103L; /* Not a directory */
3038 else if (code == CM_ERROR_ISDIR) {
3039 NTStatus = 0xC00000BAL; /* File is a directory */
3041 else if (code == CM_ERROR_BADOP) {
3043 /* I have no idea where this comes from */
3044 NTStatus = 0xC09820FFL; /* SMB no support */
3046 NTStatus = 0xC00000BBL; /* Not supported */
3047 #endif /* COMMENT */
3049 else if (code == CM_ERROR_BADSHARENAME) {
3050 NTStatus = 0xC00000CCL; /* Bad network name */
3052 else if (code == CM_ERROR_NOIPC) {
3054 NTStatus = 0xC0000022L; /* Access Denied */
3056 NTStatus = 0xC000013DL; /* Remote Resources */
3059 else if (code == CM_ERROR_CLOCKSKEW) {
3060 NTStatus = 0xC0000133L; /* Time difference at DC */
3062 else if (code == CM_ERROR_BADTID) {
3063 NTStatus = 0xC0982005L; /* SMB bad TID */
3065 else if (code == CM_ERROR_USESTD) {
3066 NTStatus = 0xC09820FBL; /* SMB use standard */
3068 else if (code == CM_ERROR_QUOTA) {
3069 NTStatus = 0xC0000044L; /* Quota exceeded */
3071 else if (code == CM_ERROR_SPACE) {
3072 NTStatus = 0xC000007FL; /* Disk full */
3074 else if (code == CM_ERROR_ATSYS) {
3075 NTStatus = 0xC0000033L; /* Object name invalid */
3077 else if (code == CM_ERROR_BADNTFILENAME) {
3078 NTStatus = 0xC0000033L; /* Object name invalid */
3080 else if (code == CM_ERROR_WOULDBLOCK) {
3081 NTStatus = 0xC0000055L; /* Lock not granted */
3083 else if (code == CM_ERROR_SHARING_VIOLATION) {
3084 NTStatus = 0xC0000043L; /* Sharing violation */
3086 else if (code == CM_ERROR_LOCK_CONFLICT) {
3087 NTStatus = 0xC0000054L; /* Lock conflict */
3089 else if (code == CM_ERROR_PARTIALWRITE) {
3090 NTStatus = 0xC000007FL; /* Disk full */
3092 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3093 NTStatus = 0xC0000023L; /* Buffer too small */
3095 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3096 NTStatus = 0xC0000035L; /* Object name collision */
3098 else if (code == CM_ERROR_BADPASSWORD) {
3099 NTStatus = 0xC000006DL; /* unknown username or bad password */
3101 else if (code == CM_ERROR_BADLOGONTYPE) {
3102 NTStatus = 0xC000015BL; /* logon type not granted */
3104 else if (code == CM_ERROR_GSSCONTINUE) {
3105 NTStatus = 0xC0000016L; /* more processing required */
3107 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3109 NTStatus = 0xC0000280L; /* reparse point not resolved */
3111 NTStatus = 0xC0000022L; /* Access Denied */
3114 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3115 NTStatus = 0xC0000257L; /* Path Not Covered */
3117 else if (code == CM_ERROR_ALLBUSY) {
3118 NTStatus = 0xC000022DL; /* Retry */
3120 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3121 NTStatus = 0xC00000BEL; /* Bad Network Path */
3123 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3124 NTStatus = 0xC0000322L; /* No Kerberos key */
3126 else if (code == CM_ERROR_BAD_LEVEL) {
3127 NTStatus = 0xC0000148L; /* Invalid Level */
3129 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3130 NTStatus = 0xC000007EL; /* Range Not Locked */
3132 else if (code == CM_ERROR_NOSUCHDEVICE) {
3133 NTStatus = 0xC000000EL; /* No Such Device */
3135 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3136 NTStatus = 0xC0000055L; /* Lock Not Granted */
3138 NTStatus = 0xC0982001L; /* SMB non-specific error */
3141 *NTStatusp = NTStatus;
3142 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3145 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3146 unsigned char *classp)
3148 unsigned char class;
3149 unsigned short error;
3151 /* map CM_ERROR_* errors to SMB errors */
3152 if (code == CM_ERROR_NOSUCHCELL) {
3154 error = 3; /* bad path */
3156 else if (code == CM_ERROR_NOSUCHVOLUME) {
3158 error = 3; /* bad path */
3160 else if (code == CM_ERROR_TIMEDOUT) {
3162 error = 81; /* server is paused */
3164 else if (code == CM_ERROR_RETRY) {
3165 class = 2; /* shouldn't happen */
3168 else if (code == CM_ERROR_NOACCESS) {
3170 error = 4; /* bad access */
3172 else if (code == CM_ERROR_READONLY) {
3174 error = 19; /* read only */
3176 else if (code == CM_ERROR_NOSUCHFILE ||
3177 code == CM_ERROR_BPLUS_NOMATCH) {
3179 error = 2; /* ENOENT! */
3181 else if (code == CM_ERROR_NOSUCHPATH) {
3183 error = 3; /* Bad path */
3185 else if (code == CM_ERROR_TOOBIG) {
3187 error = 11; /* bad format */
3189 else if (code == CM_ERROR_INVAL) {
3190 class = 2; /* server non-specific error code */
3193 else if (code == CM_ERROR_BADFD) {
3195 error = 6; /* invalid file handle */
3197 else if (code == CM_ERROR_BADFDOP) {
3198 class = 1; /* invalid op on FD */
3201 else if (code == CM_ERROR_EXISTS) {
3203 error = 80; /* file already exists */
3205 else if (code == CM_ERROR_NOTEMPTY) {
3207 error = 5; /* delete directory not empty */
3209 else if (code == CM_ERROR_CROSSDEVLINK) {
3211 error = 17; /* EXDEV */
3213 else if (code == CM_ERROR_NOTDIR) {
3214 class = 1; /* bad path */
3217 else if (code == CM_ERROR_ISDIR) {
3218 class = 1; /* access denied; DOS doesn't have a good match */
3221 else if (code == CM_ERROR_BADOP) {
3225 else if (code == CM_ERROR_BADSHARENAME) {
3229 else if (code == CM_ERROR_NOIPC) {
3231 error = 4; /* bad access */
3233 else if (code == CM_ERROR_CLOCKSKEW) {
3234 class = 1; /* invalid function */
3237 else if (code == CM_ERROR_BADTID) {
3241 else if (code == CM_ERROR_USESTD) {
3245 else if (code == CM_ERROR_REMOTECONN) {
3249 else if (code == CM_ERROR_QUOTA) {
3250 if (vcp->flags & SMB_VCFLAG_USEV3) {
3252 error = 39; /* disk full */
3256 error = 5; /* access denied */
3259 else if (code == CM_ERROR_SPACE) {
3260 if (vcp->flags & SMB_VCFLAG_USEV3) {
3262 error = 39; /* disk full */
3266 error = 5; /* access denied */
3269 else if (code == CM_ERROR_PARTIALWRITE) {
3271 error = 39; /* disk full */
3273 else if (code == CM_ERROR_ATSYS) {
3275 error = 2; /* ENOENT */
3277 else if (code == CM_ERROR_WOULDBLOCK) {
3279 error = 33; /* lock conflict */
3281 else if (code == CM_ERROR_LOCK_CONFLICT) {
3283 error = 33; /* lock conflict */
3285 else if (code == CM_ERROR_SHARING_VIOLATION) {
3287 error = 33; /* lock conflict */
3289 else if (code == CM_ERROR_NOFILES) {
3291 error = 18; /* no files in search */
3293 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3295 error = 183; /* Samba uses this */
3297 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3298 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3300 error = 2; /* bad password */
3302 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3304 error = 3; /* bad path */
3313 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3316 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3318 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3319 return CM_ERROR_BADOP;
3323 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3325 unsigned short EchoCount, i;
3326 char *data, *outdata;
3329 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3331 for (i=1; i<=EchoCount; i++) {
3332 data = smb_GetSMBData(inp, &dataSize);
3333 smb_SetSMBParm(outp, 0, i);
3334 smb_SetSMBDataLength(outp, dataSize);
3335 outdata = smb_GetSMBData(outp, NULL);
3336 memcpy(outdata, data, dataSize);
3337 smb_SendPacket(vcp, outp);
3343 /* SMB_COM_READ_RAW */
3344 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3347 long count, minCount, finalCount;
3351 smb_t *smbp = (smb_t*) inp;
3353 cm_user_t *userp = NULL;
3356 char *rawBuf = NULL;
3361 fd = smb_GetSMBParm(inp, 0);
3362 count = smb_GetSMBParm(inp, 3);
3363 minCount = smb_GetSMBParm(inp, 4);
3364 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3366 if (*inp->wctp == 10) {
3367 /* we were sent a request with 64-bit file offsets */
3368 #ifdef AFS_LARGEFILES
3369 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3371 if (LargeIntegerLessThanZero(offset)) {
3372 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3376 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3377 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3380 offset.HighPart = 0;
3384 /* we were sent a request with 32-bit file offsets */
3385 offset.HighPart = 0;
3388 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3389 fd, offset.HighPart, offset.LowPart, count);
3391 fidp = smb_FindFID(vcp, fd, 0);
3395 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3396 smb_CloseFID(vcp, fidp, NULL, 0);
3397 code = CM_ERROR_NOSUCHFILE;
3404 LARGE_INTEGER LOffset, LLength;
3407 key = cm_GenerateKey(vcp->vcID, pid, fd);
3409 LOffset.HighPart = offset.HighPart;
3410 LOffset.LowPart = offset.LowPart;
3411 LLength.HighPart = 0;
3412 LLength.LowPart = count;
3414 lock_ObtainWrite(&fidp->scp->rw);
3415 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3416 lock_ReleaseWrite(&fidp->scp->rw);
3422 lock_ObtainMutex(&smb_RawBufLock);
3424 /* Get a raw buf, from head of list */
3425 rawBuf = smb_RawBufs;
3426 smb_RawBufs = *(char **)smb_RawBufs;
3428 lock_ReleaseMutex(&smb_RawBufLock);
3432 lock_ObtainMutex(&fidp->mx);
3433 if (fidp->flags & SMB_FID_IOCTL)
3435 lock_ReleaseMutex(&fidp->mx);
3436 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3438 /* Give back raw buffer */
3439 lock_ObtainMutex(&smb_RawBufLock);
3440 *((char **) rawBuf) = smb_RawBufs;
3442 smb_RawBufs = rawBuf;
3443 lock_ReleaseMutex(&smb_RawBufLock);
3446 lock_ReleaseMutex(&fidp->mx);
3447 smb_ReleaseFID(fidp);
3450 lock_ReleaseMutex(&fidp->mx);
3452 userp = smb_GetUserFromVCP(vcp, inp);
3454 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3460 cm_ReleaseUser(userp);
3463 smb_ReleaseFID(fidp);
3467 memset((char *)ncbp, 0, sizeof(NCB));
3469 ncbp->ncb_length = (unsigned short) finalCount;
3470 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3471 ncbp->ncb_lana_num = vcp->lana;
3472 ncbp->ncb_command = NCBSEND;
3473 ncbp->ncb_buffer = rawBuf;
3475 code = Netbios(ncbp);
3477 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3480 /* Give back raw buffer */
3481 lock_ObtainMutex(&smb_RawBufLock);
3482 *((char **) rawBuf) = smb_RawBufs;
3484 smb_RawBufs = rawBuf;
3485 lock_ReleaseMutex(&smb_RawBufLock);
3491 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3493 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3498 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3500 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3505 /* SMB_COM_NEGOTIATE */
3506 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3513 int VistaProtoIndex;
3514 int protoIndex; /* index we're using */
3519 char protocol_array[10][1024]; /* protocol signature of the client */
3520 int caps; /* capabilities */
3523 TIME_ZONE_INFORMATION tzi;
3525 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3528 namep = smb_GetSMBData(inp, &dbytes);
3531 coreProtoIndex = -1; /* not found */
3534 VistaProtoIndex = -1;
3535 while(namex < dbytes) {
3536 osi_Log1(smb_logp, "Protocol %s",
3537 osi_LogSaveString(smb_logp, namep+1));
3538 strcpy(protocol_array[tcounter], namep+1);
3540 /* namep points at the first protocol, or really, a 0x02
3541 * byte preceding the null-terminated ASCII name.
3543 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3544 coreProtoIndex = tcounter;
3546 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3547 v3ProtoIndex = tcounter;
3549 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3550 NTProtoIndex = tcounter;
3552 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3553 VistaProtoIndex = tcounter;
3556 /* compute size of protocol entry */
3557 entryLength = (int)strlen(namep+1);
3558 entryLength += 2; /* 0x02 bytes and null termination */
3560 /* advance over this protocol entry */
3561 namex += entryLength;
3562 namep += entryLength;
3563 tcounter++; /* which proto entry we're looking at */
3566 lock_ObtainMutex(&vcp->mx);
3568 if (VistaProtoIndex != -1) {
3569 protoIndex = VistaProtoIndex;
3570 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3573 if (NTProtoIndex != -1) {
3574 protoIndex = NTProtoIndex;
3575 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3577 else if (v3ProtoIndex != -1) {
3578 protoIndex = v3ProtoIndex;
3579 vcp->flags |= SMB_VCFLAG_USEV3;
3581 else if (coreProtoIndex != -1) {
3582 protoIndex = coreProtoIndex;
3583 vcp->flags |= SMB_VCFLAG_USECORE;
3585 else protoIndex = -1;
3586 lock_ReleaseMutex(&vcp->mx);
3588 if (protoIndex == -1)
3589 return CM_ERROR_INVAL;
3590 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3591 smb_SetSMBParm(outp, 0, protoIndex);
3592 if (smb_authType != SMB_AUTH_NONE) {
3593 smb_SetSMBParmByte(outp, 1,
3594 NEGOTIATE_SECURITY_USER_LEVEL |
3595 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3597 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3599 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3600 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3601 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3602 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3603 /* The session key is not a well documented field however most clients
3604 * will echo back the session key to the server. Currently we are using
3605 * the same value for all sessions. We should generate a random value
3606 * and store it into the vcp
3608 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3609 smb_SetSMBParm(outp, 8, 1);
3611 * Tried changing the capabilities to support for W2K - defect 117695
3612 * Maybe something else needs to be changed here?
3616 smb_SetSMBParmLong(outp, 9, 0x43fd);
3618 smb_SetSMBParmLong(outp, 9, 0x251);
3621 * 32-bit error codes *
3627 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3629 NTNEGOTIATE_CAPABILITY_DFS |
3631 #ifdef AFS_LARGEFILES
3632 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3634 NTNEGOTIATE_CAPABILITY_NTFIND |
3635 NTNEGOTIATE_CAPABILITY_RAWMODE |
3636 NTNEGOTIATE_CAPABILITY_NTSMB;
3638 if ( smb_authType == SMB_AUTH_EXTENDED )
3639 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3642 if ( smb_UseUnicode ) {
3643 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3647 smb_SetSMBParmLong(outp, 9, caps);
3649 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3650 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3651 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3653 GetTimeZoneInformation(&tzi);
3654 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3656 if (smb_authType == SMB_AUTH_NTLM) {
3657 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3658 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3659 /* paste in encryption key */
3660 datap = smb_GetSMBData(outp, NULL);
3661 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3662 /* and the faux domain name */
3663 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3664 datap + MSV1_0_CHALLENGE_LENGTH,
3665 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3666 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3670 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3672 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3674 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3676 datap = smb_GetSMBData(outp, NULL);
3677 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3680 datap += sizeof(smb_ServerGUID);
3681 memcpy(datap, secBlob, secBlobLength);
3685 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3686 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3689 else if (v3ProtoIndex != -1) {
3690 smb_SetSMBParm(outp, 0, protoIndex);
3692 /* NOTE: Extended authentication cannot be negotiated with v3
3693 * therefore we fail over to NTLM
3695 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3696 smb_SetSMBParm(outp, 1,
3697 NEGOTIATE_SECURITY_USER_LEVEL |
3698 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3700 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3702 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3703 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3704 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3705 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3706 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3707 smb_SetSMBParm(outp, 7, 1);
3709 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3710 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3711 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3713 GetTimeZoneInformation(&tzi);
3714 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3716 /* NOTE: Extended authentication cannot be negotiated with v3
3717 * therefore we fail over to NTLM
3719 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3720 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3721 smb_SetSMBParm(outp, 12, 0); /* resvd */
3722 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3723 datap = smb_GetSMBData(outp, NULL);
3724 /* paste in a new encryption key */
3725 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3726 /* and the faux domain name */
3727 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3728 datap + MSV1_0_CHALLENGE_LENGTH,
3729 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3731 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3732 smb_SetSMBParm(outp, 12, 0); /* resvd */
3733 smb_SetSMBDataLength(outp, 0);
3736 else if (coreProtoIndex != -1) { /* not really supported anymore */
3737 smb_SetSMBParm(outp, 0, protoIndex);
3738 smb_SetSMBDataLength(outp, 0);
3743 void smb_CheckVCs(void)
3745 smb_vc_t * vcp, *nextp;
3746 smb_packet_t * outp = smb_GetPacket();
3749 lock_ObtainWrite(&smb_rctLock);
3750 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3752 if (vcp->magic != SMB_VC_MAGIC)
3753 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3754 __FILE__, __LINE__);
3758 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3761 smb_HoldVCNoLock(vcp);
3763 smb_HoldVCNoLock(nextp);
3764 smb_FormatResponsePacket(vcp, NULL, outp);
3765 smbp = (smb_t *)outp;
3766 outp->inCom = smbp->com = 0x2b /* Echo */;
3774 smb_SetSMBParm(outp, 0, 0);
3775 smb_SetSMBDataLength(outp, 0);
3776 lock_ReleaseWrite(&smb_rctLock);
3778 smb_SendPacket(vcp, outp);
3780 lock_ObtainWrite(&smb_rctLock);
3781 smb_ReleaseVCNoLock(vcp);
3783 smb_ReleaseVCNoLock(nextp);
3785 lock_ReleaseWrite(&smb_rctLock);
3786 smb_FreePacket(outp);
3789 void smb_Daemon(void *parmp)
3791 afs_uint32 count = 0;
3792 smb_username_t **unpp;
3795 while(smbShutdownFlag == 0) {
3799 if (smbShutdownFlag == 1)
3802 if ((count % 72) == 0) { /* every five minutes */
3804 time_t old_localZero = smb_localZero;
3806 /* Initialize smb_localZero */
3807 myTime.tm_isdst = -1; /* compute whether on DST or not */
3808 myTime.tm_year = 70;
3814 smb_localZero = mktime(&myTime);
3816 #ifndef USE_NUMERIC_TIME_CONV
3817 smb_CalculateNowTZ();
3818 #endif /* USE_NUMERIC_TIME_CONV */
3819 #ifdef AFS_FREELANCE
3820 if ( smb_localZero != old_localZero )
3821 cm_noteLocalMountPointChange();
3827 /* GC smb_username_t objects that will no longer be used */
3829 lock_ObtainWrite(&smb_rctLock);
3830 for ( unpp=&usernamesp; *unpp; ) {
3832 smb_username_t *unp;
3834 lock_ObtainMutex(&(*unpp)->mx);
3835 if ( (*unpp)->refCount > 0 ||
3836 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3837 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3839 else if (!smb_LogoffTokenTransfer ||
3840 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3842 lock_ReleaseMutex(&(*unpp)->mx);
3850 lock_FinalizeMutex(&unp->mx);
3856 cm_ReleaseUser(userp);
3858 unpp = &(*unpp)->nextp;
3861 lock_ReleaseWrite(&smb_rctLock);
3863 /* XXX GC dir search entries */
3867 void smb_WaitingLocksDaemon()
3869 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3870 smb_waitingLock_t *wl, *wlNext;
3873 smb_packet_t *inp, *outp;
3877 while (smbShutdownFlag == 0) {
3878 lock_ObtainWrite(&smb_globalLock);
3879 nwlRequest = smb_allWaitingLocks;
3880 if (nwlRequest == NULL) {
3881 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3886 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3893 lock_ObtainWrite(&smb_globalLock);
3895 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3897 wlRequest = nwlRequest;
3898 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3899 lock_ReleaseWrite(&smb_globalLock);
3903 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3904 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3907 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3908 code = CM_ERROR_LOCK_NOT_GRANTED;
3912 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3914 /* wl->state is either _DONE or _WAITING. _ERROR
3915 would no longer be on the queue. */
3916 code = cm_RetryLock( wl->lockp,
3917 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3920 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3921 } else if (code != CM_ERROR_WOULDBLOCK) {
3922 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3927 if (code == CM_ERROR_WOULDBLOCK) {
3930 if (wlRequest->msTimeout != 0xffffffff
3931 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3943 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3946 scp = wlRequest->scp;
3947 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3951 lock_ObtainWrite(&scp->rw);
3953 for (wl = wlRequest->locks; wl; wl = wlNext) {
3954 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3956 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3957 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3958 wl->LLength, wl->key, NULL, &req);
3960 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3965 lock_ReleaseWrite(&scp->rw);
3969 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3972 for (wl = wlRequest->locks; wl; wl = wlNext) {
3973 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3974 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3979 vcp = wlRequest->vcp;
3980 inp = wlRequest->inp;
3981 outp = wlRequest->outp;
3982 ncbp = smb_GetNCB();
3983 ncbp->ncb_length = inp->ncb_length;
3984 inp->spacep = cm_GetSpace();
3986 /* Remove waitingLock from list */
3987 lock_ObtainWrite(&smb_globalLock);
3988 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3990 lock_ReleaseWrite(&smb_globalLock);
3992 /* Resume packet processing */
3994 smb_SetSMBDataLength(outp, 0);
3995 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3996 outp->resumeCode = code;
3998 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4001 cm_FreeSpace(inp->spacep);
4002 smb_FreePacket(inp);
4003 smb_FreePacket(outp);
4005 cm_ReleaseSCache(wlRequest->scp);
4008 } while (nwlRequest && smbShutdownFlag == 0);
4013 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4015 osi_Log0(smb_logp, "SMB receive get disk attributes");
4017 smb_SetSMBParm(outp, 0, 32000);
4018 smb_SetSMBParm(outp, 1, 64);
4019 smb_SetSMBParm(outp, 2, 1024);
4020 smb_SetSMBParm(outp, 3, 30000);
4021 smb_SetSMBParm(outp, 4, 0);
4022 smb_SetSMBDataLength(outp, 0);
4026 /* SMB_COM_TREE_CONNECT */
4027 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4031 unsigned short newTid;
4032 clientchar_t shareName[AFSPATHMAX];
4033 clientchar_t *sharePath;
4036 clientchar_t *pathp;
4039 osi_Log0(smb_logp, "SMB receive tree connect");
4041 /* parse input parameters */
4044 tbp = smb_GetSMBData(inp, NULL);
4045 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4047 tp = cm_ClientStrRChr(pathp, '\\');
4049 return CM_ERROR_BADSMB;
4050 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4052 lock_ObtainMutex(&vcp->mx);
4053 newTid = vcp->tidCounter++;
4054 lock_ReleaseMutex(&vcp->mx);
4056 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4057 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4058 userp = smb_GetUserFromUID(uidp);
4059 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4061 smb_ReleaseUID(uidp);
4063 smb_ReleaseTID(tidp, FALSE);
4064 return CM_ERROR_BADSHARENAME;
4066 lock_ObtainMutex(&tidp->mx);
4067 tidp->userp = userp;
4068 tidp->pathname = sharePath;
4069 lock_ReleaseMutex(&tidp->mx);
4070 smb_ReleaseTID(tidp, FALSE);
4072 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4073 smb_SetSMBParm(rsp, 1, newTid);
4074 smb_SetSMBDataLength(rsp, 0);
4076 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4080 /* set maskp to the mask part of the incoming path.
4081 * Mask is 11 bytes long (8.3 with the dot elided).
4082 * Returns true if succeeds with a valid name, otherwise it does
4083 * its best, but returns false.
4085 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4093 /* starts off valid */
4096 /* mask starts out all blanks */
4097 memset(maskp, ' ', 11);
4100 /* find last backslash, or use whole thing if there is none */
4101 tp = cm_ClientStrRChr(pathp, '\\');
4105 tp++; /* skip slash */
4109 /* names starting with a dot are illegal */
4117 if (tc == '.' || tc == '"')
4125 /* if we get here, tp point after the dot */
4126 up = maskp+8; /* ext goes here */
4133 if (tc == '.' || tc == '"')
4136 /* copy extension if not too long */
4146 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4148 clientchar_t umask[11];
4156 /* XXX redo this, calling cm_MatchMask with a converted mask */
4158 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4162 /* otherwise, we have a valid 8.3 name; see if we have a match,
4163 * treating '?' as a wildcard in maskp (but not in the file name).
4165 tp1 = umask; /* real name, in mask format */
4166 tp2 = maskp; /* mask, in mask format */
4167 for(i=0; i<11; i++) {
4168 tc1 = *tp1++; /* clientchar_t from real name */
4169 tc2 = *tp2++; /* clientchar_t from mask */
4170 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4171 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4174 if (tc2 == '?' && tc1 != ' ')
4181 /* we got a match */
4185 clientchar_t *smb_FindMask(clientchar_t *pathp)
4189 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4192 return tp+1; /* skip the slash */
4194 return pathp; /* no slash, return the entire path */
4197 /* SMB_COM_SEARCH for a volume label
4199 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4200 dispatch function.) */
4201 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4203 clientchar_t *pathp;
4205 clientchar_t mask[12];
4206 unsigned char *statBlockp;
4207 unsigned char initStatBlock[21];
4210 osi_Log0(smb_logp, "SMB receive search volume");
4212 /* pull pathname and stat block out of request */
4213 tp = smb_GetSMBData(inp, NULL);
4214 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4215 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4216 osi_assertx(pathp != NULL, "null path");
4217 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4218 osi_assertx(statBlockp != NULL, "null statBlock");
4220 statBlockp = initStatBlock;
4224 /* for returning to caller */
4225 smb_Get8Dot3MaskFromPath(mask, pathp);
4227 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4228 tp = smb_GetSMBData(outp, NULL);
4230 *tp++ = 43; /* bytes in a dir entry */
4231 *tp++ = 0; /* high byte in counter */
4233 /* now marshall the dir entry, starting with the search status */
4234 *tp++ = statBlockp[0]; /* Reserved */
4235 memcpy(tp, mask, 11); tp += 11; /* FileName */
4237 /* now pass back server use info, with 1st byte non-zero */
4239 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4241 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4243 *tp++ = 0x8; /* attribute: volume */
4253 /* 4 byte file size */
4259 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4262 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4263 memset(tp, ' ', 13);
4266 /* set the length of the data part of the packet to 43 + 3, for the dir
4267 * entry plus the 5 and the length fields.
4269 smb_SetSMBDataLength(outp, 46);
4274 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4275 clientchar_t * tidPathp, clientchar_t * relPathp,
4276 cm_user_t *userp, cm_req_t *reqp)
4284 smb_dirListPatch_t *patchp;
4285 smb_dirListPatch_t *npatchp;
4286 clientchar_t path[AFSPATHMAX];
4288 afs_int32 mustFake = 0;
4290 code = cm_FindACLCache(dscp, userp, &rights);
4292 lock_ObtainWrite(&dscp->rw);
4293 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4294 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4295 lock_ReleaseWrite(&dscp->rw);
4296 if (code == CM_ERROR_NOACCESS) {
4304 if (!mustFake) { /* Bulk Stat */
4306 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4308 memset(bsp, 0, sizeof(cm_bulkStat_t));
4310 for (patchp = *dirPatchespp, count=0;
4312 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4313 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4317 if (lock_TryWrite(&tscp->rw)) {
4318 /* we have an entry that we can look at */
4319 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4320 /* we have a callback on it. Don't bother
4321 * fetching this stat entry, since we're happy
4322 * with the info we have.
4324 lock_ReleaseWrite(&tscp->rw);
4325 cm_ReleaseSCache(tscp);
4328 lock_ReleaseWrite(&tscp->rw);
4330 cm_ReleaseSCache(tscp);
4334 bsp->fids[i].Volume = patchp->fid.volume;
4335 bsp->fids[i].Vnode = patchp->fid.vnode;
4336 bsp->fids[i].Unique = patchp->fid.unique;
4338 if (bsp->counter == AFSCBMAX) {
4339 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4340 memset(bsp, 0, sizeof(cm_bulkStat_t));
4344 if (bsp->counter > 0)
4345 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4350 for (patchp = *dirPatchespp; patchp; patchp =
4351 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4353 dptr = patchp->dptr;
4355 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4356 relPathp ? relPathp : _C(""), patchp->dep->name);
4357 reqp->relPathp = path;
4358 reqp->tidPathp = tidPathp;
4360 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4361 reqp->relPathp = reqp->tidPathp = NULL;
4364 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4365 *dptr++ = SMB_ATTR_HIDDEN;
4368 lock_ObtainWrite(&scp->rw);
4369 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4370 lock_ReleaseWrite(&scp->rw);
4372 /* set the attribute */
4373 switch (scp->fileType) {
4374 case CM_SCACHETYPE_DIRECTORY:
4375 case CM_SCACHETYPE_MOUNTPOINT:
4376 case CM_SCACHETYPE_SYMLINK:
4377 case CM_SCACHETYPE_INVALID:
4378 attr = SMB_ATTR_DIRECTORY;
4381 /* if we get here we either have a normal file
4382 * or we have a file for which we have never
4383 * received status info. In this case, we can
4384 * check the even/odd value of the entry's vnode.
4385 * even means it is to be treated as a directory
4386 * and odd means it is to be treated as a file.
4388 if (mustFake && (scp->fid.vnode & 0x1))
4389 attr = SMB_ATTR_DIRECTORY;
4391 attr = SMB_ATTR_NORMAL;
4395 /* 1969-12-31 23:59:58 +00*/
4396 dosTime = 0xEBBFBF7D;
4399 shortTemp = (unsigned short) (dosTime & 0xffff);
4400 *((u_short *)dptr) = shortTemp;
4403 /* and copy out date */
4404 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4405 *((u_short *)dptr) = shortTemp;
4408 /* copy out file length */
4409 *((u_long *)dptr) = 0;
4412 lock_ConvertWToR(&scp->rw);
4413 attr = smb_Attributes(scp);
4414 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4415 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4416 attr |= SMB_ATTR_HIDDEN;
4420 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4423 shortTemp = (unsigned short) (dosTime & 0xffff);
4424 *((u_short *)dptr) = shortTemp;
4427 /* and copy out date */
4428 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4429 *((u_short *)dptr) = shortTemp;
4432 /* copy out file length */
4433 *((u_long *)dptr) = scp->length.LowPart;
4435 lock_ReleaseRead(&scp->rw);
4437 cm_ReleaseSCache(scp);
4440 /* now free the patches */
4441 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4442 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4446 /* and mark the list as empty */
4447 *dirPatchespp = NULL;
4453 /* SMB_COM_SEARCH */
4454 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4460 clientchar_t *pathp;
4461 cm_dirEntry_t *dep = 0;
4463 smb_dirListPatch_t *dirListPatchesp;
4464 smb_dirListPatch_t *curPatchp;
4468 osi_hyper_t dirLength;
4469 osi_hyper_t bufferOffset;
4470 osi_hyper_t curOffset;
4472 unsigned char *inCookiep;
4473 smb_dirSearch_t *dsp;
4477 unsigned long clientCookie;
4478 cm_pageHeader_t *pageHeaderp;
4479 cm_user_t *userp = NULL;
4481 clientchar_t mask[12];
4483 long nextEntryCookie;
4484 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4485 char resByte; /* reserved byte from the cookie */
4486 char *op; /* output data ptr */
4487 char *origOp; /* original value of op */
4488 cm_space_t *spacep; /* for pathname buffer */
4492 clientchar_t *tidPathp = 0;
4499 maxCount = smb_GetSMBParm(inp, 0);
4501 dirListPatchesp = NULL;
4503 caseFold = CM_FLAG_CASEFOLD;
4505 tp = smb_GetSMBData(inp, NULL);
4506 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4507 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4508 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4510 /* bail out if request looks bad */
4511 if (!tp || !pathp) {
4512 return CM_ERROR_BADSMB;
4515 /* We can handle long names */
4516 if (vcp->flags & SMB_VCFLAG_USENT)
4517 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4519 /* make sure we got a whole search status */
4520 if (dataLength < 21) {
4521 nextCookie = 0; /* start at the beginning of the dir */
4524 attribute = smb_GetSMBParm(inp, 1);
4526 /* handle volume info in another function */
4527 if (attribute & 0x8)
4528 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4530 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4531 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4533 if (*pathp == 0) { /* null pathp, treat as root dir */
4534 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4535 return CM_ERROR_NOFILES;
4539 dsp = smb_NewDirSearch(0);
4540 dsp->attribute = attribute;
4541 smb_Get8Dot3MaskFromPath(mask, pathp);
4542 memcpy(dsp->mask, mask, 12);
4544 /* track if this is likely to match a lot of entries */
4545 if (smb_IsStarMask(mask))
4550 /* pull the next cookie value out of the search status block */
4551 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4552 + (inCookiep[16]<<24);
4553 dsp = smb_FindDirSearch(inCookiep[12]);
4555 /* can't find dir search status; fatal error */
4556 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4557 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4558 return CM_ERROR_BADFD;
4560 attribute = dsp->attribute;
4561 resByte = inCookiep[0];
4563 /* copy out client cookie, in host byte order. Don't bother
4564 * interpreting it, since we're just passing it through, anyway.
4566 memcpy(&clientCookie, &inCookiep[17], 4);
4568 memcpy(mask, dsp->mask, 12);
4570 /* assume we're doing a star match if it has continued for more
4576 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4577 nextCookie, dsp->cookie, attribute);
4579 userp = smb_GetUserFromVCP(vcp, inp);
4581 /* try to get the vnode for the path name next */
4582 lock_ObtainMutex(&dsp->mx);
4585 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4589 spacep = inp->spacep;
4590 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4591 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4593 lock_ReleaseMutex(&dsp->mx);
4594 cm_ReleaseUser(userp);
4595 smb_DeleteDirSearch(dsp);
4596 smb_ReleaseDirSearch(dsp);
4597 return CM_ERROR_NOFILES;
4599 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4600 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4602 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4603 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4606 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4609 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4610 cm_ReleaseSCache(scp);
4611 lock_ReleaseMutex(&dsp->mx);
4612 cm_ReleaseUser(userp);
4613 smb_DeleteDirSearch(dsp);
4614 smb_ReleaseDirSearch(dsp);
4615 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4616 return CM_ERROR_PATH_NOT_COVERED;
4618 return CM_ERROR_BADSHARENAME;
4620 #endif /* DFS_SUPPORT */
4623 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4624 /* we need one hold for the entry we just stored into,
4625 * and one for our own processing. When we're done with this
4626 * function, we'll drop the one for our own processing.
4627 * We held it once from the namei call, and so we do another hold
4631 lock_ObtainWrite(&scp->rw);
4632 dsp->flags |= SMB_DIRSEARCH_BULKST;
4633 lock_ReleaseWrite(&scp->rw);
4636 lock_ReleaseMutex(&dsp->mx);
4638 cm_ReleaseUser(userp);
4639 smb_DeleteDirSearch(dsp);
4640 smb_ReleaseDirSearch(dsp);
4644 /* reserves space for parameter; we'll adjust it again later to the
4645 * real count of the # of entries we returned once we've actually
4646 * assembled the directory listing.
4648 smb_SetSMBParm(outp, 0, 0);
4650 /* get the directory size */
4651 lock_ObtainWrite(&scp->rw);
4652 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4653 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4655 lock_ReleaseWrite(&scp->rw);
4656 cm_ReleaseSCache(scp);
4657 cm_ReleaseUser(userp);
4658 smb_DeleteDirSearch(dsp);
4659 smb_ReleaseDirSearch(dsp);
4663 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4665 dirLength = scp->length;
4667 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4668 curOffset.HighPart = 0;
4669 curOffset.LowPart = nextCookie;
4670 origOp = op = smb_GetSMBData(outp, NULL);
4671 /* and write out the basic header */
4672 *op++ = 5; /* variable block */
4673 op += 2; /* skip vbl block length; we'll fill it in later */
4677 clientchar_t *actualName;
4678 clientchar_t shortName[13];
4679 clientchar_t *shortNameEnd;
4681 /* make sure that curOffset.LowPart doesn't point to the first
4682 * 32 bytes in the 2nd through last dir page, and that it doesn't
4683 * point at the first 13 32-byte chunks in the first dir page,
4684 * since those are dir and page headers, and don't contain useful
4687 temp = curOffset.LowPart & (2048-1);
4688 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4689 /* we're in the first page */
4690 if (temp < 13*32) temp = 13*32;
4693 /* we're in a later dir page */
4694 if (temp < 32) temp = 32;
4697 /* make sure the low order 5 bits are zero */
4700 /* now put temp bits back ito curOffset.LowPart */
4701 curOffset.LowPart &= ~(2048-1);
4702 curOffset.LowPart |= temp;
4704 /* check if we've returned all the names that will fit in the
4707 if (returnedNames >= maxCount) {
4708 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4709 returnedNames, maxCount);
4713 /* check if we've passed the dir's EOF */
4714 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4716 /* see if we can use the bufferp we have now; compute in which page
4717 * the current offset would be, and check whether that's the offset
4718 * of the buffer we have. If not, get the buffer.
4720 thyper.HighPart = curOffset.HighPart;
4721 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4722 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4725 buf_Release(bufferp);
4728 lock_ReleaseWrite(&scp->rw);
4729 code = buf_Get(scp, &thyper, &bufferp);
4730 lock_ObtainMutex(&dsp->mx);
4732 /* now, if we're doing a star match, do bulk fetching of all of
4733 * the status info for files in the dir.
4736 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4738 lock_ObtainWrite(&scp->rw);
4739 lock_ReleaseMutex(&dsp->mx);
4741 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4745 bufferOffset = thyper;
4747 /* now get the data in the cache */
4749 code = cm_SyncOp(scp, bufferp, userp, &req,
4751 CM_SCACHESYNC_NEEDCALLBACK |
4752 CM_SCACHESYNC_READ);
4754 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4758 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4760 if (cm_HaveBuffer(scp, bufferp, 0)) {
4761 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4765 /* otherwise, load the buffer and try again */
4766 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4768 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4769 scp, bufferp, code);
4774 buf_Release(bufferp);
4778 } /* if (wrong buffer) ... */
4780 /* now we have the buffer containing the entry we're interested in; copy
4781 * it out if it represents a non-deleted entry.
4783 entryInDir = curOffset.LowPart & (2048-1);
4784 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4786 /* page header will help tell us which entries are free. Page header
4787 * can change more often than once per buffer, since AFS 3 dir page size
4788 * may be less than (but not more than a buffer package buffer.
4790 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4791 temp &= ~(2048 - 1); /* turn off intra-page bits */
4792 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4794 /* now determine which entry we're looking at in the page. If it is
4795 * free (there's a free bitmap at the start of the dir), we should
4796 * skip these 32 bytes.
4798 slotInPage = (entryInDir & 0x7e0) >> 5;
4799 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4800 /* this entry is free */
4801 numDirChunks = 1; /* only skip this guy */
4805 tp = bufferp->datap + entryInBuffer;
4806 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4808 /* while we're here, compute the next entry's location, too,
4809 * since we'll need it when writing out the cookie into the dir
4812 * XXXX Probably should do more sanity checking.
4814 numDirChunks = cm_NameEntries(dep->name, NULL);
4816 /* compute the offset of the cookie representing the next entry */
4817 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4819 /* Compute 8.3 name if necessary */
4820 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4821 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4823 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4824 actualName = shortName;
4827 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
4828 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4829 osi_LogSaveClientString(smb_logp, actualName));
4831 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4832 /* this is one of the entries to use: it is not deleted
4833 * and it matches the star pattern we're looking for.
4836 /* Eliminate entries that don't match requested
4839 /* no hidden files */
4840 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4841 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4845 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4847 /* We have already done the cm_TryBulkStat above */
4848 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4849 fileType = cm_FindFileType(&fid);
4850 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4851 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4853 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4854 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4855 fileType == CM_SCACHETYPE_DFSLINK ||
4856 fileType == CM_SCACHETYPE_INVALID)
4857 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4862 memcpy(op, mask, 11); op += 11;
4863 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
4864 *op++ = (unsigned char)(nextEntryCookie & 0xff);
4865 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
4866 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
4867 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
4868 memcpy(op, &clientCookie, 4); op += 4;
4870 /* now we emit the attribute. This is sort of tricky,
4871 * since we need to really stat the file to find out
4872 * what type of entry we've got. Right now, we're
4873 * copying out data from a buffer, while holding the
4874 * scp locked, so it isn't really convenient to stat
4875 * something now. We'll put in a place holder now,
4876 * and make a second pass before returning this to get
4877 * the real attributes. So, we just skip the data for
4878 * now, and adjust it later. We allocate a patch
4879 * record to make it easy to find this point later.
4880 * The replay will happen at a time when it is safe to
4881 * unlock the directory.
4883 curPatchp = malloc(sizeof(*curPatchp));
4884 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4885 curPatchp->dptr = op;
4886 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4888 /* do hidden attribute here since name won't be around when applying
4892 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4893 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4895 curPatchp->flags = 0;
4897 op += 9; /* skip attr, time, date and size */
4899 /* zero out name area. The spec says to pad with
4900 * spaces, but Samba doesn't, and neither do we.
4904 /* finally, we get to copy out the name; we know that
4905 * it fits in 8.3 or the pattern wouldn't match, but it
4906 * never hurts to be sure.
4908 cm_ClientStringToUtf8(actualName, -1, op, 13);
4909 if (smb_StoreAnsiFilenames)
4911 /* This is a UCHAR field, which is ASCII even if Unicode
4914 /* Uppercase if requested by client */
4915 if (!KNOWS_LONG_NAMES(inp))
4920 /* now, adjust the # of entries copied */
4922 } /* if we're including this name */
4925 /* and adjust curOffset to be where the new cookie is */
4926 thyper.HighPart = 0;
4927 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4928 curOffset = LargeIntegerAdd(thyper, curOffset);
4929 } /* while copying data for dir listing */
4931 /* release the mutex */
4932 lock_ReleaseWrite(&scp->rw);
4934 buf_Release(bufferp);
4938 /* apply and free last set of patches; if not doing a star match, this
4939 * will be empty, but better safe (and freeing everything) than sorry.
4941 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4943 /* special return code for unsuccessful search */
4944 if (code == 0 && dataLength < 21 && returnedNames == 0)
4945 code = CM_ERROR_NOFILES;
4947 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4948 returnedNames, code);
4951 smb_DeleteDirSearch(dsp);
4952 smb_ReleaseDirSearch(dsp);
4953 cm_ReleaseSCache(scp);
4954 cm_ReleaseUser(userp);
4958 /* finalize the output buffer */
4959 smb_SetSMBParm(outp, 0, returnedNames);
4960 temp = (long) (op - origOp);
4961 smb_SetSMBDataLength(outp, temp);
4963 /* the data area is a variable block, which has a 5 (already there)
4964 * followed by the length of the # of data bytes. We now know this to
4965 * be "temp," although that includes the 3 bytes of vbl block header.
4966 * Deduct for them and fill in the length field.
4968 temp -= 3; /* deduct vbl block info */
4969 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4970 origOp[1] = (unsigned char)(temp & 0xff);
4971 origOp[2] = (unsigned char)((temp>>8) & 0xff);
4972 if (returnedNames == 0)
4973 smb_DeleteDirSearch(dsp);
4974 smb_ReleaseDirSearch(dsp);
4975 cm_ReleaseSCache(scp);
4976 cm_ReleaseUser(userp);
4981 /* verify that this is a valid path to a directory. I don't know why they
4982 * don't use the get file attributes call.
4984 * SMB_COM_CHECK_DIRECTORY
4986 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4988 clientchar_t *pathp;
4990 cm_scache_t *rootScp;
4991 cm_scache_t *newScp;
4995 clientchar_t *tidPathp;
5001 pdata = smb_GetSMBData(inp, NULL);
5002 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5004 return CM_ERROR_BADFD;
5005 osi_Log1(smb_logp, "SMB receive check path %S",
5006 osi_LogSaveClientString(smb_logp, pathp));
5008 rootScp = cm_data.rootSCachep;
5010 userp = smb_GetUserFromVCP(vcp, inp);
5012 caseFold = CM_FLAG_CASEFOLD;
5014 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5016 cm_ReleaseUser(userp);
5017 return CM_ERROR_NOSUCHPATH;
5019 code = cm_NameI(rootScp, pathp,
5020 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5021 userp, tidPathp, &req, &newScp);
5024 cm_ReleaseUser(userp);
5029 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5030 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5031 cm_ReleaseSCache(newScp);
5032 cm_ReleaseUser(userp);
5033 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5034 return CM_ERROR_PATH_NOT_COVERED;
5036 return CM_ERROR_BADSHARENAME;
5038 #endif /* DFS_SUPPORT */
5040 /* now lock the vnode with a callback; returns with newScp locked */
5041 lock_ObtainWrite(&newScp->rw);
5042 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5043 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5045 if (code != CM_ERROR_NOACCESS) {
5046 lock_ReleaseWrite(&newScp->rw);
5047 cm_ReleaseSCache(newScp);
5048 cm_ReleaseUser(userp);
5052 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5055 attrs = smb_Attributes(newScp);
5057 if (!(attrs & SMB_ATTR_DIRECTORY))
5058 code = CM_ERROR_NOTDIR;
5060 lock_ReleaseWrite(&newScp->rw);
5062 cm_ReleaseSCache(newScp);
5063 cm_ReleaseUser(userp);
5067 /* SMB_COM_SET_INFORMATION */
5068 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5070 clientchar_t *pathp;
5072 cm_scache_t *rootScp;
5073 unsigned short attribute;
5075 cm_scache_t *newScp;
5079 clientchar_t *tidPathp;
5085 /* decode basic attributes we're passed */
5086 attribute = smb_GetSMBParm(inp, 0);
5087 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5089 datap = smb_GetSMBData(inp, NULL);
5090 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5092 return CM_ERROR_BADSMB;
5094 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5095 dosTime, attribute);
5097 rootScp = cm_data.rootSCachep;
5099 userp = smb_GetUserFromVCP(vcp, inp);
5101 caseFold = CM_FLAG_CASEFOLD;
5103 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5105 cm_ReleaseUser(userp);
5106 return CM_ERROR_NOSUCHFILE;
5108 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5109 tidPathp, &req, &newScp);
5112 cm_ReleaseUser(userp);
5117 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5118 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5119 cm_ReleaseSCache(newScp);
5120 cm_ReleaseUser(userp);
5121 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5122 return CM_ERROR_PATH_NOT_COVERED;
5124 return CM_ERROR_BADSHARENAME;
5126 #endif /* DFS_SUPPORT */
5128 /* now lock the vnode with a callback; returns with newScp locked; we
5129 * need the current status to determine what the new status is, in some
5132 lock_ObtainWrite(&newScp->rw);
5133 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5134 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5136 lock_ReleaseWrite(&newScp->rw);
5137 cm_ReleaseSCache(newScp);
5138 cm_ReleaseUser(userp);
5142 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5144 /* Check for RO volume */
5145 if (newScp->flags & CM_SCACHEFLAG_RO) {
5146 lock_ReleaseWrite(&newScp->rw);
5147 cm_ReleaseSCache(newScp);
5148 cm_ReleaseUser(userp);
5149 return CM_ERROR_READONLY;
5152 /* prepare for setattr call */
5155 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5156 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5158 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5159 /* we're told to make a writable file read-only */
5160 attr.unixModeBits = newScp->unixModeBits & ~0222;
5161 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5163 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5164 /* we're told to make a read-only file writable */
5165 attr.unixModeBits = newScp->unixModeBits | 0222;
5166 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5168 lock_ReleaseWrite(&newScp->rw);
5170 /* now call setattr */
5172 code = cm_SetAttr(newScp, &attr, userp, &req);
5176 cm_ReleaseSCache(newScp);
5177 cm_ReleaseUser(userp);
5183 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5185 clientchar_t *pathp;
5187 cm_scache_t *rootScp;
5188 cm_scache_t *newScp, *dscp;
5193 clientchar_t *tidPathp;
5195 clientchar_t *lastComp;
5201 datap = smb_GetSMBData(inp, NULL);
5202 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5204 return CM_ERROR_BADSMB;
5206 if (*pathp == 0) /* null path */
5209 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5210 osi_LogSaveClientString(smb_logp, pathp));
5212 rootScp = cm_data.rootSCachep;
5214 userp = smb_GetUserFromVCP(vcp, inp);
5216 /* we shouldn't need this for V3 requests, but we seem to */
5217 caseFold = CM_FLAG_CASEFOLD;
5219 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5221 cm_ReleaseUser(userp);
5222 return CM_ERROR_NOSUCHFILE;
5226 * XXX Strange hack XXX
5228 * As of Patch 5 (16 July 97), we are having the following problem:
5229 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5230 * requests to look up "desktop.ini" in all the subdirectories.
5231 * This can cause zillions of timeouts looking up non-existent cells
5232 * and volumes, especially in the top-level directory.
5234 * We have not found any way to avoid this or work around it except
5235 * to explicitly ignore the requests for mount points that haven't
5236 * yet been evaluated and for directories that haven't yet been
5239 * We should modify this hack to provide a fake desktop.ini file
5240 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5242 spacep = inp->spacep;
5243 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5244 #ifndef SPECIAL_FOLDERS
5245 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5246 code = cm_NameI(rootScp, spacep->wdata,
5247 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5248 userp, tidPathp, &req, &dscp);
5251 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5252 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5254 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5255 return CM_ERROR_PATH_NOT_COVERED;
5257 return CM_ERROR_BADSHARENAME;
5259 #endif /* DFS_SUPPORT */
5260 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5261 code = CM_ERROR_NOSUCHFILE;
5262 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5263 cm_buf_t *bp = buf_Find(dscp, &hzero);
5268 code = CM_ERROR_NOSUCHFILE;
5270 cm_ReleaseSCache(dscp);
5272 cm_ReleaseUser(userp);
5277 #endif /* SPECIAL_FOLDERS */
5279 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5280 tidPathp, &req, &newScp);
5282 cm_ReleaseUser(userp);
5287 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5288 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5289 cm_ReleaseSCache(newScp);
5290 cm_ReleaseUser(userp);
5291 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5292 return CM_ERROR_PATH_NOT_COVERED;
5294 return CM_ERROR_BADSHARENAME;
5296 #endif /* DFS_SUPPORT */
5298 /* now lock the vnode with a callback; returns with newScp locked */
5299 lock_ObtainWrite(&newScp->rw);
5300 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5301 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5303 lock_ReleaseWrite(&newScp->rw);
5304 cm_ReleaseSCache(newScp);
5305 cm_ReleaseUser(userp);
5309 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5312 /* use smb_Attributes instead. Also the fact that a file is
5313 * in a readonly volume doesn't mean it shojuld be marked as RO
5315 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5316 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5317 newScp->fileType == CM_SCACHETYPE_INVALID)
5318 attrs = SMB_ATTR_DIRECTORY;
5321 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
5322 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
5324 attrs = smb_Attributes(newScp);
5327 smb_SetSMBParm(outp, 0, attrs);
5329 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5330 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5331 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5332 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5333 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5334 smb_SetSMBParm(outp, 5, 0);
5335 smb_SetSMBParm(outp, 6, 0);
5336 smb_SetSMBParm(outp, 7, 0);
5337 smb_SetSMBParm(outp, 8, 0);
5338 smb_SetSMBParm(outp, 9, 0);
5339 smb_SetSMBDataLength(outp, 0);
5340 lock_ReleaseWrite(&newScp->rw);
5342 cm_ReleaseSCache(newScp);
5343 cm_ReleaseUser(userp);
5348 /* SMB_COM_TREE_DISCONNECT */
5349 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5353 osi_Log0(smb_logp, "SMB receive tree disconnect");
5355 /* find the tree and free it */
5356 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5358 lock_ObtainWrite(&smb_rctLock);
5360 smb_ReleaseTID(tidp, TRUE);
5361 lock_ReleaseWrite(&smb_rctLock);
5368 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5371 clientchar_t *pathp;
5372 clientchar_t *lastNamep;
5381 clientchar_t *tidPathp;
5387 datap = smb_GetSMBData(inp, NULL);
5388 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5390 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5392 #ifdef DEBUG_VERBOSE
5396 hexpath = osi_HexifyString( pathp );
5397 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5402 share = smb_GetSMBParm(inp, 0);
5403 attribute = smb_GetSMBParm(inp, 1);
5405 spacep = inp->spacep;
5406 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5407 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5408 /* special case magic file name for receiving IOCTL requests
5409 * (since IOCTL calls themselves aren't getting through).
5411 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5412 smb_SetupIoctlFid(fidp, spacep);
5413 smb_SetSMBParm(outp, 0, fidp->fid);
5414 smb_SetSMBParm(outp, 1, 0); /* attrs */
5415 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5416 smb_SetSMBParm(outp, 3, 0);
5417 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5418 smb_SetSMBParm(outp, 5, 0x7fff);
5419 /* pass the open mode back */
5420 smb_SetSMBParm(outp, 6, (share & 0xf));
5421 smb_SetSMBDataLength(outp, 0);
5422 smb_ReleaseFID(fidp);
5426 userp = smb_GetUserFromVCP(vcp, inp);
5428 caseFold = CM_FLAG_CASEFOLD;
5430 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5432 cm_ReleaseUser(userp);
5433 return CM_ERROR_NOSUCHPATH;
5435 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5436 tidPathp, &req, &scp);
5439 cm_ReleaseUser(userp);
5444 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5445 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5446 cm_ReleaseSCache(scp);
5447 cm_ReleaseUser(userp);
5448 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5449 return CM_ERROR_PATH_NOT_COVERED;
5451 return CM_ERROR_BADSHARENAME;
5453 #endif /* DFS_SUPPORT */
5455 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5457 cm_ReleaseSCache(scp);
5458 cm_ReleaseUser(userp);
5462 /* don't need callback to check file type, since file types never
5463 * change, and namei and cm_Lookup all stat the object at least once on
5464 * a successful return.
5466 if (scp->fileType != CM_SCACHETYPE_FILE) {
5467 cm_ReleaseSCache(scp);
5468 cm_ReleaseUser(userp);
5469 return CM_ERROR_ISDIR;
5472 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5473 osi_assertx(fidp, "null smb_fid_t");
5475 /* save a pointer to the vnode */
5477 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5478 lock_ObtainWrite(&scp->rw);
5479 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5480 lock_ReleaseWrite(&scp->rw);
5484 fidp->userp = userp;
5486 lock_ObtainMutex(&fidp->mx);
5487 if ((share & 0xf) == 0)
5488 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5489 else if ((share & 0xf) == 1)
5490 fidp->flags |= SMB_FID_OPENWRITE;
5492 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5493 lock_ReleaseMutex(&fidp->mx);
5495 lock_ObtainRead(&scp->rw);
5496 smb_SetSMBParm(outp, 0, fidp->fid);
5497 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5498 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5499 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5500 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5501 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5502 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5503 /* pass the open mode back; XXXX add access checks */
5504 smb_SetSMBParm(outp, 6, (share & 0xf));
5505 smb_SetSMBDataLength(outp, 0);
5506 lock_ReleaseRead(&scp->rw);
5509 cm_Open(scp, 0, userp);
5511 /* send and free packet */
5512 smb_ReleaseFID(fidp);
5513 cm_ReleaseUser(userp);
5514 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5518 typedef struct smb_unlinkRock {
5523 clientchar_t *maskp; /* pointer to the star pattern */
5526 cm_dirEntryList_t * matches;
5529 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5532 smb_unlinkRock_t *rockp;
5535 normchar_t matchName[MAX_PATH];
5539 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5540 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5541 caseFold |= CM_FLAG_8DOT3;
5543 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5544 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5546 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5547 !cm_Is8Dot3(matchName)) {
5548 cm_Gen8Dot3Name(dep, matchName, NULL);
5549 /* 8.3 matches are always case insensitive */
5550 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5553 osi_Log1(smb_logp, "Found match %S",
5554 osi_LogSaveClientString(smb_logp, matchName));
5556 cm_DirEntryListAdd(dep->name, &rockp->matches);
5560 /* If we made a case sensitive exact match, we might as well quit now. */
5561 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5562 code = CM_ERROR_STOPNOW;
5571 /* SMB_COM_DELETE */
5572 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5576 clientchar_t *pathp;
5580 clientchar_t *lastNamep;
5581 smb_unlinkRock_t rock;
5585 clientchar_t *tidPathp;
5590 attribute = smb_GetSMBParm(inp, 0);
5592 tp = smb_GetSMBData(inp, NULL);
5593 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5595 osi_Log1(smb_logp, "SMB receive unlink %S",
5596 osi_LogSaveClientString(smb_logp, pathp));
5598 spacep = inp->spacep;
5599 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5601 userp = smb_GetUserFromVCP(vcp, inp);
5603 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5605 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5607 cm_ReleaseUser(userp);
5608 return CM_ERROR_NOSUCHPATH;
5610 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5613 cm_ReleaseUser(userp);
5618 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5619 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5620 cm_ReleaseSCache(dscp);
5621 cm_ReleaseUser(userp);
5622 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5623 return CM_ERROR_PATH_NOT_COVERED;
5625 return CM_ERROR_BADSHARENAME;
5627 #endif /* DFS_SUPPORT */
5629 /* otherwise, scp points to the parent directory. */
5636 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5637 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5640 thyper.HighPart = 0;
5645 rock.matches = NULL;
5647 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5648 * match. If that fails, we do a case insensitve match.
5650 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5651 !smb_IsStarMask(rock.maskp)) {
5652 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5655 thyper.HighPart = 0;
5656 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5661 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5663 if (code == CM_ERROR_STOPNOW)
5666 if (code == 0 && rock.matches) {
5667 cm_dirEntryList_t * entry;
5669 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5670 normchar_t normalizedName[MAX_PATH];
5672 /* Note: entry->name is a non-normalized name */
5674 osi_Log1(smb_logp, "Unlinking %s",
5675 osi_LogSaveString(smb_logp, entry->name));
5677 cm_FsStringToNormString(entry->name, -1,
5678 normalizedName, lengthof(normalizedName));
5680 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5682 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5683 smb_NotifyChange(FILE_ACTION_REMOVED,
5684 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5685 dscp, normalizedName, NULL, TRUE);
5689 cm_DirEntryListFree(&rock.matches);
5691 cm_ReleaseUser(userp);
5693 cm_ReleaseSCache(dscp);
5697 if (code == 0 && !rock.any)
5698 code = CM_ERROR_NOSUCHFILE;
5702 typedef struct smb_renameRock {
5703 cm_scache_t *odscp; /* old dir */
5704 cm_scache_t *ndscp; /* new dir */
5705 cm_user_t *userp; /* user */
5706 cm_req_t *reqp; /* request struct */
5707 smb_vc_t *vcp; /* virtual circuit */
5708 normchar_t *maskp; /* pointer to star pattern of old file name */
5709 int flags; /* tilde, casefold, etc */
5710 clientchar_t *newNamep; /* ptr to the new file's name */
5711 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5712 clientchar_t clOldName[MAX_PATH]; /* client name */
5716 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5719 smb_renameRock_t *rockp;
5722 normchar_t matchName[MAX_PATH];
5724 rockp = (smb_renameRock_t *) vrockp;
5726 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5727 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5728 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5729 caseFold |= CM_FLAG_8DOT3;
5731 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5733 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5734 !cm_Is8Dot3(matchName)) {
5735 cm_Gen8Dot3Name(dep, matchName, NULL);
5736 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5741 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5742 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5744 code = CM_ERROR_STOPNOW;
5754 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5757 cm_space_t *spacep = NULL;
5758 smb_renameRock_t rock;
5759 cm_scache_t *oldDscp = NULL;
5760 cm_scache_t *newDscp = NULL;
5761 cm_scache_t *tmpscp= NULL;
5762 cm_scache_t *tmpscp2 = NULL;
5763 clientchar_t *oldLastNamep;
5764 clientchar_t *newLastNamep;
5768 clientchar_t *tidPathp;
5772 userp = smb_GetUserFromVCP(vcp, inp);
5773 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5775 cm_ReleaseUser(userp);
5776 return CM_ERROR_NOSUCHPATH;
5780 spacep = inp->spacep;
5781 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5783 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5784 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5785 userp, tidPathp, &req, &oldDscp);
5787 cm_ReleaseUser(userp);
5792 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5793 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5794 cm_ReleaseSCache(oldDscp);
5795 cm_ReleaseUser(userp);
5796 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5797 return CM_ERROR_PATH_NOT_COVERED;
5799 return CM_ERROR_BADSHARENAME;
5801 #endif /* DFS_SUPPORT */
5803 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5804 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5805 userp, tidPathp, &req, &newDscp);
5808 cm_ReleaseSCache(oldDscp);
5809 cm_ReleaseUser(userp);
5814 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5815 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5816 cm_ReleaseSCache(oldDscp);
5817 cm_ReleaseSCache(newDscp);
5818 cm_ReleaseUser(userp);
5819 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5820 return CM_ERROR_PATH_NOT_COVERED;
5822 return CM_ERROR_BADSHARENAME;
5824 #endif /* DFS_SUPPORT */
5827 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5828 * next, get the component names, and lower case them.
5831 /* handle the old name first */
5833 oldLastNamep = oldPathp;
5837 /* and handle the new name, too */
5839 newLastNamep = newPathp;
5843 /* TODO: The old name could be a wildcard. The new name must not be */
5845 /* do the vnode call */
5846 rock.odscp = oldDscp;
5847 rock.ndscp = newDscp;
5851 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
5852 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5853 rock.newNamep = newLastNamep;
5854 rock.fsOldName[0] = '\0';
5855 rock.clOldName[0] = '\0';
5858 /* Check if the file already exists; if so return error */
5859 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5860 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5861 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5863 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5864 osi_LogSaveClientString(smb_logp, newLastNamep));
5866 /* Check if the old and the new names differ only in case. If so return
5867 * success, else return CM_ERROR_EXISTS
5869 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
5871 /* This would be a success only if the old file is *as same as* the new file */
5872 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5874 if (tmpscp == tmpscp2)
5877 code = CM_ERROR_EXISTS;
5878 cm_ReleaseSCache(tmpscp2);
5881 code = CM_ERROR_NOSUCHFILE;
5884 /* file exist, do not rename, also fixes move */
5885 osi_Log0(smb_logp, "Can't rename. Target already exists");
5886 code = CM_ERROR_EXISTS;
5890 cm_ReleaseSCache(tmpscp);
5891 cm_ReleaseSCache(newDscp);
5892 cm_ReleaseSCache(oldDscp);
5893 cm_ReleaseUser(userp);
5900 /* Now search the directory for the pattern, and do the appropriate rename when found */
5901 thyper.LowPart = 0; /* search dir from here */
5902 thyper.HighPart = 0;
5904 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5905 if (code == 0 && !rock.any) {
5907 thyper.HighPart = 0;
5908 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5909 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5911 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5913 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
5914 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
5915 rock.ndscp, rock.newNamep, rock.userp,
5917 /* if the call worked, stop doing the search now, since we
5918 * really only want to rename one file.
5920 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5921 } else if (code == 0) {
5922 code = CM_ERROR_NOSUCHFILE;
5925 /* Handle Change Notification */
5927 * Being lazy, not distinguishing between files and dirs in this
5928 * filter, since we'd have to do a lookup.
5931 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5932 if (oldDscp == newDscp) {
5933 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5934 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5935 filter, oldDscp, rock.clOldName,
5936 newLastNamep, TRUE);
5938 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5939 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5940 filter, oldDscp, rock.clOldName,
5942 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5943 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5944 filter, newDscp, newLastNamep,
5950 cm_ReleaseSCache(tmpscp);
5951 cm_ReleaseUser(userp);
5952 cm_ReleaseSCache(oldDscp);
5953 cm_ReleaseSCache(newDscp);
5962 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
5965 cm_space_t *spacep = NULL;
5966 cm_scache_t *oldDscp = NULL;
5967 cm_scache_t *newDscp = NULL;
5968 cm_scache_t *tmpscp= NULL;
5969 cm_scache_t *tmpscp2 = NULL;
5970 cm_scache_t *sscp = NULL;
5971 clientchar_t *oldLastNamep;
5972 clientchar_t *newLastNamep;
5975 clientchar_t *tidPathp;
5979 userp = smb_GetUserFromVCP(vcp, inp);
5981 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5983 cm_ReleaseUser(userp);
5984 return CM_ERROR_NOSUCHPATH;
5989 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5991 spacep = inp->spacep;
5992 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5994 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5995 userp, tidPathp, &req, &oldDscp);
5997 cm_ReleaseUser(userp);
6002 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6003 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6004 cm_ReleaseSCache(oldDscp);
6005 cm_ReleaseUser(userp);
6006 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6007 return CM_ERROR_PATH_NOT_COVERED;
6009 return CM_ERROR_BADSHARENAME;
6011 #endif /* DFS_SUPPORT */
6013 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6014 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6015 userp, tidPathp, &req, &newDscp);
6017 cm_ReleaseSCache(oldDscp);
6018 cm_ReleaseUser(userp);
6023 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6024 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6025 cm_ReleaseSCache(newDscp);
6026 cm_ReleaseSCache(oldDscp);
6027 cm_ReleaseUser(userp);
6028 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6029 return CM_ERROR_PATH_NOT_COVERED;
6031 return CM_ERROR_BADSHARENAME;
6033 #endif /* DFS_SUPPORT */
6035 /* Now, although we did two lookups for the two directories (because the same
6036 * directory can be referenced through different paths), we only allow hard links
6037 * within the same directory. */
6038 if (oldDscp != newDscp) {
6039 cm_ReleaseSCache(oldDscp);
6040 cm_ReleaseSCache(newDscp);
6041 cm_ReleaseUser(userp);
6042 return CM_ERROR_CROSSDEVLINK;
6045 /* handle the old name first */
6047 oldLastNamep = oldPathp;
6051 /* and handle the new name, too */
6053 newLastNamep = newPathp;
6057 /* now lookup the old name */
6058 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6059 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6061 cm_ReleaseSCache(oldDscp);
6062 cm_ReleaseSCache(newDscp);
6063 cm_ReleaseUser(userp);
6067 /* Check if the file already exists; if so return error */
6068 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6069 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6070 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6072 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6073 osi_LogSaveClientString(smb_logp, newLastNamep));
6075 /* if the existing link is to the same file, then we return success */
6077 if(sscp == tmpscp) {
6080 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6081 code = CM_ERROR_EXISTS;
6086 cm_ReleaseSCache(tmpscp);
6087 cm_ReleaseSCache(sscp);
6088 cm_ReleaseSCache(newDscp);
6089 cm_ReleaseSCache(oldDscp);
6090 cm_ReleaseUser(userp);
6094 /* now create the hardlink */
6095 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6096 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6097 osi_Log1(smb_logp," Link returns 0x%x", code);
6099 /* Handle Change Notification */
6101 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6102 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6103 smb_NotifyChange(FILE_ACTION_ADDED,
6104 filter, newDscp, newLastNamep,
6109 cm_ReleaseSCache(tmpscp);
6110 cm_ReleaseUser(userp);
6111 cm_ReleaseSCache(sscp);
6112 cm_ReleaseSCache(oldDscp);
6113 cm_ReleaseSCache(newDscp);
6117 /* SMB_COM_RENAME */
6119 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6121 clientchar_t *oldPathp;
6122 clientchar_t *newPathp;
6126 tp = smb_GetSMBData(inp, NULL);
6127 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6128 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6130 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6131 osi_LogSaveClientString(smb_logp, oldPathp),
6132 osi_LogSaveClientString(smb_logp, newPathp));
6134 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6136 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6142 typedef struct smb_rmdirRock {
6146 normchar_t *maskp; /* pointer to the star pattern */
6149 cm_dirEntryList_t * matches;
6152 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6155 smb_rmdirRock_t *rockp;
6157 normchar_t matchName[MAX_PATH];
6159 rockp = (smb_rmdirRock_t *) vrockp;
6161 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
6162 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6163 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6165 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6167 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6168 !cm_Is8Dot3(matchName)) {
6169 cm_Gen8Dot3Name(dep, matchName, NULL);
6170 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6175 cm_DirEntryListAdd(dep->name, &rockp->matches);
6182 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6185 clientchar_t *pathp;
6189 clientchar_t *lastNamep;
6190 smb_rmdirRock_t rock;
6194 clientchar_t *tidPathp;
6199 tp = smb_GetSMBData(inp, NULL);
6200 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6202 spacep = inp->spacep;
6203 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6205 userp = smb_GetUserFromVCP(vcp, inp);
6207 caseFold = CM_FLAG_CASEFOLD;
6209 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6211 cm_ReleaseUser(userp);
6212 return CM_ERROR_NOSUCHPATH;
6214 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6215 userp, tidPathp, &req, &dscp);
6218 cm_ReleaseUser(userp);
6223 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6224 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6225 cm_ReleaseSCache(dscp);
6226 cm_ReleaseUser(userp);
6227 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6228 return CM_ERROR_PATH_NOT_COVERED;
6230 return CM_ERROR_BADSHARENAME;
6232 #endif /* DFS_SUPPORT */
6234 /* otherwise, scp points to the parent directory. */
6241 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6242 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6245 thyper.HighPart = 0;
6249 rock.matches = NULL;
6251 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6252 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6253 if (code == 0 && !rock.any) {
6255 thyper.HighPart = 0;
6256 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6257 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6260 if (code == 0 && rock.matches) {
6261 cm_dirEntryList_t * entry;
6263 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6264 clientchar_t clientName[MAX_PATH];
6266 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6268 osi_Log1(smb_logp, "Removing directory %s",
6269 osi_LogSaveString(smb_logp, entry->name));
6271 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6273 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6274 smb_NotifyChange(FILE_ACTION_REMOVED,
6275 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6276 dscp, clientName, NULL, TRUE);
6280 cm_DirEntryListFree(&rock.matches);
6282 cm_ReleaseUser(userp);
6284 cm_ReleaseSCache(dscp);
6286 if (code == 0 && !rock.any)
6287 code = CM_ERROR_NOSUCHFILE;
6296 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6306 fid = smb_GetSMBParm(inp, 0);
6308 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6310 fid = smb_ChainFID(fid, inp);
6311 fidp = smb_FindFID(vcp, fid, 0);
6313 return CM_ERROR_BADFD;
6315 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6316 smb_CloseFID(vcp, fidp, NULL, 0);
6317 smb_ReleaseFID(fidp);
6318 return CM_ERROR_NOSUCHFILE;
6321 lock_ObtainMutex(&fidp->mx);
6322 if (fidp->flags & SMB_FID_IOCTL) {
6323 lock_ReleaseMutex(&fidp->mx);
6324 smb_ReleaseFID(fidp);
6325 return CM_ERROR_BADFD;
6327 lock_ReleaseMutex(&fidp->mx);
6329 userp = smb_GetUserFromVCP(vcp, inp);
6331 lock_ObtainMutex(&fidp->mx);
6332 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6333 cm_scache_t * scp = fidp->scp;
6335 lock_ReleaseMutex(&fidp->mx);
6336 code = cm_FSync(scp, userp, &req);
6337 cm_ReleaseSCache(scp);
6340 lock_ReleaseMutex(&fidp->mx);
6343 smb_ReleaseFID(fidp);
6345 cm_ReleaseUser(userp);
6350 struct smb_FullNameRock {
6353 clientchar_t *fullName;
6354 fschar_t *originalName;
6357 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6360 normchar_t matchName[MAX_PATH];
6361 struct smb_FullNameRock *vrockp;
6363 vrockp = (struct smb_FullNameRock *)rockp;
6365 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
6367 if (!cm_Is8Dot3(matchName)) {
6368 clientchar_t shortName[13];
6370 cm_Gen8Dot3Name(dep, shortName, NULL);
6372 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6373 vrockp->fullName = cm_ClientStrDup(matchName);
6374 vrockp->originalName = cm_FsStrDup(dep->name);
6375 return CM_ERROR_STOPNOW;
6378 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6379 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6380 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6381 vrockp->fullName = cm_ClientStrDup(matchName);
6382 vrockp->originalName = cm_FsStrDup(dep->name);
6383 return CM_ERROR_STOPNOW;
6388 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6389 clientchar_t **newPathp, fschar_t ** originalPathp,
6390 cm_user_t *userp, cm_req_t *reqp)
6392 struct smb_FullNameRock rock;
6395 memset(&rock, 0, sizeof(rock));
6399 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6400 if (code == CM_ERROR_STOPNOW) {
6401 *newPathp = rock.fullName;
6402 *originalPathp = rock.originalName;
6404 *newPathp = cm_ClientStrDup(pathp);
6405 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6409 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6410 afs_uint32 dosTime) {
6413 cm_scache_t *dscp = NULL;
6414 clientchar_t *pathp = NULL;
6415 cm_scache_t * scp = NULL;
6416 cm_scache_t *delscp = NULL;
6417 int nullcreator = 0;
6419 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6420 fidp, fidp->fid, scp, vcp);
6423 lock_ObtainMutex(&fidp->mx);
6424 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6425 lock_ReleaseMutex(&fidp->mx);
6426 osi_Log0(smb_logp, " No user specified. Not closing fid");
6427 return CM_ERROR_BADFD;
6430 userp = fidp->userp; /* no hold required since fidp is held
6431 throughout the function */
6432 lock_ReleaseMutex(&fidp->mx);
6437 lock_ObtainWrite(&smb_rctLock);
6438 if (fidp->deleteOk) {
6439 osi_Log0(smb_logp, " Fid already closed.");
6440 lock_ReleaseWrite(&smb_rctLock);
6441 return CM_ERROR_BADFD;
6444 lock_ReleaseWrite(&smb_rctLock);
6446 lock_ObtainMutex(&fidp->mx);
6447 if (fidp->NTopen_dscp) {
6448 dscp = fidp->NTopen_dscp;
6449 cm_HoldSCache(dscp);
6452 if (fidp->NTopen_pathp) {
6453 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6461 /* Don't jump the gun on an async raw write */
6462 while (fidp->raw_writers) {
6463 lock_ReleaseMutex(&fidp->mx);
6464 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6465 lock_ObtainMutex(&fidp->mx);
6468 /* watch for ioctl closes, and read-only opens */
6470 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6471 == SMB_FID_OPENWRITE) {
6472 if (dosTime != 0 && dosTime != -1) {
6473 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6474 /* This fixes defect 10958 */
6475 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6476 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6478 if (smb_AsyncStore != 2) {
6479 lock_ReleaseMutex(&fidp->mx);
6480 code = cm_FSync(scp, userp, &req);
6481 lock_ObtainMutex(&fidp->mx);
6487 /* unlock any pending locks */
6488 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6489 scp->fileType == CM_SCACHETYPE_FILE) {
6493 lock_ReleaseMutex(&fidp->mx);
6495 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6497 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6498 lock_ObtainWrite(&scp->rw);
6500 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6501 CM_SCACHESYNC_NEEDCALLBACK
6502 | CM_SCACHESYNC_GETSTATUS
6503 | CM_SCACHESYNC_LOCK);
6507 "smb CoreClose SyncOp failure code 0x%x", tcode);
6508 goto post_syncopdone;
6511 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6513 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6517 lock_ReleaseWrite(&scp->rw);
6518 lock_ObtainMutex(&fidp->mx);
6521 if (fidp->flags & SMB_FID_DELONCLOSE) {
6522 clientchar_t *fullPathp = NULL;
6523 fschar_t *originalNamep = NULL;
6525 lock_ReleaseMutex(&fidp->mx);
6527 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6532 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6533 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6534 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6536 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6537 smb_NotifyChange(FILE_ACTION_REMOVED,
6538 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6539 dscp, fullPathp, NULL, TRUE);
6542 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6544 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6545 smb_NotifyChange(FILE_ACTION_REMOVED,
6546 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6547 dscp, fullPathp, NULL, TRUE);
6554 free(originalNamep);
6556 lock_ObtainMutex(&fidp->mx);
6557 fidp->flags &= ~SMB_FID_DELONCLOSE;
6560 /* if this was a newly created file, then clear the creator
6561 * in the stat cache entry. */
6562 if (fidp->flags & SMB_FID_CREATED) {
6564 fidp->flags &= ~SMB_FID_CREATED;
6567 if (fidp->flags & SMB_FID_NTOPEN) {
6568 cm_ReleaseSCache(fidp->NTopen_dscp);
6569 fidp->NTopen_dscp = NULL;
6570 free(fidp->NTopen_pathp);
6571 fidp->NTopen_pathp = NULL;
6572 fidp->flags &= ~SMB_FID_NTOPEN;
6574 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6575 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6578 if (fidp->NTopen_wholepathp) {
6579 free(fidp->NTopen_wholepathp);
6580 fidp->NTopen_wholepathp = NULL;
6584 cm_ReleaseSCache(fidp->scp);
6587 lock_ReleaseMutex(&fidp->mx);
6590 cm_ReleaseSCache(dscp);
6593 cm_ReleaseSCache(delscp);
6597 lock_ObtainWrite(&scp->rw);
6598 if (nullcreator && scp->creator == userp)
6599 scp->creator = NULL;
6600 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6601 lock_ReleaseWrite(&scp->rw);
6602 cm_ReleaseSCache(scp);
6612 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6620 fid = smb_GetSMBParm(inp, 0);
6621 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6623 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6625 fid = smb_ChainFID(fid, inp);
6626 fidp = smb_FindFID(vcp, fid, 0);
6628 return CM_ERROR_BADFD;
6631 userp = smb_GetUserFromVCP(vcp, inp);
6633 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6635 smb_ReleaseFID(fidp);
6636 cm_ReleaseUser(userp);
6641 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6643 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6644 cm_user_t *userp, long *readp)
6650 osi_hyper_t fileLength;
6652 osi_hyper_t lastByte;
6653 osi_hyper_t bufferOffset;
6657 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6660 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6661 fidp->fid, offsetp->LowPart, count);
6665 lock_ObtainMutex(&fidp->mx);
6666 /* make sure we have a readable FD */
6667 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6668 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6669 fidp->fid, fidp->flags);
6670 lock_ReleaseMutex(&fidp->mx);
6671 code = CM_ERROR_BADFDOP;
6682 lock_ObtainWrite(&scp->rw);
6684 if (offset.HighPart == 0) {
6685 chunk = offset.LowPart >> cm_logChunkSize;
6686 if (chunk != fidp->curr_chunk) {
6687 fidp->prev_chunk = fidp->curr_chunk;
6688 fidp->curr_chunk = chunk;
6690 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6693 lock_ReleaseMutex(&fidp->mx);
6695 /* start by looking up the file's end */
6696 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6697 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6701 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6703 /* now we have the entry locked, look up the length */
6704 fileLength = scp->length;
6706 /* adjust count down so that it won't go past EOF */
6707 thyper.LowPart = count;
6708 thyper.HighPart = 0;
6709 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6711 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6712 /* we'd read past EOF, so just stop at fileLength bytes.
6713 * Start by computing how many bytes remain in the file.
6715 thyper = LargeIntegerSubtract(fileLength, offset);
6717 /* if we are past EOF, read 0 bytes */
6718 if (LargeIntegerLessThanZero(thyper))
6721 count = thyper.LowPart;
6726 /* now, copy the data one buffer at a time,
6727 * until we've filled the request packet
6730 /* if we've copied all the data requested, we're done */
6731 if (count <= 0) break;
6733 /* otherwise, load up a buffer of data */
6734 thyper.HighPart = offset.HighPart;
6735 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6736 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6739 buf_Release(bufferp);
6742 lock_ReleaseWrite(&scp->rw);
6744 code = buf_Get(scp, &thyper, &bufferp);
6746 lock_ObtainWrite(&scp->rw);
6747 if (code) goto done;
6748 bufferOffset = thyper;
6750 /* now get the data in the cache */
6752 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6753 CM_SCACHESYNC_NEEDCALLBACK |
6754 CM_SCACHESYNC_READ);
6758 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6760 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6762 /* otherwise, load the buffer and try again */
6763 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6767 buf_Release(bufferp);
6771 } /* if (wrong buffer) ... */
6773 /* now we have the right buffer loaded. Copy out the
6774 * data from here to the user's buffer.
6776 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6778 /* and figure out how many bytes we want from this buffer */
6779 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6780 if (nbytes > count) nbytes = count; /* don't go past EOF */
6782 /* now copy the data */
6783 memcpy(op, bufferp->datap + bufIndex, nbytes);
6785 /* adjust counters, pointers, etc. */
6788 thyper.LowPart = nbytes;
6789 thyper.HighPart = 0;
6790 offset = LargeIntegerAdd(thyper, offset);
6794 lock_ReleaseWrite(&scp->rw);
6796 buf_Release(bufferp);
6798 if (code == 0 && sequential)
6799 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6801 cm_ReleaseSCache(scp);
6804 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6805 fidp->fid, code, *readp);
6810 * smb_WriteData -- common code for Write and Raw Write
6812 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6813 cm_user_t *userp, long *writtenp)
6815 osi_hyper_t offset = *offsetp;
6818 cm_scache_t *scp = NULL;
6819 osi_hyper_t fileLength; /* file's length at start of write */
6820 osi_hyper_t minLength; /* don't read past this */
6821 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6822 cm_buf_t *bufferp = NULL;
6823 osi_hyper_t thyper; /* hyper tmp variable */
6824 osi_hyper_t bufferOffset;
6825 afs_uint32 bufIndex; /* index in buffer where our data is */
6826 int doWriteBack = 0;
6827 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6831 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6832 fidp->fid, offsetp->LowPart, count);
6836 lock_ObtainMutex(&fidp->mx);
6837 /* make sure we have a writable FD */
6838 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6839 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6840 fidp->fid, fidp->flags);
6841 lock_ReleaseMutex(&fidp->mx);
6842 code = CM_ERROR_BADFDOP;
6850 lock_ReleaseMutex(&fidp->mx);
6852 lock_ObtainWrite(&scp->rw);
6853 /* start by looking up the file's end */
6854 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6855 CM_SCACHESYNC_NEEDCALLBACK
6856 | CM_SCACHESYNC_SETSTATUS
6857 | CM_SCACHESYNC_GETSTATUS);
6861 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6863 /* now we have the entry locked, look up the length */
6864 fileLength = scp->length;
6865 minLength = fileLength;
6866 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6867 minLength = scp->serverLength;
6869 /* adjust file length if we extend past EOF */
6870 thyper.LowPart = count;
6871 thyper.HighPart = 0;
6872 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6873 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6874 /* we'd write past EOF, so extend the file */
6875 scp->mask |= CM_SCACHEMASK_LENGTH;
6876 scp->length = thyper;
6877 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6879 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6881 /* now, if the new position (thyper) and the old (offset) are in
6882 * different storeback windows, remember to store back the previous
6883 * storeback window when we're done with the write.
6885 * the purpose of this logic is to slow down the CIFS client
6886 * in order to avoid the client disconnecting during the CLOSE
6887 * operation if there are too many dirty buffers left to write
6888 * than can be accomplished during 45 seconds. This used to be
6889 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6890 * so that we can read larger amounts of data at a time.
6892 if (smb_AsyncStore == 1 &&
6893 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
6894 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
6895 /* they're different */
6897 writeBackOffset.HighPart = offset.HighPart;
6898 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
6903 /* now, copy the data one buffer at a time, until we've filled the
6906 /* if we've copied all the data requested, we're done */
6910 /* handle over quota or out of space */
6911 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6912 *writtenp = written;
6913 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6917 /* otherwise, load up a buffer of data */
6918 thyper.HighPart = offset.HighPart;
6919 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6920 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6923 lock_ReleaseMutex(&bufferp->mx);
6924 buf_Release(bufferp);
6927 lock_ReleaseWrite(&scp->rw);
6929 code = buf_Get(scp, &thyper, &bufferp);
6931 lock_ObtainMutex(&bufferp->mx);
6932 lock_ObtainWrite(&scp->rw);
6933 if (code) goto done;
6935 bufferOffset = thyper;
6937 /* now get the data in the cache */
6939 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6940 CM_SCACHESYNC_NEEDCALLBACK
6941 | CM_SCACHESYNC_WRITE
6942 | CM_SCACHESYNC_BUFLOCKED);
6946 cm_SyncOpDone(scp, bufferp,
6947 CM_SCACHESYNC_NEEDCALLBACK
6948 | CM_SCACHESYNC_WRITE
6949 | CM_SCACHESYNC_BUFLOCKED);
6951 /* If we're overwriting the entire buffer, or
6952 * if we're writing at or past EOF, mark the
6953 * buffer as current so we don't call
6954 * cm_GetBuffer. This skips the fetch from the
6955 * server in those cases where we're going to
6956 * obliterate all the data in the buffer anyway,
6957 * or in those cases where there is no useful
6958 * data at the server to start with.
6960 * Use minLength instead of scp->length, since
6961 * the latter has already been updated by this
6964 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6965 || LargeIntegerEqualTo(offset, bufferp->offset)
6966 && (count >= cm_data.buf_blockSize
6967 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6968 ConvertLongToLargeInteger(count)),
6970 if (count < cm_data.buf_blockSize
6971 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
6972 memset(bufferp->datap, 0,
6973 cm_data.buf_blockSize);
6974 bufferp->dataVersion = scp->dataVersion;
6977 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6979 /* otherwise, load the buffer and try again */
6980 lock_ReleaseMutex(&bufferp->mx);
6981 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6983 lock_ReleaseWrite(&scp->rw);
6984 lock_ObtainMutex(&bufferp->mx);
6985 lock_ObtainWrite(&scp->rw);
6989 lock_ReleaseMutex(&bufferp->mx);
6990 buf_Release(bufferp);
6994 } /* if (wrong buffer) ... */
6996 /* now we have the right buffer loaded. Copy out the
6997 * data from here to the user's buffer.
6999 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7001 /* and figure out how many bytes we want from this buffer */
7002 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7004 nbytes = count; /* don't go past end of request */
7006 /* now copy the data */
7007 memcpy(bufferp->datap + bufIndex, op, nbytes);
7008 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7010 /* adjust counters, pointers, etc. */
7014 thyper.LowPart = nbytes;
7015 thyper.HighPart = 0;
7016 offset = LargeIntegerAdd(thyper, offset);
7020 lock_ReleaseWrite(&scp->rw);
7023 lock_ReleaseMutex(&bufferp->mx);
7024 buf_Release(bufferp);
7027 lock_ObtainMutex(&fidp->mx);
7028 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7029 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
7030 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7031 fidp->NTopen_dscp, fidp->NTopen_pathp,
7034 lock_ReleaseMutex(&fidp->mx);
7037 if (smb_AsyncStore > 0) {
7041 lock_ObtainWrite(&scp->rw);
7042 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7044 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7045 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7047 lock_ReleaseWrite(&scp->rw);
7048 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7049 writeBackOffset.HighPart,
7050 smb_AsyncStoreSize, 0, userp);
7051 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7054 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7058 cm_ReleaseSCache(scp);
7061 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7062 fidp->fid, code, *writtenp);
7067 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7070 unsigned short count;
7072 unsigned short hint;
7073 long written = 0, total_written = 0;
7076 smb_t* smbp = (smb_t*) inp;
7079 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7081 int inDataBlockCount;
7083 fd = smb_GetSMBParm(inp, 0);
7084 count = smb_GetSMBParm(inp, 1);
7085 offset.HighPart = 0; /* too bad */
7086 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7087 hint = smb_GetSMBParm(inp, 4);
7089 op = smb_GetSMBData(inp, NULL);
7090 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7092 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7093 fd, offset.LowPart, count);
7095 fd = smb_ChainFID(fd, inp);
7096 fidp = smb_FindFID(vcp, fd, 0);
7098 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7099 return CM_ERROR_BADFD;
7102 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7103 smb_CloseFID(vcp, fidp, NULL, 0);
7104 smb_ReleaseFID(fidp);
7105 return CM_ERROR_NOSUCHFILE;
7108 lock_ObtainMutex(&fidp->mx);
7109 if (fidp->flags & SMB_FID_IOCTL) {
7110 lock_ReleaseMutex(&fidp->mx);
7111 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7112 smb_ReleaseFID(fidp);
7113 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7116 lock_ReleaseMutex(&fidp->mx);
7117 userp = smb_GetUserFromVCP(vcp, inp);
7121 LARGE_INTEGER LOffset;
7122 LARGE_INTEGER LLength;
7125 key = cm_GenerateKey(vcp->vcID, pid, fd);
7127 LOffset.HighPart = offset.HighPart;
7128 LOffset.LowPart = offset.LowPart;
7129 LLength.HighPart = 0;
7130 LLength.LowPart = count;
7132 lock_ObtainWrite(&fidp->scp->rw);
7133 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7134 lock_ReleaseWrite(&fidp->scp->rw);
7137 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7142 /* special case: 0 bytes transferred means truncate to this position */
7146 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7150 truncAttr.mask = CM_ATTRMASK_LENGTH;
7151 truncAttr.length.LowPart = offset.LowPart;
7152 truncAttr.length.HighPart = 0;
7153 lock_ObtainMutex(&fidp->mx);
7154 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7155 fidp->flags |= SMB_FID_LENGTHSETDONE;
7156 lock_ReleaseMutex(&fidp->mx);
7157 smb_SetSMBParm(outp, 0, 0 /* count */);
7158 smb_SetSMBDataLength(outp, 0);
7163 * Work around bug in NT client
7165 * When copying a file, the NT client should first copy the data,
7166 * then copy the last write time. But sometimes the NT client does
7167 * these in the wrong order, so the data copies would inadvertently
7168 * cause the last write time to be overwritten. We try to detect this,
7169 * and don't set client mod time if we think that would go against the
7172 lock_ObtainMutex(&fidp->mx);
7173 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7174 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7175 fidp->scp->clientModTime = time(NULL);
7177 lock_ReleaseMutex(&fidp->mx);
7180 while ( code == 0 && count > 0 ) {
7181 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7182 if (code == 0 && written == 0)
7183 code = CM_ERROR_PARTIALWRITE;
7185 offset = LargeIntegerAdd(offset,
7186 ConvertLongToLargeInteger(written));
7187 count -= (unsigned short)written;
7188 total_written += written;
7192 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7193 total_written, code);
7195 /* set the packet data length to 3 bytes for the data block header,
7196 * plus the size of the data.
7198 smb_SetSMBParm(outp, 0, total_written);
7199 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7200 smb_SetSMBParm(outp, 3, hint);
7201 smb_SetSMBDataLength(outp, 0);
7204 smb_ReleaseFID(fidp);
7205 cm_ReleaseUser(userp);
7210 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7211 NCB *ncbp, raw_write_cont_t *rwcp)
7220 fd = smb_GetSMBParm(inp, 0);
7221 fidp = smb_FindFID(vcp, fd, 0);
7223 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7224 smb_CloseFID(vcp, fidp, NULL, 0);
7225 smb_ReleaseFID(fidp);
7229 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7230 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7232 userp = smb_GetUserFromVCP(vcp, inp);
7235 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7237 if (rwcp->writeMode & 0x1) { /* synchronous */
7240 smb_FormatResponsePacket(vcp, inp, outp);
7241 op = (smb_t *) outp;
7242 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7243 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7244 smb_SetSMBDataLength(outp, 0);
7245 smb_SendPacket(vcp, outp);
7246 smb_FreePacket(outp);
7248 else { /* asynchronous */
7249 lock_ObtainMutex(&fidp->mx);
7250 fidp->raw_writers--;
7251 if (fidp->raw_writers == 0)
7252 thrd_SetEvent(fidp->raw_write_event);
7253 lock_ReleaseMutex(&fidp->mx);
7256 /* Give back raw buffer */
7257 lock_ObtainMutex(&smb_RawBufLock);
7258 *((char **)rawBuf) = smb_RawBufs;
7259 smb_RawBufs = rawBuf;
7260 lock_ReleaseMutex(&smb_RawBufLock);
7262 smb_ReleaseFID(fidp);
7263 cm_ReleaseUser(userp);
7266 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7271 /* SMB_COM_WRITE_RAW */
7272 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7275 long count, written = 0, total_written = 0;
7279 smb_t *smbp = (smb_t*) inp;
7283 unsigned short writeMode;
7285 fd = smb_GetSMBParm(inp, 0);
7286 totalCount = smb_GetSMBParm(inp, 1);
7287 count = smb_GetSMBParm(inp, 10);
7288 writeMode = smb_GetSMBParm(inp, 7);
7290 op = (char *) inp->data;
7291 op += smb_GetSMBParm(inp, 11);
7293 offset.HighPart = 0;
7294 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7296 if (*inp->wctp == 14) {
7297 /* we received a 64-bit file offset */
7298 #ifdef AFS_LARGEFILES
7299 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7301 if (LargeIntegerLessThanZero(offset)) {
7303 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7304 offset.HighPart, offset.LowPart);
7305 return CM_ERROR_BADSMB;
7308 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7310 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7311 return CM_ERROR_BADSMB;
7314 offset.HighPart = 0;
7317 offset.HighPart = 0; /* 32-bit file offset */
7321 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7322 fd, offset.HighPart, offset.LowPart, count);
7324 " WriteRaw WriteMode 0x%x",
7327 fd = smb_ChainFID(fd, inp);
7328 fidp = smb_FindFID(vcp, fd, 0);
7330 return CM_ERROR_BADFD;
7333 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7334 smb_CloseFID(vcp, fidp, NULL, 0);
7335 smb_ReleaseFID(fidp);
7336 return CM_ERROR_NOSUCHFILE;
7342 LARGE_INTEGER LOffset;
7343 LARGE_INTEGER LLength;
7346 key = cm_GenerateKey(vcp->vcID, pid, fd);
7348 LOffset.HighPart = offset.HighPart;
7349 LOffset.LowPart = offset.LowPart;
7350 LLength.HighPart = 0;
7351 LLength.LowPart = count;
7353 lock_ObtainWrite(&fidp->scp->rw);
7354 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7355 lock_ReleaseWrite(&fidp->scp->rw);
7358 smb_ReleaseFID(fidp);
7363 userp = smb_GetUserFromVCP(vcp, inp);
7366 * Work around bug in NT client
7368 * When copying a file, the NT client should first copy the data,
7369 * then copy the last write time. But sometimes the NT client does
7370 * these in the wrong order, so the data copies would inadvertently
7371 * cause the last write time to be overwritten. We try to detect this,
7372 * and don't set client mod time if we think that would go against the
7375 lock_ObtainMutex(&fidp->mx);
7376 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7377 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7378 fidp->scp->clientModTime = time(NULL);
7380 lock_ReleaseMutex(&fidp->mx);
7383 while ( code == 0 && count > 0 ) {
7384 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7385 if (code == 0 && written == 0)
7386 code = CM_ERROR_PARTIALWRITE;
7388 offset = LargeIntegerAdd(offset,
7389 ConvertLongToLargeInteger(written));
7392 total_written += written;
7396 /* Get a raw buffer */
7399 lock_ObtainMutex(&smb_RawBufLock);
7401 /* Get a raw buf, from head of list */
7402 rawBuf = smb_RawBufs;
7403 smb_RawBufs = *(char **)smb_RawBufs;
7406 code = CM_ERROR_USESTD;
7408 lock_ReleaseMutex(&smb_RawBufLock);
7411 /* Don't allow a premature Close */
7412 if (code == 0 && (writeMode & 1) == 0) {
7413 lock_ObtainMutex(&fidp->mx);
7414 fidp->raw_writers++;
7415 thrd_ResetEvent(fidp->raw_write_event);
7416 lock_ReleaseMutex(&fidp->mx);
7419 smb_ReleaseFID(fidp);
7420 cm_ReleaseUser(userp);
7423 smb_SetSMBParm(outp, 0, total_written);
7424 smb_SetSMBDataLength(outp, 0);
7425 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7430 offset = LargeIntegerAdd(offset,
7431 ConvertLongToLargeInteger(count));
7435 rwcp->offset.HighPart = offset.HighPart;
7436 rwcp->offset.LowPart = offset.LowPart;
7437 rwcp->count = totalCount - count;
7438 rwcp->writeMode = writeMode;
7439 rwcp->alreadyWritten = total_written;
7441 /* set the packet data length to 3 bytes for the data block header,
7442 * plus the size of the data.
7444 smb_SetSMBParm(outp, 0, 0xffff);
7445 smb_SetSMBDataLength(outp, 0);
7451 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7454 long count, finalCount;
7458 smb_t *smbp = (smb_t*) inp;
7463 fd = smb_GetSMBParm(inp, 0);
7464 count = smb_GetSMBParm(inp, 1);
7465 offset.HighPart = 0; /* too bad */
7466 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7468 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7469 fd, offset.LowPart, count);
7471 fd = smb_ChainFID(fd, inp);
7472 fidp = smb_FindFID(vcp, fd, 0);
7474 return CM_ERROR_BADFD;
7476 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7477 smb_CloseFID(vcp, fidp, NULL, 0);
7478 smb_ReleaseFID(fidp);
7479 return CM_ERROR_NOSUCHFILE;
7482 lock_ObtainMutex(&fidp->mx);
7483 if (fidp->flags & SMB_FID_IOCTL) {
7484 lock_ReleaseMutex(&fidp->mx);
7485 code = smb_IoctlRead(fidp, vcp, inp, outp);
7486 smb_ReleaseFID(fidp);
7489 lock_ReleaseMutex(&fidp->mx);
7492 LARGE_INTEGER LOffset, LLength;
7496 key = cm_GenerateKey(vcp->vcID, pid, fd);
7498 LOffset.HighPart = 0;
7499 LOffset.LowPart = offset.LowPart;
7500 LLength.HighPart = 0;
7501 LLength.LowPart = count;
7503 lock_ObtainWrite(&fidp->scp->rw);
7504 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7505 lock_ReleaseWrite(&fidp->scp->rw);
7508 smb_ReleaseFID(fidp);
7512 userp = smb_GetUserFromVCP(vcp, inp);
7514 /* remember this for final results */
7515 smb_SetSMBParm(outp, 0, count);
7516 smb_SetSMBParm(outp, 1, 0);
7517 smb_SetSMBParm(outp, 2, 0);
7518 smb_SetSMBParm(outp, 3, 0);
7519 smb_SetSMBParm(outp, 4, 0);
7521 /* set the packet data length to 3 bytes for the data block header,
7522 * plus the size of the data.
7524 smb_SetSMBDataLength(outp, count+3);
7526 /* get op ptr after putting in the parms, since otherwise we don't
7527 * know where the data really is.
7529 op = smb_GetSMBData(outp, NULL);
7531 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7532 *op++ = 1; /* data block marker */
7533 *op++ = (unsigned char) (count & 0xff);
7534 *op++ = (unsigned char) ((count >> 8) & 0xff);
7536 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7538 /* fix some things up */
7539 smb_SetSMBParm(outp, 0, finalCount);
7540 smb_SetSMBDataLength(outp, finalCount+3);
7542 smb_ReleaseFID(fidp);
7544 cm_ReleaseUser(userp);
7548 /* SMB_COM_CREATE_DIRECTORY */
7549 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7551 clientchar_t *pathp;
7556 cm_scache_t *dscp; /* dir we're dealing with */
7557 cm_scache_t *scp; /* file we're creating */
7559 int initialModeBits;
7560 clientchar_t *lastNamep;
7562 clientchar_t *tidPathp;
7569 /* compute initial mode bits based on read-only flag in attributes */
7570 initialModeBits = 0777;
7572 tp = smb_GetSMBData(inp, NULL);
7573 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7575 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7576 return CM_ERROR_EXISTS;
7578 spacep = inp->spacep;
7579 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7581 userp = smb_GetUserFromVCP(vcp, inp);
7583 caseFold = CM_FLAG_CASEFOLD;
7585 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7587 cm_ReleaseUser(userp);
7588 return CM_ERROR_NOSUCHPATH;
7591 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7592 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7593 userp, tidPathp, &req, &dscp);
7596 cm_ReleaseUser(userp);
7601 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7602 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7603 cm_ReleaseSCache(dscp);
7604 cm_ReleaseUser(userp);
7605 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7606 return CM_ERROR_PATH_NOT_COVERED;
7608 return CM_ERROR_BADSHARENAME;
7610 #endif /* DFS_SUPPORT */
7612 /* otherwise, scp points to the parent directory. Do a lookup, and
7613 * fail if we find it. Otherwise, we do the create.
7619 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7620 if (scp) cm_ReleaseSCache(scp);
7621 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7622 if (code == 0) code = CM_ERROR_EXISTS;
7623 cm_ReleaseSCache(dscp);
7624 cm_ReleaseUser(userp);
7628 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7629 setAttr.clientModTime = time(NULL);
7630 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7631 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7632 smb_NotifyChange(FILE_ACTION_ADDED,
7633 FILE_NOTIFY_CHANGE_DIR_NAME,
7634 dscp, lastNamep, NULL, TRUE);
7636 /* we don't need this any longer */
7637 cm_ReleaseSCache(dscp);
7640 /* something went wrong creating or truncating the file */
7641 cm_ReleaseUser(userp);
7645 /* otherwise we succeeded */
7646 smb_SetSMBDataLength(outp, 0);
7647 cm_ReleaseUser(userp);
7652 BOOL smb_IsLegalFilename(clientchar_t *filename)
7655 * Find the longest substring of filename that does not contain
7656 * any of the chars in illegalChars. If that substring is less
7657 * than the length of the whole string, then one or more of the
7658 * illegal chars is in filename.
7660 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7666 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7667 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7669 clientchar_t *pathp;
7675 cm_scache_t *dscp; /* dir we're dealing with */
7676 cm_scache_t *scp; /* file we're creating */
7678 int initialModeBits;
7681 clientchar_t *lastNamep;
7684 clientchar_t *tidPathp;
7686 int created = 0; /* the file was new */
7691 excl = (inp->inCom == 0x03)? 0 : 1;
7693 attributes = smb_GetSMBParm(inp, 0);
7694 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7696 /* compute initial mode bits based on read-only flag in attributes */
7697 initialModeBits = 0666;
7698 if (attributes & SMB_ATTR_READONLY)
7699 initialModeBits &= ~0222;
7701 tp = smb_GetSMBData(inp, NULL);
7702 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7704 spacep = inp->spacep;
7705 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7707 userp = smb_GetUserFromVCP(vcp, inp);
7709 caseFold = CM_FLAG_CASEFOLD;
7711 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7713 cm_ReleaseUser(userp);
7714 return CM_ERROR_NOSUCHPATH;
7716 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7717 userp, tidPathp, &req, &dscp);
7720 cm_ReleaseUser(userp);
7725 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7726 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7727 cm_ReleaseSCache(dscp);
7728 cm_ReleaseUser(userp);
7729 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7730 return CM_ERROR_PATH_NOT_COVERED;
7732 return CM_ERROR_BADSHARENAME;
7734 #endif /* DFS_SUPPORT */
7736 /* otherwise, scp points to the parent directory. Do a lookup, and
7737 * truncate the file if we find it, otherwise we create the file.
7744 if (!smb_IsLegalFilename(lastNamep))
7745 return CM_ERROR_BADNTFILENAME;
7747 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
7748 #ifdef DEBUG_VERBOSE
7751 hexp = osi_HexifyString( lastNamep );
7752 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7757 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7758 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7759 cm_ReleaseSCache(dscp);
7760 cm_ReleaseUser(userp);
7764 /* if we get here, if code is 0, the file exists and is represented by
7765 * scp. Otherwise, we have to create it.
7769 /* oops, file shouldn't be there */
7770 cm_ReleaseSCache(dscp);
7771 cm_ReleaseSCache(scp);
7772 cm_ReleaseUser(userp);
7773 return CM_ERROR_EXISTS;
7776 setAttr.mask = CM_ATTRMASK_LENGTH;
7777 setAttr.length.LowPart = 0;
7778 setAttr.length.HighPart = 0;
7779 code = cm_SetAttr(scp, &setAttr, userp, &req);
7782 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7783 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7784 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7788 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7789 smb_NotifyChange(FILE_ACTION_ADDED,
7790 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7791 dscp, lastNamep, NULL, TRUE);
7792 } else if (!excl && code == CM_ERROR_EXISTS) {
7793 /* not an exclusive create, and someone else tried
7794 * creating it already, then we open it anyway. We
7795 * don't bother retrying after this, since if this next
7796 * fails, that means that the file was deleted after
7797 * we started this call.
7799 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7802 setAttr.mask = CM_ATTRMASK_LENGTH;
7803 setAttr.length.LowPart = 0;
7804 setAttr.length.HighPart = 0;
7805 code = cm_SetAttr(scp, &setAttr, userp, &req);
7810 /* we don't need this any longer */
7811 cm_ReleaseSCache(dscp);
7814 /* something went wrong creating or truncating the file */
7815 if (scp) cm_ReleaseSCache(scp);
7816 cm_ReleaseUser(userp);
7820 /* make sure we only open files */
7821 if (scp->fileType != CM_SCACHETYPE_FILE) {
7822 cm_ReleaseSCache(scp);
7823 cm_ReleaseUser(userp);
7824 return CM_ERROR_ISDIR;
7827 /* now all we have to do is open the file itself */
7828 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7829 osi_assertx(fidp, "null smb_fid_t");
7833 lock_ObtainMutex(&fidp->mx);
7834 /* always create it open for read/write */
7835 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7837 /* remember that the file was newly created */
7839 fidp->flags |= SMB_FID_CREATED;
7841 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7843 /* save a pointer to the vnode */
7845 lock_ObtainWrite(&scp->rw);
7846 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7847 lock_ReleaseWrite(&scp->rw);
7850 fidp->userp = userp;
7851 lock_ReleaseMutex(&fidp->mx);
7853 smb_SetSMBParm(outp, 0, fidp->fid);
7854 smb_SetSMBDataLength(outp, 0);
7856 cm_Open(scp, 0, userp);
7858 smb_ReleaseFID(fidp);
7859 cm_ReleaseUser(userp);
7860 /* leave scp held since we put it in fidp->scp */
7865 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7868 osi_hyper_t new_offset;
7879 fd = smb_GetSMBParm(inp, 0);
7880 whence = smb_GetSMBParm(inp, 1);
7881 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7883 /* try to find the file descriptor */
7884 fd = smb_ChainFID(fd, inp);
7885 fidp = smb_FindFID(vcp, fd, 0);
7887 return CM_ERROR_BADFD;
7889 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7890 smb_CloseFID(vcp, fidp, NULL, 0);
7891 smb_ReleaseFID(fidp);
7892 return CM_ERROR_NOSUCHFILE;
7895 lock_ObtainMutex(&fidp->mx);
7896 if (fidp->flags & SMB_FID_IOCTL) {
7897 lock_ReleaseMutex(&fidp->mx);
7898 smb_ReleaseFID(fidp);
7899 return CM_ERROR_BADFD;
7901 lock_ReleaseMutex(&fidp->mx);
7903 userp = smb_GetUserFromVCP(vcp, inp);
7905 lock_ObtainMutex(&fidp->mx);
7908 lock_ReleaseMutex(&fidp->mx);
7909 lock_ObtainWrite(&scp->rw);
7910 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7911 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7913 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7915 /* offset from current offset */
7916 new_offset = LargeIntegerAdd(fidp->offset,
7917 ConvertLongToLargeInteger(offset));
7919 else if (whence == 2) {
7920 /* offset from current EOF */
7921 new_offset = LargeIntegerAdd(scp->length,
7922 ConvertLongToLargeInteger(offset));
7924 new_offset = ConvertLongToLargeInteger(offset);
7927 fidp->offset = new_offset;
7928 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7929 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7930 smb_SetSMBDataLength(outp, 0);
7932 lock_ReleaseWrite(&scp->rw);
7933 smb_ReleaseFID(fidp);
7934 cm_ReleaseSCache(scp);
7935 cm_ReleaseUser(userp);
7939 /* dispatch all of the requests received in a packet. Due to chaining, this may
7940 * be more than one request.
7942 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7943 NCB *ncbp, raw_write_cont_t *rwcp)
7947 unsigned long code = 0;
7948 unsigned char *outWctp;
7949 int nparms; /* # of bytes of parameters */
7951 int nbytes; /* bytes of data, excluding count */
7954 unsigned short errCode;
7955 unsigned long NTStatus;
7957 unsigned char errClass;
7958 unsigned int oldGen;
7959 DWORD oldTime, newTime;
7961 /* get easy pointer to the data */
7962 smbp = (smb_t *) inp->data;
7964 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7965 /* setup the basic parms for the initial request in the packet */
7966 inp->inCom = smbp->com;
7967 inp->wctp = &smbp->wct;
7969 inp->ncb_length = ncbp->ncb_length;
7974 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7975 /* log it and discard it */
7976 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7977 __FILE__, __LINE__, ncbp->ncb_length);
7978 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7982 /* We are an ongoing op */
7983 thrd_Increment(&ongoingOps);
7985 /* set up response packet for receiving output */
7986 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7987 smb_FormatResponsePacket(vcp, inp, outp);
7988 outWctp = outp->wctp;
7990 /* Remember session generation number and time */
7991 oldGen = sessionGen;
7992 oldTime = GetTickCount();
7994 while (inp->inCom != 0xff) {
7995 dp = &smb_dispatchTable[inp->inCom];
7997 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7998 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7999 code = outp->resumeCode;
8003 /* process each request in the packet; inCom, wctp and inCount
8004 * are already set up.
8006 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8009 /* now do the dispatch */
8010 /* start by formatting the response record a little, as a default */
8011 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8013 outWctp[1] = 0xff; /* no operation */
8014 outWctp[2] = 0; /* padding */
8019 /* not a chained request, this is a more reasonable default */
8020 outWctp[0] = 0; /* wct of zero */
8021 outWctp[1] = 0; /* and bcc (word) of zero */
8025 /* once set, stays set. Doesn't matter, since we never chain
8026 * "no response" calls.
8028 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8032 /* we have a recognized operation */
8033 char * opName = myCrt_Dispatch(inp->inCom);
8035 if (inp->inCom == 0x1d)
8037 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8039 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
8040 opName,vcp,vcp->lana,vcp->lsn);
8041 code = (*(dp->procp)) (vcp, inp, outp);
8042 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
8043 code,vcp,vcp->lana,vcp->lsn);
8045 if ( code == CM_ERROR_BADSMB ||
8046 code == CM_ERROR_BADOP )
8048 #endif /* LOG_PACKET */
8051 newTime = GetTickCount();
8052 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
8054 if (oldGen != sessionGen) {
8055 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8056 newTime - oldTime, ncbp->ncb_length);
8057 osi_Log3(smb_logp, "Request %s straddled session startup, "
8058 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8061 FreeSMBStrings(inp);
8063 /* bad opcode, fail the request, after displaying it */
8064 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8067 #endif /* LOG_PACKET */
8070 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8071 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8072 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8073 if (code == IDCANCEL)
8076 code = CM_ERROR_BADOP;
8079 /* catastrophic failure: log as much as possible */
8080 if (code == CM_ERROR_BADSMB) {
8081 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8085 #endif /* LOG_PACKET */
8086 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8089 code = CM_ERROR_INVAL;
8092 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8093 thrd_Decrement(&ongoingOps);
8098 /* now, if we failed, turn the current response into an empty
8099 * one, and fill in the response packet's error code.
8102 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8103 smb_MapNTError(code, &NTStatus);
8104 outWctp = outp->wctp;
8105 smbp = (smb_t *) &outp->data;
8106 if (code != CM_ERROR_PARTIALWRITE
8107 && code != CM_ERROR_BUFFERTOOSMALL
8108 && code != CM_ERROR_GSSCONTINUE) {
8109 /* nuke wct and bcc. For a partial
8110 * write or an in-process authentication handshake,
8111 * assume they're OK.
8117 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8118 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8119 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8120 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8121 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8125 smb_MapCoreError(code, vcp, &errCode, &errClass);
8126 outWctp = outp->wctp;
8127 smbp = (smb_t *) &outp->data;
8128 if (code != CM_ERROR_PARTIALWRITE) {
8129 /* nuke wct and bcc. For a partial
8130 * write, assume they're OK.
8136 smbp->errLow = (unsigned char) (errCode & 0xff);
8137 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8138 smbp->rcls = errClass;
8141 } /* error occurred */
8143 /* if we're here, we've finished one request. Look to see if
8144 * this is a chained opcode. If it is, setup things to process
8145 * the chained request, and setup the output buffer to hold the
8146 * chained response. Start by finding the next input record.
8148 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8149 break; /* not a chained req */
8150 tp = inp->wctp; /* points to start of last request */
8151 /* in a chained request, the first two
8152 * parm fields are required, and are
8153 * AndXCommand/AndXReserved and
8155 if (tp[0] < 2) break;
8156 if (tp[1] == 0xff) break; /* no more chained opcodes */
8158 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8161 /* and now append the next output request to the end of this
8162 * last request. Begin by finding out where the last response
8163 * ends, since that's where we'll put our new response.
8165 outWctp = outp->wctp; /* ptr to out parameters */
8166 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8167 nparms = outWctp[0] << 1;
8168 tp = outWctp + nparms + 1; /* now points to bcc field */
8169 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8170 tp += 2 /* for the count itself */ + nbytes;
8171 /* tp now points to the new output record; go back and patch the
8172 * second parameter (off2) to point to the new record.
8174 temp = (unsigned int)(tp - outp->data);
8175 outWctp[3] = (unsigned char) (temp & 0xff);
8176 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8177 outWctp[2] = 0; /* padding */
8178 outWctp[1] = inp->inCom; /* next opcode */
8180 /* finally, setup for the next iteration */
8183 } /* while loop over all requests in the packet */
8185 /* now send the output packet, and return */
8187 smb_SendPacket(vcp, outp);
8188 thrd_Decrement(&ongoingOps);
8193 /* Wait for Netbios() calls to return, and make the results available to server
8194 * threads. Note that server threads can't wait on the NCBevents array
8195 * themselves, because NCB events are manual-reset, and the servers would race
8196 * each other to reset them.
8198 void smb_ClientWaiter(void *parmp)
8203 while (smbShutdownFlag == 0) {
8204 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8206 if (code == WAIT_OBJECT_0)
8209 /* error checking */
8210 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8212 int abandonIdx = code - WAIT_ABANDONED_0;
8213 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8216 if (code == WAIT_IO_COMPLETION)
8218 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8222 if (code == WAIT_TIMEOUT)
8224 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8227 if (code == WAIT_FAILED)
8229 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8232 idx = code - WAIT_OBJECT_0;
8234 /* check idx range! */
8235 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8237 /* this is fatal - log as much as possible */
8238 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8239 osi_assertx(0, "invalid index");
8242 thrd_ResetEvent(NCBevents[idx]);
8243 thrd_SetEvent(NCBreturns[0][idx]);
8248 * Try to have one NCBRECV request waiting for every live session. Not more
8249 * than one, because if there is more than one, it's hard to handle Write Raw.
8251 void smb_ServerWaiter(void *parmp)
8254 int idx_session, idx_NCB;
8257 while (smbShutdownFlag == 0) {
8259 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8261 if (code == WAIT_OBJECT_0)
8264 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8266 int abandonIdx = code - WAIT_ABANDONED_0;
8267 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8270 if (code == WAIT_IO_COMPLETION)
8272 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8276 if (code == WAIT_TIMEOUT)
8278 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8281 if (code == WAIT_FAILED)
8283 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8286 idx_session = code - WAIT_OBJECT_0;
8288 /* check idx range! */
8289 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8291 /* this is fatal - log as much as possible */
8292 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8293 osi_assertx(0, "invalid index");
8298 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8300 if (code == WAIT_OBJECT_0) {
8301 if (smbShutdownFlag == 1)
8307 /* error checking */
8308 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8310 int abandonIdx = code - WAIT_ABANDONED_0;
8311 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8314 if (code == WAIT_IO_COMPLETION)
8316 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8320 if (code == WAIT_TIMEOUT)
8322 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8325 if (code == WAIT_FAILED)
8327 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8330 idx_NCB = code - WAIT_OBJECT_0;
8332 /* check idx range! */
8333 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8335 /* this is fatal - log as much as possible */
8336 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8337 osi_assertx(0, "invalid index");
8340 /* Link them together */
8341 NCBsessions[idx_NCB] = idx_session;
8344 ncbp = NCBs[idx_NCB];
8345 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8346 ncbp->ncb_command = NCBRECV | ASYNCH;
8347 ncbp->ncb_lana_num = lanas[idx_session];
8348 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8349 ncbp->ncb_event = NCBevents[idx_NCB];
8350 ncbp->ncb_length = SMB_PACKETSIZE;
8356 * The top level loop for handling SMB request messages. Each server thread
8357 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8358 * NCB and buffer for the incoming request are loaned to us.
8360 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8361 * to immediately send a request for the rest of the data. This must come
8362 * before any other traffic for that session, so we delay setting the session
8363 * event until that data has come in.
8365 void smb_Server(VOID *parmp)
8367 INT_PTR myIdx = (INT_PTR) parmp;
8371 smb_packet_t *outbufp;
8373 int idx_NCB, idx_session;
8375 smb_vc_t *vcp = NULL;
8377 extern void rx_StartClientThread(void);
8379 rx_StartClientThread();
8381 outncbp = smb_GetNCB();
8382 outbufp = smb_GetPacket();
8383 outbufp->ncbp = outncbp;
8391 smb_ResetServerPriority();
8393 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8396 /* terminate silently if shutdown flag is set */
8397 if (code == WAIT_OBJECT_0) {
8398 if (smbShutdownFlag == 1) {
8399 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8405 /* error checking */
8406 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8408 int abandonIdx = code - WAIT_ABANDONED_0;
8409 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8412 if (code == WAIT_IO_COMPLETION)
8414 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8418 if (code == WAIT_TIMEOUT)
8420 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8423 if (code == WAIT_FAILED)
8425 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8428 idx_NCB = code - WAIT_OBJECT_0;
8430 /* check idx range! */
8431 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8433 /* this is fatal - log as much as possible */
8434 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8435 osi_assertx(0, "invalid index");
8438 ncbp = NCBs[idx_NCB];
8439 idx_session = NCBsessions[idx_NCB];
8440 rc = ncbp->ncb_retcode;
8442 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8443 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8447 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8451 /* Can this happen? Or is it just my UNIX paranoia? */
8452 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8457 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8460 /* Client closed session */
8461 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8463 lock_ObtainMutex(&vcp->mx);
8464 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8465 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8467 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8468 lock_ReleaseMutex(&vcp->mx);
8469 lock_ObtainWrite(&smb_globalLock);
8470 dead_sessions[vcp->session] = TRUE;
8471 lock_ReleaseWrite(&smb_globalLock);
8473 lock_ReleaseMutex(&vcp->mx);
8475 smb_CleanupDeadVC(vcp);
8482 /* Treat as transient error */
8483 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8486 "dispatch smb recv failed, message incomplete, ncb_length %d",
8489 "SMB message incomplete, "
8490 "length %d", ncbp->ncb_length);
8493 * We used to discard the packet.
8494 * Instead, try handling it normally.
8498 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8502 /* A weird error code. Log it, sleep, and continue. */
8503 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8505 lock_ObtainMutex(&vcp->mx);
8506 if (vcp->errorCount++ > 3) {
8507 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8508 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8509 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8511 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8512 lock_ReleaseMutex(&vcp->mx);
8513 lock_ObtainWrite(&smb_globalLock);
8514 dead_sessions[vcp->session] = TRUE;
8515 lock_ReleaseWrite(&smb_globalLock);
8517 lock_ReleaseMutex(&vcp->mx);
8519 smb_CleanupDeadVC(vcp);
8525 lock_ReleaseMutex(&vcp->mx);
8529 thrd_SetEvent(SessionEvents[idx_session]);
8535 /* Success, so now dispatch on all the data in the packet */
8537 smb_concurrentCalls++;
8538 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8539 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8542 * If at this point vcp is NULL (implies that packet was invalid)
8543 * then we are in big trouble. This means either :
8544 * a) we have the wrong NCB.
8545 * b) Netbios screwed up the call.
8546 * c) The VC was already marked dead before we were able to
8548 * Obviously this implies that
8549 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8550 * lanas[idx_session] != ncbp->ncb_lana_num )
8551 * Either way, we can't do anything with this packet.
8552 * Log, sleep and resume.
8555 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8559 ncbp->ncb_lana_num);
8561 /* Also log in the trace log. */
8562 osi_Log4(smb_logp, "Server: VCP does not exist!"
8563 "LSNs[idx_session]=[%d],"
8564 "lanas[idx_session]=[%d],"
8565 "ncbp->ncb_lsn=[%d],"
8566 "ncbp->ncb_lana_num=[%d]",
8570 ncbp->ncb_lana_num);
8572 /* thrd_Sleep(1000); Don't bother sleeping */
8573 thrd_SetEvent(SessionEvents[idx_session]);
8574 smb_concurrentCalls--;
8578 smb_SetRequestStartTime();
8580 vcp->errorCount = 0;
8581 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8582 smbp = (smb_t *)bufp->data;
8589 if (smbp->com == 0x1d) {
8590 /* Special handling for Write Raw */
8591 raw_write_cont_t rwc;
8592 EVENT_HANDLE rwevent;
8593 char eventName[MAX_PATH];
8595 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8596 if (rwc.code == 0) {
8597 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8598 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8599 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8600 ncbp->ncb_command = NCBRECV | ASYNCH;
8601 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8602 ncbp->ncb_lana_num = vcp->lana;
8603 ncbp->ncb_buffer = rwc.buf;
8604 ncbp->ncb_length = 65535;
8605 ncbp->ncb_event = rwevent;
8607 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8608 thrd_CloseHandle(rwevent);
8610 thrd_SetEvent(SessionEvents[idx_session]);
8612 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8614 else if (smbp->com == 0xa0) {
8616 * Serialize the handling for NT Transact
8619 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8620 thrd_SetEvent(SessionEvents[idx_session]);
8622 thrd_SetEvent(SessionEvents[idx_session]);
8623 /* TODO: what else needs to be serialized? */
8624 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8628 __except( smb_ServerExceptionFilter() ) {
8632 smb_concurrentCalls--;
8635 thrd_SetEvent(NCBavails[idx_NCB]);
8640 smb_FreePacket(outbufp);
8642 smb_FreeNCB(outncbp);
8646 * Exception filter for the server threads. If an exception occurs in the
8647 * dispatch routines, which is where exceptions are most common, then do a
8648 * force trace and give control to upstream exception handlers. Useful for
8651 DWORD smb_ServerExceptionFilter(void) {
8652 /* While this is not the best time to do a trace, if it succeeds, then
8653 * we have a trace (assuming tracing was enabled). Otherwise, this should
8654 * throw a second exception.
8656 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8657 afsd_ForceTrace(TRUE);
8658 buf_ForceTrace(TRUE);
8659 return EXCEPTION_CONTINUE_SEARCH;
8663 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8664 * If the number of server threads is M, and the number of live sessions is
8665 * N, then the number of NCB's in use at any time either waiting for, or
8666 * holding, received messages is M + N, so that is how many NCB's get created.
8668 void InitNCBslot(int idx)
8670 struct smb_packet *bufp;
8671 EVENT_HANDLE retHandle;
8673 char eventName[MAX_PATH];
8675 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8677 NCBs[idx] = smb_GetNCB();
8678 sprintf(eventName,"NCBavails[%d]", idx);
8679 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8680 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8681 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8682 sprintf(eventName,"NCBevents[%d]", idx);
8683 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8684 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8685 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8686 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8687 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8688 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8689 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8690 for (i=0; i<smb_NumServerThreads; i++)
8691 NCBreturns[i][idx] = retHandle;
8692 bufp = smb_GetPacket();
8693 bufp->spacep = cm_GetSpace();
8697 /* listen for new connections */
8698 void smb_Listener(void *parmp)
8704 afs_uint32 session, thread;
8705 smb_vc_t *vcp = NULL;
8707 char rname[NCBNAMSZ+1];
8708 char cname[MAX_COMPUTERNAME_LENGTH+1];
8709 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8710 INT_PTR lana = (INT_PTR) parmp;
8711 char eventName[MAX_PATH];
8713 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
8714 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8715 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8716 thrd_ResetEvent(ListenerShutdown[lana]);
8718 ncbp = smb_GetNCB();
8720 /* retrieve computer name */
8721 GetComputerName(cname, &cnamelen);
8724 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8725 memset(ncbp, 0, sizeof(NCB));
8728 ncbp->ncb_command = NCBLISTEN;
8729 ncbp->ncb_rto = 0; /* No receive timeout */
8730 ncbp->ncb_sto = 0; /* No send timeout */
8732 /* pad out with spaces instead of null termination */
8733 len = (long)strlen(smb_localNamep);
8734 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8735 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8737 strcpy(ncbp->ncb_callname, "*");
8738 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8740 ncbp->ncb_lana_num = (UCHAR)lana;
8742 code = Netbios(ncbp);
8744 if (code == NRC_NAMERR) {
8745 /* An smb shutdown or Vista resume must have taken place */
8747 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8748 ncbp->ncb_lana_num, code);
8750 if (lock_TryMutex(&smb_StartedLock)) {
8751 lana_list.lana[i] = LANA_INVALID;
8752 lock_ReleaseMutex(&smb_StartedLock);
8755 } else if (code == NRC_BRIDGE || code != 0) {
8756 int lanaRemaining = 0;
8758 while (!lock_TryMutex(&smb_StartedLock)) {
8759 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8765 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8766 ncbp->ncb_lana_num, ncb_error_string(code));
8768 for (i = 0; i < lana_list.length; i++) {
8769 if (lana_list.lana[i] == lana) {
8770 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8771 lana_list.lana[i] = LANA_INVALID;
8773 if (lana_list.lana[i] != LANA_INVALID)
8777 if (lanaRemaining == 0) {
8778 cm_VolStatus_Network_Stopped(cm_NetbiosName
8783 smb_ListenerState = SMB_LISTENER_STOPPED;
8784 smb_LANadapter = LANA_INVALID;
8785 lana_list.length = 0;
8787 lock_ReleaseMutex(&smb_StartedLock);
8791 else if (code != 0) {
8792 char tbuffer[AFSPATHMAX];
8794 /* terminate silently if shutdown flag is set */
8795 while (!lock_TryMutex(&smb_StartedLock)) {
8796 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8802 "NCBLISTEN lana=%d failed with code %d [%s]",
8803 ncbp->ncb_lana_num, code, ncb_error_string(code));
8805 "Client exiting due to network failure. Please restart client.\n");
8808 "Client exiting due to network failure. Please restart client.\n"
8809 "NCBLISTEN lana=%d failed with code %d [%s]",
8810 ncbp->ncb_lana_num, code, ncb_error_string(code));
8812 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8813 MB_OK|MB_SERVICE_NOTIFICATION);
8814 osi_panic(tbuffer, __FILE__, __LINE__);
8816 lock_ReleaseMutex(&smb_StartedLock);
8821 /* check for remote conns */
8822 /* first get remote name and insert null terminator */
8823 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8824 for (i=NCBNAMSZ; i>0; i--) {
8825 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8831 /* compare with local name */
8833 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8834 flags |= SMB_VCFLAG_REMOTECONN;
8837 lock_ObtainMutex(&smb_ListenerLock);
8839 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8840 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8842 /* now ncbp->ncb_lsn is the connection ID */
8843 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8844 if (vcp->session == 0) {
8845 /* New generation */
8846 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8849 /* Log session startup */
8851 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8852 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8853 #endif /* NOTSERVICE */
8854 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8855 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8857 if (reportSessionStartups) {
8858 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8861 lock_ObtainMutex(&vcp->mx);
8862 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
8863 vcp->flags |= flags;
8864 lock_ReleaseMutex(&vcp->mx);
8866 /* Allocate slot in session arrays */
8867 /* Re-use dead session if possible, otherwise add one more */
8868 /* But don't look at session[0], it is reserved */
8869 lock_ObtainWrite(&smb_globalLock);
8870 for (session = 1; session < numSessions; session++) {
8871 if (dead_sessions[session]) {
8872 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8873 dead_sessions[session] = FALSE;
8877 lock_ReleaseWrite(&smb_globalLock);
8879 /* We are re-using an existing VC because the lsn and lana
8881 session = vcp->session;
8883 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8885 /* Log session startup */
8887 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8888 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8889 #endif /* NOTSERVICE */
8890 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8891 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8893 if (reportSessionStartups) {
8894 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8898 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8899 unsigned long code = CM_ERROR_ALLBUSY;
8900 smb_packet_t * outp = smb_GetPacket();
8901 unsigned char *outWctp;
8904 smb_FormatResponsePacket(vcp, NULL, outp);
8907 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8908 unsigned long NTStatus;
8909 smb_MapNTError(code, &NTStatus);
8910 outWctp = outp->wctp;
8911 smbp = (smb_t *) &outp->data;
8915 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8916 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8917 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8918 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8919 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8921 unsigned short errCode;
8922 unsigned char errClass;
8923 smb_MapCoreError(code, vcp, &errCode, &errClass);
8924 outWctp = outp->wctp;
8925 smbp = (smb_t *) &outp->data;
8929 smbp->errLow = (unsigned char) (errCode & 0xff);
8930 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8931 smbp->rcls = errClass;
8934 smb_SendPacket(vcp, outp);
8935 smb_FreePacket(outp);
8937 lock_ObtainMutex(&vcp->mx);
8938 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8939 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8941 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8942 lock_ReleaseMutex(&vcp->mx);
8943 lock_ObtainWrite(&smb_globalLock);
8944 dead_sessions[vcp->session] = TRUE;
8945 lock_ReleaseWrite(&smb_globalLock);
8946 smb_CleanupDeadVC(vcp);
8948 lock_ReleaseMutex(&vcp->mx);
8951 /* assert that we do not exceed the maximum number of sessions or NCBs.
8952 * we should probably want to wait for a session to be freed in case
8955 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8956 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8958 lock_ObtainMutex(&vcp->mx);
8959 vcp->session = session;
8960 lock_ReleaseMutex(&vcp->mx);
8961 lock_ObtainWrite(&smb_globalLock);
8962 LSNs[session] = ncbp->ncb_lsn;
8963 lanas[session] = ncbp->ncb_lana_num;
8964 lock_ReleaseWrite(&smb_globalLock);
8966 if (session == numSessions) {
8967 /* Add new NCB for new session */
8968 char eventName[MAX_PATH];
8970 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8972 InitNCBslot(numNCBs);
8973 lock_ObtainWrite(&smb_globalLock);
8975 lock_ReleaseWrite(&smb_globalLock);
8976 thrd_SetEvent(NCBavails[0]);
8977 thrd_SetEvent(NCBevents[0]);
8978 for (thread = 0; thread < smb_NumServerThreads; thread++)
8979 thrd_SetEvent(NCBreturns[thread][0]);
8980 /* Also add new session event */
8981 sprintf(eventName, "SessionEvents[%d]", session);
8982 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8983 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8984 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8985 lock_ObtainWrite(&smb_globalLock);
8987 lock_ReleaseWrite(&smb_globalLock);
8988 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8989 thrd_SetEvent(SessionEvents[0]);
8991 thrd_SetEvent(SessionEvents[session]);
8997 lock_ReleaseMutex(&smb_ListenerLock);
8998 } /* dispatch while loop */
9002 thrd_SetEvent(ListenerShutdown[lana]);
9007 smb_LanAdapterChangeThread(void *param)
9010 * Give the IPAddrDaemon thread a chance
9011 * to block before we trigger.
9014 smb_LanAdapterChange(0);
9017 void smb_SetLanAdapterChangeDetected(void)
9022 lock_ObtainMutex(&smb_StartedLock);
9024 if (!powerStateSuspended) {
9025 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9026 NULL, 0, &lpid, "smb_LanAdapterChange");
9027 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9028 thrd_CloseHandle(phandle);
9031 smb_LanAdapterChangeDetected = 1;
9032 lock_ReleaseMutex(&smb_StartedLock);
9035 void smb_LanAdapterChange(int locked) {
9036 lana_number_t lanaNum;
9038 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9040 LANA_ENUM temp_list;
9045 afsi_log("smb_LanAdapterChange");
9048 lock_ObtainMutex(&smb_StartedLock);
9050 smb_LanAdapterChangeDetected = 0;
9052 if (!powerStateSuspended &&
9053 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9054 LANA_NETBIOS_NAME_FULL)) &&
9055 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9056 if ( isGateway != bGateway ||
9057 strcmp(cm_NetbiosName, NetbiosName) ) {
9060 NCB *ncbp = smb_GetNCB();
9061 ncbp->ncb_command = NCBENUM;
9062 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9063 ncbp->ncb_length = sizeof(temp_list);
9064 code = Netbios(ncbp);
9066 if (temp_list.length != lana_list.length)
9069 for (i=0; i<lana_list.length; i++) {
9070 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9082 afsi_log("Lan Adapter Change detected");
9083 smb_StopListeners(1);
9084 smb_RestartListeners(1);
9087 lock_ReleaseMutex(&smb_StartedLock);
9090 /* initialize Netbios */
9091 int smb_NetbiosInit(int locked)
9094 int i, lana, code, l;
9096 int delname_tried=0;
9099 lana_number_t lanaNum;
9102 lock_ObtainMutex(&smb_StartedLock);
9104 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9105 smb_ListenerState != SMB_LISTENER_STOPPED) {
9108 lock_ReleaseMutex(&smb_StartedLock);
9111 /* setup the NCB system */
9112 ncbp = smb_GetNCB();
9114 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9115 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9116 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9118 if (smb_LANadapter != LANA_INVALID)
9119 afsi_log("LAN adapter number %d", smb_LANadapter);
9121 afsi_log("LAN adapter number not determined");
9124 afsi_log("Set for gateway service");
9126 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9128 /* something went horribly wrong. We can't proceed without a netbios name */
9130 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9131 osi_panic(buf, __FILE__, __LINE__);
9134 /* remember the name */
9135 len = (int)strlen(cm_NetbiosName);
9137 free(smb_localNamep);
9138 smb_localNamep = malloc(len+1);
9139 strcpy(smb_localNamep, cm_NetbiosName);
9140 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9142 /* Also copy the value to the client character encoded string */
9143 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9145 if (smb_LANadapter == LANA_INVALID) {
9146 ncbp->ncb_command = NCBENUM;
9147 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9148 ncbp->ncb_length = sizeof(lana_list);
9149 code = Netbios(ncbp);
9151 afsi_log("Netbios NCBENUM error code %d", code);
9152 osi_panic(s, __FILE__, __LINE__);
9156 lana_list.length = 1;
9157 lana_list.lana[0] = smb_LANadapter;
9160 for (i = 0; i < lana_list.length; i++) {
9161 /* reset the adaptor: in Win32, this is required for every process, and
9162 * acts as an init call, not as a real hardware reset.
9164 ncbp->ncb_command = NCBRESET;
9165 ncbp->ncb_callname[0] = 100;
9166 ncbp->ncb_callname[2] = 100;
9167 ncbp->ncb_lana_num = lana_list.lana[i];
9168 code = Netbios(ncbp);
9170 code = ncbp->ncb_retcode;
9172 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9173 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9175 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9179 /* and declare our name so we can receive connections */
9180 memset(ncbp, 0, sizeof(*ncbp));
9181 len=lstrlen(smb_localNamep);
9182 memset(smb_sharename,' ',NCBNAMSZ);
9183 memcpy(smb_sharename,smb_localNamep,len);
9184 afsi_log("lana_list.length %d", lana_list.length);
9186 /* Keep the name so we can unregister it later */
9187 for (l = 0; l < lana_list.length; l++) {
9188 lana = lana_list.lana[l];
9190 ncbp->ncb_command = NCBADDNAME;
9191 ncbp->ncb_lana_num = lana;
9192 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9193 code = Netbios(ncbp);
9195 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9196 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9198 char name[NCBNAMSZ+1];
9200 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9201 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9205 code = ncbp->ncb_retcode;
9208 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9211 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9212 if (code == NRC_BRIDGE) { /* invalid LANA num */
9213 lana_list.lana[l] = LANA_INVALID;
9216 else if (code == NRC_DUPNAME) {
9217 afsi_log("Name already exists; try to delete it");
9218 memset(ncbp, 0, sizeof(*ncbp));
9219 ncbp->ncb_command = NCBDELNAME;
9220 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9221 ncbp->ncb_lana_num = lana;
9222 code = Netbios(ncbp);
9224 code = ncbp->ncb_retcode;
9226 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9228 if (code != 0 || delname_tried) {
9229 lana_list.lana[l] = LANA_INVALID;
9231 else if (code == 0) {
9232 if (!delname_tried) {
9240 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9241 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9245 smb_LANadapter = lana;
9246 lana_found = 1; /* at least one worked */
9250 osi_assertx(lana_list.length >= 0, "empty lana list");
9252 afsi_log("No valid LANA numbers found!");
9253 lana_list.length = 0;
9254 smb_LANadapter = LANA_INVALID;
9255 smb_ListenerState = SMB_LISTENER_STOPPED;
9256 cm_VolStatus_Network_Stopped(cm_NetbiosName
9263 /* we're done with the NCB now */
9266 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9267 if (lana_list.length > 0)
9268 osi_assert(smb_LANadapter != LANA_INVALID);
9271 lock_ReleaseMutex(&smb_StartedLock);
9273 return (lana_list.length > 0 ? 1 : 0);
9276 void smb_StartListeners(int locked)
9283 lock_ObtainMutex(&smb_StartedLock);
9285 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9287 lock_ReleaseMutex(&smb_StartedLock);
9291 afsi_log("smb_StartListeners");
9292 smb_ListenerState = SMB_LISTENER_STARTED;
9293 cm_VolStatus_Network_Started(cm_NetbiosName
9299 for (i = 0; i < lana_list.length; i++) {
9300 if (lana_list.lana[i] == LANA_INVALID)
9302 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9303 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9304 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9305 thrd_CloseHandle(phandle);
9308 lock_ReleaseMutex(&smb_StartedLock);
9311 void smb_RestartListeners(int locked)
9314 lock_ObtainMutex(&smb_StartedLock);
9316 if (powerStateSuspended)
9317 afsi_log("smb_RestartListeners called while suspended");
9319 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9320 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9321 if (smb_NetbiosInit(1))
9322 smb_StartListeners(1);
9323 } else if (smb_LanAdapterChangeDetected) {
9324 smb_LanAdapterChange(1);
9328 lock_ReleaseMutex(&smb_StartedLock);
9331 void smb_StopListener(NCB *ncbp, int lana, int wait)
9335 memset(ncbp, 0, sizeof(*ncbp));
9336 ncbp->ncb_command = NCBDELNAME;
9337 ncbp->ncb_lana_num = lana;
9338 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9339 code = Netbios(ncbp);
9341 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9342 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9344 /* and then reset the LANA; this will cause the listener threads to exit */
9345 ncbp->ncb_command = NCBRESET;
9346 ncbp->ncb_callname[0] = 100;
9347 ncbp->ncb_callname[2] = 100;
9348 ncbp->ncb_lana_num = lana;
9349 code = Netbios(ncbp);
9351 code = ncbp->ncb_retcode;
9353 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
9355 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
9359 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9362 void smb_StopListeners(int locked)
9368 lock_ObtainMutex(&smb_StartedLock);
9370 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9372 lock_ReleaseMutex(&smb_StartedLock);
9376 afsi_log("smb_StopListeners");
9377 smb_ListenerState = SMB_LISTENER_STOPPED;
9378 cm_VolStatus_Network_Stopped(cm_NetbiosName
9384 ncbp = smb_GetNCB();
9386 /* Unregister the SMB name */
9387 for (l = 0; l < lana_list.length; l++) {
9388 lana = lana_list.lana[l];
9390 if (lana != LANA_INVALID) {
9391 smb_StopListener(ncbp, lana, TRUE);
9393 /* mark the adapter invalid */
9394 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9398 /* force a re-evaluation of the network adapters */
9399 lana_list.length = 0;
9400 smb_LANadapter = LANA_INVALID;
9403 lock_ReleaseMutex(&smb_StartedLock);
9406 void smb_Init(osi_log_t *logp, int useV3,
9416 EVENT_HANDLE retHandle;
9417 char eventName[MAX_PATH];
9418 int startListeners = 0;
9420 smb_TlsRequestSlot = TlsAlloc();
9422 smb_MBfunc = aMBfunc;
9426 /* Initialize smb_localZero */
9427 myTime.tm_isdst = -1; /* compute whether on DST or not */
9428 myTime.tm_year = 70;
9434 smb_localZero = mktime(&myTime);
9436 #ifndef USE_NUMERIC_TIME_CONV
9437 /* Initialize kludge-GMT */
9438 smb_CalculateNowTZ();
9439 #endif /* USE_NUMERIC_TIME_CONV */
9440 #ifdef AFS_FREELANCE_CLIENT
9441 /* Make sure the root.afs volume has the correct time */
9442 cm_noteLocalMountPointChange();
9445 /* initialize the remote debugging log */
9448 /* and the global lock */
9449 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
9450 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
9452 /* Raw I/O data structures */
9453 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
9455 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
9456 lock_InitializeMutex(&smb_StartedLock, "smb started lock");
9458 /* 4 Raw I/O buffers */
9459 smb_RawBufs = calloc(65536,1);
9460 *((char **)smb_RawBufs) = NULL;
9461 for (i=0; i<3; i++) {
9462 char *rawBuf = calloc(65536,1);
9463 *((char **)rawBuf) = smb_RawBufs;
9464 smb_RawBufs = rawBuf;
9467 /* global free lists */
9468 smb_ncbFreeListp = NULL;
9469 smb_packetFreeListp = NULL;
9471 lock_ObtainMutex(&smb_StartedLock);
9472 startListeners = smb_NetbiosInit(1);
9474 /* Initialize listener and server structures */
9476 memset(dead_sessions, 0, sizeof(dead_sessions));
9477 sprintf(eventName, "SessionEvents[0]");
9478 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9479 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9480 afsi_log("Event Object Already Exists: %s", eventName);
9482 smb_NumServerThreads = nThreads;
9483 sprintf(eventName, "NCBavails[0]");
9484 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9485 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9486 afsi_log("Event Object Already Exists: %s", eventName);
9487 sprintf(eventName, "NCBevents[0]");
9488 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9489 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9490 afsi_log("Event Object Already Exists: %s", eventName);
9491 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9492 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9493 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9494 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9495 afsi_log("Event Object Already Exists: %s", eventName);
9496 for (i = 0; i < smb_NumServerThreads; i++) {
9497 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9498 NCBreturns[i][0] = retHandle;
9501 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9502 for (i = 0; i < smb_NumServerThreads; i++) {
9503 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9504 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9505 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9506 afsi_log("Event Object Already Exists: %s", eventName);
9507 InitNCBslot((int)(i+1));
9509 numNCBs = smb_NumServerThreads + 1;
9511 /* Initialize dispatch table */
9512 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9513 /* Prepare the table for unknown operations */
9514 for(i=0; i<= SMB_NOPCODES; i++) {
9515 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9517 /* Fill in the ones we do know */
9518 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9519 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9520 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9521 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9522 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9523 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9524 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9525 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9526 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9527 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9528 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9529 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9530 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9531 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9532 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9533 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9534 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9535 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9536 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9537 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9538 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9539 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9540 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9541 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9542 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9543 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9544 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9545 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9546 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9547 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9548 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9549 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9550 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9551 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9552 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9553 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9554 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9555 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9556 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9557 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9558 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9559 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9560 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9561 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9562 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9563 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9564 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9565 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9566 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9567 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9568 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9569 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9570 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9571 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9572 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9573 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9574 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9575 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9576 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9577 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9578 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9579 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9580 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9581 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9582 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9583 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9584 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9585 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9586 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9587 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9588 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9589 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9590 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9591 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9593 /* setup tran 2 dispatch table */
9594 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9595 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9596 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9597 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9598 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9599 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9600 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9601 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9602 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9603 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9604 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9605 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9606 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9607 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9608 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9609 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9610 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9611 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9613 /* setup the rap dispatch table */
9614 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9615 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9616 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9617 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9618 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9622 /* if we are doing SMB authentication we have register outselves as a logon process */
9623 if (smb_authType != SMB_AUTH_NONE) {
9624 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9625 LSA_STRING afsProcessName;
9626 LSA_OPERATIONAL_MODE dummy; /*junk*/
9628 afsProcessName.Buffer = "OpenAFSClientDaemon";
9629 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9630 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9632 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9634 if (nts == STATUS_SUCCESS) {
9635 LSA_STRING packageName;
9636 /* we are registered. Find out the security package id */
9637 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9638 packageName.Length = (USHORT)strlen(packageName.Buffer);
9639 packageName.MaximumLength = packageName.Length + 1;
9640 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9641 if (nts == STATUS_SUCCESS) {
9643 * This code forces Windows to authenticate against the Logon Cache
9644 * first instead of attempting to authenticate against the Domain
9645 * Controller. When the Windows logon cache is enabled this improves
9646 * performance by removing the network access and works around a bug
9647 * seen at sites which are using a MIT Kerberos principal to login
9648 * to machines joined to a non-root domain in a multi-domain forest.
9649 * MsV1_0SetProcessOption was added in Windows XP.
9651 PVOID pResponse = NULL;
9652 ULONG cbResponse = 0;
9653 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9655 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9656 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9657 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9658 OptionsRequest.DisableOptions = FALSE;
9660 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9663 sizeof(OptionsRequest),
9669 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9670 char message[AFSPATHMAX];
9671 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9673 OutputDebugString(message);
9676 OutputDebugString("MsV1_0SetProcessOption success");
9677 afsi_log("MsV1_0SetProcessOption success");
9679 /* END - code from Larry */
9681 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9682 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9683 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9685 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9687 /* something went wrong. We report the error and revert back to no authentication
9688 because we can't perform any auth requests without a successful lsa handle
9689 or sec package id. */
9690 afsi_log("Reverting to NO SMB AUTH");
9691 smb_authType = SMB_AUTH_NONE;
9694 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9696 /* something went wrong. We report the error and revert back to no authentication
9697 because we can't perform any auth requests without a successful lsa handle
9698 or sec package id. */
9699 afsi_log("Reverting to NO SMB AUTH");
9700 smb_authType = SMB_AUTH_NONE;
9704 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9705 * time prevents the failure of authentication when logged into Windows with an
9706 * external Kerberos principal mapped to a local account.
9708 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9709 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9710 * then the only option is NTLMSSP anyway; so just fallback.
9715 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9716 if (secBlobLength == 0) {
9717 smb_authType = SMB_AUTH_NTLM;
9718 afsi_log("Reverting to SMB AUTH NTLM");
9727 /* Now get ourselves a domain name. */
9728 /* For now we are using the local computer name as the domain name.
9729 * It is actually the domain for local logins, and we are acting as
9730 * a local SMB server.
9732 bufsize = lengthof(smb_ServerDomainName) - 1;
9733 GetComputerNameW(smb_ServerDomainName, &bufsize);
9734 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9735 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
9738 /* Start listeners, waiters, servers, and daemons */
9740 smb_StartListeners(1);
9742 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9743 NULL, 0, &lpid, "smb_ClientWaiter");
9744 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9745 thrd_CloseHandle(phandle);
9747 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9748 NULL, 0, &lpid, "smb_ServerWaiter");
9749 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9750 thrd_CloseHandle(phandle);
9752 for (i=0; i<smb_NumServerThreads; i++) {
9753 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9754 (void *) i, 0, &lpid, "smb_Server");
9755 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9756 thrd_CloseHandle(phandle);
9759 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9760 NULL, 0, &lpid, "smb_Daemon");
9761 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9762 thrd_CloseHandle(phandle);
9764 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9765 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9766 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9767 thrd_CloseHandle(phandle);
9769 lock_ReleaseMutex(&smb_StartedLock);
9773 void smb_Shutdown(void)
9780 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9782 /* setup the NCB system */
9783 ncbp = smb_GetNCB();
9785 /* Block new sessions by setting shutdown flag */
9786 smbShutdownFlag = 1;
9788 /* Hang up all sessions */
9789 memset((char *)ncbp, 0, sizeof(NCB));
9790 for (i = 1; i < numSessions; i++)
9792 if (dead_sessions[i])
9795 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9796 ncbp->ncb_command = NCBHANGUP;
9797 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9798 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9799 code = Netbios(ncbp);
9800 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9801 if (code == 0) code = ncbp->ncb_retcode;
9803 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9804 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9808 /* Trigger the shutdown of all SMB threads */
9809 for (i = 0; i < smb_NumServerThreads; i++)
9810 thrd_SetEvent(NCBreturns[i][0]);
9812 thrd_SetEvent(NCBevents[0]);
9813 thrd_SetEvent(SessionEvents[0]);
9814 thrd_SetEvent(NCBavails[0]);
9816 for (i = 0;i < smb_NumServerThreads; i++) {
9817 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9818 if (code == WAIT_OBJECT_0) {
9821 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9822 thrd_SetEvent(NCBreturns[i--][0]);
9826 /* Delete Netbios name */
9827 memset((char *)ncbp, 0, sizeof(NCB));
9828 for (i = 0; i < lana_list.length; i++) {
9829 if (lana_list.lana[i] == LANA_INVALID) continue;
9830 ncbp->ncb_command = NCBDELNAME;
9831 ncbp->ncb_lana_num = lana_list.lana[i];
9832 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9833 code = Netbios(ncbp);
9835 code = ncbp->ncb_retcode;
9837 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9838 ncbp->ncb_lana_num, code);
9843 /* Release the reference counts held by the VCs */
9844 lock_ObtainWrite(&smb_rctLock);
9845 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9850 if (vcp->magic != SMB_VC_MAGIC)
9851 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9852 __FILE__, __LINE__);
9854 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9856 if (fidp->scp != NULL) {
9859 lock_ObtainMutex(&fidp->mx);
9860 if (fidp->scp != NULL) {
9863 lock_ObtainWrite(&scp->rw);
9864 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9865 lock_ReleaseWrite(&scp->rw);
9866 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9867 cm_ReleaseSCache(scp);
9869 lock_ReleaseMutex(&fidp->mx);
9873 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9875 smb_ReleaseVCNoLock(tidp->vcp);
9877 cm_user_t *userp = tidp->userp;
9879 cm_ReleaseUser(userp);
9883 lock_ReleaseWrite(&smb_rctLock);
9885 TlsFree(smb_TlsRequestSlot);
9888 /* Get the UNC \\<servername>\<sharename> prefix. */
9889 char *smb_GetSharename()
9894 /* Make sure we have been properly initialized. */
9895 if (smb_localNamep == NULL)
9898 /* Allocate space for \\<servername>\<sharename>, plus the
9901 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
9903 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
9909 void smb_LogPacket(smb_packet_t *packet)
9913 unsigned length, paramlen, datalen, i, j;
9915 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9917 if (!packet) return;
9919 osi_Log0(smb_logp, "*** SMB packet dump ***");
9921 smbp = (smb_t *) packet->data;
9922 vp = (BYTE *) packet->data;
9924 paramlen = smbp->wct * 2;
9925 datalen = *((WORD *) (smbp->vdata + paramlen));
9926 length = sizeof(*smbp) + paramlen + 1 + datalen;
9928 for (i=0;i < length; i+=16)
9930 memset( buf, ' ', 80 );
9935 buf[strlen(buf)] = ' ';
9937 cp = (BYTE*) buf + 7;
9939 for (j=0;j < 16 && (i+j)<length; j++)
9941 *(cp++) = hex[vp[i+j] >> 4];
9942 *(cp++) = hex[vp[i+j] & 0xf];
9952 for (j=0;j < 16 && (i+j)<length;j++)
9954 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9965 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9968 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9970 #endif /* LOG_PACKET */
9973 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9979 smb_username_t *unp;
9980 smb_waitingLockRequest_t *wlrp;
9983 lock_ObtainRead(&smb_rctLock);
9985 sprintf(output, "begin dumping smb_username_t\r\n");
9986 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9987 for (unp = usernamesp; unp; unp=unp->nextp)
9991 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
9992 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
9993 unp->name ? unp->name : _C("NULL"),
9994 unp->machine ? unp->machine : _C("NULL"));
9995 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9997 sprintf(output, " begin dumping cm_ucell_t\r\n");
9998 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10000 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10001 sprintf(output, " %s -- ucellp=0x%p, cellp=0x%p, flags=0x%x, tktLen=%04u, kvno=%03u, expires=%I64u, gen=%d, name=%s, cellname=%s\r\n",
10002 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10003 ucellp->expirationTime, ucellp->gen,
10005 ucellp->cellp->name);
10006 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10009 sprintf(output, " done dumping cm_ucell_t\r\n");
10010 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10013 sprintf(output, "done dumping smb_username_t\r\n");
10014 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10017 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10018 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10021 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10022 smb_waitingLock_t *lockp;
10024 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10025 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10026 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10028 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10029 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10030 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10031 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10032 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10033 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10035 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10036 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10039 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10040 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10042 sprintf(output, "begin dumping smb_vc_t\r\n");
10043 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10045 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10051 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10052 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10053 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10055 sprintf(output, " begin dumping smb_user_t\r\n");
10056 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10057 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10058 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10059 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10060 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10062 sprintf(output, " done dumping smb_user_t\r\n");
10063 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10065 sprintf(output, " begin dumping smb_tid_t\r\n");
10066 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10067 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10068 sprintf(output, " %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
10069 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10070 tidp->pathname ? tidp->pathname : _C("NULL"));
10071 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10073 sprintf(output, " done dumping smb_tid_t\r\n");
10074 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10076 sprintf(output, " begin dumping smb_fid_t\r\n");
10077 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10079 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10081 sprintf(output, " %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
10082 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10083 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10084 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10085 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10088 sprintf(output, " done dumping smb_fid_t\r\n");
10089 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10092 sprintf(output, "done dumping smb_vc_t\r\n");
10093 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10095 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10096 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10098 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10104 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10105 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10106 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10108 sprintf(output, " begin dumping smb_user_t\r\n");
10109 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10110 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10111 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10112 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10113 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10115 sprintf(output, " done dumping smb_user_t\r\n");
10116 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10118 sprintf(output, " begin dumping smb_tid_t\r\n");
10119 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10120 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10121 sprintf(output, " %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
10122 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10123 tidp->pathname ? tidp->pathname : _C("NULL"));
10124 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10126 sprintf(output, " done dumping smb_tid_t\r\n");
10127 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10129 sprintf(output, " begin dumping smb_fid_t\r\n");
10130 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10132 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10134 sprintf(output, " %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
10135 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10136 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10137 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10138 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10141 sprintf(output, " done dumping smb_fid_t\r\n");
10142 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10145 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10146 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10149 lock_ReleaseRead(&smb_rctLock);
10153 long smb_IsNetworkStarted(void)
10156 lock_ObtainWrite(&smb_globalLock);
10157 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10158 lock_ReleaseWrite(&smb_globalLock);