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 = "NRC_BUFLEN llegal buffer length"; break;
240 case 0x03: s = "NRC_ILLCMD illegal command"; break;
241 case 0x05: s = "NRC_CMDTMO command timed out"; break;
242 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
243 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
244 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
245 case 0x09: s = "NRC_NORES no resource available"; break;
246 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
247 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
248 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
249 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
250 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
251 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
252 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
253 case 0x13: s = "NRC_ILLNN illegal name number"; break;
254 case 0x14: s = "NRC_NOCALL no callname"; break;
255 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
256 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
257 case 0x17: s = "NRC_NAMERR name deleted"; break;
258 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
259 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
260 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
261 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
262 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
263 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
264 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
265 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
266 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
267 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
268 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
269 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
270 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
271 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
272 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
273 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
274 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
275 case 0x40: s = "NRC_SYSTEM 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 void smb_MarkAllVCsDead(smb_vc_t * exclude)
825 smb_vc_t **vcp_to_cleanup = NULL;
826 int n_to_cleanup = 0;
829 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
831 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
832 lock_ObtainWrite(&smb_rctLock);
833 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
835 if (vcp->magic != SMB_VC_MAGIC)
836 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
842 lock_ObtainMutex(&vcp->mx);
843 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
844 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
845 lock_ReleaseMutex(&vcp->mx);
846 dead_sessions[vcp->session] = TRUE;
848 lock_ReleaseMutex(&vcp->mx);
853 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
855 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
859 vcp_to_cleanup[i++] = vcp;
860 smb_HoldVCNoLock(vcp);
863 osi_assert(i == n_to_cleanup);
865 lock_ReleaseWrite(&smb_rctLock);
866 lock_ReleaseWrite(&smb_globalLock);
868 for (i=0; i < n_to_cleanup; i++) {
869 smb_CleanupDeadVC(vcp_to_cleanup[i]);
870 smb_ReleaseVC(vcp_to_cleanup[i]);
871 vcp_to_cleanup[i] = 0;
874 free(vcp_to_cleanup);
877 #ifdef DEBUG_SMB_REFCOUNT
878 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
880 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
885 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
886 lock_ObtainWrite(&smb_rctLock);
887 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
888 if (vcp->magic != SMB_VC_MAGIC)
889 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
892 lock_ObtainMutex(&vcp->mx);
893 if (lsn == vcp->lsn && lana == vcp->lana &&
894 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
895 lock_ReleaseMutex(&vcp->mx);
896 smb_HoldVCNoLock(vcp);
899 lock_ReleaseMutex(&vcp->mx);
901 if (!vcp && (flags & SMB_FLAG_CREATE)) {
902 vcp = malloc(sizeof(*vcp));
903 memset(vcp, 0, sizeof(*vcp));
904 vcp->vcID = ++numVCs;
905 vcp->magic = SMB_VC_MAGIC;
906 vcp->refCount = 2; /* smb_allVCsp and caller */
909 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
910 vcp->nextp = smb_allVCsp;
912 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
917 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
918 /* We must obtain a challenge for extended auth
919 * in case the client negotiates smb v3
921 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
922 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
923 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
924 ULONG lsaRespSize = 0;
926 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
928 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
935 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
936 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
937 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
938 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
939 nts, ntsEx, lsaRespSize);
941 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
943 if (ntsEx == STATUS_SUCCESS) {
944 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
947 * This will cause the subsequent authentication to fail but
948 * that is better than us dereferencing a NULL pointer and
951 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
954 LsaFreeReturnBuffer(lsaResp);
957 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
959 if (numVCs >= CM_SESSION_RESERVED) {
961 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
964 #ifdef DEBUG_SMB_REFCOUNT
966 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
967 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
970 lock_ReleaseWrite(&smb_rctLock);
971 lock_ReleaseWrite(&smb_globalLock);
975 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
980 for(i=0; i<11; i++) {
982 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
988 static int smb_IsStarMask(clientchar_t *maskp)
994 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
1000 #ifdef DEBUG_SMB_REFCOUNT
1001 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
1002 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
1004 void smb_ReleaseVCInternal(smb_vc_t *vcp)
1010 lock_AssertWrite(&smb_rctLock);
1013 if (vcp->refCount == 0) {
1014 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
1015 #ifdef DEBUG_SMB_REFCOUNT
1016 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
1017 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
1019 /* remove VCP from smb_deadVCsp */
1020 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1026 lock_FinalizeMutex(&vcp->mx);
1027 memset(vcp,0,sizeof(smb_vc_t));
1030 #ifdef DEBUG_SMB_REFCOUNT
1031 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
1033 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
1037 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
1038 avcp?"":"not ",vcp, vcp->refCount);
1040 /* This is a wrong. However, I suspect that there is an undercount
1041 * and I don't want to release 1.4.1 in a state that will allow
1042 * smb_vc_t objects to be deallocated while still in the
1043 * smb_allVCsp list. The list is supposed to keep a reference
1044 * to the smb_vc_t. Put it back.
1048 #ifdef DEBUG_SMB_REFCOUNT
1049 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
1050 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
1054 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
1055 /* The reference count is non-zero but the VC is dead.
1056 * This implies that some FIDs, TIDs, etc on the VC have yet to
1057 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
1058 * add a reference that will be dropped by
1059 * smb_CleanupDeadVC() and try to cleanup the VC again.
1060 * Eventually the refCount will drop to zero when all of the
1061 * active threads working with the VC end their task.
1063 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
1064 vcp->refCount++; /* put the refCount back */
1065 lock_ReleaseWrite(&smb_rctLock);
1066 smb_CleanupDeadVC(vcp);
1067 #ifdef DEBUG_SMB_REFCOUNT
1068 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1069 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1071 lock_ObtainWrite(&smb_rctLock);
1074 #ifdef DEBUG_SMB_REFCOUNT
1075 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1076 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1081 #ifdef DEBUG_SMB_REFCOUNT
1082 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1084 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1087 lock_AssertWrite(&smb_rctLock);
1088 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1089 smb_ReleaseVCInternal(vcp);
1092 #ifdef DEBUG_SMB_REFCOUNT
1093 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1095 void smb_ReleaseVC(smb_vc_t *vcp)
1098 lock_ObtainWrite(&smb_rctLock);
1099 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1100 smb_ReleaseVCInternal(vcp);
1101 lock_ReleaseWrite(&smb_rctLock);
1104 #ifdef DEBUG_SMB_REFCOUNT
1105 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1107 void smb_HoldVCNoLock(smb_vc_t *vcp)
1110 lock_AssertWrite(&smb_rctLock);
1112 #ifdef DEBUG_SMB_REFCOUNT
1113 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1114 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1116 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1120 #ifdef DEBUG_SMB_REFCOUNT
1121 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1123 void smb_HoldVC(smb_vc_t *vcp)
1126 lock_ObtainWrite(&smb_rctLock);
1128 #ifdef DEBUG_SMB_REFCOUNT
1129 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1130 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1132 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1134 lock_ReleaseWrite(&smb_rctLock);
1137 void smb_CleanupDeadVC(smb_vc_t *vcp)
1139 smb_fid_t *fidpIter;
1140 smb_fid_t *fidpNext;
1142 smb_tid_t *tidpIter;
1143 smb_tid_t *tidpNext;
1145 smb_user_t *uidpIter;
1146 smb_user_t *uidpNext;
1148 afs_uint32 refCount = 0;
1150 lock_ObtainMutex(&vcp->mx);
1151 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1152 lock_ReleaseMutex(&vcp->mx);
1153 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1156 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1157 lock_ReleaseMutex(&vcp->mx);
1158 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1160 lock_ObtainWrite(&smb_rctLock);
1161 /* remove VCP from smb_allVCsp */
1162 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1163 if ((*vcpp)->magic != SMB_VC_MAGIC)
1164 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1165 __FILE__, __LINE__);
1168 vcp->nextp = smb_deadVCsp;
1170 /* Hold onto the reference until we are done with this function */
1175 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1176 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1178 if (fidpIter->deleteOk)
1181 fid = fidpIter->fid;
1182 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1184 smb_HoldFIDNoLock(fidpIter);
1185 lock_ReleaseWrite(&smb_rctLock);
1187 smb_CloseFID(vcp, fidpIter, NULL, 0);
1188 smb_ReleaseFID(fidpIter);
1190 lock_ObtainWrite(&smb_rctLock);
1191 fidpNext = vcp->fidsp;
1194 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1195 tidpNext = tidpIter->nextp;
1196 if (tidpIter->deleteOk)
1198 tidpIter->deleteOk = 1;
1200 tid = tidpIter->tid;
1201 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1203 smb_HoldTIDNoLock(tidpIter);
1204 smb_ReleaseTID(tidpIter, TRUE);
1205 tidpNext = vcp->tidsp;
1208 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1209 uidpNext = uidpIter->nextp;
1210 if (uidpIter->deleteOk)
1212 uidpIter->deleteOk = 1;
1214 /* do not add an additional reference count for the smb_user_t
1215 * as the smb_vc_t already is holding a reference */
1216 lock_ReleaseWrite(&smb_rctLock);
1218 smb_ReleaseUID(uidpIter);
1220 lock_ObtainWrite(&smb_rctLock);
1221 uidpNext = vcp->usersp;
1224 /* The vcp is now on the deadVCsp list. We intentionally drop the
1225 * reference so that the refcount can reach 0 and we can delete it
1227 * If the refCount == 1 going into the ReleaseVCNoLock call
1228 * the object will be freed and it won't be safe to clear
1231 refCount = vcp->refCount;
1232 smb_ReleaseVCNoLock(vcp);
1234 lock_ObtainMutex(&vcp->mx);
1235 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1236 lock_ReleaseMutex(&vcp->mx);
1239 lock_ReleaseWrite(&smb_rctLock);
1240 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1243 #ifdef DEBUG_SMB_REFCOUNT
1244 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1246 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1251 lock_ObtainWrite(&smb_rctLock);
1253 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1254 if (tidp->refCount == 0 && tidp->deleteOk) {
1256 smb_ReleaseTID(tidp, TRUE);
1260 if (tid == tidp->tid) {
1265 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1266 tidp = malloc(sizeof(*tidp));
1267 memset(tidp, 0, sizeof(*tidp));
1268 tidp->nextp = vcp->tidsp;
1271 smb_HoldVCNoLock(vcp);
1273 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1276 #ifdef DEBUG_SMB_REFCOUNT
1278 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1279 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1282 lock_ReleaseWrite(&smb_rctLock);
1286 #ifdef DEBUG_SMB_REFCOUNT
1287 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1289 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1292 lock_AssertWrite(&smb_rctLock);
1294 #ifdef DEBUG_SMB_REFCOUNT
1295 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1296 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1300 #ifdef DEBUG_SMB_REFCOUNT
1301 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1303 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1308 cm_user_t *userp = NULL;
1309 smb_vc_t *vcp = NULL;
1312 lock_ObtainWrite(&smb_rctLock);
1314 lock_AssertWrite(&smb_rctLock);
1316 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1317 #ifdef DEBUG_SMB_REFCOUNT
1318 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1319 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1321 if (tidp->refCount == 0) {
1322 if (tidp->deleteOk) {
1323 ltpp = &tidp->vcp->tidsp;
1324 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1328 osi_assertx(tp != NULL, "null smb_tid_t");
1330 lock_FinalizeMutex(&tidp->mx);
1331 userp = tidp->userp; /* remember to drop ref later */
1339 smb_ReleaseVCNoLock(vcp);
1341 lock_ReleaseWrite(&smb_rctLock);
1343 cm_ReleaseUser(userp);
1346 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1348 smb_user_t *uidp = NULL;
1350 lock_ObtainWrite(&smb_rctLock);
1351 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1352 if (uid == uidp->userID) {
1354 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1356 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1360 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1361 uidp = malloc(sizeof(*uidp));
1362 memset(uidp, 0, sizeof(*uidp));
1363 uidp->nextp = vcp->usersp;
1364 uidp->refCount = 2; /* one for the vcp and one for the caller */
1366 smb_HoldVCNoLock(vcp);
1368 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1370 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1372 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1374 lock_ReleaseWrite(&smb_rctLock);
1378 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1381 smb_username_t *unp= NULL;
1383 lock_ObtainWrite(&smb_rctLock);
1384 for(unp = usernamesp; unp; unp = unp->nextp) {
1385 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1386 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1391 if (!unp && (flags & SMB_FLAG_CREATE)) {
1392 unp = malloc(sizeof(*unp));
1393 memset(unp, 0, sizeof(*unp));
1395 unp->nextp = usernamesp;
1396 unp->name = cm_ClientStrDup(usern);
1397 unp->machine = cm_ClientStrDup(machine);
1399 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1400 if (flags & SMB_FLAG_AFSLOGON)
1401 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1404 lock_ReleaseWrite(&smb_rctLock);
1408 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1410 smb_user_t *uidp= NULL;
1412 lock_ObtainWrite(&smb_rctLock);
1413 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1416 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1418 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1419 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1424 lock_ReleaseWrite(&smb_rctLock);
1428 void smb_ReleaseUsername(smb_username_t *unp)
1431 smb_username_t **lupp;
1432 cm_user_t *userp = NULL;
1433 time_t now = osi_Time();
1435 lock_ObtainWrite(&smb_rctLock);
1436 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1437 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1438 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1440 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1444 osi_assertx(up != NULL, "null smb_username_t");
1446 up->nextp = NULL; /* do not remove this */
1447 lock_FinalizeMutex(&unp->mx);
1453 lock_ReleaseWrite(&smb_rctLock);
1455 cm_ReleaseUser(userp);
1458 void smb_HoldUIDNoLock(smb_user_t *uidp)
1460 lock_AssertWrite(&smb_rctLock);
1464 void smb_ReleaseUID(smb_user_t *uidp)
1468 smb_username_t *unp = NULL;
1470 lock_ObtainWrite(&smb_rctLock);
1471 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1472 if (uidp->refCount == 0) {
1473 lupp = &uidp->vcp->usersp;
1474 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1478 osi_assertx(up != NULL, "null smb_user_t");
1480 lock_FinalizeMutex(&uidp->mx);
1482 smb_ReleaseVCNoLock(uidp->vcp);
1486 lock_ReleaseWrite(&smb_rctLock);
1490 cm_ReleaseUserVCRef(unp->userp);
1491 smb_ReleaseUsername(unp);
1495 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1497 cm_user_t *up = NULL;
1502 lock_ObtainMutex(&uidp->mx);
1504 up = uidp->unp->userp;
1507 lock_ReleaseMutex(&uidp->mx);
1513 /* retrieve a held reference to a user structure corresponding to an incoming
1515 * corresponding release function is cm_ReleaseUser.
1517 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1520 cm_user_t *up = NULL;
1523 smbp = (smb_t *) inp;
1524 uidp = smb_FindUID(vcp, smbp->uid, 0);
1528 up = smb_GetUserFromUID(uidp);
1530 smb_ReleaseUID(uidp);
1535 * Return a pointer to a pathname extracted from a TID structure. The
1536 * TID structure is not held; assume it won't go away.
1538 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1543 tidp = smb_FindTID(vcp, tid, 0);
1547 if (tidp->flags & SMB_TIDFLAG_IPC) {
1548 code = CM_ERROR_TIDIPC;
1549 /* tidp->pathname would be NULL, but that's fine */
1551 *treepath = tidp->pathname;
1552 smb_ReleaseTID(tidp, FALSE);
1557 /* check to see if we have a chained fid, that is, a fid that comes from an
1558 * OpenAndX message that ran earlier in this packet. In this case, the fid
1559 * field in a read, for example, request, isn't set, since the value is
1560 * supposed to be inherited from the openAndX call.
1562 int smb_ChainFID(int fid, smb_packet_t *inp)
1564 if (inp->fid == 0 || inp->inCount == 0)
1570 /* are we a priv'd user? What does this mean on NT? */
1571 int smb_SUser(cm_user_t *userp)
1576 /* find a file ID. If we pass in 0 we select an unused File ID.
1577 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1578 * smb_fid_t data structure if desired File ID cannot be found.
1580 #ifdef DEBUG_SMB_REFCOUNT
1581 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1583 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1589 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1592 lock_ObtainWrite(&smb_rctLock);
1593 /* figure out if we need to allocate a new file ID */
1596 fid = vcp->fidCounter;
1600 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1601 if (fidp->refCount == 0 && fidp->deleteOk) {
1603 lock_ReleaseWrite(&smb_rctLock);
1604 smb_ReleaseFID(fidp);
1605 lock_ObtainWrite(&smb_rctLock);
1608 if (fid == fidp->fid) {
1611 if (fid == 0xFFFF) {
1613 "New FID number wraps on vcp 0x%x", vcp);
1623 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1624 char eventName[MAX_PATH];
1626 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1627 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1628 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1629 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1630 thrd_CloseHandle(event);
1632 if (fid == 0xFFFF) {
1633 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1639 fidp = malloc(sizeof(*fidp));
1640 memset(fidp, 0, sizeof(*fidp));
1641 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1644 smb_HoldVCNoLock(vcp);
1645 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1647 fidp->curr_chunk = fidp->prev_chunk = -2;
1648 fidp->raw_write_event = event;
1650 vcp->fidCounter = fid+1;
1651 if (vcp->fidCounter == 0xFFFF) {
1652 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1654 vcp->fidCounter = 1;
1659 #ifdef DEBUG_SMB_REFCOUNT
1661 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1662 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1665 lock_ReleaseWrite(&smb_rctLock);
1670 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1671 #ifdef DEBUG_SMB_REFCOUNT
1672 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1674 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1677 smb_fid_t *fidp = NULL, *nextp = NULL;
1683 * If the fidp->scp changes out from under us then
1684 * we must not grab a refCount. It means the *fidp
1685 * was processed by smb_CloseFID() and the *fidp is
1686 * no longer valid for use.
1688 lock_ObtainWrite(&smb_rctLock);
1689 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1690 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1694 if (scp == fidp->scp) {
1695 lock_ReleaseWrite(&smb_rctLock);
1696 lock_ObtainMutex(&fidp->mx);
1697 lock_ObtainWrite(&smb_rctLock);
1698 if (scp == fidp->scp) {
1699 lock_ReleaseMutex(&fidp->mx);
1702 lock_ReleaseMutex(&fidp->mx);
1705 if (fidp->refCount > 1) {
1708 lock_ReleaseWrite(&smb_rctLock);
1709 smb_ReleaseFID(fidp);
1710 lock_ObtainWrite(&smb_rctLock);
1715 if (nextp->refCount > 1) {
1718 lock_ReleaseWrite(&smb_rctLock);
1719 smb_ReleaseFID(nextp);
1720 lock_ObtainWrite(&smb_rctLock);
1724 #ifdef DEBUG_SMB_REFCOUNT
1726 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1727 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1730 lock_ReleaseWrite(&smb_rctLock);
1734 #ifdef DEBUG_SMB_REFCOUNT
1735 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1737 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1740 lock_AssertWrite(&smb_rctLock);
1742 #ifdef DEBUG_SMB_REFCOUNT
1743 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1744 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1749 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1750 /* the smb_fid_t->mx and smb_rctLock must not be held */
1751 #ifdef DEBUG_SMB_REFCOUNT
1752 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1754 void smb_ReleaseFID(smb_fid_t *fidp)
1757 cm_scache_t *scp = NULL;
1758 cm_user_t *userp = NULL;
1759 smb_vc_t *vcp = NULL;
1760 smb_ioctl_t *ioctlp;
1762 lock_ObtainMutex(&fidp->mx);
1763 lock_ObtainWrite(&smb_rctLock);
1764 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1765 #ifdef DEBUG_SMB_REFCOUNT
1766 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1767 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1769 if (fidp->refCount == 0) {
1770 if (fidp->deleteOk) {
1773 scp = fidp->scp; /* release after lock is released */
1775 lock_ObtainWrite(&scp->rw);
1776 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1777 lock_ReleaseWrite(&scp->rw);
1778 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1781 userp = fidp->userp;
1785 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1786 thrd_CloseHandle(fidp->raw_write_event);
1788 /* and see if there is ioctl stuff to free */
1789 ioctlp = fidp->ioctlp;
1792 cm_FreeSpace(ioctlp->prefix);
1793 if (ioctlp->ioctl.inAllocp)
1794 free(ioctlp->ioctl.inAllocp);
1795 if (ioctlp->ioctl.outAllocp)
1796 free(ioctlp->ioctl.outAllocp);
1799 lock_ReleaseMutex(&fidp->mx);
1800 lock_FinalizeMutex(&fidp->mx);
1805 smb_ReleaseVCNoLock(vcp);
1809 lock_ReleaseMutex(&fidp->mx);
1811 lock_ReleaseWrite(&smb_rctLock);
1813 /* now release the scache structure */
1815 cm_ReleaseSCache(scp);
1818 cm_ReleaseUser(userp);
1822 * Case-insensitive search for one string in another;
1823 * used to find variable names in submount pathnames.
1825 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1827 clientchar_t *cursor;
1829 for (cursor = str1; *cursor; cursor++)
1830 if (cm_ClientStrCmpI(cursor, str2) == 0)
1837 * Substitute a variable value for its name in a submount pathname. Variable
1838 * name has been identified by smb_stristr() and is in substr. Variable name
1839 * length (plus one) is in substr_size. Variable value is in newstr.
1841 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1842 unsigned int substr_size, clientchar_t *newstr)
1844 clientchar_t temp[1024];
1846 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1847 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1848 cm_ClientStrCat(str1, cchstr1, temp);
1851 clientchar_t VNUserName[] = _C("%USERNAME%");
1852 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1853 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1854 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1856 typedef struct smb_findShare_rock {
1857 clientchar_t * shareName;
1858 clientchar_t * match;
1860 } smb_findShare_rock_t;
1862 #define SMB_FINDSHARE_EXACT_MATCH 1
1863 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1865 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1869 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1870 normchar_t normName[MAX_PATH];
1872 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1873 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1874 osi_LogSaveString(smb_logp, dep->name));
1878 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1879 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1880 matchType = SMB_FINDSHARE_EXACT_MATCH;
1882 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1885 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1886 vrock->matchType = matchType;
1888 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1889 return CM_ERROR_STOPNOW;
1895 /* find a shareName in the table of submounts */
1896 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1897 clientchar_t *shareName,
1898 clientchar_t **pathNamep)
1902 clientchar_t pathName[1024];
1905 clientchar_t *p, *q;
1906 fschar_t *cellname = NULL;
1909 DWORD allSubmount = 1;
1911 /* if allSubmounts == 0, only return the //mountRoot/all share
1912 * if in fact it has been been created in the subMounts table.
1913 * This is to allow sites that want to restrict access to the
1916 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1917 0, KEY_QUERY_VALUE, &parmKey);
1918 if (code == ERROR_SUCCESS) {
1919 cblen = sizeof(allSubmount);
1920 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1921 (BYTE *) &allSubmount, &cblen);
1922 if (code != ERROR_SUCCESS) {
1925 RegCloseKey (parmKey);
1928 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1933 /* In case, the all share is disabled we need to still be able
1934 * to handle ioctl requests
1936 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1937 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1941 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1942 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1943 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1944 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1945 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1951 /* Check for volume references
1953 * They look like <cell>{%,#}<volume>
1955 if (cm_ClientStrChr(shareName, '%') != NULL ||
1956 cm_ClientStrChr(shareName, '#') != NULL) {
1957 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1958 /* make room for '/@vol:' + mountchar + NULL terminator*/
1960 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1961 osi_LogSaveClientString(smb_logp, shareName));
1963 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1964 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1965 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1967 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1969 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1970 cm_ClientStrLwr(*pathNamep);
1971 osi_Log1(smb_logp, " returning pathname [%S]",
1972 osi_LogSaveClientString(smb_logp, *pathNamep));
1980 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1981 0, KEY_QUERY_VALUE, &parmKey);
1982 if (code == ERROR_SUCCESS) {
1983 cblen = sizeof(pathName);
1984 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1985 (BYTE *) pathName, &cblen);
1986 if (code != ERROR_SUCCESS)
1988 RegCloseKey (parmKey);
1992 cchlen = cblen / sizeof(clientchar_t);
1993 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1994 /* We can accept either unix or PC style AFS pathnames. Convert
1995 * Unix-style to PC style here for internal use.
1998 cchlen = lengthof(pathName);
2000 /* within this code block, we maintain, cchlen = writeable
2001 buffer length of p */
2003 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
2004 p += cm_mountRootCLen; /* skip mount path */
2005 cchlen -= (DWORD)(p - pathName);
2010 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
2016 clientchar_t temp[1024];
2018 if (var = smb_stristr(p, VNUserName)) {
2019 if (uidp && uidp->unp)
2020 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
2022 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
2024 else if (var = smb_stristr(p, VNLCUserName))
2026 if (uidp && uidp->unp)
2027 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
2029 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
2030 cm_ClientStrLwr(temp);
2031 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
2033 else if (var = smb_stristr(p, VNComputerName))
2035 sizeTemp = lengthof(temp);
2036 GetComputerNameW(temp, &sizeTemp);
2037 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
2039 else if (var = smb_stristr(p, VNLCComputerName))
2041 sizeTemp = lengthof(temp);
2042 GetComputerName((LPTSTR)temp, &sizeTemp);
2043 cm_ClientStrLwr(temp);
2044 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
2049 *pathNamep = cm_ClientStrDup(p);
2054 /* First lookup shareName in root.afs */
2056 smb_findShare_rock_t vrock;
2058 fschar_t ftemp[1024];
2059 clientchar_t * p = shareName;
2062 /* attempt to locate a partial match in root.afs. This is because
2063 when using the ANSI RAP calls, the share name is limited to 13 chars
2064 and hence is truncated. Of course we prefer exact matches. */
2066 thyper.HighPart = 0;
2069 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2070 if (vrock.shareName == NULL)
2073 vrock.matchType = 0;
2075 cm_HoldSCache(cm_data.rootSCachep);
2076 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
2077 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
2078 cm_ReleaseSCache(cm_data.rootSCachep);
2080 free(vrock.shareName);
2081 vrock.shareName = NULL;
2083 if (vrock.matchType) {
2084 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2085 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2090 /* if we get here, there was no match for the share in root.afs */
2091 /* so try to create \\<netbiosName>\<cellname> */
2096 /* Get the full name for this cell */
2097 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2098 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2099 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2100 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2101 #ifdef AFS_AFSDB_ENV
2102 if (code && cm_dnsEnabled) {
2104 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2110 /* construct the path */
2112 clientchar_t temp[1024];
2114 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2115 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2116 rw ? _C("/.%S/") : _C("/%S/"), temp);
2117 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2127 /* Client-side offline caching policy types */
2128 #define CSC_POLICY_MANUAL 0
2129 #define CSC_POLICY_DOCUMENTS 1
2130 #define CSC_POLICY_PROGRAMS 2
2131 #define CSC_POLICY_DISABLE 3
2133 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2136 clientchar_t policy[1024];
2139 int retval = CSC_POLICY_MANUAL;
2141 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2142 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2145 REG_OPTION_NON_VOLATILE,
2151 len = sizeof(policy);
2152 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2154 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2156 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2158 retval = CSC_POLICY_DOCUMENTS;
2160 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2162 retval = CSC_POLICY_PROGRAMS;
2164 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2166 retval = CSC_POLICY_DISABLE;
2169 RegCloseKey(hkCSCPolicy);
2173 /* find a dir search structure by cookie value, and return it held.
2174 * Must be called with smb_globalLock held.
2176 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2178 smb_dirSearch_t *dsp;
2180 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2181 if (dsp->cookie == cookie) {
2182 if (dsp != smb_firstDirSearchp) {
2183 /* move to head of LRU queue, too, if we're not already there */
2184 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2185 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2186 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2187 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2188 if (!smb_lastDirSearchp)
2189 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2197 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2198 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2199 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2205 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2207 lock_ObtainMutex(&dsp->mx);
2208 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2209 dsp->cookie, dsp, dsp->scp);
2210 dsp->flags |= SMB_DIRSEARCH_DELETE;
2211 if (dsp->scp != NULL) {
2212 lock_ObtainWrite(&dsp->scp->rw);
2213 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2214 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2215 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2216 dsp->scp->bulkStatProgress = hzero;
2218 lock_ReleaseWrite(&dsp->scp->rw);
2220 lock_ReleaseMutex(&dsp->mx);
2223 /* Must be called with the smb_globalLock held */
2224 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2226 cm_scache_t *scp = NULL;
2228 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2229 if (dsp->refCount == 0) {
2230 lock_ObtainMutex(&dsp->mx);
2231 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2232 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2233 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2234 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2235 lock_ReleaseMutex(&dsp->mx);
2236 lock_FinalizeMutex(&dsp->mx);
2238 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2239 dsp->cookie, dsp, scp);
2242 lock_ReleaseMutex(&dsp->mx);
2245 /* do this now to avoid spurious locking hierarchy creation */
2247 cm_ReleaseSCache(scp);
2250 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2252 lock_ObtainWrite(&smb_globalLock);
2253 smb_ReleaseDirSearchNoLock(dsp);
2254 lock_ReleaseWrite(&smb_globalLock);
2257 /* find a dir search structure by cookie value, and return it held */
2258 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2260 smb_dirSearch_t *dsp;
2262 lock_ObtainWrite(&smb_globalLock);
2263 dsp = smb_FindDirSearchNoLock(cookie);
2264 lock_ReleaseWrite(&smb_globalLock);
2268 /* GC some dir search entries, in the address space expected by the specific protocol.
2269 * Must be called with smb_globalLock held; release the lock temporarily.
2271 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2272 void smb_GCDirSearches(int isV3)
2274 smb_dirSearch_t *prevp;
2275 smb_dirSearch_t *dsp;
2276 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2280 victimCount = 0; /* how many have we got so far */
2281 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2282 /* we'll move tp from queue, so
2285 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2286 /* if no one is using this guy, and we're either in the new protocol,
2287 * or we're in the old one and this is a small enough ID to be useful
2288 * to the old protocol, GC this guy.
2290 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2291 /* hold and delete */
2292 lock_ObtainMutex(&dsp->mx);
2293 dsp->flags |= SMB_DIRSEARCH_DELETE;
2294 lock_ReleaseMutex(&dsp->mx);
2295 victimsp[victimCount++] = dsp;
2299 /* don't do more than this */
2300 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2304 /* now release them */
2305 for (i = 0; i < victimCount; i++) {
2306 smb_ReleaseDirSearchNoLock(victimsp[i]);
2310 /* function for allocating a dir search entry. We need these to remember enough context
2311 * since we don't get passed the path from call to call during a directory search.
2313 * Returns a held dir search structure, and bumps the reference count on the vnode,
2314 * since it saves a pointer to the vnode.
2316 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2318 smb_dirSearch_t *dsp;
2324 lock_ObtainWrite(&smb_globalLock);
2327 /* what's the biggest ID allowed in this version of the protocol */
2328 /* TODO: do we really want a non v3 dir search request to wrap
2329 smb_dirSearchCounter? */
2330 maxAllowed = isV3 ? 65535 : 255;
2331 if (smb_dirSearchCounter > maxAllowed)
2332 smb_dirSearchCounter = 1;
2334 start = smb_dirSearchCounter;
2337 /* twice so we have enough tries to find guys we GC after one pass;
2338 * 10 extra is just in case I mis-counted.
2340 if (++counter > 2*maxAllowed+10)
2341 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2343 if (smb_dirSearchCounter > maxAllowed) {
2344 smb_dirSearchCounter = 1;
2346 if (smb_dirSearchCounter == start) {
2348 smb_GCDirSearches(isV3);
2351 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2353 /* don't need to watch for refcount zero and deleted, since
2354 * we haven't dropped the global lock.
2357 ++smb_dirSearchCounter;
2361 dsp = malloc(sizeof(*dsp));
2362 memset(dsp, 0, sizeof(*dsp));
2363 dsp->cookie = smb_dirSearchCounter;
2364 ++smb_dirSearchCounter;
2366 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2367 dsp->lastTime = osi_Time();
2368 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2369 if (!smb_lastDirSearchp)
2370 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2372 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2376 lock_ReleaseWrite(&smb_globalLock);
2380 static smb_packet_t *smb_GetPacket(void)
2384 lock_ObtainWrite(&smb_globalLock);
2385 tbp = smb_packetFreeListp;
2387 smb_packetFreeListp = tbp->nextp;
2388 lock_ReleaseWrite(&smb_globalLock);
2390 tbp = calloc(sizeof(*tbp),1);
2391 tbp->magic = SMB_PACKETMAGIC;
2394 tbp->resumeCode = 0;
2400 tbp->ncb_length = 0;
2403 tbp->stringsp = NULL;
2405 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2410 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2413 tbp = smb_GetPacket();
2414 memcpy(tbp, pkt, sizeof(smb_packet_t));
2415 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2416 tbp->stringsp = NULL;
2418 smb_HoldVC(tbp->vcp);
2422 static NCB *smb_GetNCB(void)
2427 lock_ObtainWrite(&smb_globalLock);
2428 tbp = smb_ncbFreeListp;
2430 smb_ncbFreeListp = tbp->nextp;
2431 lock_ReleaseWrite(&smb_globalLock);
2433 tbp = calloc(sizeof(*tbp),1);
2434 tbp->magic = SMB_NCBMAGIC;
2437 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2439 memset(&tbp->ncb, 0, sizeof(NCB));
2444 static void FreeSMBStrings(smb_packet_t * pkt)
2449 for (s = pkt->stringsp; s; s = ns) {
2453 pkt->stringsp = NULL;
2456 void smb_FreePacket(smb_packet_t *tbp)
2458 smb_vc_t * vcp = NULL;
2459 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2461 lock_ObtainWrite(&smb_globalLock);
2462 tbp->nextp = smb_packetFreeListp;
2463 smb_packetFreeListp = tbp;
2464 tbp->magic = SMB_PACKETMAGIC;
2468 tbp->resumeCode = 0;
2474 tbp->ncb_length = 0;
2476 FreeSMBStrings(tbp);
2477 lock_ReleaseWrite(&smb_globalLock);
2483 static void smb_FreeNCB(NCB *bufferp)
2487 tbp = (smb_ncb_t *) bufferp;
2488 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2490 lock_ObtainWrite(&smb_globalLock);
2491 tbp->nextp = smb_ncbFreeListp;
2492 smb_ncbFreeListp = tbp;
2493 lock_ReleaseWrite(&smb_globalLock);
2496 /* get a ptr to the data part of a packet, and its count */
2497 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2501 unsigned char *afterParmsp;
2503 parmBytes = *smbp->wctp << 1;
2504 afterParmsp = smbp->wctp + parmBytes + 1;
2506 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2507 if (nbytesp) *nbytesp = dataBytes;
2509 /* don't forget to skip the data byte count, since it follows
2510 * the parameters; that's where the "2" comes from below.
2512 return (unsigned char *) (afterParmsp + 2);
2515 /* must set all the returned parameters before playing around with the
2516 * data region, since the data region is located past the end of the
2517 * variable number of parameters.
2519 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2521 unsigned char *afterParmsp;
2523 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2525 *afterParmsp++ = dsize & 0xff;
2526 *afterParmsp = (dsize>>8) & 0xff;
2529 /* return the parm'th parameter in the smbp packet */
2530 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2533 unsigned char *parmDatap;
2535 parmCount = *smbp->wctp;
2537 if (parm >= parmCount) {
2540 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2541 parm, parmCount, smbp->ncb_length);
2542 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2543 parm, parmCount, smbp->ncb_length);
2544 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2545 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2546 osi_panic(s, __FILE__, __LINE__);
2548 parmDatap = smbp->wctp + (2*parm) + 1;
2550 return parmDatap[0] + (parmDatap[1] << 8);
2553 /* return the parm'th parameter in the smbp packet */
2554 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2557 unsigned char *parmDatap;
2559 parmCount = *smbp->wctp;
2561 if (parm >= parmCount) {
2564 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2565 parm, parmCount, smbp->ncb_length);
2566 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2567 parm, parmCount, smbp->ncb_length);
2568 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2569 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2570 osi_panic(s, __FILE__, __LINE__);
2572 parmDatap = smbp->wctp + (2*parm) + 1;
2574 return parmDatap[0];
2577 /* return the parm'th parameter in the smbp packet */
2578 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2581 unsigned char *parmDatap;
2583 parmCount = *smbp->wctp;
2585 if (parm + 1 >= parmCount) {
2588 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2589 parm, parmCount, smbp->ncb_length);
2590 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2591 parm, parmCount, smbp->ncb_length);
2592 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2593 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2594 osi_panic(s, __FILE__, __LINE__);
2596 parmDatap = smbp->wctp + (2*parm) + 1;
2598 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2601 /* return the parm'th parameter in the smbp packet */
2602 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2605 unsigned char *parmDatap;
2607 parmCount = *smbp->wctp;
2609 if (parm * 2 + offset >= parmCount * 2) {
2612 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2613 parm, offset, parmCount, smbp->ncb_length);
2614 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2615 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2616 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2617 parm, offset, parmCount, smbp->ncb_length);
2618 osi_panic(s, __FILE__, __LINE__);
2620 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2622 return parmDatap[0] + (parmDatap[1] << 8);
2625 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2627 unsigned char *parmDatap;
2629 /* make sure we have enough slots */
2630 if (*smbp->wctp <= slot)
2631 *smbp->wctp = slot+1;
2633 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2634 *parmDatap++ = parmValue & 0xff;
2635 *parmDatap = (parmValue>>8) & 0xff;
2638 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2640 unsigned char *parmDatap;
2642 /* make sure we have enough slots */
2643 if (*smbp->wctp <= slot)
2644 *smbp->wctp = slot+2;
2646 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2647 *parmDatap++ = parmValue & 0xff;
2648 *parmDatap++ = (parmValue>>8) & 0xff;
2649 *parmDatap++ = (parmValue>>16) & 0xff;
2650 *parmDatap = (parmValue>>24) & 0xff;
2653 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2655 unsigned char *parmDatap;
2658 /* make sure we have enough slots */
2659 if (*smbp->wctp <= slot)
2660 *smbp->wctp = slot+4;
2662 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2664 *parmDatap++ = *parmValuep++;
2667 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2669 unsigned char *parmDatap;
2671 /* make sure we have enough slots */
2672 if (*smbp->wctp <= slot) {
2673 if (smbp->oddByte) {
2675 *smbp->wctp = slot+1;
2680 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2681 *parmDatap++ = parmValue & 0xff;
2686 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2687 clientchar_t *inPathp)
2689 clientchar_t *lastSlashp;
2691 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2693 *lastComponentp = lastSlashp;
2696 if (inPathp == lastSlashp)
2698 *outPathp++ = *inPathp++;
2707 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2708 char **chainpp, int flags)
2711 afs_uint32 type = *inp++;
2714 * The first byte specifies the type of the input string.
2715 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2719 /* Length Counted */
2720 case 0x1: /* Data Block */
2721 case 0x5: /* Variable Block */
2722 cb = *inp++ << 16 | *inp++;
2725 /* Null-terminated string */
2726 case 0x4: /* ASCII */
2727 case 0x3: /* Pathname */
2728 case 0x2: /* Dialect */
2729 cb = sizeof(pktp->data) - (inp - pktp->data);
2730 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2731 #ifdef DEBUG_UNICODE
2734 cb = sizeof(pktp->data);
2739 return NULL; /* invalid input */
2743 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2744 flags |= SMB_STRF_FORCEASCII;
2747 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2750 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2751 char ** chainpp, int flags)
2756 if (!WANTS_UNICODE(pktp))
2757 flags |= SMB_STRF_FORCEASCII;
2760 cb = sizeof(pktp->data) - (inp - pktp->data);
2761 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2762 #ifdef DEBUG_UNICODE
2765 cb = sizeof(pktp->data);
2767 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2768 flags | SMB_STRF_SRCNULTERM);
2771 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2772 size_t cb, char ** chainpp, int flags)
2775 if (!WANTS_UNICODE(pktp))
2776 flags |= SMB_STRF_FORCEASCII;
2779 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2782 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2783 size_t cch, char ** chainpp, int flags)
2788 if (!WANTS_UNICODE(pktp))
2789 flags |= SMB_STRF_FORCEASCII;
2791 cb = cch * sizeof(wchar_t);
2794 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2798 smb_ParseStringBuf(const unsigned char * bufbase,
2799 cm_space_t ** stringspp,
2800 unsigned char *inp, size_t *pcb_max,
2801 char **chainpp, int flags)
2804 if (!(flags & SMB_STRF_FORCEASCII)) {
2806 cm_space_t * spacep;
2809 if (bufbase && ((inp - bufbase) % 2) != 0) {
2810 inp++; /* unicode strings are always word aligned */
2814 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2816 cch_src = *pcb_max / sizeof(wchar_t);
2820 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2827 spacep = cm_GetSpace();
2828 spacep->nextp = *stringspp;
2829 *stringspp = spacep;
2833 *chainpp = inp + sizeof(wchar_t);
2836 *(spacep->wdata) = 0;
2837 return spacep->wdata;
2840 StringCchCopyNW(spacep->wdata,
2841 lengthof(spacep->wdata),
2842 (const clientchar_t *) inp, cch_src);
2845 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2847 return spacep->wdata;
2851 cm_space_t * spacep;
2854 /* Not using Unicode */
2856 *chainpp = inp + strlen(inp) + 1;
2859 spacep = cm_GetSpace();
2860 spacep->nextp = *stringspp;
2861 *stringspp = spacep;
2863 cchdest = lengthof(spacep->wdata);
2864 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2865 spacep->wdata, cchdest);
2867 return spacep->wdata;
2873 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2875 size_t * plen, int flags)
2881 /* we are only calculating the required size */
2888 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2890 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2891 if (!(flags & SMB_STRF_IGNORENUL))
2892 *plen += sizeof(wchar_t);
2894 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2904 cch_str = cm_ClientStrLen(str);
2905 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2908 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2916 /* if outp != NULL ... */
2918 /* Number of bytes left in the buffer.
2920 If outp lies inside the packet data buffer, we assume that the
2921 buffer is the packet data buffer. Otherwise we assume that the
2922 buffer is sizeof(packet->data).
2925 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2926 align = (int)((outp - pktp->data) % 2);
2927 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2929 align = (int)(((size_t) outp) % 2);
2930 buffersize = (int)sizeof(pktp->data);
2935 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2941 if (*str == _C('\0')) {
2943 if (buffersize < sizeof(wchar_t))
2946 *((wchar_t *) outp) = L'\0';
2947 if (plen && !(flags & SMB_STRF_IGNORENUL))
2948 *plen += sizeof(wchar_t);
2949 return outp + sizeof(wchar_t);
2952 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2954 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2955 osi_LogSaveClientString(smb_logp, str),
2961 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2963 return outp + sizeof(wchar_t) * nchars;
2971 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2974 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2976 return outp + cch_dest;
2980 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2986 tlen = inp[0] + (inp[1]<<8);
2987 inp += 2; /* skip length field */
2990 *chainpp = inp + tlen;
2999 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3003 if (*inp++ != 0x1) return NULL;
3004 tlen = inp[0] + (inp[1]<<8);
3005 inp += 2; /* skip length field */
3008 *chainpp = inp + tlen;
3011 if (lengthp) *lengthp = tlen;
3016 /* format a packet as a response */
3017 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
3022 outp = (smb_t *) op;
3024 /* zero the basic structure through the smb_wct field, and zero the data
3025 * size field, assuming that wct stays zero; otherwise, you have to
3026 * explicitly set the data size field, too.
3028 inSmbp = (smb_t *) inp;
3029 memset(outp, 0, sizeof(smb_t)+2);
3035 outp->com = inSmbp->com;
3036 outp->tid = inSmbp->tid;
3037 outp->pid = inSmbp->pid;
3038 outp->uid = inSmbp->uid;
3039 outp->mid = inSmbp->mid;
3040 outp->res[0] = inSmbp->res[0];
3041 outp->res[1] = inSmbp->res[1];
3042 op->inCom = inSmbp->com;
3044 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3045 #ifdef SEND_CANONICAL_PATHNAMES
3046 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3048 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3050 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3051 outp->flg2 |= SMB_FLAGS2_UNICODE;
3054 /* copy fields in generic packet area */
3055 op->wctp = &outp->wct;
3058 /* send a (probably response) packet; vcp tells us to whom to send it.
3059 * we compute the length by looking at wct and bcc fields.
3061 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3071 ncbp = smb_GetNCB();
3075 memset((char *)ncbp, 0, sizeof(NCB));
3077 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3078 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3079 extra += tp[0] + (tp[1]<<8);
3080 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3081 extra += 3; /* wct and length fields */
3083 ncbp->ncb_length = extra; /* bytes to send */
3084 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3085 ncbp->ncb_lana_num = vcp->lana;
3086 ncbp->ncb_command = NCBSEND; /* op means send data */
3087 ncbp->ncb_buffer = (char *) inp;/* packet */
3088 code = Netbios(ncbp);
3091 const char * s = ncb_error_string(code);
3092 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3093 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3095 lock_ObtainMutex(&vcp->mx);
3096 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3097 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3099 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3100 lock_ReleaseMutex(&vcp->mx);
3101 lock_ObtainWrite(&smb_globalLock);
3102 dead_sessions[vcp->session] = TRUE;
3103 lock_ReleaseWrite(&smb_globalLock);
3104 smb_CleanupDeadVC(vcp);
3106 lock_ReleaseMutex(&vcp->mx);
3114 void smb_MapNTError(long code, unsigned long *NTStatusp)
3116 unsigned long NTStatus;
3118 /* map CM_ERROR_* errors to NT 32-bit status codes */
3119 /* NT Status codes are listed in ntstatus.h not winerror.h */
3123 else if (code == CM_ERROR_NOSUCHCELL) {
3124 NTStatus = 0xC000000FL; /* No such file */
3126 else if (code == CM_ERROR_NOSUCHVOLUME) {
3127 NTStatus = 0xC000000FL; /* No such file */
3129 else if (code == CM_ERROR_TIMEDOUT) {
3131 NTStatus = 0xC00000CFL; /* Sharing Paused */
3133 NTStatus = 0x00000102L; /* Timeout */
3136 else if (code == CM_ERROR_RETRY) {
3137 NTStatus = 0xC000022DL; /* Retry */
3139 else if (code == CM_ERROR_NOACCESS) {
3140 NTStatus = 0xC0000022L; /* Access denied */
3142 else if (code == CM_ERROR_READONLY) {
3143 NTStatus = 0xC00000A2L; /* Write protected */
3145 else if (code == CM_ERROR_NOSUCHFILE ||
3146 code == CM_ERROR_BPLUS_NOMATCH) {
3147 NTStatus = 0xC000000FL; /* No such file */
3149 else if (code == CM_ERROR_NOSUCHPATH) {
3150 NTStatus = 0xC000003AL; /* Object path not found */
3152 else if (code == CM_ERROR_TOOBIG) {
3153 NTStatus = 0xC000007BL; /* Invalid image format */
3155 else if (code == CM_ERROR_INVAL) {
3156 NTStatus = 0xC000000DL; /* Invalid parameter */
3158 else if (code == CM_ERROR_BADFD) {
3159 NTStatus = 0xC0000008L; /* Invalid handle */
3161 else if (code == CM_ERROR_BADFDOP) {
3162 NTStatus = 0xC0000022L; /* Access denied */
3164 else if (code == CM_ERROR_EXISTS) {
3165 NTStatus = 0xC0000035L; /* Object name collision */
3167 else if (code == CM_ERROR_NOTEMPTY) {
3168 NTStatus = 0xC0000101L; /* Directory not empty */
3170 else if (code == CM_ERROR_CROSSDEVLINK) {
3171 NTStatus = 0xC00000D4L; /* Not same device */
3173 else if (code == CM_ERROR_NOTDIR) {
3174 NTStatus = 0xC0000103L; /* Not a directory */
3176 else if (code == CM_ERROR_ISDIR) {
3177 NTStatus = 0xC00000BAL; /* File is a directory */
3179 else if (code == CM_ERROR_BADOP) {
3181 /* I have no idea where this comes from */
3182 NTStatus = 0xC09820FFL; /* SMB no support */
3184 NTStatus = 0xC00000BBL; /* Not supported */
3185 #endif /* COMMENT */
3187 else if (code == CM_ERROR_BADSHARENAME) {
3188 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3190 else if (code == CM_ERROR_NOIPC) {
3192 NTStatus = 0xC0000022L; /* Access Denied */
3194 NTStatus = 0xC000013DL; /* Remote Resources */
3197 else if (code == CM_ERROR_CLOCKSKEW) {
3198 NTStatus = 0xC0000133L; /* Time difference at DC */
3200 else if (code == CM_ERROR_BADTID) {
3201 NTStatus = 0xC0982005L; /* SMB bad TID */
3203 else if (code == CM_ERROR_USESTD) {
3204 NTStatus = 0xC09820FBL; /* SMB use standard */
3206 else if (code == CM_ERROR_QUOTA) {
3207 NTStatus = 0xC0000044L; /* Quota exceeded */
3209 else if (code == CM_ERROR_SPACE) {
3210 NTStatus = 0xC000007FL; /* Disk full */
3212 else if (code == CM_ERROR_ATSYS) {
3213 NTStatus = 0xC0000033L; /* Object name invalid */
3215 else if (code == CM_ERROR_BADNTFILENAME) {
3216 NTStatus = 0xC0000033L; /* Object name invalid */
3218 else if (code == CM_ERROR_WOULDBLOCK) {
3219 NTStatus = 0xC00000D8L; /* Can't wait */
3221 else if (code == CM_ERROR_SHARING_VIOLATION) {
3222 NTStatus = 0xC0000043L; /* Sharing violation */
3224 else if (code == CM_ERROR_LOCK_CONFLICT) {
3225 NTStatus = 0xC0000054L; /* Lock conflict */
3227 else if (code == CM_ERROR_PARTIALWRITE) {
3228 NTStatus = 0xC000007FL; /* Disk full */
3230 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3231 NTStatus = 0xC0000023L; /* Buffer too small */
3233 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3234 NTStatus = 0xC0000035L; /* Object name collision */
3236 else if (code == CM_ERROR_BADPASSWORD) {
3237 NTStatus = 0xC000006DL; /* unknown username or bad password */
3239 else if (code == CM_ERROR_BADLOGONTYPE) {
3240 NTStatus = 0xC000015BL; /* logon type not granted */
3242 else if (code == CM_ERROR_GSSCONTINUE) {
3243 NTStatus = 0xC0000016L; /* more processing required */
3245 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3247 NTStatus = 0xC0000280L; /* reparse point not resolved */
3249 NTStatus = 0xC0000022L; /* Access Denied */
3252 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3253 NTStatus = 0xC0000257L; /* Path Not Covered */
3255 else if (code == CM_ERROR_ALLBUSY) {
3256 NTStatus = 0xC000022DL; /* Retry */
3258 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3259 NTStatus = 0xC000003AL; /* Path not found */
3261 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3262 NTStatus = 0xC0000322L; /* No Kerberos key */
3264 else if (code == CM_ERROR_BAD_LEVEL) {
3265 NTStatus = 0xC0000148L; /* Invalid Level */
3267 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3268 NTStatus = 0xC000007EL; /* Range Not Locked */
3270 else if (code == CM_ERROR_NOSUCHDEVICE) {
3271 NTStatus = 0xC000000EL; /* No Such Device */
3273 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3274 NTStatus = 0xC0000055L; /* Lock Not Granted */
3275 } else if (code == ENOMEM) {
3276 NTStatus = 0xC0000017L; /* Out of Memory */
3278 NTStatus = 0xC0982001L; /* SMB non-specific error */
3281 *NTStatusp = NTStatus;
3282 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3285 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3286 unsigned char *classp)
3288 unsigned char class;
3289 unsigned short error;
3291 /* map CM_ERROR_* errors to SMB errors */
3292 if (code == CM_ERROR_NOSUCHCELL) {
3294 error = 3; /* bad path */
3296 else if (code == CM_ERROR_NOSUCHVOLUME) {
3298 error = 3; /* bad path */
3300 else if (code == CM_ERROR_TIMEDOUT) {
3302 error = 81; /* server is paused */
3304 else if (code == CM_ERROR_RETRY) {
3305 class = 2; /* shouldn't happen */
3308 else if (code == CM_ERROR_NOACCESS) {
3310 error = 4; /* bad access */
3312 else if (code == CM_ERROR_READONLY) {
3314 error = 19; /* read only */
3316 else if (code == CM_ERROR_NOSUCHFILE ||
3317 code == CM_ERROR_BPLUS_NOMATCH) {
3319 error = 2; /* ENOENT! */
3321 else if (code == CM_ERROR_NOSUCHPATH) {
3323 error = 3; /* Bad path */
3325 else if (code == CM_ERROR_TOOBIG) {
3327 error = 11; /* bad format */
3329 else if (code == CM_ERROR_INVAL) {
3330 class = 2; /* server non-specific error code */
3333 else if (code == CM_ERROR_BADFD) {
3335 error = 6; /* invalid file handle */
3337 else if (code == CM_ERROR_BADFDOP) {
3338 class = 1; /* invalid op on FD */
3341 else if (code == CM_ERROR_EXISTS) {
3343 error = 80; /* file already exists */
3345 else if (code == CM_ERROR_NOTEMPTY) {
3347 error = 5; /* delete directory not empty */
3349 else if (code == CM_ERROR_CROSSDEVLINK) {
3351 error = 17; /* EXDEV */
3353 else if (code == CM_ERROR_NOTDIR) {
3354 class = 1; /* bad path */
3357 else if (code == CM_ERROR_ISDIR) {
3358 class = 1; /* access denied; DOS doesn't have a good match */
3361 else if (code == CM_ERROR_BADOP) {
3365 else if (code == CM_ERROR_BADSHARENAME) {
3369 else if (code == CM_ERROR_NOIPC) {
3371 error = 4; /* bad access */
3373 else if (code == CM_ERROR_CLOCKSKEW) {
3374 class = 1; /* invalid function */
3377 else if (code == CM_ERROR_BADTID) {
3381 else if (code == CM_ERROR_USESTD) {
3385 else if (code == CM_ERROR_REMOTECONN) {
3389 else if (code == CM_ERROR_QUOTA) {
3390 if (vcp->flags & SMB_VCFLAG_USEV3) {
3392 error = 39; /* disk full */
3396 error = 5; /* access denied */
3399 else if (code == CM_ERROR_SPACE) {
3400 if (vcp->flags & SMB_VCFLAG_USEV3) {
3402 error = 39; /* disk full */
3406 error = 5; /* access denied */
3409 else if (code == CM_ERROR_PARTIALWRITE) {
3411 error = 39; /* disk full */
3413 else if (code == CM_ERROR_ATSYS) {
3415 error = 2; /* ENOENT */
3417 else if (code == CM_ERROR_WOULDBLOCK) {
3419 error = 33; /* lock conflict */
3421 else if (code == CM_ERROR_LOCK_CONFLICT) {
3423 error = 33; /* lock conflict */
3425 else if (code == CM_ERROR_SHARING_VIOLATION) {
3427 error = 33; /* lock conflict */
3429 else if (code == CM_ERROR_NOFILES) {
3431 error = 18; /* no files in search */
3433 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3435 error = 183; /* Samba uses this */
3437 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3438 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3440 error = 2; /* bad password */
3442 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3444 error = 3; /* bad path */
3453 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3456 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3458 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3459 return CM_ERROR_BADOP;
3463 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3465 unsigned short EchoCount, i;
3466 char *data, *outdata;
3469 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3471 for (i=1; i<=EchoCount; i++) {
3472 data = smb_GetSMBData(inp, &dataSize);
3473 smb_SetSMBParm(outp, 0, i);
3474 smb_SetSMBDataLength(outp, dataSize);
3475 outdata = smb_GetSMBData(outp, NULL);
3476 memcpy(outdata, data, dataSize);
3477 smb_SendPacket(vcp, outp);
3483 /* SMB_COM_READ_RAW */
3484 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3487 long count, minCount, finalCount;
3491 smb_t *smbp = (smb_t*) inp;
3493 cm_user_t *userp = NULL;
3496 char *rawBuf = NULL;
3501 fd = smb_GetSMBParm(inp, 0);
3502 count = smb_GetSMBParm(inp, 3);
3503 minCount = smb_GetSMBParm(inp, 4);
3504 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3506 if (*inp->wctp == 10) {
3507 /* we were sent a request with 64-bit file offsets */
3508 #ifdef AFS_LARGEFILES
3509 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3511 if (LargeIntegerLessThanZero(offset)) {
3512 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3516 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3517 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3520 offset.HighPart = 0;
3524 /* we were sent a request with 32-bit file offsets */
3525 offset.HighPart = 0;
3528 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3529 fd, offset.HighPart, offset.LowPart, count);
3531 fidp = smb_FindFID(vcp, fd, 0);
3535 lock_ObtainMutex(&fidp->mx);
3537 lock_ReleaseMutex(&fidp->mx);
3538 smb_ReleaseFID(fidp);
3539 return CM_ERROR_BADFD;
3542 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3543 lock_ReleaseMutex(&fidp->mx);
3544 smb_CloseFID(vcp, fidp, NULL, 0);
3545 code = CM_ERROR_NOSUCHFILE;
3551 LARGE_INTEGER LOffset, LLength;
3554 key = cm_GenerateKey(vcp->vcID, pid, fd);
3556 LOffset.HighPart = offset.HighPart;
3557 LOffset.LowPart = offset.LowPart;
3558 LLength.HighPart = 0;
3559 LLength.LowPart = count;
3561 lock_ObtainWrite(&fidp->scp->rw);
3562 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3563 lock_ReleaseWrite(&fidp->scp->rw);
3566 lock_ReleaseMutex(&fidp->mx);
3570 lock_ObtainMutex(&smb_RawBufLock);
3572 /* Get a raw buf, from head of list */
3573 rawBuf = smb_RawBufs;
3574 smb_RawBufs = *(char **)smb_RawBufs;
3576 lock_ReleaseMutex(&smb_RawBufLock);
3578 lock_ReleaseMutex(&fidp->mx);
3582 if (fidp->flags & SMB_FID_IOCTL)
3584 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3586 /* Give back raw buffer */
3587 lock_ObtainMutex(&smb_RawBufLock);
3588 *((char **) rawBuf) = smb_RawBufs;
3590 smb_RawBufs = rawBuf;
3591 lock_ReleaseMutex(&smb_RawBufLock);
3594 lock_ReleaseMutex(&fidp->mx);
3595 smb_ReleaseFID(fidp);
3598 lock_ReleaseMutex(&fidp->mx);
3600 userp = smb_GetUserFromVCP(vcp, inp);
3602 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3608 cm_ReleaseUser(userp);
3611 smb_ReleaseFID(fidp);
3615 memset((char *)ncbp, 0, sizeof(NCB));
3617 ncbp->ncb_length = (unsigned short) finalCount;
3618 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3619 ncbp->ncb_lana_num = vcp->lana;
3620 ncbp->ncb_command = NCBSEND;
3621 ncbp->ncb_buffer = rawBuf;
3623 code = Netbios(ncbp);
3625 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3628 /* Give back raw buffer */
3629 lock_ObtainMutex(&smb_RawBufLock);
3630 *((char **) rawBuf) = smb_RawBufs;
3632 smb_RawBufs = rawBuf;
3633 lock_ReleaseMutex(&smb_RawBufLock);
3639 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3641 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3646 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3648 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3653 /* SMB_COM_NEGOTIATE */
3654 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3661 int VistaProtoIndex;
3662 int protoIndex; /* index we're using */
3667 char protocol_array[10][1024]; /* protocol signature of the client */
3668 int caps; /* capabilities */
3671 TIME_ZONE_INFORMATION tzi;
3673 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3676 namep = smb_GetSMBData(inp, &dbytes);
3679 coreProtoIndex = -1; /* not found */
3682 VistaProtoIndex = -1;
3683 while(namex < dbytes) {
3684 osi_Log1(smb_logp, "Protocol %s",
3685 osi_LogSaveString(smb_logp, namep+1));
3686 strcpy(protocol_array[tcounter], namep+1);
3688 /* namep points at the first protocol, or really, a 0x02
3689 * byte preceding the null-terminated ASCII name.
3691 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3692 coreProtoIndex = tcounter;
3694 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3695 v3ProtoIndex = tcounter;
3697 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3698 NTProtoIndex = tcounter;
3700 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3701 VistaProtoIndex = tcounter;
3704 /* compute size of protocol entry */
3705 entryLength = (int)strlen(namep+1);
3706 entryLength += 2; /* 0x02 bytes and null termination */
3708 /* advance over this protocol entry */
3709 namex += entryLength;
3710 namep += entryLength;
3711 tcounter++; /* which proto entry we're looking at */
3714 lock_ObtainMutex(&vcp->mx);
3716 if (VistaProtoIndex != -1) {
3717 protoIndex = VistaProtoIndex;
3718 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3721 if (NTProtoIndex != -1) {
3722 protoIndex = NTProtoIndex;
3723 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3725 else if (v3ProtoIndex != -1) {
3726 protoIndex = v3ProtoIndex;
3727 vcp->flags |= SMB_VCFLAG_USEV3;
3729 else if (coreProtoIndex != -1) {
3730 protoIndex = coreProtoIndex;
3731 vcp->flags |= SMB_VCFLAG_USECORE;
3733 else protoIndex = -1;
3734 lock_ReleaseMutex(&vcp->mx);
3736 if (protoIndex == -1)
3737 return CM_ERROR_INVAL;
3738 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3739 smb_SetSMBParm(outp, 0, protoIndex);
3740 if (smb_authType != SMB_AUTH_NONE) {
3741 smb_SetSMBParmByte(outp, 1,
3742 NEGOTIATE_SECURITY_USER_LEVEL |
3743 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3745 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3747 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3748 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3749 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3750 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3751 /* The session key is not a well documented field however most clients
3752 * will echo back the session key to the server. Currently we are using
3753 * the same value for all sessions. We should generate a random value
3754 * and store it into the vcp
3756 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3757 smb_SetSMBParm(outp, 8, 1);
3759 * Tried changing the capabilities to support for W2K - defect 117695
3760 * Maybe something else needs to be changed here?
3764 smb_SetSMBParmLong(outp, 9, 0x43fd);
3766 smb_SetSMBParmLong(outp, 9, 0x251);
3769 * 32-bit error codes *
3775 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3777 NTNEGOTIATE_CAPABILITY_DFS |
3779 #ifdef AFS_LARGEFILES
3780 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3782 NTNEGOTIATE_CAPABILITY_NTFIND |
3783 NTNEGOTIATE_CAPABILITY_RAWMODE |
3784 NTNEGOTIATE_CAPABILITY_NTSMB;
3786 if ( smb_authType == SMB_AUTH_EXTENDED )
3787 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3790 if ( smb_UseUnicode ) {
3791 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3795 smb_SetSMBParmLong(outp, 9, caps);
3797 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3798 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3799 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3801 GetTimeZoneInformation(&tzi);
3802 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3804 if (smb_authType == SMB_AUTH_NTLM) {
3805 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3806 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3807 /* paste in encryption key */
3808 datap = smb_GetSMBData(outp, NULL);
3809 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3810 /* and the faux domain name */
3811 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3812 datap + MSV1_0_CHALLENGE_LENGTH,
3813 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3814 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3818 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3820 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3822 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3824 datap = smb_GetSMBData(outp, NULL);
3825 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3828 datap += sizeof(smb_ServerGUID);
3829 memcpy(datap, secBlob, secBlobLength);
3833 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3834 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3837 else if (v3ProtoIndex != -1) {
3838 smb_SetSMBParm(outp, 0, protoIndex);
3840 /* NOTE: Extended authentication cannot be negotiated with v3
3841 * therefore we fail over to NTLM
3843 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3844 smb_SetSMBParm(outp, 1,
3845 NEGOTIATE_SECURITY_USER_LEVEL |
3846 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3848 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3850 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3851 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3852 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3853 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3854 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3855 smb_SetSMBParm(outp, 7, 1);
3857 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3858 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3859 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3861 GetTimeZoneInformation(&tzi);
3862 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3864 /* NOTE: Extended authentication cannot be negotiated with v3
3865 * therefore we fail over to NTLM
3867 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3868 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3869 smb_SetSMBParm(outp, 12, 0); /* resvd */
3870 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3871 datap = smb_GetSMBData(outp, NULL);
3872 /* paste in a new encryption key */
3873 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3874 /* and the faux domain name */
3875 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3876 datap + MSV1_0_CHALLENGE_LENGTH,
3877 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3879 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3880 smb_SetSMBParm(outp, 12, 0); /* resvd */
3881 smb_SetSMBDataLength(outp, 0);
3884 else if (coreProtoIndex != -1) { /* not really supported anymore */
3885 smb_SetSMBParm(outp, 0, protoIndex);
3886 smb_SetSMBDataLength(outp, 0);
3891 void smb_CheckVCs(void)
3893 smb_vc_t * vcp, *nextp;
3894 smb_packet_t * outp = smb_GetPacket();
3897 lock_ObtainWrite(&smb_rctLock);
3898 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3900 if (vcp->magic != SMB_VC_MAGIC)
3901 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3902 __FILE__, __LINE__);
3904 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3906 smb_HoldVCNoLock(vcp);
3909 * obtain a reference to 'nextp' now because we drop the
3910 * smb_rctLock later and the list contents could change
3911 * or 'vcp' could be destroyed when released.
3915 smb_HoldVCNoLock(nextp);
3917 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3918 smb_ReleaseVCNoLock(vcp);
3922 smb_FormatResponsePacket(vcp, NULL, outp);
3923 smbp = (smb_t *)outp;
3924 outp->inCom = smbp->com = 0x2b /* Echo */;
3932 smb_SetSMBParm(outp, 0, 0);
3933 smb_SetSMBDataLength(outp, 0);
3934 lock_ReleaseWrite(&smb_rctLock);
3936 smb_SendPacket(vcp, outp);
3938 lock_ObtainWrite(&smb_rctLock);
3939 smb_ReleaseVCNoLock(vcp);
3941 lock_ReleaseWrite(&smb_rctLock);
3942 smb_FreePacket(outp);
3945 void smb_Daemon(void *parmp)
3947 afs_uint32 count = 0;
3948 smb_username_t **unpp;
3951 while(smbShutdownFlag == 0) {
3955 if (smbShutdownFlag == 1)
3958 if ((count % 72) == 0) { /* every five minutes */
3960 time_t old_localZero = smb_localZero;
3962 /* Initialize smb_localZero */
3963 myTime.tm_isdst = -1; /* compute whether on DST or not */
3964 myTime.tm_year = 70;
3970 smb_localZero = mktime(&myTime);
3972 #ifndef USE_NUMERIC_TIME_CONV
3973 smb_CalculateNowTZ();
3974 #endif /* USE_NUMERIC_TIME_CONV */
3975 #ifdef AFS_FREELANCE
3976 if ( smb_localZero != old_localZero )
3977 cm_noteLocalMountPointChange();
3983 /* GC smb_username_t objects that will no longer be used */
3985 lock_ObtainWrite(&smb_rctLock);
3986 for ( unpp=&usernamesp; *unpp; ) {
3988 smb_username_t *unp;
3990 lock_ObtainMutex(&(*unpp)->mx);
3991 if ( (*unpp)->refCount > 0 ||
3992 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3993 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3995 else if (!smb_LogoffTokenTransfer ||
3996 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3998 lock_ReleaseMutex(&(*unpp)->mx);
4006 lock_FinalizeMutex(&unp->mx);
4012 cm_ReleaseUser(userp);
4014 unpp = &(*unpp)->nextp;
4017 lock_ReleaseWrite(&smb_rctLock);
4019 /* XXX GC dir search entries */
4023 void smb_WaitingLocksDaemon()
4025 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4026 smb_waitingLock_t *wl, *wlNext;
4029 smb_packet_t *inp, *outp;
4033 while (smbShutdownFlag == 0) {
4034 lock_ObtainWrite(&smb_globalLock);
4035 nwlRequest = smb_allWaitingLocks;
4036 if (nwlRequest == NULL) {
4037 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4042 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4049 lock_ObtainWrite(&smb_globalLock);
4051 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4053 wlRequest = nwlRequest;
4054 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4055 lock_ReleaseWrite(&smb_globalLock);
4059 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4060 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4063 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4064 code = CM_ERROR_LOCK_NOT_GRANTED;
4068 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4070 /* wl->state is either _DONE or _WAITING. _ERROR
4071 would no longer be on the queue. */
4072 code = cm_RetryLock( wl->lockp,
4073 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4076 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4077 } else if (code != CM_ERROR_WOULDBLOCK) {
4078 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4083 if (code == CM_ERROR_WOULDBLOCK) {
4086 if (wlRequest->msTimeout != 0xffffffff
4087 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4099 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4102 scp = wlRequest->scp;
4103 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4107 lock_ObtainWrite(&scp->rw);
4109 for (wl = wlRequest->locks; wl; wl = wlNext) {
4110 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4112 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4113 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4114 wl->LLength, wl->key, 0, NULL, &req);
4116 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4121 lock_ReleaseWrite(&scp->rw);
4125 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4128 for (wl = wlRequest->locks; wl; wl = wlNext) {
4129 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4130 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4135 vcp = wlRequest->vcp;
4136 inp = wlRequest->inp;
4137 outp = wlRequest->outp;
4138 ncbp = smb_GetNCB();
4139 ncbp->ncb_length = inp->ncb_length;
4140 inp->spacep = cm_GetSpace();
4142 /* Remove waitingLock from list */
4143 lock_ObtainWrite(&smb_globalLock);
4144 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4146 lock_ReleaseWrite(&smb_globalLock);
4148 /* Resume packet processing */
4150 smb_SetSMBDataLength(outp, 0);
4151 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4152 outp->resumeCode = code;
4154 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4157 cm_FreeSpace(inp->spacep);
4158 smb_FreePacket(inp);
4159 smb_FreePacket(outp);
4161 cm_ReleaseSCache(wlRequest->scp);
4164 } while (nwlRequest && smbShutdownFlag == 0);
4169 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4171 osi_Log0(smb_logp, "SMB receive get disk attributes");
4173 smb_SetSMBParm(outp, 0, 32000);
4174 smb_SetSMBParm(outp, 1, 64);
4175 smb_SetSMBParm(outp, 2, 1024);
4176 smb_SetSMBParm(outp, 3, 30000);
4177 smb_SetSMBParm(outp, 4, 0);
4178 smb_SetSMBDataLength(outp, 0);
4182 /* SMB_COM_TREE_CONNECT */
4183 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4187 unsigned short newTid;
4188 clientchar_t shareName[AFSPATHMAX];
4189 clientchar_t *sharePath;
4192 clientchar_t *pathp;
4195 osi_Log0(smb_logp, "SMB receive tree connect");
4197 /* parse input parameters */
4200 tbp = smb_GetSMBData(inp, NULL);
4201 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4203 return CM_ERROR_BADSMB;
4205 tp = cm_ClientStrRChr(pathp, '\\');
4207 return CM_ERROR_BADSMB;
4208 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4210 lock_ObtainMutex(&vcp->mx);
4211 newTid = vcp->tidCounter++;
4212 lock_ReleaseMutex(&vcp->mx);
4214 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4215 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4217 return CM_ERROR_BADSMB;
4218 userp = smb_GetUserFromUID(uidp);
4219 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4220 smb_ReleaseUID(uidp);
4222 smb_ReleaseTID(tidp, FALSE);
4223 return CM_ERROR_BADSHARENAME;
4225 lock_ObtainMutex(&tidp->mx);
4226 tidp->userp = userp;
4227 tidp->pathname = sharePath;
4228 lock_ReleaseMutex(&tidp->mx);
4229 smb_ReleaseTID(tidp, FALSE);
4231 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4232 smb_SetSMBParm(rsp, 1, newTid);
4233 smb_SetSMBDataLength(rsp, 0);
4235 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4239 /* set maskp to the mask part of the incoming path.
4240 * Mask is 11 bytes long (8.3 with the dot elided).
4241 * Returns true if succeeds with a valid name, otherwise it does
4242 * its best, but returns false.
4244 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4252 /* starts off valid */
4255 /* mask starts out all blanks */
4256 memset(maskp, ' ', 11);
4259 /* find last backslash, or use whole thing if there is none */
4260 tp = cm_ClientStrRChr(pathp, '\\');
4264 tp++; /* skip slash */
4268 /* names starting with a dot are illegal */
4276 if (tc == '.' || tc == '"')
4284 /* if we get here, tp point after the dot */
4285 up = maskp+8; /* ext goes here */
4292 if (tc == '.' || tc == '"')
4295 /* copy extension if not too long */
4305 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4307 clientchar_t umask[11];
4315 /* XXX redo this, calling cm_MatchMask with a converted mask */
4317 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4321 /* otherwise, we have a valid 8.3 name; see if we have a match,
4322 * treating '?' as a wildcard in maskp (but not in the file name).
4324 tp1 = umask; /* real name, in mask format */
4325 tp2 = maskp; /* mask, in mask format */
4326 for(i=0; i<11; i++) {
4327 tc1 = *tp1++; /* clientchar_t from real name */
4328 tc2 = *tp2++; /* clientchar_t from mask */
4329 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4330 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4333 if (tc2 == '?' && tc1 != ' ')
4340 /* we got a match */
4344 clientchar_t *smb_FindMask(clientchar_t *pathp)
4348 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4351 return tp+1; /* skip the slash */
4353 return pathp; /* no slash, return the entire path */
4356 /* SMB_COM_SEARCH for a volume label
4358 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4359 dispatch function.) */
4360 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4362 clientchar_t *pathp;
4364 clientchar_t mask[12];
4365 unsigned char *statBlockp;
4366 unsigned char initStatBlock[21];
4369 osi_Log0(smb_logp, "SMB receive search volume");
4371 /* pull pathname and stat block out of request */
4372 tp = smb_GetSMBData(inp, NULL);
4373 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4374 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4376 return CM_ERROR_BADSMB;
4377 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4378 osi_assertx(statBlockp != NULL, "null statBlock");
4380 statBlockp = initStatBlock;
4384 /* for returning to caller */
4385 smb_Get8Dot3MaskFromPath(mask, pathp);
4387 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4388 tp = smb_GetSMBData(outp, NULL);
4390 *tp++ = 43; /* bytes in a dir entry */
4391 *tp++ = 0; /* high byte in counter */
4393 /* now marshall the dir entry, starting with the search status */
4394 *tp++ = statBlockp[0]; /* Reserved */
4395 memcpy(tp, mask, 11); tp += 11; /* FileName */
4397 /* now pass back server use info, with 1st byte non-zero */
4399 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4401 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4403 *tp++ = 0x8; /* attribute: volume */
4413 /* 4 byte file size */
4419 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4422 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4423 memset(tp, ' ', 13);
4426 /* set the length of the data part of the packet to 43 + 3, for the dir
4427 * entry plus the 5 and the length fields.
4429 smb_SetSMBDataLength(outp, 46);
4434 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4435 clientchar_t * tidPathp, clientchar_t * relPathp,
4436 cm_user_t *userp, cm_req_t *reqp)
4444 smb_dirListPatch_t *patchp;
4445 smb_dirListPatch_t *npatchp;
4446 clientchar_t path[AFSPATHMAX];
4448 afs_int32 mustFake = 0;
4450 code = cm_FindACLCache(dscp, userp, &rights);
4452 lock_ObtainWrite(&dscp->rw);
4453 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4454 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4455 lock_ReleaseWrite(&dscp->rw);
4456 if (code == CM_ERROR_NOACCESS) {
4464 if (!mustFake) { /* Bulk Stat */
4466 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4468 memset(bsp, 0, sizeof(cm_bulkStat_t));
4470 for (patchp = *dirPatchespp, count=0;
4472 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4473 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4477 if (lock_TryWrite(&tscp->rw)) {
4478 /* we have an entry that we can look at */
4479 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4480 /* we have a callback on it. Don't bother
4481 * fetching this stat entry, since we're happy
4482 * with the info we have.
4484 lock_ReleaseWrite(&tscp->rw);
4485 cm_ReleaseSCache(tscp);
4488 lock_ReleaseWrite(&tscp->rw);
4490 cm_ReleaseSCache(tscp);
4494 bsp->fids[i].Volume = patchp->fid.volume;
4495 bsp->fids[i].Vnode = patchp->fid.vnode;
4496 bsp->fids[i].Unique = patchp->fid.unique;
4498 if (bsp->counter == AFSCBMAX) {
4499 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4500 memset(bsp, 0, sizeof(cm_bulkStat_t));
4504 if (bsp->counter > 0)
4505 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4510 for (patchp = *dirPatchespp; patchp; patchp =
4511 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4513 dptr = patchp->dptr;
4515 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4516 relPathp ? relPathp : _C(""), patchp->dep->name);
4517 reqp->relPathp = path;
4518 reqp->tidPathp = tidPathp;
4520 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4521 reqp->relPathp = reqp->tidPathp = NULL;
4524 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4525 *dptr++ = SMB_ATTR_HIDDEN;
4528 lock_ObtainWrite(&scp->rw);
4529 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4530 lock_ReleaseWrite(&scp->rw);
4532 /* set the attribute */
4533 switch (scp->fileType) {
4534 case CM_SCACHETYPE_DIRECTORY:
4535 case CM_SCACHETYPE_MOUNTPOINT:
4536 case CM_SCACHETYPE_INVALID:
4537 attr = SMB_ATTR_DIRECTORY;
4539 case CM_SCACHETYPE_SYMLINK:
4540 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4541 attr = SMB_ATTR_DIRECTORY;
4543 attr = SMB_ATTR_NORMAL;
4546 /* if we get here we either have a normal file
4547 * or we have a file for which we have never
4548 * received status info. In this case, we can
4549 * check the even/odd value of the entry's vnode.
4550 * odd means it is to be treated as a directory
4551 * and even means it is to be treated as a file.
4553 if (mustFake && (scp->fid.vnode & 0x1))
4554 attr = SMB_ATTR_DIRECTORY;
4556 attr = SMB_ATTR_NORMAL;
4560 /* 1969-12-31 23:59:58 +00*/
4561 dosTime = 0xEBBFBF7D;
4564 shortTemp = (unsigned short) (dosTime & 0xffff);
4565 *((u_short *)dptr) = shortTemp;
4568 /* and copy out date */
4569 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4570 *((u_short *)dptr) = shortTemp;
4573 /* copy out file length */
4574 *((u_long *)dptr) = 0;
4577 lock_ConvertWToR(&scp->rw);
4578 attr = smb_Attributes(scp);
4579 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4580 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4581 attr |= SMB_ATTR_HIDDEN;
4585 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4588 shortTemp = (unsigned short) (dosTime & 0xffff);
4589 *((u_short *)dptr) = shortTemp;
4592 /* and copy out date */
4593 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4594 *((u_short *)dptr) = shortTemp;
4597 /* copy out file length */
4598 *((u_long *)dptr) = scp->length.LowPart;
4600 lock_ReleaseRead(&scp->rw);
4602 cm_ReleaseSCache(scp);
4605 /* now free the patches */
4606 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4607 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4611 /* and mark the list as empty */
4612 *dirPatchespp = NULL;
4618 /* SMB_COM_SEARCH */
4619 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4625 clientchar_t *pathp;
4626 cm_dirEntry_t *dep = 0;
4628 smb_dirListPatch_t *dirListPatchesp;
4629 smb_dirListPatch_t *curPatchp;
4633 osi_hyper_t dirLength;
4634 osi_hyper_t bufferOffset;
4635 osi_hyper_t curOffset;
4637 unsigned char *inCookiep;
4638 smb_dirSearch_t *dsp;
4642 unsigned long clientCookie;
4643 cm_pageHeader_t *pageHeaderp;
4644 cm_user_t *userp = NULL;
4646 clientchar_t mask[12];
4648 long nextEntryCookie;
4649 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4650 char resByte; /* reserved byte from the cookie */
4651 char *op; /* output data ptr */
4652 char *origOp; /* original value of op */
4653 cm_space_t *spacep; /* for pathname buffer */
4657 clientchar_t *tidPathp = 0;
4664 maxCount = smb_GetSMBParm(inp, 0);
4666 dirListPatchesp = NULL;
4668 caseFold = CM_FLAG_CASEFOLD;
4670 tp = smb_GetSMBData(inp, NULL);
4671 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4672 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4674 return CM_ERROR_BADSMB;
4676 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4678 return CM_ERROR_BADSMB;
4680 /* We can handle long names */
4681 if (vcp->flags & SMB_VCFLAG_USENT)
4682 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4684 /* make sure we got a whole search status */
4685 if (dataLength < 21) {
4686 nextCookie = 0; /* start at the beginning of the dir */
4689 attribute = smb_GetSMBParm(inp, 1);
4691 /* handle volume info in another function */
4692 if (attribute & 0x8)
4693 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4695 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4696 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4698 if (*pathp == 0) { /* null pathp, treat as root dir */
4699 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4700 return CM_ERROR_NOFILES;
4704 dsp = smb_NewDirSearch(0);
4705 dsp->attribute = attribute;
4706 smb_Get8Dot3MaskFromPath(mask, pathp);
4707 memcpy(dsp->mask, mask, 12);
4709 /* track if this is likely to match a lot of entries */
4710 if (smb_Is8Dot3StarMask(mask))
4715 /* pull the next cookie value out of the search status block */
4716 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4717 + (inCookiep[16]<<24);
4718 dsp = smb_FindDirSearch(inCookiep[12]);
4720 /* can't find dir search status; fatal error */
4721 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4722 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4723 return CM_ERROR_BADFD;
4725 attribute = dsp->attribute;
4726 resByte = inCookiep[0];
4728 /* copy out client cookie, in host byte order. Don't bother
4729 * interpreting it, since we're just passing it through, anyway.
4731 memcpy(&clientCookie, &inCookiep[17], 4);
4733 memcpy(mask, dsp->mask, 12);
4735 /* assume we're doing a star match if it has continued for more
4741 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4742 nextCookie, dsp->cookie, attribute);
4744 userp = smb_GetUserFromVCP(vcp, inp);
4746 /* try to get the vnode for the path name next */
4747 lock_ObtainMutex(&dsp->mx);
4750 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4754 spacep = inp->spacep;
4755 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4756 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4758 lock_ReleaseMutex(&dsp->mx);
4759 cm_ReleaseUser(userp);
4760 smb_DeleteDirSearch(dsp);
4761 smb_ReleaseDirSearch(dsp);
4762 return CM_ERROR_NOFILES;
4764 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4765 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4767 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4768 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4771 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4774 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4775 cm_ReleaseSCache(scp);
4776 lock_ReleaseMutex(&dsp->mx);
4777 cm_ReleaseUser(userp);
4778 smb_DeleteDirSearch(dsp);
4779 smb_ReleaseDirSearch(dsp);
4780 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4781 return CM_ERROR_PATH_NOT_COVERED;
4783 return CM_ERROR_NOSUCHPATH;
4785 #endif /* DFS_SUPPORT */
4788 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4789 /* we need one hold for the entry we just stored into,
4790 * and one for our own processing. When we're done with this
4791 * function, we'll drop the one for our own processing.
4792 * We held it once from the namei call, and so we do another hold
4796 lock_ObtainWrite(&scp->rw);
4797 dsp->flags |= SMB_DIRSEARCH_BULKST;
4798 lock_ReleaseWrite(&scp->rw);
4801 lock_ReleaseMutex(&dsp->mx);
4803 cm_ReleaseUser(userp);
4804 smb_DeleteDirSearch(dsp);
4805 smb_ReleaseDirSearch(dsp);
4809 /* reserves space for parameter; we'll adjust it again later to the
4810 * real count of the # of entries we returned once we've actually
4811 * assembled the directory listing.
4813 smb_SetSMBParm(outp, 0, 0);
4815 /* get the directory size */
4816 lock_ObtainWrite(&scp->rw);
4817 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4818 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4820 lock_ReleaseWrite(&scp->rw);
4821 cm_ReleaseSCache(scp);
4822 cm_ReleaseUser(userp);
4823 smb_DeleteDirSearch(dsp);
4824 smb_ReleaseDirSearch(dsp);
4828 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4830 dirLength = scp->length;
4832 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4833 curOffset.HighPart = 0;
4834 curOffset.LowPart = nextCookie;
4835 origOp = op = smb_GetSMBData(outp, NULL);
4836 /* and write out the basic header */
4837 *op++ = 5; /* variable block */
4838 op += 2; /* skip vbl block length; we'll fill it in later */
4842 clientchar_t *actualName = NULL;
4843 int free_actualName = 0;
4844 clientchar_t shortName[13];
4845 clientchar_t *shortNameEnd;
4847 /* make sure that curOffset.LowPart doesn't point to the first
4848 * 32 bytes in the 2nd through last dir page, and that it doesn't
4849 * point at the first 13 32-byte chunks in the first dir page,
4850 * since those are dir and page headers, and don't contain useful
4853 temp = curOffset.LowPart & (2048-1);
4854 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4855 /* we're in the first page */
4856 if (temp < 13*32) temp = 13*32;
4859 /* we're in a later dir page */
4860 if (temp < 32) temp = 32;
4863 /* make sure the low order 5 bits are zero */
4866 /* now put temp bits back ito curOffset.LowPart */
4867 curOffset.LowPart &= ~(2048-1);
4868 curOffset.LowPart |= temp;
4870 /* check if we've returned all the names that will fit in the
4873 if (returnedNames >= maxCount) {
4874 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4875 returnedNames, maxCount);
4879 /* check if we've passed the dir's EOF */
4880 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4882 /* see if we can use the bufferp we have now; compute in which page
4883 * the current offset would be, and check whether that's the offset
4884 * of the buffer we have. If not, get the buffer.
4886 thyper.HighPart = curOffset.HighPart;
4887 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4888 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4891 buf_Release(bufferp);
4894 lock_ReleaseWrite(&scp->rw);
4895 code = buf_Get(scp, &thyper, &bufferp);
4896 lock_ObtainMutex(&dsp->mx);
4898 /* now, if we're doing a star match, do bulk fetching of all of
4899 * the status info for files in the dir.
4902 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4904 lock_ObtainWrite(&scp->rw);
4905 lock_ReleaseMutex(&dsp->mx);
4907 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4911 bufferOffset = thyper;
4913 /* now get the data in the cache */
4915 code = cm_SyncOp(scp, bufferp, userp, &req,
4917 CM_SCACHESYNC_NEEDCALLBACK |
4918 CM_SCACHESYNC_READ);
4920 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4924 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4926 if (cm_HaveBuffer(scp, bufferp, 0)) {
4927 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4931 /* otherwise, load the buffer and try again */
4932 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4934 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4935 scp, bufferp, code);
4940 buf_Release(bufferp);
4944 } /* if (wrong buffer) ... */
4946 /* now we have the buffer containing the entry we're interested in; copy
4947 * it out if it represents a non-deleted entry.
4949 entryInDir = curOffset.LowPart & (2048-1);
4950 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4952 /* page header will help tell us which entries are free. Page header
4953 * can change more often than once per buffer, since AFS 3 dir page size
4954 * may be less than (but not more than a buffer package buffer.
4956 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4957 temp &= ~(2048 - 1); /* turn off intra-page bits */
4958 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4960 /* now determine which entry we're looking at in the page. If it is
4961 * free (there's a free bitmap at the start of the dir), we should
4962 * skip these 32 bytes.
4964 slotInPage = (entryInDir & 0x7e0) >> 5;
4965 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4966 /* this entry is free */
4967 numDirChunks = 1; /* only skip this guy */
4971 tp = bufferp->datap + entryInBuffer;
4972 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4974 /* while we're here, compute the next entry's location, too,
4975 * since we'll need it when writing out the cookie into the dir
4978 * XXXX Probably should do more sanity checking.
4980 numDirChunks = cm_NameEntries(dep->name, NULL);
4982 /* compute the offset of the cookie representing the next entry */
4983 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4985 /* Compute 8.3 name if necessary */
4986 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4987 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4990 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4991 actualName = shortName;
4992 free_actualName = 0;
4994 free_actualName = 1;
4997 if (actualName == NULL) {
4998 /* Couldn't convert the name for some reason */
4999 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5000 osi_LogSaveString(smb_logp, dep->name));
5004 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5005 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5006 osi_LogSaveClientString(smb_logp, actualName));
5008 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5009 /* this is one of the entries to use: it is not deleted
5010 * and it matches the star pattern we're looking for.
5013 /* Eliminate entries that don't match requested
5016 /* no hidden files */
5017 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5018 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5022 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5024 /* We have already done the cm_TryBulkStat above */
5025 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5026 fileType = cm_FindFileType(&fid);
5027 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5028 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5030 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5031 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5032 fileType == CM_SCACHETYPE_DFSLINK ||
5033 fileType == CM_SCACHETYPE_INVALID)
5034 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5039 memcpy(op, mask, 11); op += 11;
5040 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5041 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5042 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5043 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5044 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5045 memcpy(op, &clientCookie, 4); op += 4;
5047 /* now we emit the attribute. This is sort of tricky,
5048 * since we need to really stat the file to find out
5049 * what type of entry we've got. Right now, we're
5050 * copying out data from a buffer, while holding the
5051 * scp locked, so it isn't really convenient to stat
5052 * something now. We'll put in a place holder now,
5053 * and make a second pass before returning this to get
5054 * the real attributes. So, we just skip the data for
5055 * now, and adjust it later. We allocate a patch
5056 * record to make it easy to find this point later.
5057 * The replay will happen at a time when it is safe to
5058 * unlock the directory.
5060 curPatchp = malloc(sizeof(*curPatchp));
5061 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5062 curPatchp->dptr = op;
5063 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5065 /* do hidden attribute here since name won't be around when applying
5069 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5070 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5072 curPatchp->flags = 0;
5074 op += 9; /* skip attr, time, date and size */
5076 /* zero out name area. The spec says to pad with
5077 * spaces, but Samba doesn't, and neither do we.
5081 /* finally, we get to copy out the name; we know that
5082 * it fits in 8.3 or the pattern wouldn't match, but it
5083 * never hurts to be sure.
5085 cm_ClientStringToUtf8(actualName, -1, op, 13);
5086 if (smb_StoreAnsiFilenames)
5088 /* This is a UCHAR field, which is ASCII even if Unicode
5091 /* Uppercase if requested by client */
5092 if (!KNOWS_LONG_NAMES(inp))
5097 /* now, adjust the # of entries copied */
5099 } /* if we're including this name */
5102 if (free_actualName && actualName) {
5107 /* and adjust curOffset to be where the new cookie is */
5108 thyper.HighPart = 0;
5109 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5110 curOffset = LargeIntegerAdd(thyper, curOffset);
5111 } /* while copying data for dir listing */
5113 /* release the mutex */
5114 lock_ReleaseWrite(&scp->rw);
5116 buf_Release(bufferp);
5120 /* apply and free last set of patches; if not doing a star match, this
5121 * will be empty, but better safe (and freeing everything) than sorry.
5123 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5125 /* special return code for unsuccessful search */
5126 if (code == 0 && dataLength < 21 && returnedNames == 0)
5127 code = CM_ERROR_NOFILES;
5129 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5130 returnedNames, code);
5133 smb_DeleteDirSearch(dsp);
5134 smb_ReleaseDirSearch(dsp);
5135 cm_ReleaseSCache(scp);
5136 cm_ReleaseUser(userp);
5140 /* finalize the output buffer */
5141 smb_SetSMBParm(outp, 0, returnedNames);
5142 temp = (long) (op - origOp);
5143 smb_SetSMBDataLength(outp, temp);
5145 /* the data area is a variable block, which has a 5 (already there)
5146 * followed by the length of the # of data bytes. We now know this to
5147 * be "temp," although that includes the 3 bytes of vbl block header.
5148 * Deduct for them and fill in the length field.
5150 temp -= 3; /* deduct vbl block info */
5151 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5152 origOp[1] = (unsigned char)(temp & 0xff);
5153 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5154 if (returnedNames == 0)
5155 smb_DeleteDirSearch(dsp);
5156 smb_ReleaseDirSearch(dsp);
5157 cm_ReleaseSCache(scp);
5158 cm_ReleaseUser(userp);
5163 /* verify that this is a valid path to a directory. I don't know why they
5164 * don't use the get file attributes call.
5166 * SMB_COM_CHECK_DIRECTORY
5168 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5170 clientchar_t *pathp;
5172 cm_scache_t *rootScp;
5173 cm_scache_t *newScp;
5177 clientchar_t *tidPathp;
5183 pdata = smb_GetSMBData(inp, NULL);
5184 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5186 return CM_ERROR_BADSMB;
5187 osi_Log1(smb_logp, "SMB receive check path %S",
5188 osi_LogSaveClientString(smb_logp, pathp));
5190 rootScp = cm_data.rootSCachep;
5192 userp = smb_GetUserFromVCP(vcp, inp);
5194 caseFold = CM_FLAG_CASEFOLD;
5196 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5198 cm_ReleaseUser(userp);
5199 return CM_ERROR_NOSUCHPATH;
5201 code = cm_NameI(rootScp, pathp,
5202 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5203 userp, tidPathp, &req, &newScp);
5206 cm_ReleaseUser(userp);
5211 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5212 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5213 cm_ReleaseSCache(newScp);
5214 cm_ReleaseUser(userp);
5215 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5216 return CM_ERROR_PATH_NOT_COVERED;
5218 return CM_ERROR_NOSUCHPATH;
5220 #endif /* DFS_SUPPORT */
5222 /* now lock the vnode with a callback; returns with newScp locked */
5223 lock_ObtainWrite(&newScp->rw);
5224 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5225 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5227 if (code != CM_ERROR_NOACCESS) {
5228 lock_ReleaseWrite(&newScp->rw);
5229 cm_ReleaseSCache(newScp);
5230 cm_ReleaseUser(userp);
5234 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5237 attrs = smb_Attributes(newScp);
5239 if (!(attrs & SMB_ATTR_DIRECTORY))
5240 code = CM_ERROR_NOTDIR;
5242 lock_ReleaseWrite(&newScp->rw);
5244 cm_ReleaseSCache(newScp);
5245 cm_ReleaseUser(userp);
5249 /* SMB_COM_SET_INFORMATION */
5250 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5252 clientchar_t *pathp;
5254 cm_scache_t *rootScp;
5255 unsigned short attribute;
5257 cm_scache_t *newScp;
5261 clientchar_t *tidPathp;
5267 /* decode basic attributes we're passed */
5268 attribute = smb_GetSMBParm(inp, 0);
5269 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5271 datap = smb_GetSMBData(inp, NULL);
5272 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5274 return CM_ERROR_BADSMB;
5276 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5277 dosTime, attribute);
5279 rootScp = cm_data.rootSCachep;
5281 userp = smb_GetUserFromVCP(vcp, inp);
5283 caseFold = CM_FLAG_CASEFOLD;
5285 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5287 cm_ReleaseUser(userp);
5288 return CM_ERROR_NOSUCHFILE;
5290 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5291 tidPathp, &req, &newScp);
5294 cm_ReleaseUser(userp);
5299 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5300 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5301 cm_ReleaseSCache(newScp);
5302 cm_ReleaseUser(userp);
5303 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5304 return CM_ERROR_PATH_NOT_COVERED;
5306 return CM_ERROR_NOSUCHPATH;
5308 #endif /* DFS_SUPPORT */
5310 /* now lock the vnode with a callback; returns with newScp locked; we
5311 * need the current status to determine what the new status is, in some
5314 lock_ObtainWrite(&newScp->rw);
5315 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5316 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5318 lock_ReleaseWrite(&newScp->rw);
5319 cm_ReleaseSCache(newScp);
5320 cm_ReleaseUser(userp);
5324 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5326 /* Check for RO volume */
5327 if (newScp->flags & CM_SCACHEFLAG_RO) {
5328 lock_ReleaseWrite(&newScp->rw);
5329 cm_ReleaseSCache(newScp);
5330 cm_ReleaseUser(userp);
5331 return CM_ERROR_READONLY;
5334 /* prepare for setattr call */
5337 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5338 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5340 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5341 /* we're told to make a writable file read-only */
5342 attr.unixModeBits = newScp->unixModeBits & ~0222;
5343 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5345 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5346 /* we're told to make a read-only file writable */
5347 attr.unixModeBits = newScp->unixModeBits | 0222;
5348 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5350 lock_ReleaseWrite(&newScp->rw);
5352 /* now call setattr */
5354 code = cm_SetAttr(newScp, &attr, userp, &req);
5358 cm_ReleaseSCache(newScp);
5359 cm_ReleaseUser(userp);
5365 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5367 clientchar_t *pathp;
5369 cm_scache_t *rootScp;
5370 cm_scache_t *newScp, *dscp;
5375 clientchar_t *tidPathp;
5377 clientchar_t *lastComp;
5383 datap = smb_GetSMBData(inp, NULL);
5384 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5386 return CM_ERROR_BADSMB;
5388 if (*pathp == 0) /* null path */
5391 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5392 osi_LogSaveClientString(smb_logp, pathp));
5394 rootScp = cm_data.rootSCachep;
5396 userp = smb_GetUserFromVCP(vcp, inp);
5398 /* we shouldn't need this for V3 requests, but we seem to */
5399 caseFold = CM_FLAG_CASEFOLD;
5401 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5403 cm_ReleaseUser(userp);
5404 return CM_ERROR_NOSUCHFILE;
5408 * XXX Strange hack XXX
5410 * As of Patch 5 (16 July 97), we are having the following problem:
5411 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5412 * requests to look up "desktop.ini" in all the subdirectories.
5413 * This can cause zillions of timeouts looking up non-existent cells
5414 * and volumes, especially in the top-level directory.
5416 * We have not found any way to avoid this or work around it except
5417 * to explicitly ignore the requests for mount points that haven't
5418 * yet been evaluated and for directories that haven't yet been
5421 * We should modify this hack to provide a fake desktop.ini file
5422 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5424 spacep = inp->spacep;
5425 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5426 #ifndef SPECIAL_FOLDERS
5427 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5428 code = cm_NameI(rootScp, spacep->wdata,
5429 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5430 userp, tidPathp, &req, &dscp);
5433 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5434 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5436 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5437 return CM_ERROR_PATH_NOT_COVERED;
5439 return CM_ERROR_NOSUCHPATH;
5441 #endif /* DFS_SUPPORT */
5442 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5443 code = CM_ERROR_NOSUCHFILE;
5444 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5445 cm_buf_t *bp = buf_Find(dscp, &hzero);
5450 code = CM_ERROR_NOSUCHFILE;
5452 cm_ReleaseSCache(dscp);
5454 cm_ReleaseUser(userp);
5459 #endif /* SPECIAL_FOLDERS */
5461 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5462 tidPathp, &req, &newScp);
5464 cm_ReleaseUser(userp);
5469 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5470 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5471 cm_ReleaseSCache(newScp);
5472 cm_ReleaseUser(userp);
5473 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5474 return CM_ERROR_PATH_NOT_COVERED;
5476 return CM_ERROR_NOSUCHPATH;
5478 #endif /* DFS_SUPPORT */
5480 /* now lock the vnode with a callback; returns with newScp locked */
5481 lock_ObtainWrite(&newScp->rw);
5482 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5483 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5485 lock_ReleaseWrite(&newScp->rw);
5486 cm_ReleaseSCache(newScp);
5487 cm_ReleaseUser(userp);
5491 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5493 attrs = smb_Attributes(newScp);
5495 smb_SetSMBParm(outp, 0, attrs);
5497 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5498 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5499 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5500 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5501 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5502 smb_SetSMBParm(outp, 5, 0);
5503 smb_SetSMBParm(outp, 6, 0);
5504 smb_SetSMBParm(outp, 7, 0);
5505 smb_SetSMBParm(outp, 8, 0);
5506 smb_SetSMBParm(outp, 9, 0);
5507 smb_SetSMBDataLength(outp, 0);
5508 lock_ReleaseWrite(&newScp->rw);
5510 cm_ReleaseSCache(newScp);
5511 cm_ReleaseUser(userp);
5516 /* SMB_COM_TREE_DISCONNECT */
5517 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5521 osi_Log0(smb_logp, "SMB receive tree disconnect");
5523 /* find the tree and free it */
5524 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5526 lock_ObtainWrite(&smb_rctLock);
5528 smb_ReleaseTID(tidp, TRUE);
5529 lock_ReleaseWrite(&smb_rctLock);
5536 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5539 clientchar_t *pathp;
5540 clientchar_t *lastNamep;
5549 clientchar_t *tidPathp;
5555 datap = smb_GetSMBData(inp, NULL);
5556 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5558 return CM_ERROR_BADSMB;
5560 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5562 #ifdef DEBUG_VERBOSE
5566 hexpath = osi_HexifyString( pathp );
5567 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5572 if (!cm_IsValidClientString(pathp)) {
5574 clientchar_t * hexp;
5576 hexp = cm_GetRawCharsAlloc(pathp, -1);
5577 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5578 osi_LogSaveClientString(smb_logp, hexp));
5582 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5584 return CM_ERROR_BADNTFILENAME;
5587 share = smb_GetSMBParm(inp, 0);
5588 attribute = smb_GetSMBParm(inp, 1);
5590 spacep = inp->spacep;
5591 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5592 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5593 /* special case magic file name for receiving IOCTL requests
5594 * (since IOCTL calls themselves aren't getting through).
5596 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5597 smb_SetupIoctlFid(fidp, spacep);
5598 smb_SetSMBParm(outp, 0, fidp->fid);
5599 smb_SetSMBParm(outp, 1, 0); /* attrs */
5600 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5601 smb_SetSMBParm(outp, 3, 0);
5602 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5603 smb_SetSMBParm(outp, 5, 0x7fff);
5604 /* pass the open mode back */
5605 smb_SetSMBParm(outp, 6, (share & 0xf));
5606 smb_SetSMBDataLength(outp, 0);
5607 smb_ReleaseFID(fidp);
5611 userp = smb_GetUserFromVCP(vcp, inp);
5613 caseFold = CM_FLAG_CASEFOLD;
5615 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5617 cm_ReleaseUser(userp);
5618 return CM_ERROR_NOSUCHPATH;
5620 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5621 tidPathp, &req, &scp);
5624 cm_ReleaseUser(userp);
5629 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5630 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5631 cm_ReleaseSCache(scp);
5632 cm_ReleaseUser(userp);
5633 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5634 return CM_ERROR_PATH_NOT_COVERED;
5636 return CM_ERROR_NOSUCHPATH;
5638 #endif /* DFS_SUPPORT */
5640 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5642 cm_ReleaseSCache(scp);
5643 cm_ReleaseUser(userp);
5647 /* don't need callback to check file type, since file types never
5648 * change, and namei and cm_Lookup all stat the object at least once on
5649 * a successful return.
5651 if (scp->fileType != CM_SCACHETYPE_FILE) {
5652 cm_ReleaseSCache(scp);
5653 cm_ReleaseUser(userp);
5654 return CM_ERROR_ISDIR;
5657 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5658 osi_assertx(fidp, "null smb_fid_t");
5660 lock_ObtainMutex(&fidp->mx);
5661 if ((share & 0xf) == 0)
5662 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5663 else if ((share & 0xf) == 1)
5664 fidp->flags |= SMB_FID_OPENWRITE;
5666 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5670 fidp->userp = userp;
5672 /* and a pointer to the vnode */
5674 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5675 lock_ObtainWrite(&scp->rw);
5676 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5678 smb_SetSMBParm(outp, 0, fidp->fid);
5679 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5680 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5681 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5682 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5683 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5684 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5685 /* pass the open mode back; XXXX add access checks */
5686 smb_SetSMBParm(outp, 6, (share & 0xf));
5687 smb_SetSMBDataLength(outp, 0);
5688 lock_ReleaseMutex(&fidp->mx);
5689 lock_ReleaseRead(&scp->rw);
5692 cm_Open(scp, 0, userp);
5694 /* send and free packet */
5695 smb_ReleaseFID(fidp);
5696 cm_ReleaseUser(userp);
5697 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5701 typedef struct smb_unlinkRock {
5706 clientchar_t *maskp; /* pointer to the star pattern */
5709 cm_dirEntryList_t * matches;
5712 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5715 smb_unlinkRock_t *rockp;
5718 normchar_t matchName[MAX_PATH];
5722 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5723 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5724 caseFold |= CM_FLAG_8DOT3;
5726 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5727 /* Can't convert name */
5728 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5729 osi_LogSaveString(smb_logp, dep->name));
5733 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5735 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5736 !cm_Is8Dot3(matchName)) {
5737 cm_Gen8Dot3Name(dep, matchName, NULL);
5738 /* 8.3 matches are always case insensitive */
5739 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5742 osi_Log1(smb_logp, "Found match %S",
5743 osi_LogSaveClientString(smb_logp, matchName));
5745 cm_DirEntryListAdd(dep->name, &rockp->matches);
5749 /* If we made a case sensitive exact match, we might as well quit now. */
5750 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5751 code = CM_ERROR_STOPNOW;
5760 /* SMB_COM_DELETE */
5761 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5765 clientchar_t *pathp;
5769 clientchar_t *lastNamep;
5770 smb_unlinkRock_t rock;
5774 clientchar_t *tidPathp;
5778 memset(&rock, 0, sizeof(rock));
5780 attribute = smb_GetSMBParm(inp, 0);
5782 tp = smb_GetSMBData(inp, NULL);
5783 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5785 return CM_ERROR_BADSMB;
5787 osi_Log1(smb_logp, "SMB receive unlink %S",
5788 osi_LogSaveClientString(smb_logp, pathp));
5790 spacep = inp->spacep;
5791 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5793 userp = smb_GetUserFromVCP(vcp, inp);
5795 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5797 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5799 cm_ReleaseUser(userp);
5800 return CM_ERROR_NOSUCHPATH;
5802 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5805 cm_ReleaseUser(userp);
5810 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5811 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5812 cm_ReleaseSCache(dscp);
5813 cm_ReleaseUser(userp);
5814 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5815 return CM_ERROR_PATH_NOT_COVERED;
5817 return CM_ERROR_NOSUCHPATH;
5819 #endif /* DFS_SUPPORT */
5821 /* otherwise, scp points to the parent directory. */
5828 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5830 code = CM_ERROR_NOSUCHFILE;
5833 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5836 thyper.HighPart = 0;
5841 rock.matches = NULL;
5843 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5844 * match. If that fails, we do a case insensitve match.
5846 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5847 !smb_IsStarMask(rock.maskp)) {
5848 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5851 thyper.HighPart = 0;
5852 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5857 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5859 if (code == CM_ERROR_STOPNOW)
5862 if (code == 0 && rock.matches) {
5863 cm_dirEntryList_t * entry;
5865 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5866 normchar_t normalizedName[MAX_PATH];
5868 /* Note: entry->name is a non-normalized name */
5870 osi_Log1(smb_logp, "Unlinking %s",
5871 osi_LogSaveString(smb_logp, entry->name));
5873 /* We assume this works because entry->name was
5874 successfully converted in smb_UnlinkProc() once. */
5875 cm_FsStringToNormString(entry->name, -1,
5876 normalizedName, lengthof(normalizedName));
5878 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5880 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5881 smb_NotifyChange(FILE_ACTION_REMOVED,
5882 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5883 dscp, normalizedName, NULL, TRUE);
5887 cm_DirEntryListFree(&rock.matches);
5891 cm_ReleaseUser(userp);
5894 cm_ReleaseSCache(dscp);
5899 if (code == 0 && !rock.any)
5900 code = CM_ERROR_NOSUCHFILE;
5904 typedef struct smb_renameRock {
5905 cm_scache_t *odscp; /* old dir */
5906 cm_scache_t *ndscp; /* new dir */
5907 cm_user_t *userp; /* user */
5908 cm_req_t *reqp; /* request struct */
5909 smb_vc_t *vcp; /* virtual circuit */
5910 normchar_t *maskp; /* pointer to star pattern of old file name */
5911 int flags; /* tilde, casefold, etc */
5912 clientchar_t *newNamep; /* ptr to the new file's name */
5913 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5914 clientchar_t clOldName[MAX_PATH]; /* client name */
5918 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5921 smb_renameRock_t *rockp;
5924 normchar_t matchName[MAX_PATH];
5926 rockp = (smb_renameRock_t *) vrockp;
5928 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5929 /* Can't convert string */
5930 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
5931 osi_LogSaveString(smb_logp, dep->name));
5935 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5936 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5937 caseFold |= CM_FLAG_8DOT3;
5939 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5941 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5942 !cm_Is8Dot3(matchName)) {
5943 cm_Gen8Dot3Name(dep, matchName, NULL);
5944 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5949 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5950 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5952 code = CM_ERROR_STOPNOW;
5962 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5965 cm_space_t *spacep = NULL;
5966 smb_renameRock_t rock;
5967 cm_scache_t *oldDscp = NULL;
5968 cm_scache_t *newDscp = NULL;
5969 cm_scache_t *tmpscp= NULL;
5970 cm_scache_t *tmpscp2 = NULL;
5971 clientchar_t *oldLastNamep;
5972 clientchar_t *newLastNamep;
5976 clientchar_t *tidPathp;
5980 userp = smb_GetUserFromVCP(vcp, inp);
5981 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5983 cm_ReleaseUser(userp);
5984 return CM_ERROR_NOSUCHPATH;
5988 memset(&rock, 0, sizeof(rock));
5990 spacep = inp->spacep;
5991 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5993 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
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_NOSUCHPATH;
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);
6018 cm_ReleaseSCache(oldDscp);
6019 cm_ReleaseUser(userp);
6024 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6025 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6026 cm_ReleaseSCache(oldDscp);
6027 cm_ReleaseSCache(newDscp);
6028 cm_ReleaseUser(userp);
6029 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6030 return CM_ERROR_PATH_NOT_COVERED;
6032 return CM_ERROR_NOSUCHPATH;
6034 #endif /* DFS_SUPPORT */
6037 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6038 * next, get the component names, and lower case them.
6041 /* handle the old name first */
6043 oldLastNamep = oldPathp;
6047 /* and handle the new name, too */
6049 newLastNamep = newPathp;
6053 /* TODO: The old name could be a wildcard. The new name must not be */
6055 /* Check if the file already exists; if so return error */
6056 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6057 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6058 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6060 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6061 osi_LogSaveClientString(smb_logp, newLastNamep));
6063 /* Check if the old and the new names differ only in case. If so return
6064 * success, else return CM_ERROR_EXISTS
6066 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6068 /* This would be a success only if the old file is *as same as* the new file */
6069 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6071 if (tmpscp == tmpscp2)
6074 code = CM_ERROR_EXISTS;
6075 cm_ReleaseSCache(tmpscp2);
6078 code = CM_ERROR_NOSUCHFILE;
6081 /* file exist, do not rename, also fixes move */
6082 osi_Log0(smb_logp, "Can't rename. Target already exists");
6083 code = CM_ERROR_EXISTS;
6088 /* do the vnode call */
6089 rock.odscp = oldDscp;
6090 rock.ndscp = newDscp;
6094 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6096 code = CM_ERROR_NOSUCHFILE;
6099 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6100 rock.newNamep = newLastNamep;
6101 rock.fsOldName[0] = '\0';
6102 rock.clOldName[0] = '\0';
6105 /* Now search the directory for the pattern, and do the appropriate rename when found */
6106 thyper.LowPart = 0; /* search dir from here */
6107 thyper.HighPart = 0;
6109 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6110 if (code == 0 && !rock.any) {
6112 thyper.HighPart = 0;
6113 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6114 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6116 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6118 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6119 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6120 rock.ndscp, rock.newNamep, rock.userp,
6122 /* if the call worked, stop doing the search now, since we
6123 * really only want to rename one file.
6126 osi_Log0(smb_logp, "cm_Rename failure");
6127 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6128 } else if (code == 0) {
6129 code = CM_ERROR_NOSUCHFILE;
6132 /* Handle Change Notification */
6134 * Being lazy, not distinguishing between files and dirs in this
6135 * filter, since we'd have to do a lookup.
6138 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6139 if (oldDscp == newDscp) {
6140 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6141 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6142 filter, oldDscp, rock.clOldName,
6143 newLastNamep, TRUE);
6145 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6146 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6147 filter, oldDscp, rock.clOldName,
6149 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6150 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6151 filter, newDscp, newLastNamep,
6158 cm_ReleaseSCache(tmpscp);
6160 cm_ReleaseUser(userp);
6162 cm_ReleaseSCache(oldDscp);
6164 cm_ReleaseSCache(newDscp);
6172 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6175 cm_space_t *spacep = NULL;
6176 cm_scache_t *oldDscp = NULL;
6177 cm_scache_t *newDscp = NULL;
6178 cm_scache_t *tmpscp= NULL;
6179 cm_scache_t *tmpscp2 = NULL;
6180 cm_scache_t *sscp = NULL;
6181 clientchar_t *oldLastNamep;
6182 clientchar_t *newLastNamep;
6185 clientchar_t *tidPathp;
6189 userp = smb_GetUserFromVCP(vcp, inp);
6191 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6193 cm_ReleaseUser(userp);
6194 return CM_ERROR_NOSUCHPATH;
6199 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6201 spacep = inp->spacep;
6202 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6204 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6205 userp, tidPathp, &req, &oldDscp);
6207 cm_ReleaseUser(userp);
6212 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6213 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6214 cm_ReleaseSCache(oldDscp);
6215 cm_ReleaseUser(userp);
6216 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6217 return CM_ERROR_PATH_NOT_COVERED;
6219 return CM_ERROR_NOSUCHPATH;
6221 #endif /* DFS_SUPPORT */
6223 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6224 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6225 userp, tidPathp, &req, &newDscp);
6227 cm_ReleaseSCache(oldDscp);
6228 cm_ReleaseUser(userp);
6233 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6234 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6235 cm_ReleaseSCache(newDscp);
6236 cm_ReleaseSCache(oldDscp);
6237 cm_ReleaseUser(userp);
6238 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6239 return CM_ERROR_PATH_NOT_COVERED;
6241 return CM_ERROR_NOSUCHPATH;
6243 #endif /* DFS_SUPPORT */
6245 /* Now, although we did two lookups for the two directories (because the same
6246 * directory can be referenced through different paths), we only allow hard links
6247 * within the same directory. */
6248 if (oldDscp != newDscp) {
6249 cm_ReleaseSCache(oldDscp);
6250 cm_ReleaseSCache(newDscp);
6251 cm_ReleaseUser(userp);
6252 return CM_ERROR_CROSSDEVLINK;
6255 /* handle the old name first */
6257 oldLastNamep = oldPathp;
6261 /* and handle the new name, too */
6263 newLastNamep = newPathp;
6267 /* now lookup the old name */
6268 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6269 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6271 cm_ReleaseSCache(oldDscp);
6272 cm_ReleaseSCache(newDscp);
6273 cm_ReleaseUser(userp);
6277 /* Check if the file already exists; if so return error */
6278 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6279 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6280 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6282 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6283 osi_LogSaveClientString(smb_logp, newLastNamep));
6285 /* if the existing link is to the same file, then we return success */
6287 if(sscp == tmpscp) {
6290 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6291 code = CM_ERROR_EXISTS;
6296 cm_ReleaseSCache(tmpscp);
6297 cm_ReleaseSCache(sscp);
6298 cm_ReleaseSCache(newDscp);
6299 cm_ReleaseSCache(oldDscp);
6300 cm_ReleaseUser(userp);
6304 /* now create the hardlink */
6305 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6306 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6307 osi_Log1(smb_logp," Link returns 0x%x", code);
6309 /* Handle Change Notification */
6311 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6312 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6313 smb_NotifyChange(FILE_ACTION_ADDED,
6314 filter, newDscp, newLastNamep,
6319 cm_ReleaseSCache(tmpscp);
6320 cm_ReleaseUser(userp);
6321 cm_ReleaseSCache(sscp);
6322 cm_ReleaseSCache(oldDscp);
6323 cm_ReleaseSCache(newDscp);
6327 /* SMB_COM_RENAME */
6329 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6331 clientchar_t *oldPathp;
6332 clientchar_t *newPathp;
6336 tp = smb_GetSMBData(inp, NULL);
6337 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6339 return CM_ERROR_BADSMB;
6340 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6342 return CM_ERROR_BADSMB;
6344 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6345 osi_LogSaveClientString(smb_logp, oldPathp),
6346 osi_LogSaveClientString(smb_logp, newPathp));
6348 if (!cm_IsValidClientString(newPathp)) {
6350 clientchar_t * hexp;
6352 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6353 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6354 osi_LogSaveClientString(smb_logp, hexp));
6358 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6360 return CM_ERROR_BADNTFILENAME;
6363 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6365 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6371 typedef struct smb_rmdirRock {
6375 normchar_t *maskp; /* pointer to the star pattern */
6378 cm_dirEntryList_t * matches;
6381 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6384 smb_rmdirRock_t *rockp;
6386 normchar_t matchName[MAX_PATH];
6388 rockp = (smb_rmdirRock_t *) vrockp;
6390 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6391 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6392 osi_LogSaveString(smb_logp, dep->name));
6396 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6397 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6399 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6401 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6402 !cm_Is8Dot3(matchName)) {
6403 cm_Gen8Dot3Name(dep, matchName, NULL);
6404 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6409 cm_DirEntryListAdd(dep->name, &rockp->matches);
6416 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6419 clientchar_t *pathp;
6423 clientchar_t *lastNamep;
6424 smb_rmdirRock_t rock;
6428 clientchar_t *tidPathp;
6432 memset(&rock, 0, sizeof(rock));
6434 tp = smb_GetSMBData(inp, NULL);
6435 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6437 return CM_ERROR_BADSMB;
6439 spacep = inp->spacep;
6440 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6442 userp = smb_GetUserFromVCP(vcp, inp);
6444 caseFold = CM_FLAG_CASEFOLD;
6446 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6448 cm_ReleaseUser(userp);
6449 return CM_ERROR_NOSUCHPATH;
6451 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6452 userp, tidPathp, &req, &dscp);
6455 cm_ReleaseUser(userp);
6460 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6461 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6462 cm_ReleaseSCache(dscp);
6463 cm_ReleaseUser(userp);
6464 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6465 return CM_ERROR_PATH_NOT_COVERED;
6467 return CM_ERROR_NOSUCHPATH;
6469 #endif /* DFS_SUPPORT */
6471 /* otherwise, scp points to the parent directory. */
6478 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6480 code = CM_ERROR_NOSUCHFILE;
6483 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6486 thyper.HighPart = 0;
6490 rock.matches = NULL;
6492 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6493 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6494 if (code == 0 && !rock.any) {
6496 thyper.HighPart = 0;
6497 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6498 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6501 if (code == 0 && rock.matches) {
6502 cm_dirEntryList_t * entry;
6504 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6505 clientchar_t clientName[MAX_PATH];
6507 /* We assume this will succeed because smb_RmdirProc()
6508 successfully converted entry->name once above. */
6509 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6511 osi_Log1(smb_logp, "Removing directory %s",
6512 osi_LogSaveString(smb_logp, entry->name));
6514 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6516 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6517 smb_NotifyChange(FILE_ACTION_REMOVED,
6518 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6519 dscp, clientName, NULL, TRUE);
6525 cm_DirEntryListFree(&rock.matches);
6528 cm_ReleaseUser(userp);
6531 cm_ReleaseSCache(dscp);
6533 if (code == 0 && !rock.any)
6534 code = CM_ERROR_NOSUCHFILE;
6543 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6553 fid = smb_GetSMBParm(inp, 0);
6555 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6557 fid = smb_ChainFID(fid, inp);
6558 fidp = smb_FindFID(vcp, fid, 0);
6560 return CM_ERROR_BADFD;
6562 userp = smb_GetUserFromVCP(vcp, inp);
6564 lock_ObtainMutex(&fidp->mx);
6565 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6566 cm_ReleaseUser(userp);
6567 lock_ReleaseMutex(&fidp->mx);
6568 smb_ReleaseFID(fidp);
6569 return CM_ERROR_BADFD;
6572 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6573 lock_ReleaseMutex(&fidp->mx);
6574 cm_ReleaseUser(userp);
6575 smb_CloseFID(vcp, fidp, NULL, 0);
6576 smb_ReleaseFID(fidp);
6577 return CM_ERROR_NOSUCHFILE;
6580 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6581 cm_scache_t * scp = fidp->scp;
6583 lock_ReleaseMutex(&fidp->mx);
6584 code = cm_FSync(scp, userp, &req);
6585 cm_ReleaseSCache(scp);
6587 lock_ReleaseMutex(&fidp->mx);
6591 cm_ReleaseUser(userp);
6592 smb_ReleaseFID(fidp);
6596 struct smb_FullNameRock {
6599 clientchar_t *fullName;
6600 fschar_t *originalName;
6603 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6606 normchar_t matchName[MAX_PATH];
6607 struct smb_FullNameRock *vrockp;
6609 vrockp = (struct smb_FullNameRock *)rockp;
6611 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6612 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6613 osi_LogSaveString(smb_logp, dep->name));
6617 if (!cm_Is8Dot3(matchName)) {
6618 clientchar_t shortName[13];
6620 cm_Gen8Dot3Name(dep, shortName, NULL);
6622 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6623 vrockp->fullName = cm_ClientStrDup(matchName);
6624 vrockp->originalName = cm_FsStrDup(dep->name);
6625 return CM_ERROR_STOPNOW;
6628 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6629 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6630 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6631 vrockp->fullName = cm_ClientStrDup(matchName);
6632 vrockp->originalName = cm_FsStrDup(dep->name);
6633 return CM_ERROR_STOPNOW;
6638 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6639 clientchar_t **newPathp, fschar_t ** originalPathp,
6640 cm_user_t *userp, cm_req_t *reqp)
6642 struct smb_FullNameRock rock;
6645 memset(&rock, 0, sizeof(rock));
6649 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6650 if (code == CM_ERROR_STOPNOW) {
6651 *newPathp = rock.fullName;
6652 *originalPathp = rock.originalName;
6654 *newPathp = cm_ClientStrDup(pathp);
6655 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6659 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6660 afs_uint32 dosTime) {
6663 cm_scache_t *dscp = NULL;
6664 clientchar_t *pathp = NULL;
6665 cm_scache_t * scp = NULL;
6666 cm_scache_t *delscp = NULL;
6667 int nullcreator = 0;
6669 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6670 fidp, fidp->fid, scp, vcp);
6673 lock_ObtainMutex(&fidp->mx);
6674 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6675 lock_ReleaseMutex(&fidp->mx);
6676 osi_Log0(smb_logp, " No user specified. Not closing fid");
6677 return CM_ERROR_BADFD;
6680 userp = fidp->userp; /* no hold required since fidp is held
6681 throughout the function */
6682 lock_ReleaseMutex(&fidp->mx);
6687 lock_ObtainWrite(&smb_rctLock);
6688 if (fidp->deleteOk) {
6689 osi_Log0(smb_logp, " Fid already closed.");
6690 lock_ReleaseWrite(&smb_rctLock);
6691 return CM_ERROR_BADFD;
6694 lock_ReleaseWrite(&smb_rctLock);
6696 lock_ObtainMutex(&fidp->mx);
6697 if (fidp->NTopen_dscp) {
6698 dscp = fidp->NTopen_dscp;
6699 cm_HoldSCache(dscp);
6702 if (fidp->NTopen_pathp)
6703 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6710 /* Don't jump the gun on an async raw write */
6711 while (fidp->raw_writers) {
6712 lock_ReleaseMutex(&fidp->mx);
6713 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6714 lock_ObtainMutex(&fidp->mx);
6717 /* watch for ioctl closes, and read-only opens */
6719 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6720 == SMB_FID_OPENWRITE) {
6721 if (dosTime != 0 && dosTime != -1) {
6722 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6723 /* This fixes defect 10958 */
6724 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6725 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6727 if (smb_AsyncStore != 2) {
6728 lock_ReleaseMutex(&fidp->mx);
6729 code = cm_FSync(scp, userp, &req);
6730 lock_ObtainMutex(&fidp->mx);
6736 /* unlock any pending locks */
6737 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6738 scp->fileType == CM_SCACHETYPE_FILE) {
6742 lock_ReleaseMutex(&fidp->mx);
6744 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6746 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6747 lock_ObtainWrite(&scp->rw);
6749 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6750 CM_SCACHESYNC_NEEDCALLBACK
6751 | CM_SCACHESYNC_GETSTATUS
6752 | CM_SCACHESYNC_LOCK);
6756 "smb CoreClose SyncOp failure code 0x%x", tcode);
6757 goto post_syncopdone;
6760 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6762 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6766 lock_ReleaseWrite(&scp->rw);
6767 lock_ObtainMutex(&fidp->mx);
6770 if (fidp->flags & SMB_FID_DELONCLOSE) {
6771 clientchar_t *fullPathp = NULL;
6772 fschar_t *originalNamep = NULL;
6774 lock_ReleaseMutex(&fidp->mx);
6776 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6781 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6782 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6783 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6785 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6786 smb_NotifyChange(FILE_ACTION_REMOVED,
6787 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6788 dscp, fullPathp, NULL, TRUE);
6791 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6793 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6794 smb_NotifyChange(FILE_ACTION_REMOVED,
6795 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6796 dscp, fullPathp, NULL, TRUE);
6803 free(originalNamep);
6805 lock_ObtainMutex(&fidp->mx);
6806 fidp->flags &= ~SMB_FID_DELONCLOSE;
6809 /* if this was a newly created file, then clear the creator
6810 * in the stat cache entry. */
6811 if (fidp->flags & SMB_FID_CREATED) {
6813 fidp->flags &= ~SMB_FID_CREATED;
6816 if (fidp->flags & SMB_FID_NTOPEN) {
6817 cm_ReleaseSCache(fidp->NTopen_dscp);
6818 fidp->NTopen_dscp = NULL;
6819 free(fidp->NTopen_pathp);
6820 fidp->NTopen_pathp = NULL;
6821 fidp->flags &= ~SMB_FID_NTOPEN;
6823 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6824 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6827 if (fidp->NTopen_wholepathp) {
6828 free(fidp->NTopen_wholepathp);
6829 fidp->NTopen_wholepathp = NULL;
6833 cm_ReleaseSCache(fidp->scp);
6836 lock_ReleaseMutex(&fidp->mx);
6839 cm_ReleaseSCache(dscp);
6842 cm_ReleaseSCache(delscp);
6846 lock_ObtainWrite(&scp->rw);
6847 if (nullcreator && scp->creator == userp)
6848 scp->creator = NULL;
6849 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6850 lock_ReleaseWrite(&scp->rw);
6851 cm_ReleaseSCache(scp);
6861 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6869 fid = smb_GetSMBParm(inp, 0);
6870 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6872 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6874 fid = smb_ChainFID(fid, inp);
6875 fidp = smb_FindFID(vcp, fid, 0);
6877 return CM_ERROR_BADFD;
6880 userp = smb_GetUserFromVCP(vcp, inp);
6882 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6884 smb_ReleaseFID(fidp);
6885 cm_ReleaseUser(userp);
6890 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6892 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6893 cm_user_t *userp, long *readp)
6899 osi_hyper_t fileLength;
6901 osi_hyper_t lastByte;
6902 osi_hyper_t bufferOffset;
6906 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6909 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6910 fidp->fid, offsetp->LowPart, count);
6914 lock_ObtainMutex(&fidp->mx);
6915 /* make sure we have a readable FD */
6916 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6917 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6918 fidp->fid, fidp->flags);
6919 lock_ReleaseMutex(&fidp->mx);
6920 code = CM_ERROR_BADFDOP;
6925 lock_ReleaseMutex(&fidp->mx);
6926 code = CM_ERROR_BADFD;
6937 lock_ObtainWrite(&scp->rw);
6939 if (offset.HighPart == 0) {
6940 chunk = offset.LowPart >> cm_logChunkSize;
6941 if (chunk != fidp->curr_chunk) {
6942 fidp->prev_chunk = fidp->curr_chunk;
6943 fidp->curr_chunk = chunk;
6945 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6948 lock_ReleaseMutex(&fidp->mx);
6950 /* start by looking up the file's end */
6951 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6952 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6956 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6958 /* now we have the entry locked, look up the length */
6959 fileLength = scp->length;
6961 /* adjust count down so that it won't go past EOF */
6962 thyper.LowPart = count;
6963 thyper.HighPart = 0;
6964 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6966 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6967 /* we'd read past EOF, so just stop at fileLength bytes.
6968 * Start by computing how many bytes remain in the file.
6970 thyper = LargeIntegerSubtract(fileLength, offset);
6972 /* if we are past EOF, read 0 bytes */
6973 if (LargeIntegerLessThanZero(thyper))
6976 count = thyper.LowPart;
6981 /* now, copy the data one buffer at a time,
6982 * until we've filled the request packet
6985 /* if we've copied all the data requested, we're done */
6986 if (count <= 0) break;
6988 /* otherwise, load up a buffer of data */
6989 thyper.HighPart = offset.HighPart;
6990 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6991 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6994 buf_Release(bufferp);
6997 lock_ReleaseWrite(&scp->rw);
6999 code = buf_Get(scp, &thyper, &bufferp);
7001 lock_ObtainWrite(&scp->rw);
7002 if (code) goto done;
7003 bufferOffset = thyper;
7005 /* now get the data in the cache */
7007 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7008 CM_SCACHESYNC_NEEDCALLBACK |
7009 CM_SCACHESYNC_READ);
7013 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7015 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7017 /* otherwise, load the buffer and try again */
7018 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7022 buf_Release(bufferp);
7026 } /* if (wrong buffer) ... */
7028 /* now we have the right buffer loaded. Copy out the
7029 * data from here to the user's buffer.
7031 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7033 /* and figure out how many bytes we want from this buffer */
7034 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7035 if (nbytes > count) nbytes = count; /* don't go past EOF */
7037 /* now copy the data */
7038 memcpy(op, bufferp->datap + bufIndex, nbytes);
7040 /* adjust counters, pointers, etc. */
7043 thyper.LowPart = nbytes;
7044 thyper.HighPart = 0;
7045 offset = LargeIntegerAdd(thyper, offset);
7049 lock_ReleaseWrite(&scp->rw);
7051 buf_Release(bufferp);
7053 if (code == 0 && sequential)
7054 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7056 cm_ReleaseSCache(scp);
7059 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7060 fidp->fid, code, *readp);
7065 * smb_WriteData -- common code for Write and Raw Write
7067 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7068 cm_user_t *userp, long *writtenp)
7070 osi_hyper_t offset = *offsetp;
7073 cm_scache_t *scp = NULL;
7074 osi_hyper_t fileLength; /* file's length at start of write */
7075 osi_hyper_t minLength; /* don't read past this */
7076 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7077 cm_buf_t *bufferp = NULL;
7078 osi_hyper_t thyper; /* hyper tmp variable */
7079 osi_hyper_t bufferOffset;
7080 afs_uint32 bufIndex; /* index in buffer where our data is */
7081 int doWriteBack = 0;
7082 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7086 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7087 fidp->fid, offsetp->LowPart, count);
7091 lock_ObtainMutex(&fidp->mx);
7092 /* make sure we have a writable FD */
7093 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7094 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7095 fidp->fid, fidp->flags);
7096 lock_ReleaseMutex(&fidp->mx);
7097 code = CM_ERROR_BADFDOP;
7105 lock_ReleaseMutex(&fidp->mx);
7107 lock_ObtainWrite(&scp->rw);
7108 /* start by looking up the file's end */
7109 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7110 CM_SCACHESYNC_NEEDCALLBACK
7111 | CM_SCACHESYNC_SETSTATUS
7112 | CM_SCACHESYNC_GETSTATUS);
7116 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7118 /* now we have the entry locked, look up the length */
7119 fileLength = scp->length;
7120 minLength = fileLength;
7121 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7122 minLength = scp->serverLength;
7124 /* adjust file length if we extend past EOF */
7125 thyper.LowPart = count;
7126 thyper.HighPart = 0;
7127 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7128 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7129 /* we'd write past EOF, so extend the file */
7130 scp->mask |= CM_SCACHEMASK_LENGTH;
7131 scp->length = thyper;
7132 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7134 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7136 /* now, if the new position (thyper) and the old (offset) are in
7137 * different storeback windows, remember to store back the previous
7138 * storeback window when we're done with the write.
7140 * the purpose of this logic is to slow down the CIFS client
7141 * in order to avoid the client disconnecting during the CLOSE
7142 * operation if there are too many dirty buffers left to write
7143 * than can be accomplished during 45 seconds. This used to be
7144 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7145 * so that we can read larger amounts of data at a time.
7147 if (smb_AsyncStore == 1 &&
7148 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7149 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7150 /* they're different */
7152 writeBackOffset.HighPart = offset.HighPart;
7153 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7158 /* now, copy the data one buffer at a time, until we've filled the
7161 /* if we've copied all the data requested, we're done */
7165 /* handle over quota or out of space */
7166 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7167 *writtenp = written;
7168 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7172 /* otherwise, load up a buffer of data */
7173 thyper.HighPart = offset.HighPart;
7174 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7175 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7178 lock_ReleaseMutex(&bufferp->mx);
7179 buf_Release(bufferp);
7182 lock_ReleaseWrite(&scp->rw);
7184 code = buf_Get(scp, &thyper, &bufferp);
7186 lock_ObtainMutex(&bufferp->mx);
7187 lock_ObtainWrite(&scp->rw);
7188 if (code) goto done;
7190 bufferOffset = thyper;
7192 /* now get the data in the cache */
7194 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7195 CM_SCACHESYNC_NEEDCALLBACK
7196 | CM_SCACHESYNC_WRITE
7197 | CM_SCACHESYNC_BUFLOCKED);
7201 cm_SyncOpDone(scp, bufferp,
7202 CM_SCACHESYNC_NEEDCALLBACK
7203 | CM_SCACHESYNC_WRITE
7204 | CM_SCACHESYNC_BUFLOCKED);
7206 /* If we're overwriting the entire buffer, or
7207 * if we're writing at or past EOF, mark the
7208 * buffer as current so we don't call
7209 * cm_GetBuffer. This skips the fetch from the
7210 * server in those cases where we're going to
7211 * obliterate all the data in the buffer anyway,
7212 * or in those cases where there is no useful
7213 * data at the server to start with.
7215 * Use minLength instead of scp->length, since
7216 * the latter has already been updated by this
7219 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7220 || LargeIntegerEqualTo(offset, bufferp->offset)
7221 && (count >= cm_data.buf_blockSize
7222 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7223 ConvertLongToLargeInteger(count)),
7225 if (count < cm_data.buf_blockSize
7226 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7227 memset(bufferp->datap, 0,
7228 cm_data.buf_blockSize);
7229 bufferp->dataVersion = scp->dataVersion;
7232 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7234 /* otherwise, load the buffer and try again */
7235 lock_ReleaseMutex(&bufferp->mx);
7236 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7238 lock_ReleaseWrite(&scp->rw);
7239 lock_ObtainMutex(&bufferp->mx);
7240 lock_ObtainWrite(&scp->rw);
7244 lock_ReleaseMutex(&bufferp->mx);
7245 buf_Release(bufferp);
7249 } /* if (wrong buffer) ... */
7251 /* now we have the right buffer loaded. Copy out the
7252 * data from here to the user's buffer.
7254 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7256 /* and figure out how many bytes we want from this buffer */
7257 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7259 nbytes = count; /* don't go past end of request */
7261 /* now copy the data */
7262 memcpy(bufferp->datap + bufIndex, op, nbytes);
7263 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7265 /* adjust counters, pointers, etc. */
7269 thyper.LowPart = nbytes;
7270 thyper.HighPart = 0;
7271 offset = LargeIntegerAdd(thyper, offset);
7275 lock_ReleaseWrite(&scp->rw);
7278 lock_ReleaseMutex(&bufferp->mx);
7279 buf_Release(bufferp);
7282 lock_ObtainMutex(&fidp->mx);
7283 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7284 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7286 lock_ReleaseMutex(&fidp->mx);
7287 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7288 fidp->NTopen_dscp, fidp->NTopen_pathp,
7291 lock_ReleaseMutex(&fidp->mx);
7295 if (smb_AsyncStore > 0) {
7299 lock_ObtainWrite(&scp->rw);
7300 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7302 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7303 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7305 lock_ReleaseWrite(&scp->rw);
7306 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7307 writeBackOffset.HighPart,
7308 smb_AsyncStoreSize, 0, userp);
7309 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7312 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7316 cm_ReleaseSCache(scp);
7319 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7320 fidp->fid, code, *writtenp);
7325 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7328 unsigned short count;
7330 unsigned short hint;
7331 long written = 0, total_written = 0;
7334 smb_t* smbp = (smb_t*) inp;
7338 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7340 int inDataBlockCount;
7342 fd = smb_GetSMBParm(inp, 0);
7343 count = smb_GetSMBParm(inp, 1);
7344 offset.HighPart = 0; /* too bad */
7345 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7346 hint = smb_GetSMBParm(inp, 4);
7348 op = smb_GetSMBData(inp, NULL);
7349 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7351 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7352 fd, offset.LowPart, count);
7354 fd = smb_ChainFID(fd, inp);
7355 fidp = smb_FindFID(vcp, fd, 0);
7357 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7358 return CM_ERROR_BADFD;
7361 lock_ObtainMutex(&fidp->mx);
7362 if (fidp->flags & SMB_FID_IOCTL) {
7363 lock_ReleaseMutex(&fidp->mx);
7364 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7365 smb_ReleaseFID(fidp);
7366 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7371 lock_ReleaseMutex(&fidp->mx);
7372 smb_ReleaseFID(fidp);
7373 return CM_ERROR_BADFD;
7376 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7377 lock_ReleaseMutex(&fidp->mx);
7378 smb_CloseFID(vcp, fidp, NULL, 0);
7379 smb_ReleaseFID(fidp);
7380 return CM_ERROR_NOSUCHFILE;
7385 lock_ReleaseMutex(&fidp->mx);
7386 userp = smb_GetUserFromVCP(vcp, inp);
7390 LARGE_INTEGER LOffset;
7391 LARGE_INTEGER LLength;
7394 key = cm_GenerateKey(vcp->vcID, pid, fd);
7396 LOffset.HighPart = offset.HighPart;
7397 LOffset.LowPart = offset.LowPart;
7398 LLength.HighPart = 0;
7399 LLength.LowPart = count;
7401 lock_ObtainWrite(&scp->rw);
7402 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7403 lock_ReleaseWrite(&scp->rw);
7406 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7411 /* special case: 0 bytes transferred means truncate to this position */
7415 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7419 truncAttr.mask = CM_ATTRMASK_LENGTH;
7420 truncAttr.length.LowPart = offset.LowPart;
7421 truncAttr.length.HighPart = 0;
7422 lock_ObtainMutex(&fidp->mx);
7423 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7424 fidp->flags |= SMB_FID_LENGTHSETDONE;
7425 lock_ReleaseMutex(&fidp->mx);
7426 smb_SetSMBParm(outp, 0, 0 /* count */);
7427 smb_SetSMBDataLength(outp, 0);
7432 * Work around bug in NT client
7434 * When copying a file, the NT client should first copy the data,
7435 * then copy the last write time. But sometimes the NT client does
7436 * these in the wrong order, so the data copies would inadvertently
7437 * cause the last write time to be overwritten. We try to detect this,
7438 * and don't set client mod time if we think that would go against the
7441 lock_ObtainMutex(&fidp->mx);
7442 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7443 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7444 fidp->scp->clientModTime = time(NULL);
7446 lock_ReleaseMutex(&fidp->mx);
7449 while ( code == 0 && count > 0 ) {
7450 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7451 if (code == 0 && written == 0)
7452 code = CM_ERROR_PARTIALWRITE;
7454 offset = LargeIntegerAdd(offset,
7455 ConvertLongToLargeInteger(written));
7456 count -= (unsigned short)written;
7457 total_written += written;
7461 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7462 total_written, code);
7464 /* set the packet data length to 3 bytes for the data block header,
7465 * plus the size of the data.
7467 smb_SetSMBParm(outp, 0, total_written);
7468 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7469 smb_SetSMBParm(outp, 3, hint);
7470 smb_SetSMBDataLength(outp, 0);
7473 smb_ReleaseFID(fidp);
7474 cm_ReleaseUser(userp);
7475 cm_ReleaseSCache(scp);
7480 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7481 NCB *ncbp, raw_write_cont_t *rwcp)
7490 fd = smb_GetSMBParm(inp, 0);
7491 fidp = smb_FindFID(vcp, fd, 0);
7493 lock_ObtainMutex(&fidp->mx);
7495 lock_ReleaseMutex(&fidp->mx);
7496 smb_ReleaseFID(fidp);
7500 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7501 lock_ReleaseMutex(&fidp->mx);
7502 smb_CloseFID(vcp, fidp, NULL, 0);
7503 smb_ReleaseFID(fidp);
7506 lock_ReleaseMutex(&fidp->mx);
7508 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7509 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7511 userp = smb_GetUserFromVCP(vcp, inp);
7514 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7516 if (rwcp->writeMode & 0x1) { /* synchronous */
7519 smb_FormatResponsePacket(vcp, inp, outp);
7520 op = (smb_t *) outp;
7521 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7522 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7523 smb_SetSMBDataLength(outp, 0);
7524 smb_SendPacket(vcp, outp);
7525 smb_FreePacket(outp);
7527 else { /* asynchronous */
7528 lock_ObtainMutex(&fidp->mx);
7529 fidp->raw_writers--;
7530 if (fidp->raw_writers == 0)
7531 thrd_SetEvent(fidp->raw_write_event);
7532 lock_ReleaseMutex(&fidp->mx);
7535 /* Give back raw buffer */
7536 lock_ObtainMutex(&smb_RawBufLock);
7537 *((char **)rawBuf) = smb_RawBufs;
7538 smb_RawBufs = rawBuf;
7539 lock_ReleaseMutex(&smb_RawBufLock);
7541 smb_ReleaseFID(fidp);
7542 cm_ReleaseUser(userp);
7545 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7550 /* SMB_COM_WRITE_RAW */
7551 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7554 long count, written = 0, total_written = 0;
7558 smb_t *smbp = (smb_t*) inp;
7563 unsigned short writeMode;
7565 fd = smb_GetSMBParm(inp, 0);
7566 totalCount = smb_GetSMBParm(inp, 1);
7567 count = smb_GetSMBParm(inp, 10);
7568 writeMode = smb_GetSMBParm(inp, 7);
7570 op = (char *) inp->data;
7571 op += smb_GetSMBParm(inp, 11);
7573 offset.HighPart = 0;
7574 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7576 if (*inp->wctp == 14) {
7577 /* we received a 64-bit file offset */
7578 #ifdef AFS_LARGEFILES
7579 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7581 if (LargeIntegerLessThanZero(offset)) {
7583 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7584 offset.HighPart, offset.LowPart);
7585 return CM_ERROR_BADSMB;
7588 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7590 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7591 return CM_ERROR_BADSMB;
7594 offset.HighPart = 0;
7597 offset.HighPart = 0; /* 32-bit file offset */
7601 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7602 fd, offset.HighPart, offset.LowPart, count);
7604 " WriteRaw WriteMode 0x%x",
7607 fd = smb_ChainFID(fd, inp);
7608 fidp = smb_FindFID(vcp, fd, 0);
7610 return CM_ERROR_BADFD;
7612 lock_ObtainMutex(&fidp->mx);
7614 lock_ReleaseMutex(&fidp->mx);
7615 smb_ReleaseFID(fidp);
7616 return CM_ERROR_BADFD;
7619 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7620 lock_ReleaseMutex(&fidp->mx);
7621 smb_CloseFID(vcp, fidp, NULL, 0);
7622 smb_ReleaseFID(fidp);
7623 return CM_ERROR_NOSUCHFILE;
7628 lock_ReleaseMutex(&fidp->mx);
7633 LARGE_INTEGER LOffset;
7634 LARGE_INTEGER LLength;
7637 key = cm_GenerateKey(vcp->vcID, pid, fd);
7639 LOffset.HighPart = offset.HighPart;
7640 LOffset.LowPart = offset.LowPart;
7641 LLength.HighPart = 0;
7642 LLength.LowPart = count;
7644 lock_ObtainWrite(&scp->rw);
7645 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7646 lock_ReleaseWrite(&scp->rw);
7649 cm_ReleaseSCache(scp);
7650 smb_ReleaseFID(fidp);
7655 userp = smb_GetUserFromVCP(vcp, inp);
7658 * Work around bug in NT client
7660 * When copying a file, the NT client should first copy the data,
7661 * then copy the last write time. But sometimes the NT client does
7662 * these in the wrong order, so the data copies would inadvertently
7663 * cause the last write time to be overwritten. We try to detect this,
7664 * and don't set client mod time if we think that would go against the
7667 lock_ObtainMutex(&fidp->mx);
7668 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7669 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7670 fidp->scp->clientModTime = time(NULL);
7672 lock_ReleaseMutex(&fidp->mx);
7675 while ( code == 0 && count > 0 ) {
7676 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7677 if (code == 0 && written == 0)
7678 code = CM_ERROR_PARTIALWRITE;
7680 offset = LargeIntegerAdd(offset,
7681 ConvertLongToLargeInteger(written));
7684 total_written += written;
7688 /* Get a raw buffer */
7691 lock_ObtainMutex(&smb_RawBufLock);
7693 /* Get a raw buf, from head of list */
7694 rawBuf = smb_RawBufs;
7695 smb_RawBufs = *(char **)smb_RawBufs;
7698 code = CM_ERROR_USESTD;
7700 lock_ReleaseMutex(&smb_RawBufLock);
7703 /* Don't allow a premature Close */
7704 if (code == 0 && (writeMode & 1) == 0) {
7705 lock_ObtainMutex(&fidp->mx);
7706 fidp->raw_writers++;
7707 thrd_ResetEvent(fidp->raw_write_event);
7708 lock_ReleaseMutex(&fidp->mx);
7711 smb_ReleaseFID(fidp);
7712 cm_ReleaseUser(userp);
7713 cm_ReleaseSCache(scp);
7716 smb_SetSMBParm(outp, 0, total_written);
7717 smb_SetSMBDataLength(outp, 0);
7718 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7723 offset = LargeIntegerAdd(offset,
7724 ConvertLongToLargeInteger(count));
7728 rwcp->offset.HighPart = offset.HighPart;
7729 rwcp->offset.LowPart = offset.LowPart;
7730 rwcp->count = totalCount - count;
7731 rwcp->writeMode = writeMode;
7732 rwcp->alreadyWritten = total_written;
7734 /* set the packet data length to 3 bytes for the data block header,
7735 * plus the size of the data.
7737 smb_SetSMBParm(outp, 0, 0xffff);
7738 smb_SetSMBDataLength(outp, 0);
7744 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7747 long count, finalCount;
7751 smb_t *smbp = (smb_t*) inp;
7757 fd = smb_GetSMBParm(inp, 0);
7758 count = smb_GetSMBParm(inp, 1);
7759 offset.HighPart = 0; /* too bad */
7760 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7762 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7763 fd, offset.LowPart, count);
7765 fd = smb_ChainFID(fd, inp);
7766 fidp = smb_FindFID(vcp, fd, 0);
7768 return CM_ERROR_BADFD;
7770 lock_ObtainMutex(&fidp->mx);
7771 if (fidp->flags & SMB_FID_IOCTL) {
7772 lock_ReleaseMutex(&fidp->mx);
7773 code = smb_IoctlRead(fidp, vcp, inp, outp);
7774 smb_ReleaseFID(fidp);
7779 lock_ReleaseMutex(&fidp->mx);
7780 smb_ReleaseFID(fidp);
7781 return CM_ERROR_BADFD;
7784 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7785 lock_ReleaseMutex(&fidp->mx);
7786 smb_CloseFID(vcp, fidp, NULL, 0);
7787 smb_ReleaseFID(fidp);
7788 return CM_ERROR_NOSUCHFILE;
7793 lock_ReleaseMutex(&fidp->mx);
7796 LARGE_INTEGER LOffset, LLength;
7800 key = cm_GenerateKey(vcp->vcID, pid, fd);
7802 LOffset.HighPart = 0;
7803 LOffset.LowPart = offset.LowPart;
7804 LLength.HighPart = 0;
7805 LLength.LowPart = count;
7807 lock_ObtainWrite(&scp->rw);
7808 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7809 lock_ReleaseWrite(&scp->rw);
7812 cm_ReleaseSCache(scp);
7813 smb_ReleaseFID(fidp);
7817 userp = smb_GetUserFromVCP(vcp, inp);
7819 /* remember this for final results */
7820 smb_SetSMBParm(outp, 0, count);
7821 smb_SetSMBParm(outp, 1, 0);
7822 smb_SetSMBParm(outp, 2, 0);
7823 smb_SetSMBParm(outp, 3, 0);
7824 smb_SetSMBParm(outp, 4, 0);
7826 /* set the packet data length to 3 bytes for the data block header,
7827 * plus the size of the data.
7829 smb_SetSMBDataLength(outp, count+3);
7831 /* get op ptr after putting in the parms, since otherwise we don't
7832 * know where the data really is.
7834 op = smb_GetSMBData(outp, NULL);
7836 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7837 *op++ = 1; /* data block marker */
7838 *op++ = (unsigned char) (count & 0xff);
7839 *op++ = (unsigned char) ((count >> 8) & 0xff);
7841 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7843 /* fix some things up */
7844 smb_SetSMBParm(outp, 0, finalCount);
7845 smb_SetSMBDataLength(outp, finalCount+3);
7847 smb_ReleaseFID(fidp);
7849 cm_ReleaseUser(userp);
7850 cm_ReleaseSCache(scp);
7854 /* SMB_COM_CREATE_DIRECTORY */
7855 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7857 clientchar_t *pathp;
7862 cm_scache_t *dscp; /* dir we're dealing with */
7863 cm_scache_t *scp; /* file we're creating */
7865 int initialModeBits;
7866 clientchar_t *lastNamep;
7868 clientchar_t *tidPathp;
7875 /* compute initial mode bits based on read-only flag in attributes */
7876 initialModeBits = 0777;
7878 tp = smb_GetSMBData(inp, NULL);
7879 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7881 return CM_ERROR_BADSMB;
7883 spacep = inp->spacep;
7884 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7886 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7887 return CM_ERROR_EXISTS;
7889 userp = smb_GetUserFromVCP(vcp, inp);
7891 caseFold = CM_FLAG_CASEFOLD;
7893 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7895 cm_ReleaseUser(userp);
7896 return CM_ERROR_NOSUCHPATH;
7899 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7900 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7901 userp, tidPathp, &req, &dscp);
7904 cm_ReleaseUser(userp);
7909 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7910 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7911 cm_ReleaseSCache(dscp);
7912 cm_ReleaseUser(userp);
7913 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7914 return CM_ERROR_PATH_NOT_COVERED;
7916 return CM_ERROR_NOSUCHPATH;
7918 #endif /* DFS_SUPPORT */
7920 /* otherwise, scp points to the parent directory. Do a lookup, and
7921 * fail if we find it. Otherwise, we do the create.
7927 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7928 if (scp) cm_ReleaseSCache(scp);
7929 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7930 if (code == 0) code = CM_ERROR_EXISTS;
7931 cm_ReleaseSCache(dscp);
7932 cm_ReleaseUser(userp);
7936 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7937 setAttr.clientModTime = time(NULL);
7938 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7939 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7940 smb_NotifyChange(FILE_ACTION_ADDED,
7941 FILE_NOTIFY_CHANGE_DIR_NAME,
7942 dscp, lastNamep, NULL, TRUE);
7944 /* we don't need this any longer */
7945 cm_ReleaseSCache(dscp);
7948 /* something went wrong creating or truncating the file */
7949 cm_ReleaseUser(userp);
7953 /* otherwise we succeeded */
7954 smb_SetSMBDataLength(outp, 0);
7955 cm_ReleaseUser(userp);
7960 BOOL smb_IsLegalFilename(clientchar_t *filename)
7963 * Find the longest substring of filename that does not contain
7964 * any of the chars in illegalChars. If that substring is less
7965 * than the length of the whole string, then one or more of the
7966 * illegal chars is in filename.
7968 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7974 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7975 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7977 clientchar_t *pathp;
7983 cm_scache_t *dscp; /* dir we're dealing with */
7984 cm_scache_t *scp; /* file we're creating */
7986 int initialModeBits;
7989 clientchar_t *lastNamep;
7992 clientchar_t *tidPathp;
7994 int created = 0; /* the file was new */
7999 excl = (inp->inCom == 0x03)? 0 : 1;
8001 attributes = smb_GetSMBParm(inp, 0);
8002 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8004 /* compute initial mode bits based on read-only flag in attributes */
8005 initialModeBits = 0666;
8006 if (attributes & SMB_ATTR_READONLY)
8007 initialModeBits &= ~0222;
8009 tp = smb_GetSMBData(inp, NULL);
8010 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8012 return CM_ERROR_BADSMB;
8014 if (!cm_IsValidClientString(pathp)) {
8016 clientchar_t * hexp;
8018 hexp = cm_GetRawCharsAlloc(pathp, -1);
8019 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8020 osi_LogSaveClientString(smb_logp, hexp));
8024 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8026 return CM_ERROR_BADNTFILENAME;
8029 spacep = inp->spacep;
8030 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8032 userp = smb_GetUserFromVCP(vcp, inp);
8034 caseFold = CM_FLAG_CASEFOLD;
8036 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8038 cm_ReleaseUser(userp);
8039 return CM_ERROR_NOSUCHPATH;
8041 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8042 userp, tidPathp, &req, &dscp);
8045 cm_ReleaseUser(userp);
8050 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8051 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8052 cm_ReleaseSCache(dscp);
8053 cm_ReleaseUser(userp);
8054 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8055 return CM_ERROR_PATH_NOT_COVERED;
8057 return CM_ERROR_NOSUCHPATH;
8059 #endif /* DFS_SUPPORT */
8061 /* otherwise, scp points to the parent directory. Do a lookup, and
8062 * truncate the file if we find it, otherwise we create the file.
8069 if (!smb_IsLegalFilename(lastNamep))
8070 return CM_ERROR_BADNTFILENAME;
8072 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8073 #ifdef DEBUG_VERBOSE
8076 hexp = osi_HexifyString( lastNamep );
8077 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8082 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8083 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8084 cm_ReleaseSCache(dscp);
8085 cm_ReleaseUser(userp);
8089 /* if we get here, if code is 0, the file exists and is represented by
8090 * scp. Otherwise, we have to create it.
8094 /* oops, file shouldn't be there */
8095 cm_ReleaseSCache(dscp);
8096 cm_ReleaseSCache(scp);
8097 cm_ReleaseUser(userp);
8098 return CM_ERROR_EXISTS;
8101 setAttr.mask = CM_ATTRMASK_LENGTH;
8102 setAttr.length.LowPart = 0;
8103 setAttr.length.HighPart = 0;
8104 code = cm_SetAttr(scp, &setAttr, userp, &req);
8107 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8108 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8109 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8113 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8114 smb_NotifyChange(FILE_ACTION_ADDED,
8115 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8116 dscp, lastNamep, NULL, TRUE);
8117 } else if (!excl && code == CM_ERROR_EXISTS) {
8118 /* not an exclusive create, and someone else tried
8119 * creating it already, then we open it anyway. We
8120 * don't bother retrying after this, since if this next
8121 * fails, that means that the file was deleted after
8122 * we started this call.
8124 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8127 setAttr.mask = CM_ATTRMASK_LENGTH;
8128 setAttr.length.LowPart = 0;
8129 setAttr.length.HighPart = 0;
8130 code = cm_SetAttr(scp, &setAttr, userp, &req);
8135 /* we don't need this any longer */
8136 cm_ReleaseSCache(dscp);
8139 /* something went wrong creating or truncating the file */
8140 if (scp) cm_ReleaseSCache(scp);
8141 cm_ReleaseUser(userp);
8145 /* make sure we only open files */
8146 if (scp->fileType != CM_SCACHETYPE_FILE) {
8147 cm_ReleaseSCache(scp);
8148 cm_ReleaseUser(userp);
8149 return CM_ERROR_ISDIR;
8152 /* now all we have to do is open the file itself */
8153 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8154 osi_assertx(fidp, "null smb_fid_t");
8158 lock_ObtainMutex(&fidp->mx);
8159 /* always create it open for read/write */
8160 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8162 /* remember that the file was newly created */
8164 fidp->flags |= SMB_FID_CREATED;
8166 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8168 /* save a pointer to the vnode */
8170 lock_ObtainWrite(&scp->rw);
8171 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8172 lock_ReleaseWrite(&scp->rw);
8175 fidp->userp = userp;
8176 lock_ReleaseMutex(&fidp->mx);
8178 smb_SetSMBParm(outp, 0, fidp->fid);
8179 smb_SetSMBDataLength(outp, 0);
8181 cm_Open(scp, 0, userp);
8183 smb_ReleaseFID(fidp);
8184 cm_ReleaseUser(userp);
8185 /* leave scp held since we put it in fidp->scp */
8190 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8193 osi_hyper_t new_offset;
8204 fd = smb_GetSMBParm(inp, 0);
8205 whence = smb_GetSMBParm(inp, 1);
8206 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8208 /* try to find the file descriptor */
8209 fd = smb_ChainFID(fd, inp);
8210 fidp = smb_FindFID(vcp, fd, 0);
8212 return CM_ERROR_BADFD;
8214 lock_ObtainMutex(&fidp->mx);
8215 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8216 lock_ReleaseMutex(&fidp->mx);
8217 smb_ReleaseFID(fidp);
8218 return CM_ERROR_BADFD;
8221 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8222 lock_ReleaseMutex(&fidp->mx);
8223 smb_CloseFID(vcp, fidp, NULL, 0);
8224 smb_ReleaseFID(fidp);
8225 return CM_ERROR_NOSUCHFILE;
8228 lock_ReleaseMutex(&fidp->mx);
8230 userp = smb_GetUserFromVCP(vcp, inp);
8232 lock_ObtainMutex(&fidp->mx);
8235 lock_ReleaseMutex(&fidp->mx);
8236 lock_ObtainWrite(&scp->rw);
8237 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8238 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8240 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8242 /* offset from current offset */
8243 new_offset = LargeIntegerAdd(fidp->offset,
8244 ConvertLongToLargeInteger(offset));
8246 else if (whence == 2) {
8247 /* offset from current EOF */
8248 new_offset = LargeIntegerAdd(scp->length,
8249 ConvertLongToLargeInteger(offset));
8251 new_offset = ConvertLongToLargeInteger(offset);
8254 fidp->offset = new_offset;
8255 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8256 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8257 smb_SetSMBDataLength(outp, 0);
8259 lock_ReleaseWrite(&scp->rw);
8260 smb_ReleaseFID(fidp);
8261 cm_ReleaseSCache(scp);
8262 cm_ReleaseUser(userp);
8266 /* dispatch all of the requests received in a packet. Due to chaining, this may
8267 * be more than one request.
8269 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8270 NCB *ncbp, raw_write_cont_t *rwcp)
8274 unsigned long code = 0;
8275 unsigned char *outWctp;
8276 int nparms; /* # of bytes of parameters */
8278 int nbytes; /* bytes of data, excluding count */
8281 unsigned short errCode;
8282 unsigned long NTStatus;
8284 unsigned char errClass;
8285 unsigned int oldGen;
8286 DWORD oldTime, newTime;
8288 /* get easy pointer to the data */
8289 smbp = (smb_t *) inp->data;
8291 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8292 /* setup the basic parms for the initial request in the packet */
8293 inp->inCom = smbp->com;
8294 inp->wctp = &smbp->wct;
8296 inp->ncb_length = ncbp->ncb_length;
8301 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8302 /* log it and discard it */
8303 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8304 __FILE__, __LINE__, ncbp->ncb_length);
8305 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8309 /* We are an ongoing op */
8310 thrd_Increment(&ongoingOps);
8312 /* set up response packet for receiving output */
8313 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8314 smb_FormatResponsePacket(vcp, inp, outp);
8315 outWctp = outp->wctp;
8317 /* Remember session generation number and time */
8318 oldGen = sessionGen;
8319 oldTime = GetTickCount();
8321 while (inp->inCom != 0xff) {
8322 dp = &smb_dispatchTable[inp->inCom];
8324 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8325 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8326 code = outp->resumeCode;
8330 /* process each request in the packet; inCom, wctp and inCount
8331 * are already set up.
8333 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8336 /* now do the dispatch */
8337 /* start by formatting the response record a little, as a default */
8338 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8340 outWctp[1] = 0xff; /* no operation */
8341 outWctp[2] = 0; /* padding */
8346 /* not a chained request, this is a more reasonable default */
8347 outWctp[0] = 0; /* wct of zero */
8348 outWctp[1] = 0; /* and bcc (word) of zero */
8352 /* once set, stays set. Doesn't matter, since we never chain
8353 * "no response" calls.
8355 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8359 /* we have a recognized operation */
8360 char * opName = myCrt_Dispatch(inp->inCom);
8363 smbp = (smb_t *) inp;
8365 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8366 opName, smbp->mid, vcp,vcp->lana,vcp->lsn);
8367 if (inp->inCom == 0x1d) {
8369 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8371 code = (*(dp->procp)) (vcp, inp, outp);
8373 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8374 code, smbp->mid, vcp,vcp->lana,vcp->lsn);
8376 newTime = GetTickCount();
8377 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8378 opName, smbp->mid, newTime - oldTime);
8381 if ( code == CM_ERROR_BADSMB ||
8382 code == CM_ERROR_BADOP )
8384 #endif /* LOG_PACKET */
8386 /* ReceiveV3Tran2A handles its own logging */
8387 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8390 clientchar_t *treepath = NULL; /* do not free */
8391 clientchar_t *pathname = NULL;
8392 cm_fid_t afid = {0,0,0,0,0};
8394 uidp = smb_FindUID(vcp, smbp->uid, 0);
8395 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8396 fidp = smb_FindFID(vcp, inp->fid, 0);
8399 lock_ObtainMutex(&fidp->mx);
8400 if (fidp->NTopen_pathp)
8401 pathname = fidp->NTopen_pathp;
8403 afid = fidp->scp->fid;
8405 if (inp->stringsp->wdata)
8406 pathname = inp->stringsp->wdata;
8409 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
8410 opName, newTime - oldTime,
8411 smbp->uid, uidp ? uidp->unp->name : NULL,
8412 smbp->pid, smbp->mid, smbp->tid,
8415 afid.cell, afid.volume, afid.vnode, afid.unique);
8418 lock_ReleaseMutex(&fidp->mx);
8421 smb_ReleaseUID(uidp);
8423 smb_ReleaseFID(fidp);
8426 if (oldGen != sessionGen) {
8427 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8428 newTime - oldTime, ncbp->ncb_length);
8429 osi_Log3(smb_logp, "Request %s straddled session startup, "
8430 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8433 FreeSMBStrings(inp);
8435 /* bad opcode, fail the request, after displaying it */
8436 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8439 #endif /* LOG_PACKET */
8442 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8443 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8444 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8445 if (code == IDCANCEL)
8448 code = CM_ERROR_BADOP;
8451 /* catastrophic failure: log as much as possible */
8452 if (code == CM_ERROR_BADSMB) {
8453 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8457 #endif /* LOG_PACKET */
8458 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8461 code = CM_ERROR_INVAL;
8464 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8465 thrd_Decrement(&ongoingOps);
8470 /* now, if we failed, turn the current response into an empty
8471 * one, and fill in the response packet's error code.
8474 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8475 smb_MapNTError(code, &NTStatus);
8476 outWctp = outp->wctp;
8477 smbp = (smb_t *) &outp->data;
8478 if (code != CM_ERROR_PARTIALWRITE
8479 && code != CM_ERROR_BUFFERTOOSMALL
8480 && code != CM_ERROR_GSSCONTINUE) {
8481 /* nuke wct and bcc. For a partial
8482 * write or an in-process authentication handshake,
8483 * assume they're OK.
8489 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8490 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8491 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8492 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8493 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8497 smb_MapCoreError(code, vcp, &errCode, &errClass);
8498 outWctp = outp->wctp;
8499 smbp = (smb_t *) &outp->data;
8500 if (code != CM_ERROR_PARTIALWRITE) {
8501 /* nuke wct and bcc. For a partial
8502 * write, assume they're OK.
8508 smbp->errLow = (unsigned char) (errCode & 0xff);
8509 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8510 smbp->rcls = errClass;
8513 } /* error occurred */
8515 /* if we're here, we've finished one request. Look to see if
8516 * this is a chained opcode. If it is, setup things to process
8517 * the chained request, and setup the output buffer to hold the
8518 * chained response. Start by finding the next input record.
8520 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8521 break; /* not a chained req */
8522 tp = inp->wctp; /* points to start of last request */
8523 /* in a chained request, the first two
8524 * parm fields are required, and are
8525 * AndXCommand/AndXReserved and
8527 if (tp[0] < 2) break;
8528 if (tp[1] == 0xff) break; /* no more chained opcodes */
8530 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8533 /* and now append the next output request to the end of this
8534 * last request. Begin by finding out where the last response
8535 * ends, since that's where we'll put our new response.
8537 outWctp = outp->wctp; /* ptr to out parameters */
8538 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8539 nparms = outWctp[0] << 1;
8540 tp = outWctp + nparms + 1; /* now points to bcc field */
8541 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8542 tp += 2 /* for the count itself */ + nbytes;
8543 /* tp now points to the new output record; go back and patch the
8544 * second parameter (off2) to point to the new record.
8546 temp = (unsigned int)(tp - outp->data);
8547 outWctp[3] = (unsigned char) (temp & 0xff);
8548 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8549 outWctp[2] = 0; /* padding */
8550 outWctp[1] = inp->inCom; /* next opcode */
8552 /* finally, setup for the next iteration */
8555 } /* while loop over all requests in the packet */
8557 /* now send the output packet, and return */
8559 smb_SendPacket(vcp, outp);
8560 thrd_Decrement(&ongoingOps);
8565 /* Wait for Netbios() calls to return, and make the results available to server
8566 * threads. Note that server threads can't wait on the NCBevents array
8567 * themselves, because NCB events are manual-reset, and the servers would race
8568 * each other to reset them.
8570 void smb_ClientWaiter(void *parmp)
8575 while (smbShutdownFlag == 0) {
8576 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8578 if (code == WAIT_OBJECT_0)
8581 /* error checking */
8582 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8584 int abandonIdx = code - WAIT_ABANDONED_0;
8585 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8588 if (code == WAIT_IO_COMPLETION)
8590 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8594 if (code == WAIT_TIMEOUT)
8596 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8599 if (code == WAIT_FAILED)
8601 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8604 idx = code - WAIT_OBJECT_0;
8606 /* check idx range! */
8607 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8609 /* this is fatal - log as much as possible */
8610 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8611 osi_assertx(0, "invalid index");
8614 thrd_ResetEvent(NCBevents[idx]);
8615 thrd_SetEvent(NCBreturns[0][idx]);
8620 * Try to have one NCBRECV request waiting for every live session. Not more
8621 * than one, because if there is more than one, it's hard to handle Write Raw.
8623 void smb_ServerWaiter(void *parmp)
8626 int idx_session, idx_NCB;
8629 while (smbShutdownFlag == 0) {
8631 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8633 if (code == WAIT_OBJECT_0)
8636 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8638 int abandonIdx = code - WAIT_ABANDONED_0;
8639 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8642 if (code == WAIT_IO_COMPLETION)
8644 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8648 if (code == WAIT_TIMEOUT)
8650 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8653 if (code == WAIT_FAILED)
8655 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8658 idx_session = code - WAIT_OBJECT_0;
8660 /* check idx range! */
8661 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8663 /* this is fatal - log as much as possible */
8664 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8665 osi_assertx(0, "invalid index");
8670 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8672 if (code == WAIT_OBJECT_0) {
8673 if (smbShutdownFlag == 1)
8679 /* error checking */
8680 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8682 int abandonIdx = code - WAIT_ABANDONED_0;
8683 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8686 if (code == WAIT_IO_COMPLETION)
8688 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8692 if (code == WAIT_TIMEOUT)
8694 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8697 if (code == WAIT_FAILED)
8699 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8702 idx_NCB = code - WAIT_OBJECT_0;
8704 /* check idx range! */
8705 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8707 /* this is fatal - log as much as possible */
8708 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8709 osi_assertx(0, "invalid index");
8712 /* Link them together */
8713 NCBsessions[idx_NCB] = idx_session;
8716 ncbp = NCBs[idx_NCB];
8717 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8718 ncbp->ncb_command = NCBRECV | ASYNCH;
8719 ncbp->ncb_lana_num = lanas[idx_session];
8720 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8721 ncbp->ncb_event = NCBevents[idx_NCB];
8722 ncbp->ncb_length = SMB_PACKETSIZE;
8728 * The top level loop for handling SMB request messages. Each server thread
8729 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8730 * NCB and buffer for the incoming request are loaned to us.
8732 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8733 * to immediately send a request for the rest of the data. This must come
8734 * before any other traffic for that session, so we delay setting the session
8735 * event until that data has come in.
8737 void smb_Server(VOID *parmp)
8739 INT_PTR myIdx = (INT_PTR) parmp;
8743 smb_packet_t *outbufp;
8745 int idx_NCB, idx_session;
8747 smb_vc_t *vcp = NULL;
8749 extern void rx_StartClientThread(void);
8751 rx_StartClientThread();
8753 outncbp = smb_GetNCB();
8754 outbufp = smb_GetPacket();
8755 outbufp->ncbp = outncbp;
8763 smb_ResetServerPriority();
8765 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8768 /* terminate silently if shutdown flag is set */
8769 if (code == WAIT_OBJECT_0) {
8770 if (smbShutdownFlag == 1) {
8771 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8777 /* error checking */
8778 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8780 int abandonIdx = code - WAIT_ABANDONED_0;
8781 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8784 if (code == WAIT_IO_COMPLETION)
8786 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8790 if (code == WAIT_TIMEOUT)
8792 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8795 if (code == WAIT_FAILED)
8797 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8800 idx_NCB = code - WAIT_OBJECT_0;
8802 /* check idx range! */
8803 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8805 /* this is fatal - log as much as possible */
8806 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8807 osi_assertx(0, "invalid index");
8810 ncbp = NCBs[idx_NCB];
8811 idx_session = NCBsessions[idx_NCB];
8812 rc = ncbp->ncb_retcode;
8814 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8815 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8819 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8823 /* Can this happen? Or is it just my UNIX paranoia? */
8824 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8829 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8832 /* Client closed session */
8833 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8835 lock_ObtainMutex(&vcp->mx);
8836 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8837 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8839 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8840 lock_ReleaseMutex(&vcp->mx);
8841 lock_ObtainWrite(&smb_globalLock);
8842 dead_sessions[vcp->session] = TRUE;
8843 lock_ReleaseWrite(&smb_globalLock);
8845 lock_ReleaseMutex(&vcp->mx);
8847 smb_CleanupDeadVC(vcp);
8854 /* Treat as transient error */
8855 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8858 "dispatch smb recv failed, message incomplete, ncb_length %d",
8861 "SMB message incomplete, "
8862 "length %d", ncbp->ncb_length);
8865 * We used to discard the packet.
8866 * Instead, try handling it normally.
8870 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8874 /* A weird error code. Log it, sleep, and continue. */
8875 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8877 lock_ObtainMutex(&vcp->mx);
8878 if (vcp->errorCount++ > 3) {
8879 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8880 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8881 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8883 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8884 lock_ReleaseMutex(&vcp->mx);
8885 lock_ObtainWrite(&smb_globalLock);
8886 dead_sessions[vcp->session] = TRUE;
8887 lock_ReleaseWrite(&smb_globalLock);
8889 lock_ReleaseMutex(&vcp->mx);
8891 smb_CleanupDeadVC(vcp);
8897 lock_ReleaseMutex(&vcp->mx);
8901 thrd_SetEvent(SessionEvents[idx_session]);
8907 /* Success, so now dispatch on all the data in the packet */
8909 smb_concurrentCalls++;
8910 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8911 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8914 * If at this point vcp is NULL (implies that packet was invalid)
8915 * then we are in big trouble. This means either :
8916 * a) we have the wrong NCB.
8917 * b) Netbios screwed up the call.
8918 * c) The VC was already marked dead before we were able to
8920 * Obviously this implies that
8921 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8922 * lanas[idx_session] != ncbp->ncb_lana_num )
8923 * Either way, we can't do anything with this packet.
8924 * Log, sleep and resume.
8927 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8931 ncbp->ncb_lana_num);
8933 /* Also log in the trace log. */
8934 osi_Log4(smb_logp, "Server: VCP does not exist!"
8935 "LSNs[idx_session]=[%d],"
8936 "lanas[idx_session]=[%d],"
8937 "ncbp->ncb_lsn=[%d],"
8938 "ncbp->ncb_lana_num=[%d]",
8942 ncbp->ncb_lana_num);
8944 /* thrd_Sleep(1000); Don't bother sleeping */
8945 thrd_SetEvent(SessionEvents[idx_session]);
8946 smb_concurrentCalls--;
8950 smb_SetRequestStartTime();
8952 vcp->errorCount = 0;
8953 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8954 smbp = (smb_t *)bufp->data;
8961 if (smbp->com == 0x1d) {
8962 /* Special handling for Write Raw */
8963 raw_write_cont_t rwc;
8965 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8966 if (rwc.code == 0) {
8967 EVENT_HANDLE rwevent;
8968 char eventName[MAX_PATH];
8970 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
8971 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8972 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8973 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8975 ncbp->ncb_command = NCBRECV | ASYNCH;
8976 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8977 ncbp->ncb_lana_num = vcp->lana;
8978 ncbp->ncb_buffer = rwc.buf;
8979 ncbp->ncb_length = 65535;
8980 ncbp->ncb_event = rwevent;
8982 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8983 thrd_CloseHandle(rwevent);
8985 thrd_SetEvent(SessionEvents[idx_session]);
8987 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8989 else if (smbp->com == 0xa0) {
8991 * Serialize the handling for NT Transact
8994 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8995 thrd_SetEvent(SessionEvents[idx_session]);
8997 thrd_SetEvent(SessionEvents[idx_session]);
8998 /* TODO: what else needs to be serialized? */
8999 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9003 __except( smb_ServerExceptionFilter() ) {
9007 smb_concurrentCalls--;
9010 thrd_SetEvent(NCBavails[idx_NCB]);
9015 smb_FreePacket(outbufp);
9017 smb_FreeNCB(outncbp);
9021 * Exception filter for the server threads. If an exception occurs in the
9022 * dispatch routines, which is where exceptions are most common, then do a
9023 * force trace and give control to upstream exception handlers. Useful for
9026 DWORD smb_ServerExceptionFilter(void) {
9027 /* While this is not the best time to do a trace, if it succeeds, then
9028 * we have a trace (assuming tracing was enabled). Otherwise, this should
9029 * throw a second exception.
9031 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9032 afsd_ForceTrace(TRUE);
9033 buf_ForceTrace(TRUE);
9034 return EXCEPTION_CONTINUE_SEARCH;
9038 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9039 * If the number of server threads is M, and the number of live sessions is
9040 * N, then the number of NCB's in use at any time either waiting for, or
9041 * holding, received messages is M + N, so that is how many NCB's get created.
9043 void InitNCBslot(int idx)
9045 struct smb_packet *bufp;
9046 EVENT_HANDLE retHandle;
9048 char eventName[MAX_PATH];
9050 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9052 NCBs[idx] = smb_GetNCB();
9053 sprintf(eventName,"NCBavails[%d]", idx);
9054 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9055 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9056 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9057 sprintf(eventName,"NCBevents[%d]", idx);
9058 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9059 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9060 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9061 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9062 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9063 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9064 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9065 for (i=0; i<smb_NumServerThreads; i++)
9066 NCBreturns[i][idx] = retHandle;
9067 bufp = smb_GetPacket();
9068 bufp->spacep = cm_GetSpace();
9072 /* listen for new connections */
9073 void smb_Listener(void *parmp)
9079 afs_uint32 session, thread;
9080 smb_vc_t *vcp = NULL;
9082 char rname[NCBNAMSZ+1];
9083 char cname[MAX_COMPUTERNAME_LENGTH+1];
9084 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9085 INT_PTR lana = (INT_PTR) parmp;
9086 char eventName[MAX_PATH];
9087 int bridgeCount = 0;
9088 int nowildCount = 0;
9090 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9091 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9092 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9093 thrd_ResetEvent(ListenerShutdown[lana]);
9095 ncbp = smb_GetNCB();
9097 /* retrieve computer name */
9098 GetComputerName(cname, &cnamelen);
9101 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9102 memset(ncbp, 0, sizeof(NCB));
9105 ncbp->ncb_command = NCBLISTEN;
9106 ncbp->ncb_rto = 0; /* No receive timeout */
9107 ncbp->ncb_sto = 0; /* No send timeout */
9109 /* pad out with spaces instead of null termination */
9110 len = (long)strlen(smb_localNamep);
9111 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9112 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9114 strcpy(ncbp->ncb_callname, "*");
9115 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9117 ncbp->ncb_lana_num = (UCHAR)lana;
9119 code = Netbios(ncbp);
9121 if (code == NRC_NAMERR) {
9122 /* An smb shutdown or Vista resume must have taken place */
9124 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9125 ncbp->ncb_lana_num);
9126 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9128 if (lock_TryMutex(&smb_StartedLock)) {
9129 lana_list.lana[i] = LANA_INVALID;
9130 lock_ReleaseMutex(&smb_StartedLock);
9133 } else if (code == NRC_BRIDGE || code != 0) {
9134 int lanaRemaining = 0;
9136 if (code == NRC_BRIDGE) {
9137 if (++bridgeCount <= 5) {
9138 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9141 } else if (code == NRC_NOWILD) {
9142 if (++nowildCount <= 5) {
9143 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9145 if (bridgeCount > 0) {
9146 memset(ncbp, 0, sizeof(*ncbp));
9147 ncbp->ncb_command = NCBADDNAME;
9148 ncbp->ncb_lana_num = (UCHAR)lana;
9149 /* pad out with spaces instead of null termination */
9150 len = (long)strlen(smb_localNamep);
9151 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9152 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9153 code = Netbios(ncbp);
9159 while (!lock_TryMutex(&smb_StartedLock)) {
9160 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9166 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9167 ncbp->ncb_lana_num, ncb_error_string(code));
9168 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9169 ncbp->ncb_lana_num, ncb_error_string(code));
9171 for (i = 0; i < lana_list.length; i++) {
9172 if (lana_list.lana[i] == lana) {
9173 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9174 lana_list.lana[i] = LANA_INVALID;
9176 if (lana_list.lana[i] != LANA_INVALID)
9180 if (lanaRemaining == 0) {
9181 cm_VolStatus_Network_Stopped(cm_NetbiosName
9186 smb_ListenerState = SMB_LISTENER_STOPPED;
9187 smb_LANadapter = LANA_INVALID;
9188 lana_list.length = 0;
9190 lock_ReleaseMutex(&smb_StartedLock);
9194 else if (code != 0) {
9195 char tbuffer[AFSPATHMAX];
9197 /* terminate silently if shutdown flag is set */
9198 while (!lock_TryMutex(&smb_StartedLock)) {
9199 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9205 "NCBLISTEN lana=%d failed with code %d [%s]",
9206 ncbp->ncb_lana_num, code, ncb_error_string(code));
9208 "Client exiting due to network failure. Please restart client.\n");
9211 "Client exiting due to network failure. Please restart client.\n"
9212 "NCBLISTEN lana=%d failed with code %d [%s]",
9213 ncbp->ncb_lana_num, code, ncb_error_string(code));
9215 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9216 MB_OK|MB_SERVICE_NOTIFICATION);
9217 osi_panic(tbuffer, __FILE__, __LINE__);
9219 lock_ReleaseMutex(&smb_StartedLock);
9224 /* a successful packet received. clear bridge error count */
9228 /* check for remote conns */
9229 /* first get remote name and insert null terminator */
9230 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9231 for (i=NCBNAMSZ; i>0; i--) {
9232 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9238 /* compare with local name */
9240 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9241 flags |= SMB_VCFLAG_REMOTECONN;
9244 lock_ObtainMutex(&smb_ListenerLock);
9246 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9247 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9249 /* now ncbp->ncb_lsn is the connection ID */
9250 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9251 if (vcp->session == 0) {
9252 /* New generation */
9253 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9256 /* Log session startup */
9258 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9259 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9260 #endif /* NOTSERVICE */
9261 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9262 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9264 if (reportSessionStartups) {
9265 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9268 lock_ObtainMutex(&vcp->mx);
9269 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9270 vcp->flags |= flags;
9271 lock_ReleaseMutex(&vcp->mx);
9273 /* Allocate slot in session arrays */
9274 /* Re-use dead session if possible, otherwise add one more */
9275 /* But don't look at session[0], it is reserved */
9276 lock_ObtainWrite(&smb_globalLock);
9277 for (session = 1; session < numSessions; session++) {
9278 if (dead_sessions[session]) {
9279 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9280 dead_sessions[session] = FALSE;
9284 lock_ReleaseWrite(&smb_globalLock);
9286 /* We are re-using an existing VC because the lsn and lana
9288 session = vcp->session;
9290 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9292 /* Log session startup */
9294 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9295 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9296 #endif /* NOTSERVICE */
9297 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9298 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9300 if (reportSessionStartups) {
9301 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9305 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9306 unsigned long code = CM_ERROR_ALLBUSY;
9307 smb_packet_t * outp = smb_GetPacket();
9308 unsigned char *outWctp;
9311 smb_FormatResponsePacket(vcp, NULL, outp);
9314 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9315 unsigned long NTStatus;
9316 smb_MapNTError(code, &NTStatus);
9317 outWctp = outp->wctp;
9318 smbp = (smb_t *) &outp->data;
9322 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9323 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9324 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9325 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9326 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9328 unsigned short errCode;
9329 unsigned char errClass;
9330 smb_MapCoreError(code, vcp, &errCode, &errClass);
9331 outWctp = outp->wctp;
9332 smbp = (smb_t *) &outp->data;
9336 smbp->errLow = (unsigned char) (errCode & 0xff);
9337 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9338 smbp->rcls = errClass;
9341 smb_SendPacket(vcp, outp);
9342 smb_FreePacket(outp);
9344 lock_ObtainMutex(&vcp->mx);
9345 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9346 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9348 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9349 lock_ReleaseMutex(&vcp->mx);
9350 lock_ObtainWrite(&smb_globalLock);
9351 dead_sessions[vcp->session] = TRUE;
9352 lock_ReleaseWrite(&smb_globalLock);
9353 smb_CleanupDeadVC(vcp);
9355 lock_ReleaseMutex(&vcp->mx);
9358 /* assert that we do not exceed the maximum number of sessions or NCBs.
9359 * we should probably want to wait for a session to be freed in case
9362 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9363 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9365 lock_ObtainMutex(&vcp->mx);
9366 vcp->session = session;
9367 lock_ReleaseMutex(&vcp->mx);
9368 lock_ObtainWrite(&smb_globalLock);
9369 LSNs[session] = ncbp->ncb_lsn;
9370 lanas[session] = ncbp->ncb_lana_num;
9371 lock_ReleaseWrite(&smb_globalLock);
9373 if (session == numSessions) {
9374 /* Add new NCB for new session */
9375 char eventName[MAX_PATH];
9377 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9379 InitNCBslot(numNCBs);
9380 lock_ObtainWrite(&smb_globalLock);
9382 lock_ReleaseWrite(&smb_globalLock);
9383 thrd_SetEvent(NCBavails[0]);
9384 thrd_SetEvent(NCBevents[0]);
9385 for (thread = 0; thread < smb_NumServerThreads; thread++)
9386 thrd_SetEvent(NCBreturns[thread][0]);
9387 /* Also add new session event */
9388 sprintf(eventName, "SessionEvents[%d]", session);
9389 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9390 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9391 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9392 lock_ObtainWrite(&smb_globalLock);
9394 lock_ReleaseWrite(&smb_globalLock);
9395 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9396 thrd_SetEvent(SessionEvents[0]);
9398 thrd_SetEvent(SessionEvents[session]);
9404 lock_ReleaseMutex(&smb_ListenerLock);
9405 } /* dispatch while loop */
9409 thrd_SetEvent(ListenerShutdown[lana]);
9414 configureBackConnectionHostNames(void)
9416 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9417 * there is a restriction on the use of SMB authentication on loopback connections.
9418 * There are two work arounds available:
9420 * (1) We can disable the check for matching host names. This does not
9422 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9423 * "DisableLoopbackCheck"=dword:00000001
9425 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9426 * does require a reboot:
9427 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9428 * "BackConnectionHostNames"=multi-sz
9430 * The algorithm will be:
9431 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9432 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9433 * (2b1) and check to see if DisableLoopbackCheck is set.
9434 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9435 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9436 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9437 * check for the UnsetDisableLoopbackCheck value.
9438 * If set, set the DisableLoopbackCheck flag to 0x0
9439 * and delete the UnsetDisableLoopbackCheck value
9441 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9442 * force Windows to use the loopback authentication mechanism for the specified
9445 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9446 * service session that set it.
9452 DWORD dwSize, dwAllocSize;
9454 PBYTE pHostNames = NULL, pName = NULL;
9455 BOOL bNameFound = FALSE;
9456 static BOOL bLoopbackCheckDisabled = FALSE;
9458 /* BackConnectionHostNames and DisableLoopbackCheck */
9459 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9460 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9463 &hkMSV10) == ERROR_SUCCESS )
9465 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9466 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9467 (dwType == REG_MULTI_SZ))
9469 dwAllocSize += 1 /* in case the source string is not nul terminated */
9470 + (DWORD)strlen(cm_NetbiosName) + 2;
9471 pHostNames = malloc(dwAllocSize);
9472 dwSize = dwAllocSize;
9473 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9474 pHostNames, &dwSize) == ERROR_SUCCESS)
9476 for (pName = pHostNames;
9477 (pName - pHostNames < (int) dwSize) && *pName ;
9478 pName += strlen(pName) + 1)
9480 if ( !stricmp(pName, cm_NetbiosName) ) {
9488 if ( !bNameFound ) {
9489 size_t size = strlen(cm_NetbiosName) + 2;
9490 if ( !pHostNames ) {
9491 pHostNames = malloc(size);
9494 StringCbCopyA(pName, size, cm_NetbiosName);
9496 *pName = '\0'; /* add a second nul terminator */
9498 dwType = REG_MULTI_SZ;
9499 dwSize = (DWORD)(pName - pHostNames + 1);
9500 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9502 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9503 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9506 &hkLsa) == ERROR_SUCCESS )
9508 dwSize = sizeof(DWORD);
9509 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9512 dwSize = sizeof(DWORD);
9514 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9516 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9517 AFSREG_CLT_OPENAFS_SUBKEY,
9520 REG_OPTION_NON_VOLATILE,
9524 NULL) == ERROR_SUCCESS) {
9527 dwSize = sizeof(DWORD);
9529 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9530 bLoopbackCheckDisabled = TRUE;
9531 RegCloseKey(hkClient);
9536 } else if (!bLoopbackCheckDisabled) {
9537 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9538 AFSREG_CLT_OPENAFS_SUBKEY,
9541 REG_OPTION_NON_VOLATILE,
9545 NULL) == ERROR_SUCCESS) {
9547 dwSize = sizeof(DWORD);
9548 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9550 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9551 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9554 &hkLsa) == ERROR_SUCCESS )
9556 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9560 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9561 RegCloseKey(hkClient);
9570 RegCloseKey(hkMSV10);
9576 configureExtendedSMBSessionTimeouts(void)
9579 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9580 * new functionality:
9582 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9583 * "ReconnectableServers" REG_MULTI_SZ
9584 * "ExtendedSessTimeout" REG_DWORD (seconds)
9585 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9587 * These values can be used to prevent the smb redirector from timing out
9588 * smb connection to the afs smb server prematurely.
9592 DWORD dwSize, dwAllocSize;
9594 PBYTE pHostNames = NULL, pName = NULL;
9595 BOOL bNameFound = FALSE;
9597 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9598 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9601 &hkLanMan) == ERROR_SUCCESS )
9603 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9604 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9605 (dwType == REG_MULTI_SZ))
9607 dwAllocSize += 1 /* in case the source string is not nul terminated */
9608 + (DWORD)strlen(cm_NetbiosName) + 2;
9609 pHostNames = malloc(dwAllocSize);
9610 dwSize = dwAllocSize;
9611 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9612 pHostNames, &dwSize) == ERROR_SUCCESS)
9614 for (pName = pHostNames;
9615 (pName - pHostNames < (int) dwSize) && *pName ;
9616 pName += strlen(pName) + 1)
9618 if ( !stricmp(pName, cm_NetbiosName) ) {
9626 if ( !bNameFound ) {
9627 size_t size = strlen(cm_NetbiosName) + 2;
9628 if ( !pHostNames ) {
9629 pHostNames = malloc(size);
9632 StringCbCopyA(pName, size, cm_NetbiosName);
9634 *pName = '\0'; /* add a second nul terminator */
9636 dwType = REG_MULTI_SZ;
9637 dwSize = (DWORD)(pName - pHostNames + 1);
9638 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9646 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9647 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9648 (dwType == REG_MULTI_SZ))
9650 dwAllocSize += 1 /* in case the source string is not nul terminated */
9651 + (DWORD)strlen(cm_NetbiosName) + 2;
9652 pHostNames = malloc(dwAllocSize);
9653 dwSize = dwAllocSize;
9654 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9655 pHostNames, &dwSize) == ERROR_SUCCESS)
9657 for (pName = pHostNames;
9658 (pName - pHostNames < (int) dwSize) && *pName ;
9659 pName += strlen(pName) + 1)
9661 if ( !stricmp(pName, cm_NetbiosName) ) {
9669 if ( !bNameFound ) {
9670 size_t size = strlen(cm_NetbiosName) + 2;
9671 if ( !pHostNames ) {
9672 pHostNames = malloc(size);
9675 StringCbCopyA(pName, size, cm_NetbiosName);
9677 *pName = '\0'; /* add a second nul terminator */
9679 dwType = REG_MULTI_SZ;
9680 dwSize = (DWORD)(pName - pHostNames + 1);
9681 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9689 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9690 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9691 (dwType != REG_DWORD))
9694 dwSize = sizeof(dwValue);
9695 dwValue = 600; /* 10 minutes */
9696 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9698 RegCloseKey(hkLanMan);
9703 smb_LanAdapterChangeThread(void *param)
9706 * Give the IPAddrDaemon thread a chance
9707 * to block before we trigger.
9710 smb_LanAdapterChange(0);
9713 void smb_SetLanAdapterChangeDetected(void)
9718 lock_ObtainMutex(&smb_StartedLock);
9720 if (!powerStateSuspended) {
9721 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9722 NULL, 0, &lpid, "smb_LanAdapterChange");
9723 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9724 thrd_CloseHandle(phandle);
9727 smb_LanAdapterChangeDetected = 1;
9728 lock_ReleaseMutex(&smb_StartedLock);
9731 void smb_LanAdapterChange(int locked) {
9732 lana_number_t lanaNum;
9734 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9736 LANA_ENUM temp_list;
9741 afsi_log("smb_LanAdapterChange");
9744 lock_ObtainMutex(&smb_StartedLock);
9746 smb_LanAdapterChangeDetected = 0;
9748 if (!powerStateSuspended &&
9749 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9750 LANA_NETBIOS_NAME_FULL)) &&
9751 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9752 if ( isGateway != bGateway ) {
9753 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9754 smb_LANadapter, lanaNum, isGateway, bGateway);
9756 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9757 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9758 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9761 NCB *ncbp = smb_GetNCB();
9762 ncbp->ncb_command = NCBENUM;
9763 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9764 ncbp->ncb_length = sizeof(temp_list);
9765 code = Netbios(ncbp);
9767 if (temp_list.length != lana_list.length) {
9768 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9769 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9772 for (i=0; i<lana_list.length; i++) {
9773 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9774 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9775 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9787 smb_StopListeners(1);
9788 smb_RestartListeners(1);
9791 lock_ReleaseMutex(&smb_StartedLock);
9794 /* initialize Netbios */
9795 int smb_NetbiosInit(int locked)
9798 int i, lana, code, l;
9800 int delname_tried=0;
9803 lana_number_t lanaNum;
9806 lock_ObtainMutex(&smb_StartedLock);
9808 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9809 smb_ListenerState != SMB_LISTENER_STOPPED) {
9812 lock_ReleaseMutex(&smb_StartedLock);
9815 /* setup the NCB system */
9816 ncbp = smb_GetNCB();
9818 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9819 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9820 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9822 if (smb_LANadapter != LANA_INVALID)
9823 afsi_log("LAN adapter number %d", smb_LANadapter);
9825 afsi_log("LAN adapter number not determined");
9828 afsi_log("Set for gateway service");
9830 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9832 /* something went horribly wrong. We can't proceed without a netbios name */
9834 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9835 osi_panic(buf, __FILE__, __LINE__);
9838 /* remember the name */
9839 len = (int)strlen(cm_NetbiosName);
9841 free(smb_localNamep);
9842 smb_localNamep = malloc(len+1);
9843 strcpy(smb_localNamep, cm_NetbiosName);
9844 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9846 /* Also copy the value to the client character encoded string */
9847 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9849 if (smb_LANadapter == LANA_INVALID) {
9850 ncbp->ncb_command = NCBENUM;
9851 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9852 ncbp->ncb_length = sizeof(lana_list);
9853 code = Netbios(ncbp);
9855 afsi_log("Netbios NCBENUM error code %d", code);
9856 osi_panic(s, __FILE__, __LINE__);
9860 lana_list.length = 1;
9861 lana_list.lana[0] = smb_LANadapter;
9864 for (i = 0; i < lana_list.length; i++) {
9865 /* reset the adaptor: in Win32, this is required for every process, and
9866 * acts as an init call, not as a real hardware reset.
9868 ncbp->ncb_command = NCBRESET;
9869 ncbp->ncb_callname[0] = 100;
9870 ncbp->ncb_callname[2] = 100;
9871 ncbp->ncb_lana_num = lana_list.lana[i];
9872 code = Netbios(ncbp);
9874 code = ncbp->ncb_retcode;
9876 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9877 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9879 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9883 /* and declare our name so we can receive connections */
9884 memset(ncbp, 0, sizeof(*ncbp));
9885 len=lstrlen(smb_localNamep);
9886 memset(smb_sharename,' ',NCBNAMSZ);
9887 memcpy(smb_sharename,smb_localNamep,len);
9888 afsi_log("lana_list.length %d", lana_list.length);
9890 /* Keep the name so we can unregister it later */
9891 for (l = 0; l < lana_list.length; l++) {
9892 lana = lana_list.lana[l];
9894 ncbp->ncb_command = NCBADDNAME;
9895 ncbp->ncb_lana_num = lana;
9896 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9897 code = Netbios(ncbp);
9899 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9900 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9902 char name[NCBNAMSZ+1];
9904 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9905 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9909 code = ncbp->ncb_retcode;
9912 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9915 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9916 if (code == NRC_BRIDGE) { /* invalid LANA num */
9917 lana_list.lana[l] = LANA_INVALID;
9920 else if (code == NRC_DUPNAME) {
9921 afsi_log("Name already exists; try to delete it");
9922 memset(ncbp, 0, sizeof(*ncbp));
9923 ncbp->ncb_command = NCBDELNAME;
9924 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9925 ncbp->ncb_lana_num = lana;
9926 code = Netbios(ncbp);
9928 code = ncbp->ncb_retcode;
9930 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9932 if (code != 0 || delname_tried) {
9933 lana_list.lana[l] = LANA_INVALID;
9935 else if (code == 0) {
9936 if (!delname_tried) {
9944 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9945 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9949 smb_LANadapter = lana;
9950 lana_found = 1; /* at least one worked */
9954 osi_assertx(lana_list.length >= 0, "empty lana list");
9956 afsi_log("No valid LANA numbers found!");
9957 lana_list.length = 0;
9958 smb_LANadapter = LANA_INVALID;
9959 smb_ListenerState = SMB_LISTENER_STOPPED;
9960 cm_VolStatus_Network_Stopped(cm_NetbiosName
9967 /* we're done with the NCB now */
9970 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9971 if (lana_list.length > 0)
9972 osi_assert(smb_LANadapter != LANA_INVALID);
9975 lock_ReleaseMutex(&smb_StartedLock);
9977 return (lana_list.length > 0 ? 1 : 0);
9980 void smb_StartListeners(int locked)
9987 lock_ObtainMutex(&smb_StartedLock);
9989 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9991 lock_ReleaseMutex(&smb_StartedLock);
9995 afsi_log("smb_StartListeners");
9996 /* Ensure the AFS Netbios Name is registered to allow loopback access */
9997 configureBackConnectionHostNames();
9999 /* Configure Extended SMB Session Timeouts */
10000 configureExtendedSMBSessionTimeouts();
10002 smb_ListenerState = SMB_LISTENER_STARTED;
10003 cm_VolStatus_Network_Started(cm_NetbiosName
10009 for (i = 0; i < lana_list.length; i++) {
10010 if (lana_list.lana[i] == LANA_INVALID)
10012 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10013 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10014 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10015 thrd_CloseHandle(phandle);
10018 lock_ReleaseMutex(&smb_StartedLock);
10021 void smb_RestartListeners(int locked)
10024 lock_ObtainMutex(&smb_StartedLock);
10026 if (powerStateSuspended)
10027 afsi_log("smb_RestartListeners called while suspended");
10029 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10030 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10031 if (smb_NetbiosInit(1))
10032 smb_StartListeners(1);
10033 } else if (smb_LanAdapterChangeDetected) {
10034 smb_LanAdapterChange(1);
10038 lock_ReleaseMutex(&smb_StartedLock);
10041 void smb_StopListener(NCB *ncbp, int lana, int wait)
10045 memset(ncbp, 0, sizeof(*ncbp));
10046 ncbp->ncb_command = NCBDELNAME;
10047 ncbp->ncb_lana_num = lana;
10048 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10049 code = Netbios(ncbp);
10051 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10052 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10054 /* and then reset the LANA; this will cause the listener threads to exit */
10055 ncbp->ncb_command = NCBRESET;
10056 ncbp->ncb_callname[0] = 100;
10057 ncbp->ncb_callname[2] = 100;
10058 ncbp->ncb_lana_num = lana;
10059 code = Netbios(ncbp);
10061 code = ncbp->ncb_retcode;
10063 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10065 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10069 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10072 void smb_StopListeners(int locked)
10078 lock_ObtainMutex(&smb_StartedLock);
10080 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10082 lock_ReleaseMutex(&smb_StartedLock);
10086 afsi_log("smb_StopListeners");
10087 smb_ListenerState = SMB_LISTENER_STOPPED;
10088 cm_VolStatus_Network_Stopped(cm_NetbiosName
10094 ncbp = smb_GetNCB();
10096 /* Unregister the SMB name */
10097 for (l = 0; l < lana_list.length; l++) {
10098 lana = lana_list.lana[l];
10100 if (lana != LANA_INVALID) {
10101 smb_StopListener(ncbp, lana, TRUE);
10103 /* mark the adapter invalid */
10104 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10108 /* force a re-evaluation of the network adapters */
10109 lana_list.length = 0;
10110 smb_LANadapter = LANA_INVALID;
10113 lock_ReleaseMutex(&smb_StartedLock);
10116 void smb_Init(osi_log_t *logp, int useV3,
10126 EVENT_HANDLE retHandle;
10127 char eventName[MAX_PATH];
10128 int startListeners = 0;
10130 smb_TlsRequestSlot = TlsAlloc();
10132 smb_MBfunc = aMBfunc;
10136 /* Initialize smb_localZero */
10137 myTime.tm_isdst = -1; /* compute whether on DST or not */
10138 myTime.tm_year = 70;
10140 myTime.tm_mday = 1;
10141 myTime.tm_hour = 0;
10144 smb_localZero = mktime(&myTime);
10146 #ifndef USE_NUMERIC_TIME_CONV
10147 /* Initialize kludge-GMT */
10148 smb_CalculateNowTZ();
10149 #endif /* USE_NUMERIC_TIME_CONV */
10150 #ifdef AFS_FREELANCE_CLIENT
10151 /* Make sure the root.afs volume has the correct time */
10152 cm_noteLocalMountPointChange();
10155 /* initialize the remote debugging log */
10158 /* and the global lock */
10159 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10160 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10162 /* Raw I/O data structures */
10163 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10165 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10166 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10168 /* 4 Raw I/O buffers */
10169 smb_RawBufs = calloc(65536,1);
10170 *((char **)smb_RawBufs) = NULL;
10171 for (i=0; i<3; i++) {
10172 char *rawBuf = calloc(65536,1);
10173 *((char **)rawBuf) = smb_RawBufs;
10174 smb_RawBufs = rawBuf;
10177 /* global free lists */
10178 smb_ncbFreeListp = NULL;
10179 smb_packetFreeListp = NULL;
10181 lock_ObtainMutex(&smb_StartedLock);
10182 startListeners = smb_NetbiosInit(1);
10184 /* Initialize listener and server structures */
10186 memset(dead_sessions, 0, sizeof(dead_sessions));
10187 sprintf(eventName, "SessionEvents[0]");
10188 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10189 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10190 afsi_log("Event Object Already Exists: %s", eventName);
10192 smb_NumServerThreads = nThreads;
10193 sprintf(eventName, "NCBavails[0]");
10194 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10195 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10196 afsi_log("Event Object Already Exists: %s", eventName);
10197 sprintf(eventName, "NCBevents[0]");
10198 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10199 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10200 afsi_log("Event Object Already Exists: %s", eventName);
10201 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10202 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10203 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10204 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10205 afsi_log("Event Object Already Exists: %s", eventName);
10206 for (i = 0; i < smb_NumServerThreads; i++) {
10207 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10208 NCBreturns[i][0] = retHandle;
10211 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10212 for (i = 0; i < smb_NumServerThreads; i++) {
10213 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10214 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10215 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10216 afsi_log("Event Object Already Exists: %s", eventName);
10217 InitNCBslot((int)(i+1));
10219 numNCBs = smb_NumServerThreads + 1;
10221 /* Initialize dispatch table */
10222 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10223 /* Prepare the table for unknown operations */
10224 for(i=0; i<= SMB_NOPCODES; i++) {
10225 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10227 /* Fill in the ones we do know */
10228 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10229 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10230 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10231 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10232 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10233 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10234 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10235 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10236 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10237 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10238 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10239 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10240 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10241 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10242 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10243 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10244 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10245 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10246 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10247 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10248 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10249 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10250 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10251 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10252 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10253 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10254 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10255 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10256 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10257 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10258 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10259 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10260 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10261 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10262 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10263 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10264 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10265 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10266 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10267 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10268 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10269 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10270 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10271 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10272 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10273 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10274 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10275 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10276 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10277 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10278 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10279 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10280 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10281 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10282 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10283 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10284 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10285 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10286 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10287 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10288 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10289 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10290 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10291 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10292 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10293 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10294 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10295 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10296 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10297 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10298 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10299 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10300 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10301 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10303 /* setup tran 2 dispatch table */
10304 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10305 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10306 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10307 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10308 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10309 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10310 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10311 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10312 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10313 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10314 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10315 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10316 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10317 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10318 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10319 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10320 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10321 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10323 /* setup the rap dispatch table */
10324 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10325 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10326 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10327 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10328 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10332 /* if we are doing SMB authentication we have register outselves as a logon process */
10333 if (smb_authType != SMB_AUTH_NONE) {
10334 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10335 LSA_STRING afsProcessName;
10336 LSA_OPERATIONAL_MODE dummy; /*junk*/
10338 afsProcessName.Buffer = "OpenAFSClientDaemon";
10339 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10340 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10342 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10344 if (nts == STATUS_SUCCESS) {
10345 LSA_STRING packageName;
10346 /* we are registered. Find out the security package id */
10347 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10348 packageName.Length = (USHORT)strlen(packageName.Buffer);
10349 packageName.MaximumLength = packageName.Length + 1;
10350 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10351 if (nts == STATUS_SUCCESS) {
10353 * This code forces Windows to authenticate against the Logon Cache
10354 * first instead of attempting to authenticate against the Domain
10355 * Controller. When the Windows logon cache is enabled this improves
10356 * performance by removing the network access and works around a bug
10357 * seen at sites which are using a MIT Kerberos principal to login
10358 * to machines joined to a non-root domain in a multi-domain forest.
10359 * MsV1_0SetProcessOption was added in Windows XP.
10361 PVOID pResponse = NULL;
10362 ULONG cbResponse = 0;
10363 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10365 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10366 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10367 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10368 OptionsRequest.DisableOptions = FALSE;
10370 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10373 sizeof(OptionsRequest),
10379 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10380 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10383 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10385 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10386 afsi_log("MsV1_0SetProcessOption success");
10388 /* END - code from Larry */
10390 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10391 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10392 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10394 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10396 /* something went wrong. We report the error and revert back to no authentication
10397 because we can't perform any auth requests without a successful lsa handle
10398 or sec package id. */
10399 afsi_log("Reverting to NO SMB AUTH");
10400 smb_authType = SMB_AUTH_NONE;
10403 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10405 /* something went wrong. We report the error and revert back to no authentication
10406 because we can't perform any auth requests without a successful lsa handle
10407 or sec package id. */
10408 afsi_log("Reverting to NO SMB AUTH");
10409 smb_authType = SMB_AUTH_NONE;
10413 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10414 * time prevents the failure of authentication when logged into Windows with an
10415 * external Kerberos principal mapped to a local account.
10417 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10418 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10419 * then the only option is NTLMSSP anyway; so just fallback.
10424 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10425 if (secBlobLength == 0) {
10426 smb_authType = SMB_AUTH_NTLM;
10427 afsi_log("Reverting to SMB AUTH NTLM");
10436 /* Now get ourselves a domain name. */
10437 /* For now we are using the local computer name as the domain name.
10438 * It is actually the domain for local logins, and we are acting as
10439 * a local SMB server.
10441 bufsize = lengthof(smb_ServerDomainName) - 1;
10442 GetComputerNameW(smb_ServerDomainName, &bufsize);
10443 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10444 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10447 /* Start listeners, waiters, servers, and daemons */
10448 if (startListeners)
10449 smb_StartListeners(1);
10451 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10452 NULL, 0, &lpid, "smb_ClientWaiter");
10453 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10454 thrd_CloseHandle(phandle);
10456 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10457 NULL, 0, &lpid, "smb_ServerWaiter");
10458 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10459 thrd_CloseHandle(phandle);
10461 for (i=0; i<smb_NumServerThreads; i++) {
10462 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10463 (void *) i, 0, &lpid, "smb_Server");
10464 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10465 thrd_CloseHandle(phandle);
10468 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10469 NULL, 0, &lpid, "smb_Daemon");
10470 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10471 thrd_CloseHandle(phandle);
10473 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10474 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10475 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10476 thrd_CloseHandle(phandle);
10478 lock_ReleaseMutex(&smb_StartedLock);
10482 void smb_Shutdown(void)
10489 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10491 /* setup the NCB system */
10492 ncbp = smb_GetNCB();
10494 /* Block new sessions by setting shutdown flag */
10495 smbShutdownFlag = 1;
10497 /* Hang up all sessions */
10498 memset((char *)ncbp, 0, sizeof(NCB));
10499 for (i = 1; i < numSessions; i++)
10501 if (dead_sessions[i])
10504 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10505 ncbp->ncb_command = NCBHANGUP;
10506 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10507 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10508 code = Netbios(ncbp);
10509 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10510 if (code == 0) code = ncbp->ncb_retcode;
10512 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10513 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10517 /* Trigger the shutdown of all SMB threads */
10518 for (i = 0; i < smb_NumServerThreads; i++)
10519 thrd_SetEvent(NCBreturns[i][0]);
10521 thrd_SetEvent(NCBevents[0]);
10522 thrd_SetEvent(SessionEvents[0]);
10523 thrd_SetEvent(NCBavails[0]);
10525 for (i = 0;i < smb_NumServerThreads; i++) {
10526 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10527 if (code == WAIT_OBJECT_0) {
10530 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10531 thrd_SetEvent(NCBreturns[i--][0]);
10535 /* Delete Netbios name */
10536 memset((char *)ncbp, 0, sizeof(NCB));
10537 for (i = 0; i < lana_list.length; i++) {
10538 if (lana_list.lana[i] == LANA_INVALID) continue;
10539 ncbp->ncb_command = NCBDELNAME;
10540 ncbp->ncb_lana_num = lana_list.lana[i];
10541 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10542 code = Netbios(ncbp);
10544 code = ncbp->ncb_retcode;
10546 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10547 ncbp->ncb_lana_num, code);
10552 /* Release the reference counts held by the VCs */
10553 lock_ObtainWrite(&smb_rctLock);
10554 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10559 if (vcp->magic != SMB_VC_MAGIC)
10560 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10561 __FILE__, __LINE__);
10563 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10565 if (fidp->scp != NULL) {
10568 lock_ReleaseWrite(&smb_rctLock);
10569 lock_ObtainMutex(&fidp->mx);
10570 if (fidp->scp != NULL) {
10573 lock_ObtainWrite(&scp->rw);
10574 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10575 lock_ReleaseWrite(&scp->rw);
10576 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10577 cm_ReleaseSCache(scp);
10579 lock_ReleaseMutex(&fidp->mx);
10580 lock_ObtainWrite(&smb_rctLock);
10584 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10586 smb_ReleaseVCNoLock(tidp->vcp);
10588 cm_user_t *userp = tidp->userp;
10589 tidp->userp = NULL;
10590 cm_ReleaseUser(userp);
10594 lock_ReleaseWrite(&smb_rctLock);
10596 TlsFree(smb_TlsRequestSlot);
10599 /* Get the UNC \\<servername>\<sharename> prefix. */
10600 char *smb_GetSharename()
10605 /* Make sure we have been properly initialized. */
10606 if (smb_localNamep == NULL)
10609 /* Allocate space for \\<servername>\<sharename>, plus the
10612 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10613 name = malloc(len);
10614 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10620 void smb_LogPacket(smb_packet_t *packet)
10624 unsigned length, paramlen, datalen, i, j;
10626 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10628 if (!packet) return;
10630 osi_Log0(smb_logp, "*** SMB packet dump ***");
10632 smbp = (smb_t *) packet->data;
10633 vp = (BYTE *) packet->data;
10635 paramlen = smbp->wct * 2;
10636 datalen = *((WORD *) (smbp->vdata + paramlen));
10637 length = sizeof(*smbp) + paramlen + 1 + datalen;
10639 for (i=0;i < length; i+=16)
10641 memset( buf, ' ', 80 );
10644 itoa( i, buf, 16 );
10646 buf[strlen(buf)] = ' ';
10648 cp = (BYTE*) buf + 7;
10650 for (j=0;j < 16 && (i+j)<length; j++)
10652 *(cp++) = hex[vp[i+j] >> 4];
10653 *(cp++) = hex[vp[i+j] & 0xf];
10663 for (j=0;j < 16 && (i+j)<length;j++)
10665 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10676 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10679 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10681 #endif /* LOG_PACKET */
10684 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10690 smb_username_t *unp;
10691 smb_waitingLockRequest_t *wlrp;
10694 lock_ObtainRead(&smb_rctLock);
10696 sprintf(output, "begin dumping smb_username_t\r\n");
10697 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10698 for (unp = usernamesp; unp; unp=unp->nextp)
10700 cm_ucell_t *ucellp;
10702 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10703 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10704 unp->name ? unp->name : _C("NULL"),
10705 unp->machine ? unp->machine : _C("NULL"));
10706 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10708 sprintf(output, " begin dumping cm_ucell_t\r\n");
10709 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10711 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10712 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",
10713 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10714 ucellp->expirationTime, ucellp->gen,
10716 ucellp->cellp->name);
10717 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10720 sprintf(output, " done dumping cm_ucell_t\r\n");
10721 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10724 sprintf(output, "done dumping smb_username_t\r\n");
10725 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10728 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10729 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10732 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10733 smb_waitingLock_t *lockp;
10735 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10736 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10737 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10739 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10740 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10741 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10742 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10743 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10744 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10746 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10747 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10750 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10751 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10753 sprintf(output, "begin dumping smb_vc_t\r\n");
10754 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10756 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10762 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10763 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10764 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10766 sprintf(output, " begin dumping smb_user_t\r\n");
10767 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10768 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10769 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10770 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10771 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10773 sprintf(output, " done dumping smb_user_t\r\n");
10774 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10776 sprintf(output, " begin dumping smb_tid_t\r\n");
10777 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10778 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10779 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",
10780 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10781 tidp->pathname ? tidp->pathname : _C("NULL"));
10782 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10784 sprintf(output, " done dumping smb_tid_t\r\n");
10785 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10787 sprintf(output, " begin dumping smb_fid_t\r\n");
10788 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10790 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10792 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",
10793 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10794 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10795 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10796 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10799 sprintf(output, " done dumping smb_fid_t\r\n");
10800 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10803 sprintf(output, "done dumping smb_vc_t\r\n");
10804 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10806 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10807 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10809 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10815 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10816 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10817 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10819 sprintf(output, " begin dumping smb_user_t\r\n");
10820 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10821 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10822 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10823 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10824 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10826 sprintf(output, " done dumping smb_user_t\r\n");
10827 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10829 sprintf(output, " begin dumping smb_tid_t\r\n");
10830 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10831 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10832 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",
10833 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10834 tidp->pathname ? tidp->pathname : _C("NULL"));
10835 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10837 sprintf(output, " done dumping smb_tid_t\r\n");
10838 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10840 sprintf(output, " begin dumping smb_fid_t\r\n");
10841 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10843 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10845 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",
10846 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10847 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10848 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10849 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10852 sprintf(output, " done dumping smb_fid_t\r\n");
10853 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10856 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10857 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10860 lock_ReleaseRead(&smb_rctLock);
10864 long smb_IsNetworkStarted(void)
10867 lock_ObtainWrite(&smb_globalLock);
10868 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10869 lock_ReleaseWrite(&smb_globalLock);