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 lock_ReleaseWrite(&smb_rctLock);
1341 cm_ReleaseUser(userp);
1343 smb_ReleaseVCNoLock(vcp);
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_SearchCellFile(cellname, ftemp, 0, 0);
2099 #ifdef AFS_AFSDB_ENV
2100 if (code && cm_dnsEnabled) {
2102 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2108 /* construct the path */
2110 clientchar_t temp[1024];
2112 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2113 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2114 rw ? _C("/.%S/") : _C("/%S/"), temp);
2115 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2125 /* Client-side offline caching policy types */
2126 #define CSC_POLICY_MANUAL 0
2127 #define CSC_POLICY_DOCUMENTS 1
2128 #define CSC_POLICY_PROGRAMS 2
2129 #define CSC_POLICY_DISABLE 3
2131 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2134 clientchar_t policy[1024];
2137 int retval = CSC_POLICY_MANUAL;
2139 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2140 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2143 REG_OPTION_NON_VOLATILE,
2149 len = sizeof(policy);
2150 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2152 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2154 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2156 retval = CSC_POLICY_DOCUMENTS;
2158 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2160 retval = CSC_POLICY_PROGRAMS;
2162 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2164 retval = CSC_POLICY_DISABLE;
2167 RegCloseKey(hkCSCPolicy);
2171 /* find a dir search structure by cookie value, and return it held.
2172 * Must be called with smb_globalLock held.
2174 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2176 smb_dirSearch_t *dsp;
2178 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2179 if (dsp->cookie == cookie) {
2180 if (dsp != smb_firstDirSearchp) {
2181 /* move to head of LRU queue, too, if we're not already there */
2182 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2183 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2184 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2185 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2186 if (!smb_lastDirSearchp)
2187 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2195 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2196 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2197 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2203 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2205 lock_ObtainMutex(&dsp->mx);
2206 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2207 dsp->cookie, dsp, dsp->scp);
2208 dsp->flags |= SMB_DIRSEARCH_DELETE;
2209 if (dsp->scp != NULL) {
2210 lock_ObtainWrite(&dsp->scp->rw);
2211 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2212 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2213 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2214 dsp->scp->bulkStatProgress = hzero;
2216 lock_ReleaseWrite(&dsp->scp->rw);
2218 lock_ReleaseMutex(&dsp->mx);
2221 /* Must be called with the smb_globalLock held */
2222 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2224 cm_scache_t *scp = NULL;
2226 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2227 if (dsp->refCount == 0) {
2228 lock_ObtainMutex(&dsp->mx);
2229 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2230 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2231 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2232 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2233 lock_ReleaseMutex(&dsp->mx);
2234 lock_FinalizeMutex(&dsp->mx);
2236 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2237 dsp->cookie, dsp, scp);
2240 lock_ReleaseMutex(&dsp->mx);
2243 /* do this now to avoid spurious locking hierarchy creation */
2245 cm_ReleaseSCache(scp);
2248 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2250 lock_ObtainWrite(&smb_globalLock);
2251 smb_ReleaseDirSearchNoLock(dsp);
2252 lock_ReleaseWrite(&smb_globalLock);
2255 /* find a dir search structure by cookie value, and return it held */
2256 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2258 smb_dirSearch_t *dsp;
2260 lock_ObtainWrite(&smb_globalLock);
2261 dsp = smb_FindDirSearchNoLock(cookie);
2262 lock_ReleaseWrite(&smb_globalLock);
2266 /* GC some dir search entries, in the address space expected by the specific protocol.
2267 * Must be called with smb_globalLock held; release the lock temporarily.
2269 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2270 void smb_GCDirSearches(int isV3)
2272 smb_dirSearch_t *prevp;
2273 smb_dirSearch_t *dsp;
2274 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2278 victimCount = 0; /* how many have we got so far */
2279 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2280 /* we'll move tp from queue, so
2283 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2284 /* if no one is using this guy, and we're either in the new protocol,
2285 * or we're in the old one and this is a small enough ID to be useful
2286 * to the old protocol, GC this guy.
2288 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2289 /* hold and delete */
2290 lock_ObtainMutex(&dsp->mx);
2291 dsp->flags |= SMB_DIRSEARCH_DELETE;
2292 lock_ReleaseMutex(&dsp->mx);
2293 victimsp[victimCount++] = dsp;
2297 /* don't do more than this */
2298 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2302 /* now release them */
2303 for (i = 0; i < victimCount; i++) {
2304 smb_ReleaseDirSearchNoLock(victimsp[i]);
2308 /* function for allocating a dir search entry. We need these to remember enough context
2309 * since we don't get passed the path from call to call during a directory search.
2311 * Returns a held dir search structure, and bumps the reference count on the vnode,
2312 * since it saves a pointer to the vnode.
2314 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2316 smb_dirSearch_t *dsp;
2322 lock_ObtainWrite(&smb_globalLock);
2325 /* what's the biggest ID allowed in this version of the protocol */
2326 /* TODO: do we really want a non v3 dir search request to wrap
2327 smb_dirSearchCounter? */
2328 maxAllowed = isV3 ? 65535 : 255;
2329 if (smb_dirSearchCounter > maxAllowed)
2330 smb_dirSearchCounter = 1;
2332 start = smb_dirSearchCounter;
2335 /* twice so we have enough tries to find guys we GC after one pass;
2336 * 10 extra is just in case I mis-counted.
2338 if (++counter > 2*maxAllowed+10)
2339 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2341 if (smb_dirSearchCounter > maxAllowed) {
2342 smb_dirSearchCounter = 1;
2344 if (smb_dirSearchCounter == start) {
2346 smb_GCDirSearches(isV3);
2349 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2351 /* don't need to watch for refcount zero and deleted, since
2352 * we haven't dropped the global lock.
2355 ++smb_dirSearchCounter;
2359 dsp = malloc(sizeof(*dsp));
2360 memset(dsp, 0, sizeof(*dsp));
2361 dsp->cookie = smb_dirSearchCounter;
2362 ++smb_dirSearchCounter;
2364 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2365 dsp->lastTime = osi_Time();
2366 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2367 if (!smb_lastDirSearchp)
2368 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2370 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2374 lock_ReleaseWrite(&smb_globalLock);
2378 static smb_packet_t *smb_GetPacket(void)
2382 lock_ObtainWrite(&smb_globalLock);
2383 tbp = smb_packetFreeListp;
2385 smb_packetFreeListp = tbp->nextp;
2386 lock_ReleaseWrite(&smb_globalLock);
2388 tbp = calloc(sizeof(*tbp),1);
2389 tbp->magic = SMB_PACKETMAGIC;
2392 tbp->resumeCode = 0;
2398 tbp->ncb_length = 0;
2401 tbp->stringsp = NULL;
2403 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2408 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2411 tbp = smb_GetPacket();
2412 memcpy(tbp, pkt, sizeof(smb_packet_t));
2413 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2414 tbp->stringsp = NULL;
2416 smb_HoldVC(tbp->vcp);
2420 static NCB *smb_GetNCB(void)
2425 lock_ObtainWrite(&smb_globalLock);
2426 tbp = smb_ncbFreeListp;
2428 smb_ncbFreeListp = tbp->nextp;
2429 lock_ReleaseWrite(&smb_globalLock);
2431 tbp = calloc(sizeof(*tbp),1);
2432 tbp->magic = SMB_NCBMAGIC;
2435 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2437 memset(&tbp->ncb, 0, sizeof(NCB));
2442 static void FreeSMBStrings(smb_packet_t * pkt)
2447 for (s = pkt->stringsp; s; s = ns) {
2451 pkt->stringsp = NULL;
2454 void smb_FreePacket(smb_packet_t *tbp)
2456 smb_vc_t * vcp = NULL;
2457 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2459 lock_ObtainWrite(&smb_globalLock);
2460 tbp->nextp = smb_packetFreeListp;
2461 smb_packetFreeListp = tbp;
2462 tbp->magic = SMB_PACKETMAGIC;
2466 tbp->resumeCode = 0;
2472 tbp->ncb_length = 0;
2474 FreeSMBStrings(tbp);
2475 lock_ReleaseWrite(&smb_globalLock);
2481 static void smb_FreeNCB(NCB *bufferp)
2485 tbp = (smb_ncb_t *) bufferp;
2486 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2488 lock_ObtainWrite(&smb_globalLock);
2489 tbp->nextp = smb_ncbFreeListp;
2490 smb_ncbFreeListp = tbp;
2491 lock_ReleaseWrite(&smb_globalLock);
2494 /* get a ptr to the data part of a packet, and its count */
2495 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2499 unsigned char *afterParmsp;
2501 parmBytes = *smbp->wctp << 1;
2502 afterParmsp = smbp->wctp + parmBytes + 1;
2504 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2505 if (nbytesp) *nbytesp = dataBytes;
2507 /* don't forget to skip the data byte count, since it follows
2508 * the parameters; that's where the "2" comes from below.
2510 return (unsigned char *) (afterParmsp + 2);
2513 /* must set all the returned parameters before playing around with the
2514 * data region, since the data region is located past the end of the
2515 * variable number of parameters.
2517 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2519 unsigned char *afterParmsp;
2521 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2523 *afterParmsp++ = dsize & 0xff;
2524 *afterParmsp = (dsize>>8) & 0xff;
2527 /* return the parm'th parameter in the smbp packet */
2528 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2531 unsigned char *parmDatap;
2533 parmCount = *smbp->wctp;
2535 if (parm >= parmCount) {
2538 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2539 parm, parmCount, smbp->ncb_length);
2540 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2541 parm, parmCount, smbp->ncb_length);
2542 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2543 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2544 osi_panic(s, __FILE__, __LINE__);
2546 parmDatap = smbp->wctp + (2*parm) + 1;
2548 return parmDatap[0] + (parmDatap[1] << 8);
2551 /* return the parm'th parameter in the smbp packet */
2552 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2555 unsigned char *parmDatap;
2557 parmCount = *smbp->wctp;
2559 if (parm >= parmCount) {
2562 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2563 parm, parmCount, smbp->ncb_length);
2564 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2565 parm, parmCount, smbp->ncb_length);
2566 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2567 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2568 osi_panic(s, __FILE__, __LINE__);
2570 parmDatap = smbp->wctp + (2*parm) + 1;
2572 return parmDatap[0];
2575 /* return the parm'th parameter in the smbp packet */
2576 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2579 unsigned char *parmDatap;
2581 parmCount = *smbp->wctp;
2583 if (parm + 1 >= parmCount) {
2586 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2587 parm, parmCount, smbp->ncb_length);
2588 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2589 parm, parmCount, smbp->ncb_length);
2590 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2591 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2592 osi_panic(s, __FILE__, __LINE__);
2594 parmDatap = smbp->wctp + (2*parm) + 1;
2596 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2599 /* return the parm'th parameter in the smbp packet */
2600 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2603 unsigned char *parmDatap;
2605 parmCount = *smbp->wctp;
2607 if (parm * 2 + offset >= parmCount * 2) {
2610 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2611 parm, offset, parmCount, smbp->ncb_length);
2612 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2613 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2614 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2615 parm, offset, parmCount, smbp->ncb_length);
2616 osi_panic(s, __FILE__, __LINE__);
2618 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2620 return parmDatap[0] + (parmDatap[1] << 8);
2623 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2625 unsigned char *parmDatap;
2627 /* make sure we have enough slots */
2628 if (*smbp->wctp <= slot)
2629 *smbp->wctp = slot+1;
2631 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2632 *parmDatap++ = parmValue & 0xff;
2633 *parmDatap = (parmValue>>8) & 0xff;
2636 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2638 unsigned char *parmDatap;
2640 /* make sure we have enough slots */
2641 if (*smbp->wctp <= slot)
2642 *smbp->wctp = slot+2;
2644 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2645 *parmDatap++ = parmValue & 0xff;
2646 *parmDatap++ = (parmValue>>8) & 0xff;
2647 *parmDatap++ = (parmValue>>16) & 0xff;
2648 *parmDatap = (parmValue>>24) & 0xff;
2651 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2653 unsigned char *parmDatap;
2656 /* make sure we have enough slots */
2657 if (*smbp->wctp <= slot)
2658 *smbp->wctp = slot+4;
2660 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2662 *parmDatap++ = *parmValuep++;
2665 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2667 unsigned char *parmDatap;
2669 /* make sure we have enough slots */
2670 if (*smbp->wctp <= slot) {
2671 if (smbp->oddByte) {
2673 *smbp->wctp = slot+1;
2678 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2679 *parmDatap++ = parmValue & 0xff;
2684 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2685 clientchar_t *inPathp)
2687 clientchar_t *lastSlashp;
2689 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2691 *lastComponentp = lastSlashp;
2694 if (inPathp == lastSlashp)
2696 *outPathp++ = *inPathp++;
2705 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2706 char **chainpp, int flags)
2709 afs_uint32 type = *inp++;
2712 * The first byte specifies the type of the input string.
2713 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2717 /* Length Counted */
2718 case 0x1: /* Data Block */
2719 case 0x5: /* Variable Block */
2720 cb = *inp++ << 16 | *inp++;
2723 /* Null-terminated string */
2724 case 0x4: /* ASCII */
2725 case 0x3: /* Pathname */
2726 case 0x2: /* Dialect */
2727 cb = sizeof(pktp->data) - (inp - pktp->data);
2728 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2729 #ifdef DEBUG_UNICODE
2732 cb = sizeof(pktp->data);
2737 return NULL; /* invalid input */
2741 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2742 flags |= SMB_STRF_FORCEASCII;
2745 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2748 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2749 char ** chainpp, int flags)
2754 if (!WANTS_UNICODE(pktp))
2755 flags |= SMB_STRF_FORCEASCII;
2758 cb = sizeof(pktp->data) - (inp - pktp->data);
2759 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2760 #ifdef DEBUG_UNICODE
2763 cb = sizeof(pktp->data);
2765 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2766 flags | SMB_STRF_SRCNULTERM);
2769 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2770 size_t cb, char ** chainpp, int flags)
2773 if (!WANTS_UNICODE(pktp))
2774 flags |= SMB_STRF_FORCEASCII;
2777 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2780 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2781 size_t cch, char ** chainpp, int flags)
2786 if (!WANTS_UNICODE(pktp))
2787 flags |= SMB_STRF_FORCEASCII;
2789 cb = cch * sizeof(wchar_t);
2792 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2796 smb_ParseStringBuf(const unsigned char * bufbase,
2797 cm_space_t ** stringspp,
2798 unsigned char *inp, size_t *pcb_max,
2799 char **chainpp, int flags)
2802 if (!(flags & SMB_STRF_FORCEASCII)) {
2804 cm_space_t * spacep;
2807 if (bufbase && ((inp - bufbase) % 2) != 0) {
2808 inp++; /* unicode strings are always word aligned */
2812 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2814 cch_src = *pcb_max / sizeof(wchar_t);
2818 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2825 spacep = cm_GetSpace();
2826 spacep->nextp = *stringspp;
2827 *stringspp = spacep;
2831 *chainpp = inp + sizeof(wchar_t);
2834 *(spacep->wdata) = 0;
2835 return spacep->wdata;
2838 StringCchCopyNW(spacep->wdata,
2839 lengthof(spacep->wdata),
2840 (const clientchar_t *) inp, cch_src);
2843 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2845 return spacep->wdata;
2849 cm_space_t * spacep;
2852 /* Not using Unicode */
2854 *chainpp = inp + strlen(inp) + 1;
2857 spacep = cm_GetSpace();
2858 spacep->nextp = *stringspp;
2859 *stringspp = spacep;
2861 cchdest = lengthof(spacep->wdata);
2862 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2863 spacep->wdata, cchdest);
2865 return spacep->wdata;
2871 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2873 size_t * plen, int flags)
2879 /* we are only calculating the required size */
2886 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2888 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2889 if (!(flags & SMB_STRF_IGNORENUL))
2890 *plen += sizeof(wchar_t);
2892 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2902 cch_str = cm_ClientStrLen(str);
2903 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2906 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2914 /* if outp != NULL ... */
2916 /* Number of bytes left in the buffer.
2918 If outp lies inside the packet data buffer, we assume that the
2919 buffer is the packet data buffer. Otherwise we assume that the
2920 buffer is sizeof(packet->data).
2923 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2924 align = (int)((outp - pktp->data) % 2);
2925 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2927 align = (int)(((size_t) outp) % 2);
2928 buffersize = (int)sizeof(pktp->data);
2933 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2939 if (*str == _C('\0')) {
2941 if (buffersize < sizeof(wchar_t))
2944 *((wchar_t *) outp) = L'\0';
2945 if (plen && !(flags & SMB_STRF_IGNORENUL))
2946 *plen += sizeof(wchar_t);
2947 return outp + sizeof(wchar_t);
2950 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2952 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2953 osi_LogSaveClientString(smb_logp, str),
2959 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2961 return outp + sizeof(wchar_t) * nchars;
2969 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2972 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2974 return outp + cch_dest;
2978 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2984 tlen = inp[0] + (inp[1]<<8);
2985 inp += 2; /* skip length field */
2988 *chainpp = inp + tlen;
2997 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3001 if (*inp++ != 0x1) return NULL;
3002 tlen = inp[0] + (inp[1]<<8);
3003 inp += 2; /* skip length field */
3006 *chainpp = inp + tlen;
3009 if (lengthp) *lengthp = tlen;
3014 /* format a packet as a response */
3015 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
3020 outp = (smb_t *) op;
3022 /* zero the basic structure through the smb_wct field, and zero the data
3023 * size field, assuming that wct stays zero; otherwise, you have to
3024 * explicitly set the data size field, too.
3026 inSmbp = (smb_t *) inp;
3027 memset(outp, 0, sizeof(smb_t)+2);
3033 outp->com = inSmbp->com;
3034 outp->tid = inSmbp->tid;
3035 outp->pid = inSmbp->pid;
3036 outp->uid = inSmbp->uid;
3037 outp->mid = inSmbp->mid;
3038 outp->res[0] = inSmbp->res[0];
3039 outp->res[1] = inSmbp->res[1];
3040 op->inCom = inSmbp->com;
3042 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3043 #ifdef SEND_CANONICAL_PATHNAMES
3044 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3046 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3048 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3049 outp->flg2 |= SMB_FLAGS2_UNICODE;
3052 /* copy fields in generic packet area */
3053 op->wctp = &outp->wct;
3056 /* send a (probably response) packet; vcp tells us to whom to send it.
3057 * we compute the length by looking at wct and bcc fields.
3059 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3069 ncbp = smb_GetNCB();
3073 memset((char *)ncbp, 0, sizeof(NCB));
3075 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3076 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3077 extra += tp[0] + (tp[1]<<8);
3078 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3079 extra += 3; /* wct and length fields */
3081 ncbp->ncb_length = extra; /* bytes to send */
3082 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3083 ncbp->ncb_lana_num = vcp->lana;
3084 ncbp->ncb_command = NCBSEND; /* op means send data */
3085 ncbp->ncb_buffer = (char *) inp;/* packet */
3086 code = Netbios(ncbp);
3089 const char * s = ncb_error_string(code);
3090 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3091 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3093 lock_ObtainMutex(&vcp->mx);
3094 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3095 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3097 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3098 lock_ReleaseMutex(&vcp->mx);
3099 lock_ObtainWrite(&smb_globalLock);
3100 dead_sessions[vcp->session] = TRUE;
3101 lock_ReleaseWrite(&smb_globalLock);
3102 smb_CleanupDeadVC(vcp);
3104 lock_ReleaseMutex(&vcp->mx);
3112 void smb_MapNTError(long code, unsigned long *NTStatusp)
3114 unsigned long NTStatus;
3116 /* map CM_ERROR_* errors to NT 32-bit status codes */
3117 /* NT Status codes are listed in ntstatus.h not winerror.h */
3121 else if (code == CM_ERROR_NOSUCHCELL) {
3122 NTStatus = 0xC000000FL; /* No such file */
3124 else if (code == CM_ERROR_NOSUCHVOLUME) {
3125 NTStatus = 0xC000000FL; /* No such file */
3127 else if (code == CM_ERROR_TIMEDOUT) {
3129 NTStatus = 0xC00000CFL; /* Sharing Paused */
3131 NTStatus = 0x00000102L; /* Timeout */
3134 else if (code == CM_ERROR_RETRY) {
3135 NTStatus = 0xC000022DL; /* Retry */
3137 else if (code == CM_ERROR_NOACCESS) {
3138 NTStatus = 0xC0000022L; /* Access denied */
3140 else if (code == CM_ERROR_READONLY) {
3141 NTStatus = 0xC00000A2L; /* Write protected */
3143 else if (code == CM_ERROR_NOSUCHFILE ||
3144 code == CM_ERROR_BPLUS_NOMATCH) {
3145 NTStatus = 0xC000000FL; /* No such file */
3147 else if (code == CM_ERROR_NOSUCHPATH) {
3148 NTStatus = 0xC000003AL; /* Object path not found */
3150 else if (code == CM_ERROR_TOOBIG) {
3151 NTStatus = 0xC000007BL; /* Invalid image format */
3153 else if (code == CM_ERROR_INVAL) {
3154 NTStatus = 0xC000000DL; /* Invalid parameter */
3156 else if (code == CM_ERROR_BADFD) {
3157 NTStatus = 0xC0000008L; /* Invalid handle */
3159 else if (code == CM_ERROR_BADFDOP) {
3160 NTStatus = 0xC0000022L; /* Access denied */
3162 else if (code == CM_ERROR_EXISTS) {
3163 NTStatus = 0xC0000035L; /* Object name collision */
3165 else if (code == CM_ERROR_NOTEMPTY) {
3166 NTStatus = 0xC0000101L; /* Directory not empty */
3168 else if (code == CM_ERROR_CROSSDEVLINK) {
3169 NTStatus = 0xC00000D4L; /* Not same device */
3171 else if (code == CM_ERROR_NOTDIR) {
3172 NTStatus = 0xC0000103L; /* Not a directory */
3174 else if (code == CM_ERROR_ISDIR) {
3175 NTStatus = 0xC00000BAL; /* File is a directory */
3177 else if (code == CM_ERROR_BADOP) {
3179 /* I have no idea where this comes from */
3180 NTStatus = 0xC09820FFL; /* SMB no support */
3182 NTStatus = 0xC00000BBL; /* Not supported */
3183 #endif /* COMMENT */
3185 else if (code == CM_ERROR_BADSHARENAME) {
3186 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3188 else if (code == CM_ERROR_NOIPC) {
3190 NTStatus = 0xC0000022L; /* Access Denied */
3192 NTStatus = 0xC000013DL; /* Remote Resources */
3195 else if (code == CM_ERROR_CLOCKSKEW) {
3196 NTStatus = 0xC0000133L; /* Time difference at DC */
3198 else if (code == CM_ERROR_BADTID) {
3199 NTStatus = 0xC0982005L; /* SMB bad TID */
3201 else if (code == CM_ERROR_USESTD) {
3202 NTStatus = 0xC09820FBL; /* SMB use standard */
3204 else if (code == CM_ERROR_QUOTA) {
3205 NTStatus = 0xC0000044L; /* Quota exceeded */
3207 else if (code == CM_ERROR_SPACE) {
3208 NTStatus = 0xC000007FL; /* Disk full */
3210 else if (code == CM_ERROR_ATSYS) {
3211 NTStatus = 0xC0000033L; /* Object name invalid */
3213 else if (code == CM_ERROR_BADNTFILENAME) {
3214 NTStatus = 0xC0000033L; /* Object name invalid */
3216 else if (code == CM_ERROR_WOULDBLOCK) {
3217 NTStatus = 0xC00000D8L; /* Can't wait */
3219 else if (code == CM_ERROR_SHARING_VIOLATION) {
3220 NTStatus = 0xC0000043L; /* Sharing violation */
3222 else if (code == CM_ERROR_LOCK_CONFLICT) {
3223 NTStatus = 0xC0000054L; /* Lock conflict */
3225 else if (code == CM_ERROR_PARTIALWRITE) {
3226 NTStatus = 0xC000007FL; /* Disk full */
3228 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3229 NTStatus = 0xC0000023L; /* Buffer too small */
3231 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3232 NTStatus = 0xC0000035L; /* Object name collision */
3234 else if (code == CM_ERROR_BADPASSWORD) {
3235 NTStatus = 0xC000006DL; /* unknown username or bad password */
3237 else if (code == CM_ERROR_BADLOGONTYPE) {
3238 NTStatus = 0xC000015BL; /* logon type not granted */
3240 else if (code == CM_ERROR_GSSCONTINUE) {
3241 NTStatus = 0xC0000016L; /* more processing required */
3243 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3245 NTStatus = 0xC0000280L; /* reparse point not resolved */
3247 NTStatus = 0xC0000022L; /* Access Denied */
3250 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3251 NTStatus = 0xC0000257L; /* Path Not Covered */
3253 else if (code == CM_ERROR_ALLBUSY) {
3254 NTStatus = 0xC000022DL; /* Retry */
3256 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3257 NTStatus = 0xC000003AL; /* Path not found */
3259 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3260 NTStatus = 0xC0000322L; /* No Kerberos key */
3262 else if (code == CM_ERROR_BAD_LEVEL) {
3263 NTStatus = 0xC0000148L; /* Invalid Level */
3265 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3266 NTStatus = 0xC000007EL; /* Range Not Locked */
3268 else if (code == CM_ERROR_NOSUCHDEVICE) {
3269 NTStatus = 0xC000000EL; /* No Such Device */
3271 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3272 NTStatus = 0xC0000055L; /* Lock Not Granted */
3273 } else if (code == ENOMEM) {
3274 NTStatus = 0xC0000017L; /* Out of Memory */
3276 NTStatus = 0xC0982001L; /* SMB non-specific error */
3279 *NTStatusp = NTStatus;
3280 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3283 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3284 unsigned char *classp)
3286 unsigned char class;
3287 unsigned short error;
3289 /* map CM_ERROR_* errors to SMB errors */
3290 if (code == CM_ERROR_NOSUCHCELL) {
3292 error = 3; /* bad path */
3294 else if (code == CM_ERROR_NOSUCHVOLUME) {
3296 error = 3; /* bad path */
3298 else if (code == CM_ERROR_TIMEDOUT) {
3300 error = 81; /* server is paused */
3302 else if (code == CM_ERROR_RETRY) {
3303 class = 2; /* shouldn't happen */
3306 else if (code == CM_ERROR_NOACCESS) {
3308 error = 4; /* bad access */
3310 else if (code == CM_ERROR_READONLY) {
3312 error = 19; /* read only */
3314 else if (code == CM_ERROR_NOSUCHFILE ||
3315 code == CM_ERROR_BPLUS_NOMATCH) {
3317 error = 2; /* ENOENT! */
3319 else if (code == CM_ERROR_NOSUCHPATH) {
3321 error = 3; /* Bad path */
3323 else if (code == CM_ERROR_TOOBIG) {
3325 error = 11; /* bad format */
3327 else if (code == CM_ERROR_INVAL) {
3328 class = 2; /* server non-specific error code */
3331 else if (code == CM_ERROR_BADFD) {
3333 error = 6; /* invalid file handle */
3335 else if (code == CM_ERROR_BADFDOP) {
3336 class = 1; /* invalid op on FD */
3339 else if (code == CM_ERROR_EXISTS) {
3341 error = 80; /* file already exists */
3343 else if (code == CM_ERROR_NOTEMPTY) {
3345 error = 5; /* delete directory not empty */
3347 else if (code == CM_ERROR_CROSSDEVLINK) {
3349 error = 17; /* EXDEV */
3351 else if (code == CM_ERROR_NOTDIR) {
3352 class = 1; /* bad path */
3355 else if (code == CM_ERROR_ISDIR) {
3356 class = 1; /* access denied; DOS doesn't have a good match */
3359 else if (code == CM_ERROR_BADOP) {
3363 else if (code == CM_ERROR_BADSHARENAME) {
3367 else if (code == CM_ERROR_NOIPC) {
3369 error = 4; /* bad access */
3371 else if (code == CM_ERROR_CLOCKSKEW) {
3372 class = 1; /* invalid function */
3375 else if (code == CM_ERROR_BADTID) {
3379 else if (code == CM_ERROR_USESTD) {
3383 else if (code == CM_ERROR_REMOTECONN) {
3387 else if (code == CM_ERROR_QUOTA) {
3388 if (vcp->flags & SMB_VCFLAG_USEV3) {
3390 error = 39; /* disk full */
3394 error = 5; /* access denied */
3397 else if (code == CM_ERROR_SPACE) {
3398 if (vcp->flags & SMB_VCFLAG_USEV3) {
3400 error = 39; /* disk full */
3404 error = 5; /* access denied */
3407 else if (code == CM_ERROR_PARTIALWRITE) {
3409 error = 39; /* disk full */
3411 else if (code == CM_ERROR_ATSYS) {
3413 error = 2; /* ENOENT */
3415 else if (code == CM_ERROR_WOULDBLOCK) {
3417 error = 33; /* lock conflict */
3419 else if (code == CM_ERROR_LOCK_CONFLICT) {
3421 error = 33; /* lock conflict */
3423 else if (code == CM_ERROR_SHARING_VIOLATION) {
3425 error = 33; /* lock conflict */
3427 else if (code == CM_ERROR_NOFILES) {
3429 error = 18; /* no files in search */
3431 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3433 error = 183; /* Samba uses this */
3435 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3436 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3438 error = 2; /* bad password */
3440 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3442 error = 3; /* bad path */
3451 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3454 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3456 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3457 return CM_ERROR_BADOP;
3461 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3463 unsigned short EchoCount, i;
3464 char *data, *outdata;
3467 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3469 for (i=1; i<=EchoCount; i++) {
3470 data = smb_GetSMBData(inp, &dataSize);
3471 smb_SetSMBParm(outp, 0, i);
3472 smb_SetSMBDataLength(outp, dataSize);
3473 outdata = smb_GetSMBData(outp, NULL);
3474 memcpy(outdata, data, dataSize);
3475 smb_SendPacket(vcp, outp);
3481 /* SMB_COM_READ_RAW */
3482 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3485 long count, minCount, finalCount;
3489 smb_t *smbp = (smb_t*) inp;
3491 cm_user_t *userp = NULL;
3494 char *rawBuf = NULL;
3499 fd = smb_GetSMBParm(inp, 0);
3500 count = smb_GetSMBParm(inp, 3);
3501 minCount = smb_GetSMBParm(inp, 4);
3502 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3504 if (*inp->wctp == 10) {
3505 /* we were sent a request with 64-bit file offsets */
3506 #ifdef AFS_LARGEFILES
3507 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3509 if (LargeIntegerLessThanZero(offset)) {
3510 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3514 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3515 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3518 offset.HighPart = 0;
3522 /* we were sent a request with 32-bit file offsets */
3523 offset.HighPart = 0;
3526 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3527 fd, offset.HighPart, offset.LowPart, count);
3529 fidp = smb_FindFID(vcp, fd, 0);
3533 lock_ObtainMutex(&fidp->mx);
3535 lock_ReleaseMutex(&fidp->mx);
3536 smb_ReleaseFID(fidp);
3537 return CM_ERROR_BADFD;
3540 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3541 lock_ReleaseMutex(&fidp->mx);
3542 smb_CloseFID(vcp, fidp, NULL, 0);
3543 code = CM_ERROR_NOSUCHFILE;
3549 LARGE_INTEGER LOffset, LLength;
3552 key = cm_GenerateKey(vcp->vcID, pid, fd);
3554 LOffset.HighPart = offset.HighPart;
3555 LOffset.LowPart = offset.LowPart;
3556 LLength.HighPart = 0;
3557 LLength.LowPart = count;
3559 lock_ObtainWrite(&fidp->scp->rw);
3560 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3561 lock_ReleaseWrite(&fidp->scp->rw);
3564 lock_ReleaseMutex(&fidp->mx);
3568 lock_ObtainMutex(&smb_RawBufLock);
3570 /* Get a raw buf, from head of list */
3571 rawBuf = smb_RawBufs;
3572 smb_RawBufs = *(char **)smb_RawBufs;
3574 lock_ReleaseMutex(&smb_RawBufLock);
3576 lock_ReleaseMutex(&fidp->mx);
3580 if (fidp->flags & SMB_FID_IOCTL)
3582 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3584 /* Give back raw buffer */
3585 lock_ObtainMutex(&smb_RawBufLock);
3586 *((char **) rawBuf) = smb_RawBufs;
3588 smb_RawBufs = rawBuf;
3589 lock_ReleaseMutex(&smb_RawBufLock);
3592 lock_ReleaseMutex(&fidp->mx);
3593 smb_ReleaseFID(fidp);
3596 lock_ReleaseMutex(&fidp->mx);
3598 userp = smb_GetUserFromVCP(vcp, inp);
3600 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3606 cm_ReleaseUser(userp);
3609 smb_ReleaseFID(fidp);
3613 memset((char *)ncbp, 0, sizeof(NCB));
3615 ncbp->ncb_length = (unsigned short) finalCount;
3616 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3617 ncbp->ncb_lana_num = vcp->lana;
3618 ncbp->ncb_command = NCBSEND;
3619 ncbp->ncb_buffer = rawBuf;
3621 code = Netbios(ncbp);
3623 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3626 /* Give back raw buffer */
3627 lock_ObtainMutex(&smb_RawBufLock);
3628 *((char **) rawBuf) = smb_RawBufs;
3630 smb_RawBufs = rawBuf;
3631 lock_ReleaseMutex(&smb_RawBufLock);
3637 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3639 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3644 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3646 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3651 /* SMB_COM_NEGOTIATE */
3652 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3659 int VistaProtoIndex;
3660 int protoIndex; /* index we're using */
3665 char protocol_array[10][1024]; /* protocol signature of the client */
3666 int caps; /* capabilities */
3669 TIME_ZONE_INFORMATION tzi;
3671 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3674 namep = smb_GetSMBData(inp, &dbytes);
3677 coreProtoIndex = -1; /* not found */
3680 VistaProtoIndex = -1;
3681 while(namex < dbytes) {
3682 osi_Log1(smb_logp, "Protocol %s",
3683 osi_LogSaveString(smb_logp, namep+1));
3684 strcpy(protocol_array[tcounter], namep+1);
3686 /* namep points at the first protocol, or really, a 0x02
3687 * byte preceding the null-terminated ASCII name.
3689 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3690 coreProtoIndex = tcounter;
3692 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3693 v3ProtoIndex = tcounter;
3695 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3696 NTProtoIndex = tcounter;
3698 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3699 VistaProtoIndex = tcounter;
3702 /* compute size of protocol entry */
3703 entryLength = (int)strlen(namep+1);
3704 entryLength += 2; /* 0x02 bytes and null termination */
3706 /* advance over this protocol entry */
3707 namex += entryLength;
3708 namep += entryLength;
3709 tcounter++; /* which proto entry we're looking at */
3712 lock_ObtainMutex(&vcp->mx);
3714 if (VistaProtoIndex != -1) {
3715 protoIndex = VistaProtoIndex;
3716 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3719 if (NTProtoIndex != -1) {
3720 protoIndex = NTProtoIndex;
3721 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3723 else if (v3ProtoIndex != -1) {
3724 protoIndex = v3ProtoIndex;
3725 vcp->flags |= SMB_VCFLAG_USEV3;
3727 else if (coreProtoIndex != -1) {
3728 protoIndex = coreProtoIndex;
3729 vcp->flags |= SMB_VCFLAG_USECORE;
3731 else protoIndex = -1;
3732 lock_ReleaseMutex(&vcp->mx);
3734 if (protoIndex == -1)
3735 return CM_ERROR_INVAL;
3736 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3737 smb_SetSMBParm(outp, 0, protoIndex);
3738 if (smb_authType != SMB_AUTH_NONE) {
3739 smb_SetSMBParmByte(outp, 1,
3740 NEGOTIATE_SECURITY_USER_LEVEL |
3741 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3743 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3745 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3746 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3747 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3748 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3749 /* The session key is not a well documented field however most clients
3750 * will echo back the session key to the server. Currently we are using
3751 * the same value for all sessions. We should generate a random value
3752 * and store it into the vcp
3754 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3755 smb_SetSMBParm(outp, 8, 1);
3757 * Tried changing the capabilities to support for W2K - defect 117695
3758 * Maybe something else needs to be changed here?
3762 smb_SetSMBParmLong(outp, 9, 0x43fd);
3764 smb_SetSMBParmLong(outp, 9, 0x251);
3767 * 32-bit error codes *
3773 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3775 NTNEGOTIATE_CAPABILITY_DFS |
3777 #ifdef AFS_LARGEFILES
3778 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3780 NTNEGOTIATE_CAPABILITY_NTFIND |
3781 NTNEGOTIATE_CAPABILITY_RAWMODE |
3782 NTNEGOTIATE_CAPABILITY_NTSMB;
3784 if ( smb_authType == SMB_AUTH_EXTENDED )
3785 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3788 if ( smb_UseUnicode ) {
3789 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3793 smb_SetSMBParmLong(outp, 9, caps);
3795 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3796 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3797 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3799 GetTimeZoneInformation(&tzi);
3800 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3802 if (smb_authType == SMB_AUTH_NTLM) {
3803 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3804 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3805 /* paste in encryption key */
3806 datap = smb_GetSMBData(outp, NULL);
3807 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3808 /* and the faux domain name */
3809 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3810 datap + MSV1_0_CHALLENGE_LENGTH,
3811 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3812 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3816 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3818 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3820 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3822 datap = smb_GetSMBData(outp, NULL);
3823 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3826 datap += sizeof(smb_ServerGUID);
3827 memcpy(datap, secBlob, secBlobLength);
3831 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3832 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3835 else if (v3ProtoIndex != -1) {
3836 smb_SetSMBParm(outp, 0, protoIndex);
3838 /* NOTE: Extended authentication cannot be negotiated with v3
3839 * therefore we fail over to NTLM
3841 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3842 smb_SetSMBParm(outp, 1,
3843 NEGOTIATE_SECURITY_USER_LEVEL |
3844 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3846 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3848 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3849 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3850 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3851 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3852 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3853 smb_SetSMBParm(outp, 7, 1);
3855 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3856 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3857 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3859 GetTimeZoneInformation(&tzi);
3860 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3862 /* NOTE: Extended authentication cannot be negotiated with v3
3863 * therefore we fail over to NTLM
3865 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3866 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3867 smb_SetSMBParm(outp, 12, 0); /* resvd */
3868 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3869 datap = smb_GetSMBData(outp, NULL);
3870 /* paste in a new encryption key */
3871 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3872 /* and the faux domain name */
3873 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3874 datap + MSV1_0_CHALLENGE_LENGTH,
3875 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3877 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3878 smb_SetSMBParm(outp, 12, 0); /* resvd */
3879 smb_SetSMBDataLength(outp, 0);
3882 else if (coreProtoIndex != -1) { /* not really supported anymore */
3883 smb_SetSMBParm(outp, 0, protoIndex);
3884 smb_SetSMBDataLength(outp, 0);
3889 void smb_CheckVCs(void)
3891 smb_vc_t * vcp, *nextp;
3892 smb_packet_t * outp = smb_GetPacket();
3895 lock_ObtainWrite(&smb_rctLock);
3896 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3898 if (vcp->magic != SMB_VC_MAGIC)
3899 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3900 __FILE__, __LINE__);
3902 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3904 smb_HoldVCNoLock(vcp);
3907 * obtain a reference to 'nextp' now because we drop the
3908 * smb_rctLock later and the list contents could change
3909 * or 'vcp' could be destroyed when released.
3913 smb_HoldVCNoLock(nextp);
3915 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3916 smb_ReleaseVCNoLock(vcp);
3920 smb_FormatResponsePacket(vcp, NULL, outp);
3921 smbp = (smb_t *)outp;
3922 outp->inCom = smbp->com = 0x2b /* Echo */;
3930 smb_SetSMBParm(outp, 0, 0);
3931 smb_SetSMBDataLength(outp, 0);
3932 lock_ReleaseWrite(&smb_rctLock);
3934 smb_SendPacket(vcp, outp);
3936 lock_ObtainWrite(&smb_rctLock);
3937 smb_ReleaseVCNoLock(vcp);
3939 lock_ReleaseWrite(&smb_rctLock);
3940 smb_FreePacket(outp);
3943 void smb_Daemon(void *parmp)
3945 afs_uint32 count = 0;
3946 smb_username_t **unpp;
3949 while(smbShutdownFlag == 0) {
3953 if (smbShutdownFlag == 1)
3956 if ((count % 72) == 0) { /* every five minutes */
3958 time_t old_localZero = smb_localZero;
3960 /* Initialize smb_localZero */
3961 myTime.tm_isdst = -1; /* compute whether on DST or not */
3962 myTime.tm_year = 70;
3968 smb_localZero = mktime(&myTime);
3970 #ifndef USE_NUMERIC_TIME_CONV
3971 smb_CalculateNowTZ();
3972 #endif /* USE_NUMERIC_TIME_CONV */
3973 #ifdef AFS_FREELANCE
3974 if ( smb_localZero != old_localZero )
3975 cm_noteLocalMountPointChange();
3981 /* GC smb_username_t objects that will no longer be used */
3983 lock_ObtainWrite(&smb_rctLock);
3984 for ( unpp=&usernamesp; *unpp; ) {
3986 smb_username_t *unp;
3988 lock_ObtainMutex(&(*unpp)->mx);
3989 if ( (*unpp)->refCount > 0 ||
3990 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3991 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3993 else if (!smb_LogoffTokenTransfer ||
3994 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3996 lock_ReleaseMutex(&(*unpp)->mx);
4004 lock_FinalizeMutex(&unp->mx);
4010 cm_ReleaseUser(userp);
4012 unpp = &(*unpp)->nextp;
4015 lock_ReleaseWrite(&smb_rctLock);
4017 /* XXX GC dir search entries */
4021 void smb_WaitingLocksDaemon()
4023 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4024 smb_waitingLock_t *wl, *wlNext;
4027 smb_packet_t *inp, *outp;
4031 while (smbShutdownFlag == 0) {
4032 lock_ObtainWrite(&smb_globalLock);
4033 nwlRequest = smb_allWaitingLocks;
4034 if (nwlRequest == NULL) {
4035 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4040 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4047 lock_ObtainWrite(&smb_globalLock);
4049 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4051 wlRequest = nwlRequest;
4052 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4053 lock_ReleaseWrite(&smb_globalLock);
4057 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4058 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4061 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4062 code = CM_ERROR_LOCK_NOT_GRANTED;
4066 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4068 /* wl->state is either _DONE or _WAITING. _ERROR
4069 would no longer be on the queue. */
4070 code = cm_RetryLock( wl->lockp,
4071 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4074 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4075 } else if (code != CM_ERROR_WOULDBLOCK) {
4076 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4081 if (code == CM_ERROR_WOULDBLOCK) {
4084 if (wlRequest->msTimeout != 0xffffffff
4085 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4097 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4100 scp = wlRequest->scp;
4101 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4105 lock_ObtainWrite(&scp->rw);
4107 for (wl = wlRequest->locks; wl; wl = wlNext) {
4108 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4110 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4111 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4112 wl->LLength, wl->key, 0, NULL, &req);
4114 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4119 lock_ReleaseWrite(&scp->rw);
4123 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4126 for (wl = wlRequest->locks; wl; wl = wlNext) {
4127 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4128 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4133 vcp = wlRequest->vcp;
4134 inp = wlRequest->inp;
4135 outp = wlRequest->outp;
4136 ncbp = smb_GetNCB();
4137 ncbp->ncb_length = inp->ncb_length;
4138 inp->spacep = cm_GetSpace();
4140 /* Remove waitingLock from list */
4141 lock_ObtainWrite(&smb_globalLock);
4142 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4144 lock_ReleaseWrite(&smb_globalLock);
4146 /* Resume packet processing */
4148 smb_SetSMBDataLength(outp, 0);
4149 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4150 outp->resumeCode = code;
4152 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4155 cm_FreeSpace(inp->spacep);
4156 smb_FreePacket(inp);
4157 smb_FreePacket(outp);
4159 cm_ReleaseSCache(wlRequest->scp);
4162 } while (nwlRequest && smbShutdownFlag == 0);
4167 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4169 osi_Log0(smb_logp, "SMB receive get disk attributes");
4171 smb_SetSMBParm(outp, 0, 32000);
4172 smb_SetSMBParm(outp, 1, 64);
4173 smb_SetSMBParm(outp, 2, 1024);
4174 smb_SetSMBParm(outp, 3, 30000);
4175 smb_SetSMBParm(outp, 4, 0);
4176 smb_SetSMBDataLength(outp, 0);
4180 /* SMB_COM_TREE_CONNECT */
4181 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4185 unsigned short newTid;
4186 clientchar_t shareName[AFSPATHMAX];
4187 clientchar_t *sharePath;
4190 clientchar_t *pathp;
4193 osi_Log0(smb_logp, "SMB receive tree connect");
4195 /* parse input parameters */
4198 tbp = smb_GetSMBData(inp, NULL);
4199 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4201 return CM_ERROR_BADSMB;
4203 tp = cm_ClientStrRChr(pathp, '\\');
4205 return CM_ERROR_BADSMB;
4206 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4208 lock_ObtainMutex(&vcp->mx);
4209 newTid = vcp->tidCounter++;
4210 lock_ReleaseMutex(&vcp->mx);
4212 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4213 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4215 return CM_ERROR_BADSMB;
4216 userp = smb_GetUserFromUID(uidp);
4217 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4218 smb_ReleaseUID(uidp);
4220 smb_ReleaseTID(tidp, FALSE);
4221 return CM_ERROR_BADSHARENAME;
4223 lock_ObtainMutex(&tidp->mx);
4224 tidp->userp = userp;
4225 tidp->pathname = sharePath;
4226 lock_ReleaseMutex(&tidp->mx);
4227 smb_ReleaseTID(tidp, FALSE);
4229 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4230 smb_SetSMBParm(rsp, 1, newTid);
4231 smb_SetSMBDataLength(rsp, 0);
4233 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4237 /* set maskp to the mask part of the incoming path.
4238 * Mask is 11 bytes long (8.3 with the dot elided).
4239 * Returns true if succeeds with a valid name, otherwise it does
4240 * its best, but returns false.
4242 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4250 /* starts off valid */
4253 /* mask starts out all blanks */
4254 memset(maskp, ' ', 11);
4257 /* find last backslash, or use whole thing if there is none */
4258 tp = cm_ClientStrRChr(pathp, '\\');
4262 tp++; /* skip slash */
4266 /* names starting with a dot are illegal */
4274 if (tc == '.' || tc == '"')
4282 /* if we get here, tp point after the dot */
4283 up = maskp+8; /* ext goes here */
4290 if (tc == '.' || tc == '"')
4293 /* copy extension if not too long */
4303 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4305 clientchar_t umask[11];
4313 /* XXX redo this, calling cm_MatchMask with a converted mask */
4315 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4319 /* otherwise, we have a valid 8.3 name; see if we have a match,
4320 * treating '?' as a wildcard in maskp (but not in the file name).
4322 tp1 = umask; /* real name, in mask format */
4323 tp2 = maskp; /* mask, in mask format */
4324 for(i=0; i<11; i++) {
4325 tc1 = *tp1++; /* clientchar_t from real name */
4326 tc2 = *tp2++; /* clientchar_t from mask */
4327 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4328 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4331 if (tc2 == '?' && tc1 != ' ')
4338 /* we got a match */
4342 clientchar_t *smb_FindMask(clientchar_t *pathp)
4346 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4349 return tp+1; /* skip the slash */
4351 return pathp; /* no slash, return the entire path */
4354 /* SMB_COM_SEARCH for a volume label
4356 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4357 dispatch function.) */
4358 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4360 clientchar_t *pathp;
4362 clientchar_t mask[12];
4363 unsigned char *statBlockp;
4364 unsigned char initStatBlock[21];
4367 osi_Log0(smb_logp, "SMB receive search volume");
4369 /* pull pathname and stat block out of request */
4370 tp = smb_GetSMBData(inp, NULL);
4371 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4372 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4374 return CM_ERROR_BADSMB;
4375 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4376 osi_assertx(statBlockp != NULL, "null statBlock");
4378 statBlockp = initStatBlock;
4382 /* for returning to caller */
4383 smb_Get8Dot3MaskFromPath(mask, pathp);
4385 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4386 tp = smb_GetSMBData(outp, NULL);
4388 *tp++ = 43; /* bytes in a dir entry */
4389 *tp++ = 0; /* high byte in counter */
4391 /* now marshall the dir entry, starting with the search status */
4392 *tp++ = statBlockp[0]; /* Reserved */
4393 memcpy(tp, mask, 11); tp += 11; /* FileName */
4395 /* now pass back server use info, with 1st byte non-zero */
4397 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4399 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4401 *tp++ = 0x8; /* attribute: volume */
4411 /* 4 byte file size */
4417 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4420 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4421 memset(tp, ' ', 13);
4424 /* set the length of the data part of the packet to 43 + 3, for the dir
4425 * entry plus the 5 and the length fields.
4427 smb_SetSMBDataLength(outp, 46);
4432 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4433 clientchar_t * tidPathp, clientchar_t * relPathp,
4434 cm_user_t *userp, cm_req_t *reqp)
4442 smb_dirListPatch_t *patchp;
4443 smb_dirListPatch_t *npatchp;
4444 clientchar_t path[AFSPATHMAX];
4446 afs_int32 mustFake = 0;
4448 code = cm_FindACLCache(dscp, userp, &rights);
4450 lock_ObtainWrite(&dscp->rw);
4451 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4452 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4453 lock_ReleaseWrite(&dscp->rw);
4454 if (code == CM_ERROR_NOACCESS) {
4462 if (!mustFake) { /* Bulk Stat */
4464 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4466 memset(bsp, 0, sizeof(cm_bulkStat_t));
4468 for (patchp = *dirPatchespp, count=0;
4470 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4471 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4475 if (lock_TryWrite(&tscp->rw)) {
4476 /* we have an entry that we can look at */
4477 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4478 /* we have a callback on it. Don't bother
4479 * fetching this stat entry, since we're happy
4480 * with the info we have.
4482 lock_ReleaseWrite(&tscp->rw);
4483 cm_ReleaseSCache(tscp);
4486 lock_ReleaseWrite(&tscp->rw);
4488 cm_ReleaseSCache(tscp);
4492 bsp->fids[i].Volume = patchp->fid.volume;
4493 bsp->fids[i].Vnode = patchp->fid.vnode;
4494 bsp->fids[i].Unique = patchp->fid.unique;
4496 if (bsp->counter == AFSCBMAX) {
4497 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4498 memset(bsp, 0, sizeof(cm_bulkStat_t));
4502 if (bsp->counter > 0)
4503 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4508 for (patchp = *dirPatchespp; patchp; patchp =
4509 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4511 dptr = patchp->dptr;
4513 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4514 relPathp ? relPathp : _C(""), patchp->dep->name);
4515 reqp->relPathp = path;
4516 reqp->tidPathp = tidPathp;
4518 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4519 reqp->relPathp = reqp->tidPathp = NULL;
4522 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4523 *dptr++ = SMB_ATTR_HIDDEN;
4526 lock_ObtainWrite(&scp->rw);
4527 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4528 lock_ReleaseWrite(&scp->rw);
4530 /* set the attribute */
4531 switch (scp->fileType) {
4532 case CM_SCACHETYPE_DIRECTORY:
4533 case CM_SCACHETYPE_MOUNTPOINT:
4534 case CM_SCACHETYPE_INVALID:
4535 attr = SMB_ATTR_DIRECTORY;
4537 case CM_SCACHETYPE_SYMLINK:
4538 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4539 attr = SMB_ATTR_DIRECTORY;
4541 attr = SMB_ATTR_NORMAL;
4544 /* if we get here we either have a normal file
4545 * or we have a file for which we have never
4546 * received status info. In this case, we can
4547 * check the even/odd value of the entry's vnode.
4548 * odd means it is to be treated as a directory
4549 * and even means it is to be treated as a file.
4551 if (mustFake && (scp->fid.vnode & 0x1))
4552 attr = SMB_ATTR_DIRECTORY;
4554 attr = SMB_ATTR_NORMAL;
4558 /* 1969-12-31 23:59:58 +00*/
4559 dosTime = 0xEBBFBF7D;
4562 shortTemp = (unsigned short) (dosTime & 0xffff);
4563 *((u_short *)dptr) = shortTemp;
4566 /* and copy out date */
4567 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4568 *((u_short *)dptr) = shortTemp;
4571 /* copy out file length */
4572 *((u_long *)dptr) = 0;
4575 lock_ConvertWToR(&scp->rw);
4576 attr = smb_Attributes(scp);
4577 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4578 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4579 attr |= SMB_ATTR_HIDDEN;
4583 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4586 shortTemp = (unsigned short) (dosTime & 0xffff);
4587 *((u_short *)dptr) = shortTemp;
4590 /* and copy out date */
4591 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4592 *((u_short *)dptr) = shortTemp;
4595 /* copy out file length */
4596 *((u_long *)dptr) = scp->length.LowPart;
4598 lock_ReleaseRead(&scp->rw);
4600 cm_ReleaseSCache(scp);
4603 /* now free the patches */
4604 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4605 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4609 /* and mark the list as empty */
4610 *dirPatchespp = NULL;
4616 /* SMB_COM_SEARCH */
4617 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4623 clientchar_t *pathp;
4624 cm_dirEntry_t *dep = 0;
4626 smb_dirListPatch_t *dirListPatchesp;
4627 smb_dirListPatch_t *curPatchp;
4631 osi_hyper_t dirLength;
4632 osi_hyper_t bufferOffset;
4633 osi_hyper_t curOffset;
4635 unsigned char *inCookiep;
4636 smb_dirSearch_t *dsp;
4640 unsigned long clientCookie;
4641 cm_pageHeader_t *pageHeaderp;
4642 cm_user_t *userp = NULL;
4644 clientchar_t mask[12];
4646 long nextEntryCookie;
4647 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4648 char resByte; /* reserved byte from the cookie */
4649 char *op; /* output data ptr */
4650 char *origOp; /* original value of op */
4651 cm_space_t *spacep; /* for pathname buffer */
4655 clientchar_t *tidPathp = 0;
4662 maxCount = smb_GetSMBParm(inp, 0);
4664 dirListPatchesp = NULL;
4666 caseFold = CM_FLAG_CASEFOLD;
4668 tp = smb_GetSMBData(inp, NULL);
4669 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4670 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4672 return CM_ERROR_BADSMB;
4674 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4676 return CM_ERROR_BADSMB;
4678 /* We can handle long names */
4679 if (vcp->flags & SMB_VCFLAG_USENT)
4680 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4682 /* make sure we got a whole search status */
4683 if (dataLength < 21) {
4684 nextCookie = 0; /* start at the beginning of the dir */
4687 attribute = smb_GetSMBParm(inp, 1);
4689 /* handle volume info in another function */
4690 if (attribute & 0x8)
4691 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4693 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4694 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4696 if (*pathp == 0) { /* null pathp, treat as root dir */
4697 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4698 return CM_ERROR_NOFILES;
4702 dsp = smb_NewDirSearch(0);
4703 dsp->attribute = attribute;
4704 smb_Get8Dot3MaskFromPath(mask, pathp);
4705 memcpy(dsp->mask, mask, 12);
4707 /* track if this is likely to match a lot of entries */
4708 if (smb_Is8Dot3StarMask(mask))
4713 /* pull the next cookie value out of the search status block */
4714 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4715 + (inCookiep[16]<<24);
4716 dsp = smb_FindDirSearch(inCookiep[12]);
4718 /* can't find dir search status; fatal error */
4719 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4720 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4721 return CM_ERROR_BADFD;
4723 attribute = dsp->attribute;
4724 resByte = inCookiep[0];
4726 /* copy out client cookie, in host byte order. Don't bother
4727 * interpreting it, since we're just passing it through, anyway.
4729 memcpy(&clientCookie, &inCookiep[17], 4);
4731 memcpy(mask, dsp->mask, 12);
4733 /* assume we're doing a star match if it has continued for more
4739 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4740 nextCookie, dsp->cookie, attribute);
4742 userp = smb_GetUserFromVCP(vcp, inp);
4744 /* try to get the vnode for the path name next */
4745 lock_ObtainMutex(&dsp->mx);
4748 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4752 spacep = inp->spacep;
4753 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4754 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4756 lock_ReleaseMutex(&dsp->mx);
4757 cm_ReleaseUser(userp);
4758 smb_DeleteDirSearch(dsp);
4759 smb_ReleaseDirSearch(dsp);
4760 return CM_ERROR_NOFILES;
4762 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4763 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4765 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4766 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4769 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4772 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4773 cm_ReleaseSCache(scp);
4774 lock_ReleaseMutex(&dsp->mx);
4775 cm_ReleaseUser(userp);
4776 smb_DeleteDirSearch(dsp);
4777 smb_ReleaseDirSearch(dsp);
4778 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4779 return CM_ERROR_PATH_NOT_COVERED;
4781 return CM_ERROR_NOSUCHPATH;
4783 #endif /* DFS_SUPPORT */
4786 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4787 /* we need one hold for the entry we just stored into,
4788 * and one for our own processing. When we're done with this
4789 * function, we'll drop the one for our own processing.
4790 * We held it once from the namei call, and so we do another hold
4794 lock_ObtainWrite(&scp->rw);
4795 dsp->flags |= SMB_DIRSEARCH_BULKST;
4796 lock_ReleaseWrite(&scp->rw);
4799 lock_ReleaseMutex(&dsp->mx);
4801 cm_ReleaseUser(userp);
4802 smb_DeleteDirSearch(dsp);
4803 smb_ReleaseDirSearch(dsp);
4807 /* reserves space for parameter; we'll adjust it again later to the
4808 * real count of the # of entries we returned once we've actually
4809 * assembled the directory listing.
4811 smb_SetSMBParm(outp, 0, 0);
4813 /* get the directory size */
4814 lock_ObtainWrite(&scp->rw);
4815 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4816 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4818 lock_ReleaseWrite(&scp->rw);
4819 cm_ReleaseSCache(scp);
4820 cm_ReleaseUser(userp);
4821 smb_DeleteDirSearch(dsp);
4822 smb_ReleaseDirSearch(dsp);
4826 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4828 dirLength = scp->length;
4830 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4831 curOffset.HighPart = 0;
4832 curOffset.LowPart = nextCookie;
4833 origOp = op = smb_GetSMBData(outp, NULL);
4834 /* and write out the basic header */
4835 *op++ = 5; /* variable block */
4836 op += 2; /* skip vbl block length; we'll fill it in later */
4840 clientchar_t *actualName = NULL;
4841 int free_actualName = 0;
4842 clientchar_t shortName[13];
4843 clientchar_t *shortNameEnd;
4845 /* make sure that curOffset.LowPart doesn't point to the first
4846 * 32 bytes in the 2nd through last dir page, and that it doesn't
4847 * point at the first 13 32-byte chunks in the first dir page,
4848 * since those are dir and page headers, and don't contain useful
4851 temp = curOffset.LowPart & (2048-1);
4852 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4853 /* we're in the first page */
4854 if (temp < 13*32) temp = 13*32;
4857 /* we're in a later dir page */
4858 if (temp < 32) temp = 32;
4861 /* make sure the low order 5 bits are zero */
4864 /* now put temp bits back ito curOffset.LowPart */
4865 curOffset.LowPart &= ~(2048-1);
4866 curOffset.LowPart |= temp;
4868 /* check if we've returned all the names that will fit in the
4871 if (returnedNames >= maxCount) {
4872 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4873 returnedNames, maxCount);
4877 /* check if we've passed the dir's EOF */
4878 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4880 /* see if we can use the bufferp we have now; compute in which page
4881 * the current offset would be, and check whether that's the offset
4882 * of the buffer we have. If not, get the buffer.
4884 thyper.HighPart = curOffset.HighPart;
4885 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4886 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4889 buf_Release(bufferp);
4892 lock_ReleaseWrite(&scp->rw);
4893 code = buf_Get(scp, &thyper, &bufferp);
4894 lock_ObtainMutex(&dsp->mx);
4896 /* now, if we're doing a star match, do bulk fetching of all of
4897 * the status info for files in the dir.
4900 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4902 lock_ObtainWrite(&scp->rw);
4903 lock_ReleaseMutex(&dsp->mx);
4905 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4909 bufferOffset = thyper;
4911 /* now get the data in the cache */
4913 code = cm_SyncOp(scp, bufferp, userp, &req,
4915 CM_SCACHESYNC_NEEDCALLBACK |
4916 CM_SCACHESYNC_READ);
4918 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4922 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4924 if (cm_HaveBuffer(scp, bufferp, 0)) {
4925 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4929 /* otherwise, load the buffer and try again */
4930 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4932 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4933 scp, bufferp, code);
4938 buf_Release(bufferp);
4942 } /* if (wrong buffer) ... */
4944 /* now we have the buffer containing the entry we're interested in; copy
4945 * it out if it represents a non-deleted entry.
4947 entryInDir = curOffset.LowPart & (2048-1);
4948 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4950 /* page header will help tell us which entries are free. Page header
4951 * can change more often than once per buffer, since AFS 3 dir page size
4952 * may be less than (but not more than a buffer package buffer.
4954 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4955 temp &= ~(2048 - 1); /* turn off intra-page bits */
4956 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4958 /* now determine which entry we're looking at in the page. If it is
4959 * free (there's a free bitmap at the start of the dir), we should
4960 * skip these 32 bytes.
4962 slotInPage = (entryInDir & 0x7e0) >> 5;
4963 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4964 /* this entry is free */
4965 numDirChunks = 1; /* only skip this guy */
4969 tp = bufferp->datap + entryInBuffer;
4970 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4972 /* while we're here, compute the next entry's location, too,
4973 * since we'll need it when writing out the cookie into the dir
4976 * XXXX Probably should do more sanity checking.
4978 numDirChunks = cm_NameEntries(dep->name, NULL);
4980 /* compute the offset of the cookie representing the next entry */
4981 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4983 /* Compute 8.3 name if necessary */
4984 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4985 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4988 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4989 actualName = shortName;
4990 free_actualName = 0;
4992 free_actualName = 1;
4995 if (actualName == NULL) {
4996 /* Couldn't convert the name for some reason */
4997 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
4998 osi_LogSaveString(smb_logp, dep->name));
5002 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5003 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5004 osi_LogSaveClientString(smb_logp, actualName));
5006 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5007 /* this is one of the entries to use: it is not deleted
5008 * and it matches the star pattern we're looking for.
5011 /* Eliminate entries that don't match requested
5014 /* no hidden files */
5015 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5016 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5020 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5022 /* We have already done the cm_TryBulkStat above */
5023 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5024 fileType = cm_FindFileType(&fid);
5025 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5026 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5028 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5029 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5030 fileType == CM_SCACHETYPE_DFSLINK ||
5031 fileType == CM_SCACHETYPE_INVALID)
5032 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5037 memcpy(op, mask, 11); op += 11;
5038 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5039 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5040 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5041 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5042 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5043 memcpy(op, &clientCookie, 4); op += 4;
5045 /* now we emit the attribute. This is sort of tricky,
5046 * since we need to really stat the file to find out
5047 * what type of entry we've got. Right now, we're
5048 * copying out data from a buffer, while holding the
5049 * scp locked, so it isn't really convenient to stat
5050 * something now. We'll put in a place holder now,
5051 * and make a second pass before returning this to get
5052 * the real attributes. So, we just skip the data for
5053 * now, and adjust it later. We allocate a patch
5054 * record to make it easy to find this point later.
5055 * The replay will happen at a time when it is safe to
5056 * unlock the directory.
5058 curPatchp = malloc(sizeof(*curPatchp));
5059 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5060 curPatchp->dptr = op;
5061 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5063 /* do hidden attribute here since name won't be around when applying
5067 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5068 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5070 curPatchp->flags = 0;
5072 op += 9; /* skip attr, time, date and size */
5074 /* zero out name area. The spec says to pad with
5075 * spaces, but Samba doesn't, and neither do we.
5079 /* finally, we get to copy out the name; we know that
5080 * it fits in 8.3 or the pattern wouldn't match, but it
5081 * never hurts to be sure.
5083 cm_ClientStringToUtf8(actualName, -1, op, 13);
5084 if (smb_StoreAnsiFilenames)
5086 /* This is a UCHAR field, which is ASCII even if Unicode
5089 /* Uppercase if requested by client */
5090 if (!KNOWS_LONG_NAMES(inp))
5095 /* now, adjust the # of entries copied */
5097 } /* if we're including this name */
5100 if (free_actualName && actualName) {
5105 /* and adjust curOffset to be where the new cookie is */
5106 thyper.HighPart = 0;
5107 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5108 curOffset = LargeIntegerAdd(thyper, curOffset);
5109 } /* while copying data for dir listing */
5111 /* release the mutex */
5112 lock_ReleaseWrite(&scp->rw);
5114 buf_Release(bufferp);
5118 /* apply and free last set of patches; if not doing a star match, this
5119 * will be empty, but better safe (and freeing everything) than sorry.
5121 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5123 /* special return code for unsuccessful search */
5124 if (code == 0 && dataLength < 21 && returnedNames == 0)
5125 code = CM_ERROR_NOFILES;
5127 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5128 returnedNames, code);
5131 smb_DeleteDirSearch(dsp);
5132 smb_ReleaseDirSearch(dsp);
5133 cm_ReleaseSCache(scp);
5134 cm_ReleaseUser(userp);
5138 /* finalize the output buffer */
5139 smb_SetSMBParm(outp, 0, returnedNames);
5140 temp = (long) (op - origOp);
5141 smb_SetSMBDataLength(outp, temp);
5143 /* the data area is a variable block, which has a 5 (already there)
5144 * followed by the length of the # of data bytes. We now know this to
5145 * be "temp," although that includes the 3 bytes of vbl block header.
5146 * Deduct for them and fill in the length field.
5148 temp -= 3; /* deduct vbl block info */
5149 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5150 origOp[1] = (unsigned char)(temp & 0xff);
5151 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5152 if (returnedNames == 0)
5153 smb_DeleteDirSearch(dsp);
5154 smb_ReleaseDirSearch(dsp);
5155 cm_ReleaseSCache(scp);
5156 cm_ReleaseUser(userp);
5161 /* verify that this is a valid path to a directory. I don't know why they
5162 * don't use the get file attributes call.
5164 * SMB_COM_CHECK_DIRECTORY
5166 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5168 clientchar_t *pathp;
5170 cm_scache_t *rootScp;
5171 cm_scache_t *newScp;
5175 clientchar_t *tidPathp;
5181 pdata = smb_GetSMBData(inp, NULL);
5182 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5184 return CM_ERROR_BADSMB;
5185 osi_Log1(smb_logp, "SMB receive check path %S",
5186 osi_LogSaveClientString(smb_logp, pathp));
5188 rootScp = cm_data.rootSCachep;
5190 userp = smb_GetUserFromVCP(vcp, inp);
5192 caseFold = CM_FLAG_CASEFOLD;
5194 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5196 cm_ReleaseUser(userp);
5197 return CM_ERROR_NOSUCHPATH;
5199 code = cm_NameI(rootScp, pathp,
5200 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5201 userp, tidPathp, &req, &newScp);
5204 cm_ReleaseUser(userp);
5209 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5210 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5211 cm_ReleaseSCache(newScp);
5212 cm_ReleaseUser(userp);
5213 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5214 return CM_ERROR_PATH_NOT_COVERED;
5216 return CM_ERROR_NOSUCHPATH;
5218 #endif /* DFS_SUPPORT */
5220 /* now lock the vnode with a callback; returns with newScp locked */
5221 lock_ObtainWrite(&newScp->rw);
5222 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5223 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5225 if (code != CM_ERROR_NOACCESS) {
5226 lock_ReleaseWrite(&newScp->rw);
5227 cm_ReleaseSCache(newScp);
5228 cm_ReleaseUser(userp);
5232 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5235 attrs = smb_Attributes(newScp);
5237 if (!(attrs & SMB_ATTR_DIRECTORY))
5238 code = CM_ERROR_NOTDIR;
5240 lock_ReleaseWrite(&newScp->rw);
5242 cm_ReleaseSCache(newScp);
5243 cm_ReleaseUser(userp);
5247 /* SMB_COM_SET_INFORMATION */
5248 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5250 clientchar_t *pathp;
5252 cm_scache_t *rootScp;
5253 unsigned short attribute;
5255 cm_scache_t *newScp;
5259 clientchar_t *tidPathp;
5265 /* decode basic attributes we're passed */
5266 attribute = smb_GetSMBParm(inp, 0);
5267 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5269 datap = smb_GetSMBData(inp, NULL);
5270 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5272 return CM_ERROR_BADSMB;
5274 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5275 dosTime, attribute);
5277 rootScp = cm_data.rootSCachep;
5279 userp = smb_GetUserFromVCP(vcp, inp);
5281 caseFold = CM_FLAG_CASEFOLD;
5283 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5285 cm_ReleaseUser(userp);
5286 return CM_ERROR_NOSUCHFILE;
5288 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5289 tidPathp, &req, &newScp);
5292 cm_ReleaseUser(userp);
5297 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5298 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5299 cm_ReleaseSCache(newScp);
5300 cm_ReleaseUser(userp);
5301 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5302 return CM_ERROR_PATH_NOT_COVERED;
5304 return CM_ERROR_NOSUCHPATH;
5306 #endif /* DFS_SUPPORT */
5308 /* now lock the vnode with a callback; returns with newScp locked; we
5309 * need the current status to determine what the new status is, in some
5312 lock_ObtainWrite(&newScp->rw);
5313 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5314 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5316 lock_ReleaseWrite(&newScp->rw);
5317 cm_ReleaseSCache(newScp);
5318 cm_ReleaseUser(userp);
5322 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5324 /* Check for RO volume */
5325 if (newScp->flags & CM_SCACHEFLAG_RO) {
5326 lock_ReleaseWrite(&newScp->rw);
5327 cm_ReleaseSCache(newScp);
5328 cm_ReleaseUser(userp);
5329 return CM_ERROR_READONLY;
5332 /* prepare for setattr call */
5335 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5336 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5338 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5339 /* we're told to make a writable file read-only */
5340 attr.unixModeBits = newScp->unixModeBits & ~0222;
5341 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5343 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5344 /* we're told to make a read-only file writable */
5345 attr.unixModeBits = newScp->unixModeBits | 0222;
5346 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5348 lock_ReleaseWrite(&newScp->rw);
5350 /* now call setattr */
5352 code = cm_SetAttr(newScp, &attr, userp, &req);
5356 cm_ReleaseSCache(newScp);
5357 cm_ReleaseUser(userp);
5363 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5365 clientchar_t *pathp;
5367 cm_scache_t *rootScp;
5368 cm_scache_t *newScp, *dscp;
5373 clientchar_t *tidPathp;
5375 clientchar_t *lastComp;
5381 datap = smb_GetSMBData(inp, NULL);
5382 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5384 return CM_ERROR_BADSMB;
5386 if (*pathp == 0) /* null path */
5389 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5390 osi_LogSaveClientString(smb_logp, pathp));
5392 rootScp = cm_data.rootSCachep;
5394 userp = smb_GetUserFromVCP(vcp, inp);
5396 /* we shouldn't need this for V3 requests, but we seem to */
5397 caseFold = CM_FLAG_CASEFOLD;
5399 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5401 cm_ReleaseUser(userp);
5402 return CM_ERROR_NOSUCHFILE;
5406 * XXX Strange hack XXX
5408 * As of Patch 5 (16 July 97), we are having the following problem:
5409 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5410 * requests to look up "desktop.ini" in all the subdirectories.
5411 * This can cause zillions of timeouts looking up non-existent cells
5412 * and volumes, especially in the top-level directory.
5414 * We have not found any way to avoid this or work around it except
5415 * to explicitly ignore the requests for mount points that haven't
5416 * yet been evaluated and for directories that haven't yet been
5419 * We should modify this hack to provide a fake desktop.ini file
5420 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5422 spacep = inp->spacep;
5423 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5424 #ifndef SPECIAL_FOLDERS
5425 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5426 code = cm_NameI(rootScp, spacep->wdata,
5427 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5428 userp, tidPathp, &req, &dscp);
5431 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5432 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5434 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5435 return CM_ERROR_PATH_NOT_COVERED;
5437 return CM_ERROR_NOSUCHPATH;
5439 #endif /* DFS_SUPPORT */
5440 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5441 code = CM_ERROR_NOSUCHFILE;
5442 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5443 cm_buf_t *bp = buf_Find(dscp, &hzero);
5448 code = CM_ERROR_NOSUCHFILE;
5450 cm_ReleaseSCache(dscp);
5452 cm_ReleaseUser(userp);
5457 #endif /* SPECIAL_FOLDERS */
5459 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5460 tidPathp, &req, &newScp);
5462 cm_ReleaseUser(userp);
5467 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5468 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5469 cm_ReleaseSCache(newScp);
5470 cm_ReleaseUser(userp);
5471 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5472 return CM_ERROR_PATH_NOT_COVERED;
5474 return CM_ERROR_NOSUCHPATH;
5476 #endif /* DFS_SUPPORT */
5478 /* now lock the vnode with a callback; returns with newScp locked */
5479 lock_ObtainWrite(&newScp->rw);
5480 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5481 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5483 lock_ReleaseWrite(&newScp->rw);
5484 cm_ReleaseSCache(newScp);
5485 cm_ReleaseUser(userp);
5489 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5491 attrs = smb_Attributes(newScp);
5493 smb_SetSMBParm(outp, 0, attrs);
5495 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5496 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5497 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5498 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5499 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5500 smb_SetSMBParm(outp, 5, 0);
5501 smb_SetSMBParm(outp, 6, 0);
5502 smb_SetSMBParm(outp, 7, 0);
5503 smb_SetSMBParm(outp, 8, 0);
5504 smb_SetSMBParm(outp, 9, 0);
5505 smb_SetSMBDataLength(outp, 0);
5506 lock_ReleaseWrite(&newScp->rw);
5508 cm_ReleaseSCache(newScp);
5509 cm_ReleaseUser(userp);
5514 /* SMB_COM_TREE_DISCONNECT */
5515 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5519 osi_Log0(smb_logp, "SMB receive tree disconnect");
5521 /* find the tree and free it */
5522 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5524 lock_ObtainWrite(&smb_rctLock);
5526 smb_ReleaseTID(tidp, TRUE);
5527 lock_ReleaseWrite(&smb_rctLock);
5534 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5537 clientchar_t *pathp;
5538 clientchar_t *lastNamep;
5547 clientchar_t *tidPathp;
5553 datap = smb_GetSMBData(inp, NULL);
5554 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5556 return CM_ERROR_BADSMB;
5558 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5560 #ifdef DEBUG_VERBOSE
5564 hexpath = osi_HexifyString( pathp );
5565 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5570 if (!cm_IsValidClientString(pathp)) {
5572 clientchar_t * hexp;
5574 hexp = cm_GetRawCharsAlloc(pathp, -1);
5575 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5576 osi_LogSaveClientString(smb_logp, hexp));
5580 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5582 return CM_ERROR_BADNTFILENAME;
5585 share = smb_GetSMBParm(inp, 0);
5586 attribute = smb_GetSMBParm(inp, 1);
5588 spacep = inp->spacep;
5589 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5590 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5591 /* special case magic file name for receiving IOCTL requests
5592 * (since IOCTL calls themselves aren't getting through).
5594 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5595 smb_SetupIoctlFid(fidp, spacep);
5596 smb_SetSMBParm(outp, 0, fidp->fid);
5597 smb_SetSMBParm(outp, 1, 0); /* attrs */
5598 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5599 smb_SetSMBParm(outp, 3, 0);
5600 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5601 smb_SetSMBParm(outp, 5, 0x7fff);
5602 /* pass the open mode back */
5603 smb_SetSMBParm(outp, 6, (share & 0xf));
5604 smb_SetSMBDataLength(outp, 0);
5605 smb_ReleaseFID(fidp);
5609 userp = smb_GetUserFromVCP(vcp, inp);
5611 caseFold = CM_FLAG_CASEFOLD;
5613 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5615 cm_ReleaseUser(userp);
5616 return CM_ERROR_NOSUCHPATH;
5618 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5619 tidPathp, &req, &scp);
5622 cm_ReleaseUser(userp);
5627 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5628 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5629 cm_ReleaseSCache(scp);
5630 cm_ReleaseUser(userp);
5631 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5632 return CM_ERROR_PATH_NOT_COVERED;
5634 return CM_ERROR_NOSUCHPATH;
5636 #endif /* DFS_SUPPORT */
5638 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5640 cm_ReleaseSCache(scp);
5641 cm_ReleaseUser(userp);
5645 /* don't need callback to check file type, since file types never
5646 * change, and namei and cm_Lookup all stat the object at least once on
5647 * a successful return.
5649 if (scp->fileType != CM_SCACHETYPE_FILE) {
5650 cm_ReleaseSCache(scp);
5651 cm_ReleaseUser(userp);
5652 return CM_ERROR_ISDIR;
5655 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5656 osi_assertx(fidp, "null smb_fid_t");
5658 lock_ObtainMutex(&fidp->mx);
5659 if ((share & 0xf) == 0)
5660 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5661 else if ((share & 0xf) == 1)
5662 fidp->flags |= SMB_FID_OPENWRITE;
5664 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5668 fidp->userp = userp;
5670 /* and a pointer to the vnode */
5672 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5673 lock_ObtainWrite(&scp->rw);
5674 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5676 smb_SetSMBParm(outp, 0, fidp->fid);
5677 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5678 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5679 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5680 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5681 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5682 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5683 /* pass the open mode back; XXXX add access checks */
5684 smb_SetSMBParm(outp, 6, (share & 0xf));
5685 smb_SetSMBDataLength(outp, 0);
5686 lock_ReleaseMutex(&fidp->mx);
5687 lock_ReleaseRead(&scp->rw);
5690 cm_Open(scp, 0, userp);
5692 /* send and free packet */
5693 smb_ReleaseFID(fidp);
5694 cm_ReleaseUser(userp);
5695 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5699 typedef struct smb_unlinkRock {
5704 clientchar_t *maskp; /* pointer to the star pattern */
5707 cm_dirEntryList_t * matches;
5710 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5713 smb_unlinkRock_t *rockp;
5716 normchar_t matchName[MAX_PATH];
5720 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5721 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5722 caseFold |= CM_FLAG_8DOT3;
5724 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5725 /* Can't convert name */
5726 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5727 osi_LogSaveString(smb_logp, dep->name));
5731 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5733 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5734 !cm_Is8Dot3(matchName)) {
5735 cm_Gen8Dot3Name(dep, matchName, NULL);
5736 /* 8.3 matches are always case insensitive */
5737 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5740 osi_Log1(smb_logp, "Found match %S",
5741 osi_LogSaveClientString(smb_logp, matchName));
5743 cm_DirEntryListAdd(dep->name, &rockp->matches);
5747 /* If we made a case sensitive exact match, we might as well quit now. */
5748 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5749 code = CM_ERROR_STOPNOW;
5758 /* SMB_COM_DELETE */
5759 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5763 clientchar_t *pathp;
5767 clientchar_t *lastNamep;
5768 smb_unlinkRock_t rock;
5772 clientchar_t *tidPathp;
5776 memset(&rock, 0, sizeof(rock));
5778 attribute = smb_GetSMBParm(inp, 0);
5780 tp = smb_GetSMBData(inp, NULL);
5781 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5783 return CM_ERROR_BADSMB;
5785 osi_Log1(smb_logp, "SMB receive unlink %S",
5786 osi_LogSaveClientString(smb_logp, pathp));
5788 spacep = inp->spacep;
5789 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5791 userp = smb_GetUserFromVCP(vcp, inp);
5793 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5795 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5797 cm_ReleaseUser(userp);
5798 return CM_ERROR_NOSUCHPATH;
5800 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5803 cm_ReleaseUser(userp);
5808 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5809 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5810 cm_ReleaseSCache(dscp);
5811 cm_ReleaseUser(userp);
5812 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5813 return CM_ERROR_PATH_NOT_COVERED;
5815 return CM_ERROR_NOSUCHPATH;
5817 #endif /* DFS_SUPPORT */
5819 /* otherwise, scp points to the parent directory. */
5826 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5828 code = CM_ERROR_NOSUCHFILE;
5831 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5834 thyper.HighPart = 0;
5839 rock.matches = NULL;
5841 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5842 * match. If that fails, we do a case insensitve match.
5844 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5845 !smb_IsStarMask(rock.maskp)) {
5846 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5849 thyper.HighPart = 0;
5850 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5855 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5857 if (code == CM_ERROR_STOPNOW)
5860 if (code == 0 && rock.matches) {
5861 cm_dirEntryList_t * entry;
5863 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5864 normchar_t normalizedName[MAX_PATH];
5866 /* Note: entry->name is a non-normalized name */
5868 osi_Log1(smb_logp, "Unlinking %s",
5869 osi_LogSaveString(smb_logp, entry->name));
5871 /* We assume this works because entry->name was
5872 successfully converted in smb_UnlinkProc() once. */
5873 cm_FsStringToNormString(entry->name, -1,
5874 normalizedName, lengthof(normalizedName));
5876 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5878 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5879 smb_NotifyChange(FILE_ACTION_REMOVED,
5880 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5881 dscp, normalizedName, NULL, TRUE);
5885 cm_DirEntryListFree(&rock.matches);
5889 cm_ReleaseUser(userp);
5892 cm_ReleaseSCache(dscp);
5897 if (code == 0 && !rock.any)
5898 code = CM_ERROR_NOSUCHFILE;
5902 typedef struct smb_renameRock {
5903 cm_scache_t *odscp; /* old dir */
5904 cm_scache_t *ndscp; /* new dir */
5905 cm_user_t *userp; /* user */
5906 cm_req_t *reqp; /* request struct */
5907 smb_vc_t *vcp; /* virtual circuit */
5908 normchar_t *maskp; /* pointer to star pattern of old file name */
5909 int flags; /* tilde, casefold, etc */
5910 clientchar_t *newNamep; /* ptr to the new file's name */
5911 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5912 clientchar_t clOldName[MAX_PATH]; /* client name */
5916 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5919 smb_renameRock_t *rockp;
5922 normchar_t matchName[MAX_PATH];
5924 rockp = (smb_renameRock_t *) vrockp;
5926 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5927 /* Can't convert string */
5928 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
5929 osi_LogSaveString(smb_logp, dep->name));
5933 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5934 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5935 caseFold |= CM_FLAG_8DOT3;
5937 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5939 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5940 !cm_Is8Dot3(matchName)) {
5941 cm_Gen8Dot3Name(dep, matchName, NULL);
5942 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5947 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5948 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5950 code = CM_ERROR_STOPNOW;
5960 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5963 cm_space_t *spacep = NULL;
5964 smb_renameRock_t rock;
5965 cm_scache_t *oldDscp = NULL;
5966 cm_scache_t *newDscp = NULL;
5967 cm_scache_t *tmpscp= NULL;
5968 cm_scache_t *tmpscp2 = NULL;
5969 clientchar_t *oldLastNamep;
5970 clientchar_t *newLastNamep;
5974 clientchar_t *tidPathp;
5978 userp = smb_GetUserFromVCP(vcp, inp);
5979 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5981 cm_ReleaseUser(userp);
5982 return CM_ERROR_NOSUCHPATH;
5986 memset(&rock, 0, sizeof(rock));
5988 spacep = inp->spacep;
5989 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5991 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5992 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5993 userp, tidPathp, &req, &oldDscp);
5995 cm_ReleaseUser(userp);
6000 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6001 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6002 cm_ReleaseSCache(oldDscp);
6003 cm_ReleaseUser(userp);
6004 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6005 return CM_ERROR_PATH_NOT_COVERED;
6007 return CM_ERROR_NOSUCHPATH;
6009 #endif /* DFS_SUPPORT */
6011 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6012 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6013 userp, tidPathp, &req, &newDscp);
6016 cm_ReleaseSCache(oldDscp);
6017 cm_ReleaseUser(userp);
6022 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6023 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6024 cm_ReleaseSCache(oldDscp);
6025 cm_ReleaseSCache(newDscp);
6026 cm_ReleaseUser(userp);
6027 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6028 return CM_ERROR_PATH_NOT_COVERED;
6030 return CM_ERROR_NOSUCHPATH;
6032 #endif /* DFS_SUPPORT */
6035 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6036 * next, get the component names, and lower case them.
6039 /* handle the old name first */
6041 oldLastNamep = oldPathp;
6045 /* and handle the new name, too */
6047 newLastNamep = newPathp;
6051 /* TODO: The old name could be a wildcard. The new name must not be */
6053 /* Check if the file already exists; if so return error */
6054 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6055 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6056 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6058 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6059 osi_LogSaveClientString(smb_logp, newLastNamep));
6061 /* Check if the old and the new names differ only in case. If so return
6062 * success, else return CM_ERROR_EXISTS
6064 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6066 /* This would be a success only if the old file is *as same as* the new file */
6067 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6069 if (tmpscp == tmpscp2)
6072 code = CM_ERROR_EXISTS;
6073 cm_ReleaseSCache(tmpscp2);
6076 code = CM_ERROR_NOSUCHFILE;
6079 /* file exist, do not rename, also fixes move */
6080 osi_Log0(smb_logp, "Can't rename. Target already exists");
6081 code = CM_ERROR_EXISTS;
6086 /* do the vnode call */
6087 rock.odscp = oldDscp;
6088 rock.ndscp = newDscp;
6092 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6094 code = CM_ERROR_NOSUCHFILE;
6097 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6098 rock.newNamep = newLastNamep;
6099 rock.fsOldName[0] = '\0';
6100 rock.clOldName[0] = '\0';
6103 /* Now search the directory for the pattern, and do the appropriate rename when found */
6104 thyper.LowPart = 0; /* search dir from here */
6105 thyper.HighPart = 0;
6107 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6108 if (code == 0 && !rock.any) {
6110 thyper.HighPart = 0;
6111 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6112 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6114 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6116 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6117 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6118 rock.ndscp, rock.newNamep, rock.userp,
6120 /* if the call worked, stop doing the search now, since we
6121 * really only want to rename one file.
6124 osi_Log0(smb_logp, "cm_Rename failure");
6125 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6126 } else if (code == 0) {
6127 code = CM_ERROR_NOSUCHFILE;
6130 /* Handle Change Notification */
6132 * Being lazy, not distinguishing between files and dirs in this
6133 * filter, since we'd have to do a lookup.
6136 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6137 if (oldDscp == newDscp) {
6138 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6139 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6140 filter, oldDscp, rock.clOldName,
6141 newLastNamep, TRUE);
6143 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6144 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6145 filter, oldDscp, rock.clOldName,
6147 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6148 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6149 filter, newDscp, newLastNamep,
6156 cm_ReleaseSCache(tmpscp);
6158 cm_ReleaseUser(userp);
6160 cm_ReleaseSCache(oldDscp);
6162 cm_ReleaseSCache(newDscp);
6170 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6173 cm_space_t *spacep = NULL;
6174 cm_scache_t *oldDscp = NULL;
6175 cm_scache_t *newDscp = NULL;
6176 cm_scache_t *tmpscp= NULL;
6177 cm_scache_t *tmpscp2 = NULL;
6178 cm_scache_t *sscp = NULL;
6179 clientchar_t *oldLastNamep;
6180 clientchar_t *newLastNamep;
6183 clientchar_t *tidPathp;
6187 userp = smb_GetUserFromVCP(vcp, inp);
6189 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6191 cm_ReleaseUser(userp);
6192 return CM_ERROR_NOSUCHPATH;
6197 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6199 spacep = inp->spacep;
6200 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6202 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6203 userp, tidPathp, &req, &oldDscp);
6205 cm_ReleaseUser(userp);
6210 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6211 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6212 cm_ReleaseSCache(oldDscp);
6213 cm_ReleaseUser(userp);
6214 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6215 return CM_ERROR_PATH_NOT_COVERED;
6217 return CM_ERROR_NOSUCHPATH;
6219 #endif /* DFS_SUPPORT */
6221 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6222 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6223 userp, tidPathp, &req, &newDscp);
6225 cm_ReleaseSCache(oldDscp);
6226 cm_ReleaseUser(userp);
6231 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6232 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6233 cm_ReleaseSCache(newDscp);
6234 cm_ReleaseSCache(oldDscp);
6235 cm_ReleaseUser(userp);
6236 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6237 return CM_ERROR_PATH_NOT_COVERED;
6239 return CM_ERROR_NOSUCHPATH;
6241 #endif /* DFS_SUPPORT */
6243 /* Now, although we did two lookups for the two directories (because the same
6244 * directory can be referenced through different paths), we only allow hard links
6245 * within the same directory. */
6246 if (oldDscp != newDscp) {
6247 cm_ReleaseSCache(oldDscp);
6248 cm_ReleaseSCache(newDscp);
6249 cm_ReleaseUser(userp);
6250 return CM_ERROR_CROSSDEVLINK;
6253 /* handle the old name first */
6255 oldLastNamep = oldPathp;
6259 /* and handle the new name, too */
6261 newLastNamep = newPathp;
6265 /* now lookup the old name */
6266 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6267 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6269 cm_ReleaseSCache(oldDscp);
6270 cm_ReleaseSCache(newDscp);
6271 cm_ReleaseUser(userp);
6275 /* Check if the file already exists; if so return error */
6276 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6277 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6278 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6280 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6281 osi_LogSaveClientString(smb_logp, newLastNamep));
6283 /* if the existing link is to the same file, then we return success */
6285 if(sscp == tmpscp) {
6288 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6289 code = CM_ERROR_EXISTS;
6294 cm_ReleaseSCache(tmpscp);
6295 cm_ReleaseSCache(sscp);
6296 cm_ReleaseSCache(newDscp);
6297 cm_ReleaseSCache(oldDscp);
6298 cm_ReleaseUser(userp);
6302 /* now create the hardlink */
6303 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6304 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6305 osi_Log1(smb_logp," Link returns 0x%x", code);
6307 /* Handle Change Notification */
6309 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6310 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6311 smb_NotifyChange(FILE_ACTION_ADDED,
6312 filter, newDscp, newLastNamep,
6317 cm_ReleaseSCache(tmpscp);
6318 cm_ReleaseUser(userp);
6319 cm_ReleaseSCache(sscp);
6320 cm_ReleaseSCache(oldDscp);
6321 cm_ReleaseSCache(newDscp);
6325 /* SMB_COM_RENAME */
6327 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6329 clientchar_t *oldPathp;
6330 clientchar_t *newPathp;
6334 tp = smb_GetSMBData(inp, NULL);
6335 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6337 return CM_ERROR_BADSMB;
6338 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6340 return CM_ERROR_BADSMB;
6342 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6343 osi_LogSaveClientString(smb_logp, oldPathp),
6344 osi_LogSaveClientString(smb_logp, newPathp));
6346 if (!cm_IsValidClientString(newPathp)) {
6348 clientchar_t * hexp;
6350 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6351 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6352 osi_LogSaveClientString(smb_logp, hexp));
6356 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6358 return CM_ERROR_BADNTFILENAME;
6361 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6363 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6369 typedef struct smb_rmdirRock {
6373 normchar_t *maskp; /* pointer to the star pattern */
6376 cm_dirEntryList_t * matches;
6379 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6382 smb_rmdirRock_t *rockp;
6384 normchar_t matchName[MAX_PATH];
6386 rockp = (smb_rmdirRock_t *) vrockp;
6388 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6389 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6390 osi_LogSaveString(smb_logp, dep->name));
6394 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6395 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6397 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6399 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6400 !cm_Is8Dot3(matchName)) {
6401 cm_Gen8Dot3Name(dep, matchName, NULL);
6402 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6407 cm_DirEntryListAdd(dep->name, &rockp->matches);
6414 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6417 clientchar_t *pathp;
6421 clientchar_t *lastNamep;
6422 smb_rmdirRock_t rock;
6426 clientchar_t *tidPathp;
6430 memset(&rock, 0, sizeof(rock));
6432 tp = smb_GetSMBData(inp, NULL);
6433 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6435 return CM_ERROR_BADSMB;
6437 spacep = inp->spacep;
6438 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6440 userp = smb_GetUserFromVCP(vcp, inp);
6442 caseFold = CM_FLAG_CASEFOLD;
6444 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6446 cm_ReleaseUser(userp);
6447 return CM_ERROR_NOSUCHPATH;
6449 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6450 userp, tidPathp, &req, &dscp);
6453 cm_ReleaseUser(userp);
6458 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6459 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6460 cm_ReleaseSCache(dscp);
6461 cm_ReleaseUser(userp);
6462 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6463 return CM_ERROR_PATH_NOT_COVERED;
6465 return CM_ERROR_NOSUCHPATH;
6467 #endif /* DFS_SUPPORT */
6469 /* otherwise, scp points to the parent directory. */
6476 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6478 code = CM_ERROR_NOSUCHFILE;
6481 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6484 thyper.HighPart = 0;
6488 rock.matches = NULL;
6490 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6491 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6492 if (code == 0 && !rock.any) {
6494 thyper.HighPart = 0;
6495 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6496 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6499 if (code == 0 && rock.matches) {
6500 cm_dirEntryList_t * entry;
6502 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6503 clientchar_t clientName[MAX_PATH];
6505 /* We assume this will succeed because smb_RmdirProc()
6506 successfully converted entry->name once above. */
6507 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6509 osi_Log1(smb_logp, "Removing directory %s",
6510 osi_LogSaveString(smb_logp, entry->name));
6512 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6514 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6515 smb_NotifyChange(FILE_ACTION_REMOVED,
6516 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6517 dscp, clientName, NULL, TRUE);
6523 cm_DirEntryListFree(&rock.matches);
6526 cm_ReleaseUser(userp);
6529 cm_ReleaseSCache(dscp);
6531 if (code == 0 && !rock.any)
6532 code = CM_ERROR_NOSUCHFILE;
6541 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6551 fid = smb_GetSMBParm(inp, 0);
6553 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6555 fid = smb_ChainFID(fid, inp);
6556 fidp = smb_FindFID(vcp, fid, 0);
6558 return CM_ERROR_BADFD;
6560 userp = smb_GetUserFromVCP(vcp, inp);
6562 lock_ObtainMutex(&fidp->mx);
6563 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6564 cm_ReleaseUser(userp);
6565 lock_ReleaseMutex(&fidp->mx);
6566 smb_ReleaseFID(fidp);
6567 return CM_ERROR_BADFD;
6570 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6571 lock_ReleaseMutex(&fidp->mx);
6572 cm_ReleaseUser(userp);
6573 smb_CloseFID(vcp, fidp, NULL, 0);
6574 smb_ReleaseFID(fidp);
6575 return CM_ERROR_NOSUCHFILE;
6578 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6579 cm_scache_t * scp = fidp->scp;
6581 lock_ReleaseMutex(&fidp->mx);
6582 code = cm_FSync(scp, userp, &req);
6583 cm_ReleaseSCache(scp);
6585 lock_ReleaseMutex(&fidp->mx);
6589 cm_ReleaseUser(userp);
6590 smb_ReleaseFID(fidp);
6594 struct smb_FullNameRock {
6597 clientchar_t *fullName;
6598 fschar_t *originalName;
6601 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6604 normchar_t matchName[MAX_PATH];
6605 struct smb_FullNameRock *vrockp;
6607 vrockp = (struct smb_FullNameRock *)rockp;
6609 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6610 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6611 osi_LogSaveString(smb_logp, dep->name));
6615 if (!cm_Is8Dot3(matchName)) {
6616 clientchar_t shortName[13];
6618 cm_Gen8Dot3Name(dep, shortName, NULL);
6620 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6621 vrockp->fullName = cm_ClientStrDup(matchName);
6622 vrockp->originalName = cm_FsStrDup(dep->name);
6623 return CM_ERROR_STOPNOW;
6626 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6627 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6628 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6629 vrockp->fullName = cm_ClientStrDup(matchName);
6630 vrockp->originalName = cm_FsStrDup(dep->name);
6631 return CM_ERROR_STOPNOW;
6636 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6637 clientchar_t **newPathp, fschar_t ** originalPathp,
6638 cm_user_t *userp, cm_req_t *reqp)
6640 struct smb_FullNameRock rock;
6643 memset(&rock, 0, sizeof(rock));
6647 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6648 if (code == CM_ERROR_STOPNOW) {
6649 *newPathp = rock.fullName;
6650 *originalPathp = rock.originalName;
6652 *newPathp = cm_ClientStrDup(pathp);
6653 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6657 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6658 afs_uint32 dosTime) {
6661 cm_scache_t *dscp = NULL;
6662 clientchar_t *pathp = NULL;
6663 cm_scache_t * scp = NULL;
6664 cm_scache_t *delscp = NULL;
6665 int nullcreator = 0;
6667 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6668 fidp, fidp->fid, scp, vcp);
6671 lock_ObtainMutex(&fidp->mx);
6672 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6673 lock_ReleaseMutex(&fidp->mx);
6674 osi_Log0(smb_logp, " No user specified. Not closing fid");
6675 return CM_ERROR_BADFD;
6678 userp = fidp->userp; /* no hold required since fidp is held
6679 throughout the function */
6680 lock_ReleaseMutex(&fidp->mx);
6685 lock_ObtainWrite(&smb_rctLock);
6686 if (fidp->deleteOk) {
6687 osi_Log0(smb_logp, " Fid already closed.");
6688 lock_ReleaseWrite(&smb_rctLock);
6689 return CM_ERROR_BADFD;
6692 lock_ReleaseWrite(&smb_rctLock);
6694 lock_ObtainMutex(&fidp->mx);
6695 if (fidp->NTopen_dscp) {
6696 dscp = fidp->NTopen_dscp;
6697 cm_HoldSCache(dscp);
6700 if (fidp->NTopen_pathp)
6701 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6708 /* Don't jump the gun on an async raw write */
6709 while (fidp->raw_writers) {
6710 lock_ReleaseMutex(&fidp->mx);
6711 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6712 lock_ObtainMutex(&fidp->mx);
6715 /* watch for ioctl closes, and read-only opens */
6717 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6718 == SMB_FID_OPENWRITE) {
6719 if (dosTime != 0 && dosTime != -1) {
6720 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6721 /* This fixes defect 10958 */
6722 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6723 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6725 if (smb_AsyncStore != 2) {
6726 lock_ReleaseMutex(&fidp->mx);
6727 code = cm_FSync(scp, userp, &req);
6728 lock_ObtainMutex(&fidp->mx);
6734 /* unlock any pending locks */
6735 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6736 scp->fileType == CM_SCACHETYPE_FILE) {
6740 lock_ReleaseMutex(&fidp->mx);
6742 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6744 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6745 lock_ObtainWrite(&scp->rw);
6747 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6748 CM_SCACHESYNC_NEEDCALLBACK
6749 | CM_SCACHESYNC_GETSTATUS
6750 | CM_SCACHESYNC_LOCK);
6754 "smb CoreClose SyncOp failure code 0x%x", tcode);
6755 goto post_syncopdone;
6758 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6760 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6764 lock_ReleaseWrite(&scp->rw);
6765 lock_ObtainMutex(&fidp->mx);
6768 if (fidp->flags & SMB_FID_DELONCLOSE) {
6769 clientchar_t *fullPathp = NULL;
6770 fschar_t *originalNamep = NULL;
6772 lock_ReleaseMutex(&fidp->mx);
6774 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6779 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6780 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6781 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6783 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6784 smb_NotifyChange(FILE_ACTION_REMOVED,
6785 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6786 dscp, fullPathp, NULL, TRUE);
6789 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6791 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6792 smb_NotifyChange(FILE_ACTION_REMOVED,
6793 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6794 dscp, fullPathp, NULL, TRUE);
6801 free(originalNamep);
6803 lock_ObtainMutex(&fidp->mx);
6804 fidp->flags &= ~SMB_FID_DELONCLOSE;
6807 /* if this was a newly created file, then clear the creator
6808 * in the stat cache entry. */
6809 if (fidp->flags & SMB_FID_CREATED) {
6811 fidp->flags &= ~SMB_FID_CREATED;
6814 if (fidp->flags & SMB_FID_NTOPEN) {
6815 cm_ReleaseSCache(fidp->NTopen_dscp);
6816 fidp->NTopen_dscp = NULL;
6817 free(fidp->NTopen_pathp);
6818 fidp->NTopen_pathp = NULL;
6819 fidp->flags &= ~SMB_FID_NTOPEN;
6821 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6822 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6825 if (fidp->NTopen_wholepathp) {
6826 free(fidp->NTopen_wholepathp);
6827 fidp->NTopen_wholepathp = NULL;
6831 cm_ReleaseSCache(fidp->scp);
6834 lock_ReleaseMutex(&fidp->mx);
6837 cm_ReleaseSCache(dscp);
6840 cm_ReleaseSCache(delscp);
6844 lock_ObtainWrite(&scp->rw);
6845 if (nullcreator && scp->creator == userp)
6846 scp->creator = NULL;
6847 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6848 lock_ReleaseWrite(&scp->rw);
6849 cm_ReleaseSCache(scp);
6859 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6867 fid = smb_GetSMBParm(inp, 0);
6868 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6870 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6872 fid = smb_ChainFID(fid, inp);
6873 fidp = smb_FindFID(vcp, fid, 0);
6875 return CM_ERROR_BADFD;
6878 userp = smb_GetUserFromVCP(vcp, inp);
6880 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6882 smb_ReleaseFID(fidp);
6883 cm_ReleaseUser(userp);
6888 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6890 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6891 cm_user_t *userp, long *readp)
6897 osi_hyper_t fileLength;
6899 osi_hyper_t lastByte;
6900 osi_hyper_t bufferOffset;
6904 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6907 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6908 fidp->fid, offsetp->LowPart, count);
6912 lock_ObtainMutex(&fidp->mx);
6913 /* make sure we have a readable FD */
6914 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6915 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6916 fidp->fid, fidp->flags);
6917 lock_ReleaseMutex(&fidp->mx);
6918 code = CM_ERROR_BADFDOP;
6923 lock_ReleaseMutex(&fidp->mx);
6924 code = CM_ERROR_BADFD;
6935 lock_ObtainWrite(&scp->rw);
6937 if (offset.HighPart == 0) {
6938 chunk = offset.LowPart >> cm_logChunkSize;
6939 if (chunk != fidp->curr_chunk) {
6940 fidp->prev_chunk = fidp->curr_chunk;
6941 fidp->curr_chunk = chunk;
6943 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6946 lock_ReleaseMutex(&fidp->mx);
6948 /* start by looking up the file's end */
6949 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6950 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6954 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6956 /* now we have the entry locked, look up the length */
6957 fileLength = scp->length;
6959 /* adjust count down so that it won't go past EOF */
6960 thyper.LowPart = count;
6961 thyper.HighPart = 0;
6962 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6964 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6965 /* we'd read past EOF, so just stop at fileLength bytes.
6966 * Start by computing how many bytes remain in the file.
6968 thyper = LargeIntegerSubtract(fileLength, offset);
6970 /* if we are past EOF, read 0 bytes */
6971 if (LargeIntegerLessThanZero(thyper))
6974 count = thyper.LowPart;
6979 /* now, copy the data one buffer at a time,
6980 * until we've filled the request packet
6983 /* if we've copied all the data requested, we're done */
6984 if (count <= 0) break;
6986 /* otherwise, load up a buffer of data */
6987 thyper.HighPart = offset.HighPart;
6988 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6989 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6992 buf_Release(bufferp);
6995 lock_ReleaseWrite(&scp->rw);
6997 code = buf_Get(scp, &thyper, &bufferp);
6999 lock_ObtainWrite(&scp->rw);
7000 if (code) goto done;
7001 bufferOffset = thyper;
7003 /* now get the data in the cache */
7005 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7006 CM_SCACHESYNC_NEEDCALLBACK |
7007 CM_SCACHESYNC_READ);
7011 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7013 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7015 /* otherwise, load the buffer and try again */
7016 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7020 buf_Release(bufferp);
7024 } /* if (wrong buffer) ... */
7026 /* now we have the right buffer loaded. Copy out the
7027 * data from here to the user's buffer.
7029 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7031 /* and figure out how many bytes we want from this buffer */
7032 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7033 if (nbytes > count) nbytes = count; /* don't go past EOF */
7035 /* now copy the data */
7036 memcpy(op, bufferp->datap + bufIndex, nbytes);
7038 /* adjust counters, pointers, etc. */
7041 thyper.LowPart = nbytes;
7042 thyper.HighPart = 0;
7043 offset = LargeIntegerAdd(thyper, offset);
7047 lock_ReleaseWrite(&scp->rw);
7049 buf_Release(bufferp);
7051 if (code == 0 && sequential)
7052 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7054 cm_ReleaseSCache(scp);
7057 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7058 fidp->fid, code, *readp);
7063 * smb_WriteData -- common code for Write and Raw Write
7065 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7066 cm_user_t *userp, long *writtenp)
7068 osi_hyper_t offset = *offsetp;
7071 cm_scache_t *scp = NULL;
7072 osi_hyper_t fileLength; /* file's length at start of write */
7073 osi_hyper_t minLength; /* don't read past this */
7074 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7075 cm_buf_t *bufferp = NULL;
7076 osi_hyper_t thyper; /* hyper tmp variable */
7077 osi_hyper_t bufferOffset;
7078 afs_uint32 bufIndex; /* index in buffer where our data is */
7079 int doWriteBack = 0;
7080 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7084 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7085 fidp->fid, offsetp->LowPart, count);
7089 lock_ObtainMutex(&fidp->mx);
7090 /* make sure we have a writable FD */
7091 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7092 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7093 fidp->fid, fidp->flags);
7094 lock_ReleaseMutex(&fidp->mx);
7095 code = CM_ERROR_BADFDOP;
7103 lock_ReleaseMutex(&fidp->mx);
7105 lock_ObtainWrite(&scp->rw);
7106 /* start by looking up the file's end */
7107 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7108 CM_SCACHESYNC_NEEDCALLBACK
7109 | CM_SCACHESYNC_SETSTATUS
7110 | CM_SCACHESYNC_GETSTATUS);
7114 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7116 /* now we have the entry locked, look up the length */
7117 fileLength = scp->length;
7118 minLength = fileLength;
7119 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7120 minLength = scp->serverLength;
7122 /* adjust file length if we extend past EOF */
7123 thyper.LowPart = count;
7124 thyper.HighPart = 0;
7125 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7126 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7127 /* we'd write past EOF, so extend the file */
7128 scp->mask |= CM_SCACHEMASK_LENGTH;
7129 scp->length = thyper;
7130 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7132 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7134 /* now, if the new position (thyper) and the old (offset) are in
7135 * different storeback windows, remember to store back the previous
7136 * storeback window when we're done with the write.
7138 * the purpose of this logic is to slow down the CIFS client
7139 * in order to avoid the client disconnecting during the CLOSE
7140 * operation if there are too many dirty buffers left to write
7141 * than can be accomplished during 45 seconds. This used to be
7142 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7143 * so that we can read larger amounts of data at a time.
7145 if (smb_AsyncStore == 1 &&
7146 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7147 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7148 /* they're different */
7150 writeBackOffset.HighPart = offset.HighPart;
7151 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7156 /* now, copy the data one buffer at a time, until we've filled the
7159 /* if we've copied all the data requested, we're done */
7163 /* handle over quota or out of space */
7164 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7165 *writtenp = written;
7166 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7170 /* otherwise, load up a buffer of data */
7171 thyper.HighPart = offset.HighPart;
7172 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7173 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7176 lock_ReleaseMutex(&bufferp->mx);
7177 buf_Release(bufferp);
7180 lock_ReleaseWrite(&scp->rw);
7182 code = buf_Get(scp, &thyper, &bufferp);
7184 lock_ObtainMutex(&bufferp->mx);
7185 lock_ObtainWrite(&scp->rw);
7186 if (code) goto done;
7188 bufferOffset = thyper;
7190 /* now get the data in the cache */
7192 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7193 CM_SCACHESYNC_NEEDCALLBACK
7194 | CM_SCACHESYNC_WRITE
7195 | CM_SCACHESYNC_BUFLOCKED);
7199 cm_SyncOpDone(scp, bufferp,
7200 CM_SCACHESYNC_NEEDCALLBACK
7201 | CM_SCACHESYNC_WRITE
7202 | CM_SCACHESYNC_BUFLOCKED);
7204 /* If we're overwriting the entire buffer, or
7205 * if we're writing at or past EOF, mark the
7206 * buffer as current so we don't call
7207 * cm_GetBuffer. This skips the fetch from the
7208 * server in those cases where we're going to
7209 * obliterate all the data in the buffer anyway,
7210 * or in those cases where there is no useful
7211 * data at the server to start with.
7213 * Use minLength instead of scp->length, since
7214 * the latter has already been updated by this
7217 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7218 || LargeIntegerEqualTo(offset, bufferp->offset)
7219 && (count >= cm_data.buf_blockSize
7220 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7221 ConvertLongToLargeInteger(count)),
7223 if (count < cm_data.buf_blockSize
7224 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7225 memset(bufferp->datap, 0,
7226 cm_data.buf_blockSize);
7227 bufferp->dataVersion = scp->dataVersion;
7230 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7232 /* otherwise, load the buffer and try again */
7233 lock_ReleaseMutex(&bufferp->mx);
7234 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7236 lock_ReleaseWrite(&scp->rw);
7237 lock_ObtainMutex(&bufferp->mx);
7238 lock_ObtainWrite(&scp->rw);
7242 lock_ReleaseMutex(&bufferp->mx);
7243 buf_Release(bufferp);
7247 } /* if (wrong buffer) ... */
7249 /* now we have the right buffer loaded. Copy out the
7250 * data from here to the user's buffer.
7252 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7254 /* and figure out how many bytes we want from this buffer */
7255 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7257 nbytes = count; /* don't go past end of request */
7259 /* now copy the data */
7260 memcpy(bufferp->datap + bufIndex, op, nbytes);
7261 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7263 /* adjust counters, pointers, etc. */
7267 thyper.LowPart = nbytes;
7268 thyper.HighPart = 0;
7269 offset = LargeIntegerAdd(thyper, offset);
7273 lock_ReleaseWrite(&scp->rw);
7276 lock_ReleaseMutex(&bufferp->mx);
7277 buf_Release(bufferp);
7280 lock_ObtainMutex(&fidp->mx);
7281 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7282 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7284 lock_ReleaseMutex(&fidp->mx);
7285 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7286 fidp->NTopen_dscp, fidp->NTopen_pathp,
7289 lock_ReleaseMutex(&fidp->mx);
7293 if (smb_AsyncStore > 0) {
7297 lock_ObtainWrite(&scp->rw);
7298 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7300 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7301 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7303 lock_ReleaseWrite(&scp->rw);
7304 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7305 writeBackOffset.HighPart,
7306 smb_AsyncStoreSize, 0, userp);
7307 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7310 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7314 cm_ReleaseSCache(scp);
7317 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7318 fidp->fid, code, *writtenp);
7323 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7326 unsigned short count;
7328 unsigned short hint;
7329 long written = 0, total_written = 0;
7332 smb_t* smbp = (smb_t*) inp;
7336 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7338 int inDataBlockCount;
7340 fd = smb_GetSMBParm(inp, 0);
7341 count = smb_GetSMBParm(inp, 1);
7342 offset.HighPart = 0; /* too bad */
7343 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7344 hint = smb_GetSMBParm(inp, 4);
7346 op = smb_GetSMBData(inp, NULL);
7347 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7349 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7350 fd, offset.LowPart, count);
7352 fd = smb_ChainFID(fd, inp);
7353 fidp = smb_FindFID(vcp, fd, 0);
7355 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7356 return CM_ERROR_BADFD;
7359 lock_ObtainMutex(&fidp->mx);
7360 if (fidp->flags & SMB_FID_IOCTL) {
7361 lock_ReleaseMutex(&fidp->mx);
7362 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7363 smb_ReleaseFID(fidp);
7364 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7369 lock_ReleaseMutex(&fidp->mx);
7370 smb_ReleaseFID(fidp);
7371 return CM_ERROR_BADFD;
7374 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7375 lock_ReleaseMutex(&fidp->mx);
7376 smb_CloseFID(vcp, fidp, NULL, 0);
7377 smb_ReleaseFID(fidp);
7378 return CM_ERROR_NOSUCHFILE;
7383 lock_ReleaseMutex(&fidp->mx);
7384 userp = smb_GetUserFromVCP(vcp, inp);
7388 LARGE_INTEGER LOffset;
7389 LARGE_INTEGER LLength;
7392 key = cm_GenerateKey(vcp->vcID, pid, fd);
7394 LOffset.HighPart = offset.HighPart;
7395 LOffset.LowPart = offset.LowPart;
7396 LLength.HighPart = 0;
7397 LLength.LowPart = count;
7399 lock_ObtainWrite(&scp->rw);
7400 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7401 lock_ReleaseWrite(&scp->rw);
7404 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7409 /* special case: 0 bytes transferred means truncate to this position */
7413 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7417 truncAttr.mask = CM_ATTRMASK_LENGTH;
7418 truncAttr.length.LowPart = offset.LowPart;
7419 truncAttr.length.HighPart = 0;
7420 lock_ObtainMutex(&fidp->mx);
7421 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7422 fidp->flags |= SMB_FID_LENGTHSETDONE;
7423 lock_ReleaseMutex(&fidp->mx);
7424 smb_SetSMBParm(outp, 0, 0 /* count */);
7425 smb_SetSMBDataLength(outp, 0);
7430 * Work around bug in NT client
7432 * When copying a file, the NT client should first copy the data,
7433 * then copy the last write time. But sometimes the NT client does
7434 * these in the wrong order, so the data copies would inadvertently
7435 * cause the last write time to be overwritten. We try to detect this,
7436 * and don't set client mod time if we think that would go against the
7439 lock_ObtainMutex(&fidp->mx);
7440 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7441 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7442 fidp->scp->clientModTime = time(NULL);
7444 lock_ReleaseMutex(&fidp->mx);
7447 while ( code == 0 && count > 0 ) {
7448 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7449 if (code == 0 && written == 0)
7450 code = CM_ERROR_PARTIALWRITE;
7452 offset = LargeIntegerAdd(offset,
7453 ConvertLongToLargeInteger(written));
7454 count -= (unsigned short)written;
7455 total_written += written;
7459 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7460 total_written, code);
7462 /* set the packet data length to 3 bytes for the data block header,
7463 * plus the size of the data.
7465 smb_SetSMBParm(outp, 0, total_written);
7466 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7467 smb_SetSMBParm(outp, 3, hint);
7468 smb_SetSMBDataLength(outp, 0);
7471 smb_ReleaseFID(fidp);
7472 cm_ReleaseUser(userp);
7473 cm_ReleaseSCache(scp);
7478 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7479 NCB *ncbp, raw_write_cont_t *rwcp)
7488 fd = smb_GetSMBParm(inp, 0);
7489 fidp = smb_FindFID(vcp, fd, 0);
7491 lock_ObtainMutex(&fidp->mx);
7493 lock_ReleaseMutex(&fidp->mx);
7494 smb_ReleaseFID(fidp);
7498 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7499 lock_ReleaseMutex(&fidp->mx);
7500 smb_CloseFID(vcp, fidp, NULL, 0);
7501 smb_ReleaseFID(fidp);
7504 lock_ReleaseMutex(&fidp->mx);
7506 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7507 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7509 userp = smb_GetUserFromVCP(vcp, inp);
7512 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7514 if (rwcp->writeMode & 0x1) { /* synchronous */
7517 smb_FormatResponsePacket(vcp, inp, outp);
7518 op = (smb_t *) outp;
7519 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7520 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7521 smb_SetSMBDataLength(outp, 0);
7522 smb_SendPacket(vcp, outp);
7523 smb_FreePacket(outp);
7525 else { /* asynchronous */
7526 lock_ObtainMutex(&fidp->mx);
7527 fidp->raw_writers--;
7528 if (fidp->raw_writers == 0)
7529 thrd_SetEvent(fidp->raw_write_event);
7530 lock_ReleaseMutex(&fidp->mx);
7533 /* Give back raw buffer */
7534 lock_ObtainMutex(&smb_RawBufLock);
7535 *((char **)rawBuf) = smb_RawBufs;
7536 smb_RawBufs = rawBuf;
7537 lock_ReleaseMutex(&smb_RawBufLock);
7539 smb_ReleaseFID(fidp);
7540 cm_ReleaseUser(userp);
7543 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7548 /* SMB_COM_WRITE_RAW */
7549 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7552 long count, written = 0, total_written = 0;
7556 smb_t *smbp = (smb_t*) inp;
7561 unsigned short writeMode;
7563 fd = smb_GetSMBParm(inp, 0);
7564 totalCount = smb_GetSMBParm(inp, 1);
7565 count = smb_GetSMBParm(inp, 10);
7566 writeMode = smb_GetSMBParm(inp, 7);
7568 op = (char *) inp->data;
7569 op += smb_GetSMBParm(inp, 11);
7571 offset.HighPart = 0;
7572 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7574 if (*inp->wctp == 14) {
7575 /* we received a 64-bit file offset */
7576 #ifdef AFS_LARGEFILES
7577 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7579 if (LargeIntegerLessThanZero(offset)) {
7581 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7582 offset.HighPart, offset.LowPart);
7583 return CM_ERROR_BADSMB;
7586 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7588 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7589 return CM_ERROR_BADSMB;
7592 offset.HighPart = 0;
7595 offset.HighPart = 0; /* 32-bit file offset */
7599 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7600 fd, offset.HighPart, offset.LowPart, count);
7602 " WriteRaw WriteMode 0x%x",
7605 fd = smb_ChainFID(fd, inp);
7606 fidp = smb_FindFID(vcp, fd, 0);
7608 return CM_ERROR_BADFD;
7610 lock_ObtainMutex(&fidp->mx);
7612 lock_ReleaseMutex(&fidp->mx);
7613 smb_ReleaseFID(fidp);
7614 return CM_ERROR_BADFD;
7617 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7618 lock_ReleaseMutex(&fidp->mx);
7619 smb_CloseFID(vcp, fidp, NULL, 0);
7620 smb_ReleaseFID(fidp);
7621 return CM_ERROR_NOSUCHFILE;
7626 lock_ReleaseMutex(&fidp->mx);
7631 LARGE_INTEGER LOffset;
7632 LARGE_INTEGER LLength;
7635 key = cm_GenerateKey(vcp->vcID, pid, fd);
7637 LOffset.HighPart = offset.HighPart;
7638 LOffset.LowPart = offset.LowPart;
7639 LLength.HighPart = 0;
7640 LLength.LowPart = count;
7642 lock_ObtainWrite(&scp->rw);
7643 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7644 lock_ReleaseWrite(&scp->rw);
7647 cm_ReleaseSCache(scp);
7648 smb_ReleaseFID(fidp);
7653 userp = smb_GetUserFromVCP(vcp, inp);
7656 * Work around bug in NT client
7658 * When copying a file, the NT client should first copy the data,
7659 * then copy the last write time. But sometimes the NT client does
7660 * these in the wrong order, so the data copies would inadvertently
7661 * cause the last write time to be overwritten. We try to detect this,
7662 * and don't set client mod time if we think that would go against the
7665 lock_ObtainMutex(&fidp->mx);
7666 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7667 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7668 fidp->scp->clientModTime = time(NULL);
7670 lock_ReleaseMutex(&fidp->mx);
7673 while ( code == 0 && count > 0 ) {
7674 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7675 if (code == 0 && written == 0)
7676 code = CM_ERROR_PARTIALWRITE;
7678 offset = LargeIntegerAdd(offset,
7679 ConvertLongToLargeInteger(written));
7682 total_written += written;
7686 /* Get a raw buffer */
7689 lock_ObtainMutex(&smb_RawBufLock);
7691 /* Get a raw buf, from head of list */
7692 rawBuf = smb_RawBufs;
7693 smb_RawBufs = *(char **)smb_RawBufs;
7696 code = CM_ERROR_USESTD;
7698 lock_ReleaseMutex(&smb_RawBufLock);
7701 /* Don't allow a premature Close */
7702 if (code == 0 && (writeMode & 1) == 0) {
7703 lock_ObtainMutex(&fidp->mx);
7704 fidp->raw_writers++;
7705 thrd_ResetEvent(fidp->raw_write_event);
7706 lock_ReleaseMutex(&fidp->mx);
7709 smb_ReleaseFID(fidp);
7710 cm_ReleaseUser(userp);
7711 cm_ReleaseSCache(scp);
7714 smb_SetSMBParm(outp, 0, total_written);
7715 smb_SetSMBDataLength(outp, 0);
7716 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7721 offset = LargeIntegerAdd(offset,
7722 ConvertLongToLargeInteger(count));
7726 rwcp->offset.HighPart = offset.HighPart;
7727 rwcp->offset.LowPart = offset.LowPart;
7728 rwcp->count = totalCount - count;
7729 rwcp->writeMode = writeMode;
7730 rwcp->alreadyWritten = total_written;
7732 /* set the packet data length to 3 bytes for the data block header,
7733 * plus the size of the data.
7735 smb_SetSMBParm(outp, 0, 0xffff);
7736 smb_SetSMBDataLength(outp, 0);
7742 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7745 long count, finalCount;
7749 smb_t *smbp = (smb_t*) inp;
7755 fd = smb_GetSMBParm(inp, 0);
7756 count = smb_GetSMBParm(inp, 1);
7757 offset.HighPart = 0; /* too bad */
7758 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7760 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7761 fd, offset.LowPart, count);
7763 fd = smb_ChainFID(fd, inp);
7764 fidp = smb_FindFID(vcp, fd, 0);
7766 return CM_ERROR_BADFD;
7768 lock_ObtainMutex(&fidp->mx);
7769 if (fidp->flags & SMB_FID_IOCTL) {
7770 lock_ReleaseMutex(&fidp->mx);
7771 code = smb_IoctlRead(fidp, vcp, inp, outp);
7772 smb_ReleaseFID(fidp);
7777 lock_ReleaseMutex(&fidp->mx);
7778 smb_ReleaseFID(fidp);
7779 return CM_ERROR_BADFD;
7782 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7783 lock_ReleaseMutex(&fidp->mx);
7784 smb_CloseFID(vcp, fidp, NULL, 0);
7785 smb_ReleaseFID(fidp);
7786 return CM_ERROR_NOSUCHFILE;
7791 lock_ReleaseMutex(&fidp->mx);
7794 LARGE_INTEGER LOffset, LLength;
7798 key = cm_GenerateKey(vcp->vcID, pid, fd);
7800 LOffset.HighPart = 0;
7801 LOffset.LowPart = offset.LowPart;
7802 LLength.HighPart = 0;
7803 LLength.LowPart = count;
7805 lock_ObtainWrite(&scp->rw);
7806 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7807 lock_ReleaseWrite(&scp->rw);
7810 cm_ReleaseSCache(scp);
7811 smb_ReleaseFID(fidp);
7815 userp = smb_GetUserFromVCP(vcp, inp);
7817 /* remember this for final results */
7818 smb_SetSMBParm(outp, 0, count);
7819 smb_SetSMBParm(outp, 1, 0);
7820 smb_SetSMBParm(outp, 2, 0);
7821 smb_SetSMBParm(outp, 3, 0);
7822 smb_SetSMBParm(outp, 4, 0);
7824 /* set the packet data length to 3 bytes for the data block header,
7825 * plus the size of the data.
7827 smb_SetSMBDataLength(outp, count+3);
7829 /* get op ptr after putting in the parms, since otherwise we don't
7830 * know where the data really is.
7832 op = smb_GetSMBData(outp, NULL);
7834 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7835 *op++ = 1; /* data block marker */
7836 *op++ = (unsigned char) (count & 0xff);
7837 *op++ = (unsigned char) ((count >> 8) & 0xff);
7839 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7841 /* fix some things up */
7842 smb_SetSMBParm(outp, 0, finalCount);
7843 smb_SetSMBDataLength(outp, finalCount+3);
7845 smb_ReleaseFID(fidp);
7847 cm_ReleaseUser(userp);
7848 cm_ReleaseSCache(scp);
7852 /* SMB_COM_CREATE_DIRECTORY */
7853 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7855 clientchar_t *pathp;
7860 cm_scache_t *dscp; /* dir we're dealing with */
7861 cm_scache_t *scp; /* file we're creating */
7863 int initialModeBits;
7864 clientchar_t *lastNamep;
7866 clientchar_t *tidPathp;
7873 /* compute initial mode bits based on read-only flag in attributes */
7874 initialModeBits = 0777;
7876 tp = smb_GetSMBData(inp, NULL);
7877 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7879 return CM_ERROR_BADSMB;
7881 spacep = inp->spacep;
7882 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7884 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7885 return CM_ERROR_EXISTS;
7887 userp = smb_GetUserFromVCP(vcp, inp);
7889 caseFold = CM_FLAG_CASEFOLD;
7891 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7893 cm_ReleaseUser(userp);
7894 return CM_ERROR_NOSUCHPATH;
7897 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7898 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7899 userp, tidPathp, &req, &dscp);
7902 cm_ReleaseUser(userp);
7907 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7908 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7909 cm_ReleaseSCache(dscp);
7910 cm_ReleaseUser(userp);
7911 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7912 return CM_ERROR_PATH_NOT_COVERED;
7914 return CM_ERROR_NOSUCHPATH;
7916 #endif /* DFS_SUPPORT */
7918 /* otherwise, scp points to the parent directory. Do a lookup, and
7919 * fail if we find it. Otherwise, we do the create.
7925 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7926 if (scp) cm_ReleaseSCache(scp);
7927 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7928 if (code == 0) code = CM_ERROR_EXISTS;
7929 cm_ReleaseSCache(dscp);
7930 cm_ReleaseUser(userp);
7934 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7935 setAttr.clientModTime = time(NULL);
7936 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7937 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7938 smb_NotifyChange(FILE_ACTION_ADDED,
7939 FILE_NOTIFY_CHANGE_DIR_NAME,
7940 dscp, lastNamep, NULL, TRUE);
7942 /* we don't need this any longer */
7943 cm_ReleaseSCache(dscp);
7946 /* something went wrong creating or truncating the file */
7947 cm_ReleaseUser(userp);
7951 /* otherwise we succeeded */
7952 smb_SetSMBDataLength(outp, 0);
7953 cm_ReleaseUser(userp);
7958 BOOL smb_IsLegalFilename(clientchar_t *filename)
7961 * Find the longest substring of filename that does not contain
7962 * any of the chars in illegalChars. If that substring is less
7963 * than the length of the whole string, then one or more of the
7964 * illegal chars is in filename.
7966 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7972 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7973 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7975 clientchar_t *pathp;
7981 cm_scache_t *dscp; /* dir we're dealing with */
7982 cm_scache_t *scp; /* file we're creating */
7984 int initialModeBits;
7987 clientchar_t *lastNamep;
7990 clientchar_t *tidPathp;
7992 int created = 0; /* the file was new */
7997 excl = (inp->inCom == 0x03)? 0 : 1;
7999 attributes = smb_GetSMBParm(inp, 0);
8000 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8002 /* compute initial mode bits based on read-only flag in attributes */
8003 initialModeBits = 0666;
8004 if (attributes & SMB_ATTR_READONLY)
8005 initialModeBits &= ~0222;
8007 tp = smb_GetSMBData(inp, NULL);
8008 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8010 return CM_ERROR_BADSMB;
8012 if (!cm_IsValidClientString(pathp)) {
8014 clientchar_t * hexp;
8016 hexp = cm_GetRawCharsAlloc(pathp, -1);
8017 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8018 osi_LogSaveClientString(smb_logp, hexp));
8022 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8024 return CM_ERROR_BADNTFILENAME;
8027 spacep = inp->spacep;
8028 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8030 userp = smb_GetUserFromVCP(vcp, inp);
8032 caseFold = CM_FLAG_CASEFOLD;
8034 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8036 cm_ReleaseUser(userp);
8037 return CM_ERROR_NOSUCHPATH;
8039 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8040 userp, tidPathp, &req, &dscp);
8043 cm_ReleaseUser(userp);
8048 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8049 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8050 cm_ReleaseSCache(dscp);
8051 cm_ReleaseUser(userp);
8052 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8053 return CM_ERROR_PATH_NOT_COVERED;
8055 return CM_ERROR_NOSUCHPATH;
8057 #endif /* DFS_SUPPORT */
8059 /* otherwise, scp points to the parent directory. Do a lookup, and
8060 * truncate the file if we find it, otherwise we create the file.
8067 if (!smb_IsLegalFilename(lastNamep))
8068 return CM_ERROR_BADNTFILENAME;
8070 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8071 #ifdef DEBUG_VERBOSE
8074 hexp = osi_HexifyString( lastNamep );
8075 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8080 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8081 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8082 cm_ReleaseSCache(dscp);
8083 cm_ReleaseUser(userp);
8087 /* if we get here, if code is 0, the file exists and is represented by
8088 * scp. Otherwise, we have to create it.
8092 /* oops, file shouldn't be there */
8093 cm_ReleaseSCache(dscp);
8094 cm_ReleaseSCache(scp);
8095 cm_ReleaseUser(userp);
8096 return CM_ERROR_EXISTS;
8099 setAttr.mask = CM_ATTRMASK_LENGTH;
8100 setAttr.length.LowPart = 0;
8101 setAttr.length.HighPart = 0;
8102 code = cm_SetAttr(scp, &setAttr, userp, &req);
8105 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8106 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8107 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8111 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8112 smb_NotifyChange(FILE_ACTION_ADDED,
8113 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8114 dscp, lastNamep, NULL, TRUE);
8115 } else if (!excl && code == CM_ERROR_EXISTS) {
8116 /* not an exclusive create, and someone else tried
8117 * creating it already, then we open it anyway. We
8118 * don't bother retrying after this, since if this next
8119 * fails, that means that the file was deleted after
8120 * we started this call.
8122 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8125 setAttr.mask = CM_ATTRMASK_LENGTH;
8126 setAttr.length.LowPart = 0;
8127 setAttr.length.HighPart = 0;
8128 code = cm_SetAttr(scp, &setAttr, userp, &req);
8133 /* we don't need this any longer */
8134 cm_ReleaseSCache(dscp);
8137 /* something went wrong creating or truncating the file */
8138 if (scp) cm_ReleaseSCache(scp);
8139 cm_ReleaseUser(userp);
8143 /* make sure we only open files */
8144 if (scp->fileType != CM_SCACHETYPE_FILE) {
8145 cm_ReleaseSCache(scp);
8146 cm_ReleaseUser(userp);
8147 return CM_ERROR_ISDIR;
8150 /* now all we have to do is open the file itself */
8151 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8152 osi_assertx(fidp, "null smb_fid_t");
8156 lock_ObtainMutex(&fidp->mx);
8157 /* always create it open for read/write */
8158 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8160 /* remember that the file was newly created */
8162 fidp->flags |= SMB_FID_CREATED;
8164 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8166 /* save a pointer to the vnode */
8168 lock_ObtainWrite(&scp->rw);
8169 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8170 lock_ReleaseWrite(&scp->rw);
8173 fidp->userp = userp;
8174 lock_ReleaseMutex(&fidp->mx);
8176 smb_SetSMBParm(outp, 0, fidp->fid);
8177 smb_SetSMBDataLength(outp, 0);
8179 cm_Open(scp, 0, userp);
8181 smb_ReleaseFID(fidp);
8182 cm_ReleaseUser(userp);
8183 /* leave scp held since we put it in fidp->scp */
8188 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8191 osi_hyper_t new_offset;
8202 fd = smb_GetSMBParm(inp, 0);
8203 whence = smb_GetSMBParm(inp, 1);
8204 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8206 /* try to find the file descriptor */
8207 fd = smb_ChainFID(fd, inp);
8208 fidp = smb_FindFID(vcp, fd, 0);
8210 return CM_ERROR_BADFD;
8212 lock_ObtainMutex(&fidp->mx);
8213 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8214 lock_ReleaseMutex(&fidp->mx);
8215 smb_ReleaseFID(fidp);
8216 return CM_ERROR_BADFD;
8219 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8220 lock_ReleaseMutex(&fidp->mx);
8221 smb_CloseFID(vcp, fidp, NULL, 0);
8222 smb_ReleaseFID(fidp);
8223 return CM_ERROR_NOSUCHFILE;
8226 lock_ReleaseMutex(&fidp->mx);
8228 userp = smb_GetUserFromVCP(vcp, inp);
8230 lock_ObtainMutex(&fidp->mx);
8233 lock_ReleaseMutex(&fidp->mx);
8234 lock_ObtainWrite(&scp->rw);
8235 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8236 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8238 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8240 /* offset from current offset */
8241 new_offset = LargeIntegerAdd(fidp->offset,
8242 ConvertLongToLargeInteger(offset));
8244 else if (whence == 2) {
8245 /* offset from current EOF */
8246 new_offset = LargeIntegerAdd(scp->length,
8247 ConvertLongToLargeInteger(offset));
8249 new_offset = ConvertLongToLargeInteger(offset);
8252 fidp->offset = new_offset;
8253 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8254 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8255 smb_SetSMBDataLength(outp, 0);
8257 lock_ReleaseWrite(&scp->rw);
8258 smb_ReleaseFID(fidp);
8259 cm_ReleaseSCache(scp);
8260 cm_ReleaseUser(userp);
8264 /* dispatch all of the requests received in a packet. Due to chaining, this may
8265 * be more than one request.
8267 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8268 NCB *ncbp, raw_write_cont_t *rwcp)
8272 unsigned long code = 0;
8273 unsigned char *outWctp;
8274 int nparms; /* # of bytes of parameters */
8276 int nbytes; /* bytes of data, excluding count */
8279 unsigned short errCode;
8280 unsigned long NTStatus;
8282 unsigned char errClass;
8283 unsigned int oldGen;
8284 DWORD oldTime, newTime;
8286 /* get easy pointer to the data */
8287 smbp = (smb_t *) inp->data;
8289 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8290 /* setup the basic parms for the initial request in the packet */
8291 inp->inCom = smbp->com;
8292 inp->wctp = &smbp->wct;
8294 inp->ncb_length = ncbp->ncb_length;
8299 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8300 /* log it and discard it */
8301 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8302 __FILE__, __LINE__, ncbp->ncb_length);
8303 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8307 /* We are an ongoing op */
8308 thrd_Increment(&ongoingOps);
8310 /* set up response packet for receiving output */
8311 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8312 smb_FormatResponsePacket(vcp, inp, outp);
8313 outWctp = outp->wctp;
8315 /* Remember session generation number and time */
8316 oldGen = sessionGen;
8317 oldTime = GetTickCount();
8319 while (inp->inCom != 0xff) {
8320 dp = &smb_dispatchTable[inp->inCom];
8322 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8323 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8324 code = outp->resumeCode;
8328 /* process each request in the packet; inCom, wctp and inCount
8329 * are already set up.
8331 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8334 /* now do the dispatch */
8335 /* start by formatting the response record a little, as a default */
8336 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8338 outWctp[1] = 0xff; /* no operation */
8339 outWctp[2] = 0; /* padding */
8344 /* not a chained request, this is a more reasonable default */
8345 outWctp[0] = 0; /* wct of zero */
8346 outWctp[1] = 0; /* and bcc (word) of zero */
8350 /* once set, stays set. Doesn't matter, since we never chain
8351 * "no response" calls.
8353 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8357 /* we have a recognized operation */
8358 char * opName = myCrt_Dispatch(inp->inCom);
8361 smbp = (smb_t *) inp;
8363 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8364 opName, smbp->mid, vcp,vcp->lana,vcp->lsn);
8365 if (inp->inCom == 0x1d) {
8367 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8369 code = (*(dp->procp)) (vcp, inp, outp);
8371 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8372 code, smbp->mid, vcp,vcp->lana,vcp->lsn);
8374 newTime = GetTickCount();
8375 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8376 opName, smbp->mid, newTime - oldTime);
8379 if ( code == CM_ERROR_BADSMB ||
8380 code == CM_ERROR_BADOP )
8382 #endif /* LOG_PACKET */
8384 /* ReceiveV3Tran2A handles its own logging */
8385 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8388 clientchar_t *treepath = NULL; /* do not free */
8389 clientchar_t *pathname = NULL;
8390 cm_fid_t afid = {0,0,0,0,0};
8392 uidp = smb_FindUID(vcp, smbp->uid, 0);
8393 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8394 fidp = smb_FindFID(vcp, inp->fid, 0);
8397 lock_ObtainMutex(&fidp->mx);
8398 if (fidp->NTopen_pathp)
8399 pathname = fidp->NTopen_pathp;
8401 afid = fidp->scp->fid;
8403 if (inp->stringsp->wdata)
8404 pathname = inp->stringsp->wdata;
8407 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)",
8408 opName, newTime - oldTime,
8409 smbp->uid, uidp ? uidp->unp->name : NULL,
8410 smbp->pid, smbp->mid, smbp->tid,
8413 afid.cell, afid.volume, afid.vnode, afid.unique);
8416 lock_ReleaseMutex(&fidp->mx);
8419 smb_ReleaseUID(uidp);
8421 smb_ReleaseFID(fidp);
8424 if (oldGen != sessionGen) {
8425 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8426 newTime - oldTime, ncbp->ncb_length);
8427 osi_Log3(smb_logp, "Request %s straddled session startup, "
8428 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8431 FreeSMBStrings(inp);
8433 /* bad opcode, fail the request, after displaying it */
8434 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8437 #endif /* LOG_PACKET */
8440 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8441 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8442 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8443 if (code == IDCANCEL)
8446 code = CM_ERROR_BADOP;
8449 /* catastrophic failure: log as much as possible */
8450 if (code == CM_ERROR_BADSMB) {
8451 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8455 #endif /* LOG_PACKET */
8456 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8459 code = CM_ERROR_INVAL;
8462 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8463 thrd_Decrement(&ongoingOps);
8468 /* now, if we failed, turn the current response into an empty
8469 * one, and fill in the response packet's error code.
8472 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8473 smb_MapNTError(code, &NTStatus);
8474 outWctp = outp->wctp;
8475 smbp = (smb_t *) &outp->data;
8476 if (code != CM_ERROR_PARTIALWRITE
8477 && code != CM_ERROR_BUFFERTOOSMALL
8478 && code != CM_ERROR_GSSCONTINUE) {
8479 /* nuke wct and bcc. For a partial
8480 * write or an in-process authentication handshake,
8481 * assume they're OK.
8487 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8488 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8489 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8490 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8491 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8495 smb_MapCoreError(code, vcp, &errCode, &errClass);
8496 outWctp = outp->wctp;
8497 smbp = (smb_t *) &outp->data;
8498 if (code != CM_ERROR_PARTIALWRITE) {
8499 /* nuke wct and bcc. For a partial
8500 * write, assume they're OK.
8506 smbp->errLow = (unsigned char) (errCode & 0xff);
8507 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8508 smbp->rcls = errClass;
8511 } /* error occurred */
8513 /* if we're here, we've finished one request. Look to see if
8514 * this is a chained opcode. If it is, setup things to process
8515 * the chained request, and setup the output buffer to hold the
8516 * chained response. Start by finding the next input record.
8518 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8519 break; /* not a chained req */
8520 tp = inp->wctp; /* points to start of last request */
8521 /* in a chained request, the first two
8522 * parm fields are required, and are
8523 * AndXCommand/AndXReserved and
8525 if (tp[0] < 2) break;
8526 if (tp[1] == 0xff) break; /* no more chained opcodes */
8528 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8531 /* and now append the next output request to the end of this
8532 * last request. Begin by finding out where the last response
8533 * ends, since that's where we'll put our new response.
8535 outWctp = outp->wctp; /* ptr to out parameters */
8536 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8537 nparms = outWctp[0] << 1;
8538 tp = outWctp + nparms + 1; /* now points to bcc field */
8539 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8540 tp += 2 /* for the count itself */ + nbytes;
8541 /* tp now points to the new output record; go back and patch the
8542 * second parameter (off2) to point to the new record.
8544 temp = (unsigned int)(tp - outp->data);
8545 outWctp[3] = (unsigned char) (temp & 0xff);
8546 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8547 outWctp[2] = 0; /* padding */
8548 outWctp[1] = inp->inCom; /* next opcode */
8550 /* finally, setup for the next iteration */
8553 } /* while loop over all requests in the packet */
8555 /* now send the output packet, and return */
8557 smb_SendPacket(vcp, outp);
8558 thrd_Decrement(&ongoingOps);
8563 /* Wait for Netbios() calls to return, and make the results available to server
8564 * threads. Note that server threads can't wait on the NCBevents array
8565 * themselves, because NCB events are manual-reset, and the servers would race
8566 * each other to reset them.
8568 void smb_ClientWaiter(void *parmp)
8573 while (smbShutdownFlag == 0) {
8574 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8576 if (code == WAIT_OBJECT_0)
8579 /* error checking */
8580 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8582 int abandonIdx = code - WAIT_ABANDONED_0;
8583 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8586 if (code == WAIT_IO_COMPLETION)
8588 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8592 if (code == WAIT_TIMEOUT)
8594 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8597 if (code == WAIT_FAILED)
8599 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8602 idx = code - WAIT_OBJECT_0;
8604 /* check idx range! */
8605 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8607 /* this is fatal - log as much as possible */
8608 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8609 osi_assertx(0, "invalid index");
8612 thrd_ResetEvent(NCBevents[idx]);
8613 thrd_SetEvent(NCBreturns[0][idx]);
8618 * Try to have one NCBRECV request waiting for every live session. Not more
8619 * than one, because if there is more than one, it's hard to handle Write Raw.
8621 void smb_ServerWaiter(void *parmp)
8624 int idx_session, idx_NCB;
8627 while (smbShutdownFlag == 0) {
8629 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8631 if (code == WAIT_OBJECT_0)
8634 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8636 int abandonIdx = code - WAIT_ABANDONED_0;
8637 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8640 if (code == WAIT_IO_COMPLETION)
8642 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8646 if (code == WAIT_TIMEOUT)
8648 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8651 if (code == WAIT_FAILED)
8653 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8656 idx_session = code - WAIT_OBJECT_0;
8658 /* check idx range! */
8659 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8661 /* this is fatal - log as much as possible */
8662 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8663 osi_assertx(0, "invalid index");
8668 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8670 if (code == WAIT_OBJECT_0) {
8671 if (smbShutdownFlag == 1)
8677 /* error checking */
8678 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8680 int abandonIdx = code - WAIT_ABANDONED_0;
8681 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8684 if (code == WAIT_IO_COMPLETION)
8686 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8690 if (code == WAIT_TIMEOUT)
8692 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8695 if (code == WAIT_FAILED)
8697 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8700 idx_NCB = code - WAIT_OBJECT_0;
8702 /* check idx range! */
8703 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8705 /* this is fatal - log as much as possible */
8706 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8707 osi_assertx(0, "invalid index");
8710 /* Link them together */
8711 NCBsessions[idx_NCB] = idx_session;
8714 ncbp = NCBs[idx_NCB];
8715 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8716 ncbp->ncb_command = NCBRECV | ASYNCH;
8717 ncbp->ncb_lana_num = lanas[idx_session];
8718 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8719 ncbp->ncb_event = NCBevents[idx_NCB];
8720 ncbp->ncb_length = SMB_PACKETSIZE;
8726 * The top level loop for handling SMB request messages. Each server thread
8727 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8728 * NCB and buffer for the incoming request are loaned to us.
8730 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8731 * to immediately send a request for the rest of the data. This must come
8732 * before any other traffic for that session, so we delay setting the session
8733 * event until that data has come in.
8735 void smb_Server(VOID *parmp)
8737 INT_PTR myIdx = (INT_PTR) parmp;
8741 smb_packet_t *outbufp;
8743 int idx_NCB, idx_session;
8745 smb_vc_t *vcp = NULL;
8747 extern void rx_StartClientThread(void);
8749 rx_StartClientThread();
8751 outncbp = smb_GetNCB();
8752 outbufp = smb_GetPacket();
8753 outbufp->ncbp = outncbp;
8761 smb_ResetServerPriority();
8763 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8766 /* terminate silently if shutdown flag is set */
8767 if (code == WAIT_OBJECT_0) {
8768 if (smbShutdownFlag == 1) {
8769 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8775 /* error checking */
8776 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8778 int abandonIdx = code - WAIT_ABANDONED_0;
8779 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8782 if (code == WAIT_IO_COMPLETION)
8784 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8788 if (code == WAIT_TIMEOUT)
8790 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8793 if (code == WAIT_FAILED)
8795 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8798 idx_NCB = code - WAIT_OBJECT_0;
8800 /* check idx range! */
8801 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8803 /* this is fatal - log as much as possible */
8804 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8805 osi_assertx(0, "invalid index");
8808 ncbp = NCBs[idx_NCB];
8809 idx_session = NCBsessions[idx_NCB];
8810 rc = ncbp->ncb_retcode;
8812 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8813 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8817 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8821 /* Can this happen? Or is it just my UNIX paranoia? */
8822 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8827 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8830 /* Client closed session */
8831 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8833 lock_ObtainMutex(&vcp->mx);
8834 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8835 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8837 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8838 lock_ReleaseMutex(&vcp->mx);
8839 lock_ObtainWrite(&smb_globalLock);
8840 dead_sessions[vcp->session] = TRUE;
8841 lock_ReleaseWrite(&smb_globalLock);
8843 lock_ReleaseMutex(&vcp->mx);
8845 smb_CleanupDeadVC(vcp);
8852 /* Treat as transient error */
8853 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8856 "dispatch smb recv failed, message incomplete, ncb_length %d",
8859 "SMB message incomplete, "
8860 "length %d", ncbp->ncb_length);
8863 * We used to discard the packet.
8864 * Instead, try handling it normally.
8868 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8872 /* A weird error code. Log it, sleep, and continue. */
8873 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8875 lock_ObtainMutex(&vcp->mx);
8876 if (vcp->errorCount++ > 3) {
8877 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8878 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8879 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8881 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8882 lock_ReleaseMutex(&vcp->mx);
8883 lock_ObtainWrite(&smb_globalLock);
8884 dead_sessions[vcp->session] = TRUE;
8885 lock_ReleaseWrite(&smb_globalLock);
8887 lock_ReleaseMutex(&vcp->mx);
8889 smb_CleanupDeadVC(vcp);
8895 lock_ReleaseMutex(&vcp->mx);
8899 thrd_SetEvent(SessionEvents[idx_session]);
8905 /* Success, so now dispatch on all the data in the packet */
8907 smb_concurrentCalls++;
8908 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8909 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8912 * If at this point vcp is NULL (implies that packet was invalid)
8913 * then we are in big trouble. This means either :
8914 * a) we have the wrong NCB.
8915 * b) Netbios screwed up the call.
8916 * c) The VC was already marked dead before we were able to
8918 * Obviously this implies that
8919 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8920 * lanas[idx_session] != ncbp->ncb_lana_num )
8921 * Either way, we can't do anything with this packet.
8922 * Log, sleep and resume.
8925 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8929 ncbp->ncb_lana_num);
8931 /* Also log in the trace log. */
8932 osi_Log4(smb_logp, "Server: VCP does not exist!"
8933 "LSNs[idx_session]=[%d],"
8934 "lanas[idx_session]=[%d],"
8935 "ncbp->ncb_lsn=[%d],"
8936 "ncbp->ncb_lana_num=[%d]",
8940 ncbp->ncb_lana_num);
8942 /* thrd_Sleep(1000); Don't bother sleeping */
8943 thrd_SetEvent(SessionEvents[idx_session]);
8944 smb_concurrentCalls--;
8948 smb_SetRequestStartTime();
8950 vcp->errorCount = 0;
8951 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8952 smbp = (smb_t *)bufp->data;
8959 if (smbp->com == 0x1d) {
8960 /* Special handling for Write Raw */
8961 raw_write_cont_t rwc;
8963 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8964 if (rwc.code == 0) {
8965 EVENT_HANDLE rwevent;
8966 char eventName[MAX_PATH];
8968 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
8969 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8970 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8971 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8973 ncbp->ncb_command = NCBRECV | ASYNCH;
8974 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8975 ncbp->ncb_lana_num = vcp->lana;
8976 ncbp->ncb_buffer = rwc.buf;
8977 ncbp->ncb_length = 65535;
8978 ncbp->ncb_event = rwevent;
8980 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8981 thrd_CloseHandle(rwevent);
8983 thrd_SetEvent(SessionEvents[idx_session]);
8985 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8987 else if (smbp->com == 0xa0) {
8989 * Serialize the handling for NT Transact
8992 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8993 thrd_SetEvent(SessionEvents[idx_session]);
8995 thrd_SetEvent(SessionEvents[idx_session]);
8996 /* TODO: what else needs to be serialized? */
8997 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9001 __except( smb_ServerExceptionFilter() ) {
9005 smb_concurrentCalls--;
9008 thrd_SetEvent(NCBavails[idx_NCB]);
9013 smb_FreePacket(outbufp);
9015 smb_FreeNCB(outncbp);
9019 * Exception filter for the server threads. If an exception occurs in the
9020 * dispatch routines, which is where exceptions are most common, then do a
9021 * force trace and give control to upstream exception handlers. Useful for
9024 DWORD smb_ServerExceptionFilter(void) {
9025 /* While this is not the best time to do a trace, if it succeeds, then
9026 * we have a trace (assuming tracing was enabled). Otherwise, this should
9027 * throw a second exception.
9029 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9030 afsd_ForceTrace(TRUE);
9031 buf_ForceTrace(TRUE);
9032 return EXCEPTION_CONTINUE_SEARCH;
9036 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9037 * If the number of server threads is M, and the number of live sessions is
9038 * N, then the number of NCB's in use at any time either waiting for, or
9039 * holding, received messages is M + N, so that is how many NCB's get created.
9041 void InitNCBslot(int idx)
9043 struct smb_packet *bufp;
9044 EVENT_HANDLE retHandle;
9046 char eventName[MAX_PATH];
9048 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9050 NCBs[idx] = smb_GetNCB();
9051 sprintf(eventName,"NCBavails[%d]", idx);
9052 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9053 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9054 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9055 sprintf(eventName,"NCBevents[%d]", idx);
9056 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9057 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9058 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9059 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9060 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9061 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9062 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9063 for (i=0; i<smb_NumServerThreads; i++)
9064 NCBreturns[i][idx] = retHandle;
9065 bufp = smb_GetPacket();
9066 bufp->spacep = cm_GetSpace();
9070 /* listen for new connections */
9071 void smb_Listener(void *parmp)
9077 afs_uint32 session, thread;
9078 smb_vc_t *vcp = NULL;
9080 char rname[NCBNAMSZ+1];
9081 char cname[MAX_COMPUTERNAME_LENGTH+1];
9082 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9083 INT_PTR lana = (INT_PTR) parmp;
9084 char eventName[MAX_PATH];
9085 int bridgeCount = 0;
9086 int nowildCount = 0;
9088 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9089 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9090 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9091 thrd_ResetEvent(ListenerShutdown[lana]);
9093 ncbp = smb_GetNCB();
9095 /* retrieve computer name */
9096 GetComputerName(cname, &cnamelen);
9099 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9100 memset(ncbp, 0, sizeof(NCB));
9103 ncbp->ncb_command = NCBLISTEN;
9104 ncbp->ncb_rto = 0; /* No receive timeout */
9105 ncbp->ncb_sto = 0; /* No send timeout */
9107 /* pad out with spaces instead of null termination */
9108 len = (long)strlen(smb_localNamep);
9109 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9110 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9112 strcpy(ncbp->ncb_callname, "*");
9113 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9115 ncbp->ncb_lana_num = (UCHAR)lana;
9117 code = Netbios(ncbp);
9119 if (code == NRC_NAMERR) {
9120 /* An smb shutdown or Vista resume must have taken place */
9122 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9123 ncbp->ncb_lana_num);
9124 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9126 if (lock_TryMutex(&smb_StartedLock)) {
9127 lana_list.lana[i] = LANA_INVALID;
9128 lock_ReleaseMutex(&smb_StartedLock);
9131 } else if (code == NRC_BRIDGE || code != 0) {
9132 int lanaRemaining = 0;
9134 if (code == NRC_BRIDGE) {
9135 if (++bridgeCount <= 5) {
9136 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9139 } else if (code == NRC_NOWILD) {
9140 if (++nowildCount <= 5) {
9141 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9143 if (bridgeCount > 0) {
9144 memset(ncbp, 0, sizeof(*ncbp));
9145 ncbp->ncb_command = NCBADDNAME;
9146 ncbp->ncb_lana_num = (UCHAR)lana;
9147 /* pad out with spaces instead of null termination */
9148 len = (long)strlen(smb_localNamep);
9149 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9150 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9151 code = Netbios(ncbp);
9157 while (!lock_TryMutex(&smb_StartedLock)) {
9158 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9164 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9165 ncbp->ncb_lana_num, ncb_error_string(code));
9166 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9167 ncbp->ncb_lana_num, ncb_error_string(code));
9169 for (i = 0; i < lana_list.length; i++) {
9170 if (lana_list.lana[i] == lana) {
9171 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9172 lana_list.lana[i] = LANA_INVALID;
9174 if (lana_list.lana[i] != LANA_INVALID)
9178 if (lanaRemaining == 0) {
9179 cm_VolStatus_Network_Stopped(cm_NetbiosName
9184 smb_ListenerState = SMB_LISTENER_STOPPED;
9185 smb_LANadapter = LANA_INVALID;
9186 lana_list.length = 0;
9188 lock_ReleaseMutex(&smb_StartedLock);
9192 else if (code != 0) {
9193 char tbuffer[AFSPATHMAX];
9195 /* terminate silently if shutdown flag is set */
9196 while (!lock_TryMutex(&smb_StartedLock)) {
9197 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9203 "NCBLISTEN lana=%d failed with code %d [%s]",
9204 ncbp->ncb_lana_num, code, ncb_error_string(code));
9206 "Client exiting due to network failure. Please restart client.\n");
9209 "Client exiting due to network failure. Please restart client.\n"
9210 "NCBLISTEN lana=%d failed with code %d [%s]",
9211 ncbp->ncb_lana_num, code, ncb_error_string(code));
9213 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9214 MB_OK|MB_SERVICE_NOTIFICATION);
9215 osi_panic(tbuffer, __FILE__, __LINE__);
9217 lock_ReleaseMutex(&smb_StartedLock);
9222 /* a successful packet received. clear bridge error count */
9226 /* check for remote conns */
9227 /* first get remote name and insert null terminator */
9228 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9229 for (i=NCBNAMSZ; i>0; i--) {
9230 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9236 /* compare with local name */
9238 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9239 flags |= SMB_VCFLAG_REMOTECONN;
9242 lock_ObtainMutex(&smb_ListenerLock);
9244 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9245 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9247 /* now ncbp->ncb_lsn is the connection ID */
9248 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9249 if (vcp->session == 0) {
9250 /* New generation */
9251 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9254 /* Log session startup */
9256 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9257 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9258 #endif /* NOTSERVICE */
9259 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9260 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9262 if (reportSessionStartups) {
9263 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9266 lock_ObtainMutex(&vcp->mx);
9267 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9268 vcp->flags |= flags;
9269 lock_ReleaseMutex(&vcp->mx);
9271 /* Allocate slot in session arrays */
9272 /* Re-use dead session if possible, otherwise add one more */
9273 /* But don't look at session[0], it is reserved */
9274 lock_ObtainWrite(&smb_globalLock);
9275 for (session = 1; session < numSessions; session++) {
9276 if (dead_sessions[session]) {
9277 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9278 dead_sessions[session] = FALSE;
9282 lock_ReleaseWrite(&smb_globalLock);
9284 /* We are re-using an existing VC because the lsn and lana
9286 session = vcp->session;
9288 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9290 /* Log session startup */
9292 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9293 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9294 #endif /* NOTSERVICE */
9295 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9296 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9298 if (reportSessionStartups) {
9299 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9303 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9304 unsigned long code = CM_ERROR_ALLBUSY;
9305 smb_packet_t * outp = smb_GetPacket();
9306 unsigned char *outWctp;
9309 smb_FormatResponsePacket(vcp, NULL, outp);
9312 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9313 unsigned long NTStatus;
9314 smb_MapNTError(code, &NTStatus);
9315 outWctp = outp->wctp;
9316 smbp = (smb_t *) &outp->data;
9320 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9321 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9322 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9323 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9324 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9326 unsigned short errCode;
9327 unsigned char errClass;
9328 smb_MapCoreError(code, vcp, &errCode, &errClass);
9329 outWctp = outp->wctp;
9330 smbp = (smb_t *) &outp->data;
9334 smbp->errLow = (unsigned char) (errCode & 0xff);
9335 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9336 smbp->rcls = errClass;
9339 smb_SendPacket(vcp, outp);
9340 smb_FreePacket(outp);
9342 lock_ObtainMutex(&vcp->mx);
9343 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9344 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9346 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9347 lock_ReleaseMutex(&vcp->mx);
9348 lock_ObtainWrite(&smb_globalLock);
9349 dead_sessions[vcp->session] = TRUE;
9350 lock_ReleaseWrite(&smb_globalLock);
9351 smb_CleanupDeadVC(vcp);
9353 lock_ReleaseMutex(&vcp->mx);
9356 /* assert that we do not exceed the maximum number of sessions or NCBs.
9357 * we should probably want to wait for a session to be freed in case
9360 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9361 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9363 lock_ObtainMutex(&vcp->mx);
9364 vcp->session = session;
9365 lock_ReleaseMutex(&vcp->mx);
9366 lock_ObtainWrite(&smb_globalLock);
9367 LSNs[session] = ncbp->ncb_lsn;
9368 lanas[session] = ncbp->ncb_lana_num;
9369 lock_ReleaseWrite(&smb_globalLock);
9371 if (session == numSessions) {
9372 /* Add new NCB for new session */
9373 char eventName[MAX_PATH];
9375 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9377 InitNCBslot(numNCBs);
9378 lock_ObtainWrite(&smb_globalLock);
9380 lock_ReleaseWrite(&smb_globalLock);
9381 thrd_SetEvent(NCBavails[0]);
9382 thrd_SetEvent(NCBevents[0]);
9383 for (thread = 0; thread < smb_NumServerThreads; thread++)
9384 thrd_SetEvent(NCBreturns[thread][0]);
9385 /* Also add new session event */
9386 sprintf(eventName, "SessionEvents[%d]", session);
9387 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9388 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9389 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9390 lock_ObtainWrite(&smb_globalLock);
9392 lock_ReleaseWrite(&smb_globalLock);
9393 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9394 thrd_SetEvent(SessionEvents[0]);
9396 thrd_SetEvent(SessionEvents[session]);
9402 lock_ReleaseMutex(&smb_ListenerLock);
9403 } /* dispatch while loop */
9407 thrd_SetEvent(ListenerShutdown[lana]);
9412 configureBackConnectionHostNames(void)
9414 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9415 * there is a restriction on the use of SMB authentication on loopback connections.
9416 * There are two work arounds available:
9418 * (1) We can disable the check for matching host names. This does not
9420 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9421 * "DisableLoopbackCheck"=dword:00000001
9423 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9424 * does require a reboot:
9425 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9426 * "BackConnectionHostNames"=multi-sz
9428 * The algorithm will be:
9429 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9430 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9431 * (2b1) and check to see if DisableLoopbackCheck is set.
9432 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9433 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9434 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9435 * check for the UnsetDisableLoopbackCheck value.
9436 * If set, set the DisableLoopbackCheck flag to 0x0
9437 * and delete the UnsetDisableLoopbackCheck value
9439 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9440 * force Windows to use the loopback authentication mechanism for the specified
9443 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9444 * service session that set it.
9450 DWORD dwSize, dwAllocSize;
9452 PBYTE pHostNames = NULL, pName = NULL;
9453 BOOL bNameFound = FALSE;
9454 static BOOL bLoopbackCheckDisabled = FALSE;
9456 /* BackConnectionHostNames and DisableLoopbackCheck */
9457 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9458 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9461 &hkMSV10) == ERROR_SUCCESS )
9463 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9464 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9465 (dwType == REG_MULTI_SZ))
9467 dwAllocSize += 1 /* in case the source string is not nul terminated */
9468 + (DWORD)strlen(cm_NetbiosName) + 2;
9469 pHostNames = malloc(dwAllocSize);
9470 dwSize = dwAllocSize;
9471 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9472 pHostNames, &dwSize) == ERROR_SUCCESS)
9474 for (pName = pHostNames;
9475 (pName - pHostNames < (int) dwSize) && *pName ;
9476 pName += strlen(pName) + 1)
9478 if ( !stricmp(pName, cm_NetbiosName) ) {
9486 if ( !bNameFound ) {
9487 size_t size = strlen(cm_NetbiosName) + 2;
9488 if ( !pHostNames ) {
9489 pHostNames = malloc(size);
9492 StringCbCopyA(pName, size, cm_NetbiosName);
9494 *pName = '\0'; /* add a second nul terminator */
9496 dwType = REG_MULTI_SZ;
9497 dwSize = (DWORD)(pName - pHostNames + 1);
9498 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9500 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9501 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9504 &hkLsa) == ERROR_SUCCESS )
9506 dwSize = sizeof(DWORD);
9507 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9510 dwSize = sizeof(DWORD);
9512 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9514 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9515 AFSREG_CLT_OPENAFS_SUBKEY,
9518 REG_OPTION_NON_VOLATILE,
9522 NULL) == ERROR_SUCCESS) {
9525 dwSize = sizeof(DWORD);
9527 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9528 bLoopbackCheckDisabled = TRUE;
9529 RegCloseKey(hkClient);
9534 } else if (!bLoopbackCheckDisabled) {
9535 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9536 AFSREG_CLT_OPENAFS_SUBKEY,
9539 REG_OPTION_NON_VOLATILE,
9543 NULL) == ERROR_SUCCESS) {
9545 dwSize = sizeof(DWORD);
9546 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9548 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9549 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9552 &hkLsa) == ERROR_SUCCESS )
9554 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9558 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9559 RegCloseKey(hkClient);
9568 RegCloseKey(hkMSV10);
9574 configureExtendedSMBSessionTimeouts(void)
9577 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9578 * new functionality:
9580 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9581 * "ReconnectableServers" REG_MULTI_SZ
9582 * "ExtendedSessTimeout" REG_DWORD (seconds)
9583 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9585 * These values can be used to prevent the smb redirector from timing out
9586 * smb connection to the afs smb server prematurely.
9590 DWORD dwSize, dwAllocSize;
9592 PBYTE pHostNames = NULL, pName = NULL;
9593 BOOL bNameFound = FALSE;
9595 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9596 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9599 &hkLanMan) == ERROR_SUCCESS )
9601 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9602 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9603 (dwType == REG_MULTI_SZ))
9605 dwAllocSize += 1 /* in case the source string is not nul terminated */
9606 + (DWORD)strlen(cm_NetbiosName) + 2;
9607 pHostNames = malloc(dwAllocSize);
9608 dwSize = dwAllocSize;
9609 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9610 pHostNames, &dwSize) == ERROR_SUCCESS)
9612 for (pName = pHostNames;
9613 (pName - pHostNames < (int) dwSize) && *pName ;
9614 pName += strlen(pName) + 1)
9616 if ( !stricmp(pName, cm_NetbiosName) ) {
9624 if ( !bNameFound ) {
9625 size_t size = strlen(cm_NetbiosName) + 2;
9626 if ( !pHostNames ) {
9627 pHostNames = malloc(size);
9630 StringCbCopyA(pName, size, cm_NetbiosName);
9632 *pName = '\0'; /* add a second nul terminator */
9634 dwType = REG_MULTI_SZ;
9635 dwSize = (DWORD)(pName - pHostNames + 1);
9636 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9644 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9645 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9646 (dwType == REG_MULTI_SZ))
9648 dwAllocSize += 1 /* in case the source string is not nul terminated */
9649 + (DWORD)strlen(cm_NetbiosName) + 2;
9650 pHostNames = malloc(dwAllocSize);
9651 dwSize = dwAllocSize;
9652 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9653 pHostNames, &dwSize) == ERROR_SUCCESS)
9655 for (pName = pHostNames;
9656 (pName - pHostNames < (int) dwSize) && *pName ;
9657 pName += strlen(pName) + 1)
9659 if ( !stricmp(pName, cm_NetbiosName) ) {
9667 if ( !bNameFound ) {
9668 size_t size = strlen(cm_NetbiosName) + 2;
9669 if ( !pHostNames ) {
9670 pHostNames = malloc(size);
9673 StringCbCopyA(pName, size, cm_NetbiosName);
9675 *pName = '\0'; /* add a second nul terminator */
9677 dwType = REG_MULTI_SZ;
9678 dwSize = (DWORD)(pName - pHostNames + 1);
9679 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9687 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9688 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9689 (dwType != REG_DWORD))
9692 dwSize = sizeof(dwValue);
9693 dwValue = 600; /* 10 minutes */
9694 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9696 RegCloseKey(hkLanMan);
9701 smb_LanAdapterChangeThread(void *param)
9704 * Give the IPAddrDaemon thread a chance
9705 * to block before we trigger.
9708 smb_LanAdapterChange(0);
9711 void smb_SetLanAdapterChangeDetected(void)
9716 lock_ObtainMutex(&smb_StartedLock);
9718 if (!powerStateSuspended) {
9719 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9720 NULL, 0, &lpid, "smb_LanAdapterChange");
9721 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9722 thrd_CloseHandle(phandle);
9725 smb_LanAdapterChangeDetected = 1;
9726 lock_ReleaseMutex(&smb_StartedLock);
9729 void smb_LanAdapterChange(int locked) {
9730 lana_number_t lanaNum;
9732 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9734 LANA_ENUM temp_list;
9739 afsi_log("smb_LanAdapterChange");
9742 lock_ObtainMutex(&smb_StartedLock);
9744 smb_LanAdapterChangeDetected = 0;
9746 if (!powerStateSuspended &&
9747 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9748 LANA_NETBIOS_NAME_FULL)) &&
9749 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9750 if ( isGateway != bGateway ) {
9751 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9752 smb_LANadapter, lanaNum, isGateway, bGateway);
9754 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9755 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9756 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9759 NCB *ncbp = smb_GetNCB();
9760 ncbp->ncb_command = NCBENUM;
9761 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9762 ncbp->ncb_length = sizeof(temp_list);
9763 code = Netbios(ncbp);
9765 if (temp_list.length != lana_list.length) {
9766 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9767 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9770 for (i=0; i<lana_list.length; i++) {
9771 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9772 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9773 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9785 smb_StopListeners(1);
9786 smb_RestartListeners(1);
9789 lock_ReleaseMutex(&smb_StartedLock);
9792 /* initialize Netbios */
9793 int smb_NetbiosInit(int locked)
9796 int i, lana, code, l;
9798 int delname_tried=0;
9801 lana_number_t lanaNum;
9804 lock_ObtainMutex(&smb_StartedLock);
9806 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9807 smb_ListenerState != SMB_LISTENER_STOPPED) {
9810 lock_ReleaseMutex(&smb_StartedLock);
9813 /* setup the NCB system */
9814 ncbp = smb_GetNCB();
9816 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9817 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9818 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9820 if (smb_LANadapter != LANA_INVALID)
9821 afsi_log("LAN adapter number %d", smb_LANadapter);
9823 afsi_log("LAN adapter number not determined");
9826 afsi_log("Set for gateway service");
9828 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9830 /* something went horribly wrong. We can't proceed without a netbios name */
9832 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9833 osi_panic(buf, __FILE__, __LINE__);
9836 /* remember the name */
9837 len = (int)strlen(cm_NetbiosName);
9839 free(smb_localNamep);
9840 smb_localNamep = malloc(len+1);
9841 strcpy(smb_localNamep, cm_NetbiosName);
9842 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9844 /* Also copy the value to the client character encoded string */
9845 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9847 if (smb_LANadapter == LANA_INVALID) {
9848 ncbp->ncb_command = NCBENUM;
9849 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9850 ncbp->ncb_length = sizeof(lana_list);
9851 code = Netbios(ncbp);
9853 afsi_log("Netbios NCBENUM error code %d", code);
9854 osi_panic(s, __FILE__, __LINE__);
9858 lana_list.length = 1;
9859 lana_list.lana[0] = smb_LANadapter;
9862 for (i = 0; i < lana_list.length; i++) {
9863 /* reset the adaptor: in Win32, this is required for every process, and
9864 * acts as an init call, not as a real hardware reset.
9866 ncbp->ncb_command = NCBRESET;
9867 ncbp->ncb_callname[0] = 100;
9868 ncbp->ncb_callname[2] = 100;
9869 ncbp->ncb_lana_num = lana_list.lana[i];
9870 code = Netbios(ncbp);
9872 code = ncbp->ncb_retcode;
9874 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9875 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9877 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9881 /* and declare our name so we can receive connections */
9882 memset(ncbp, 0, sizeof(*ncbp));
9883 len=lstrlen(smb_localNamep);
9884 memset(smb_sharename,' ',NCBNAMSZ);
9885 memcpy(smb_sharename,smb_localNamep,len);
9886 afsi_log("lana_list.length %d", lana_list.length);
9888 /* Keep the name so we can unregister it later */
9889 for (l = 0; l < lana_list.length; l++) {
9890 lana = lana_list.lana[l];
9892 ncbp->ncb_command = NCBADDNAME;
9893 ncbp->ncb_lana_num = lana;
9894 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9895 code = Netbios(ncbp);
9897 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9898 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9900 char name[NCBNAMSZ+1];
9902 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9903 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9907 code = ncbp->ncb_retcode;
9910 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9913 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9914 if (code == NRC_BRIDGE) { /* invalid LANA num */
9915 lana_list.lana[l] = LANA_INVALID;
9918 else if (code == NRC_DUPNAME) {
9919 afsi_log("Name already exists; try to delete it");
9920 memset(ncbp, 0, sizeof(*ncbp));
9921 ncbp->ncb_command = NCBDELNAME;
9922 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9923 ncbp->ncb_lana_num = lana;
9924 code = Netbios(ncbp);
9926 code = ncbp->ncb_retcode;
9928 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9930 if (code != 0 || delname_tried) {
9931 lana_list.lana[l] = LANA_INVALID;
9933 else if (code == 0) {
9934 if (!delname_tried) {
9942 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9943 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9947 smb_LANadapter = lana;
9948 lana_found = 1; /* at least one worked */
9952 osi_assertx(lana_list.length >= 0, "empty lana list");
9954 afsi_log("No valid LANA numbers found!");
9955 lana_list.length = 0;
9956 smb_LANadapter = LANA_INVALID;
9957 smb_ListenerState = SMB_LISTENER_STOPPED;
9958 cm_VolStatus_Network_Stopped(cm_NetbiosName
9965 /* we're done with the NCB now */
9968 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9969 if (lana_list.length > 0)
9970 osi_assert(smb_LANadapter != LANA_INVALID);
9973 lock_ReleaseMutex(&smb_StartedLock);
9975 return (lana_list.length > 0 ? 1 : 0);
9978 void smb_StartListeners(int locked)
9985 lock_ObtainMutex(&smb_StartedLock);
9987 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9989 lock_ReleaseMutex(&smb_StartedLock);
9993 afsi_log("smb_StartListeners");
9994 /* Ensure the AFS Netbios Name is registered to allow loopback access */
9995 configureBackConnectionHostNames();
9997 /* Configure Extended SMB Session Timeouts */
9998 configureExtendedSMBSessionTimeouts();
10000 smb_ListenerState = SMB_LISTENER_STARTED;
10001 cm_VolStatus_Network_Started(cm_NetbiosName
10007 for (i = 0; i < lana_list.length; i++) {
10008 if (lana_list.lana[i] == LANA_INVALID)
10010 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10011 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10012 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10013 thrd_CloseHandle(phandle);
10016 lock_ReleaseMutex(&smb_StartedLock);
10019 void smb_RestartListeners(int locked)
10022 lock_ObtainMutex(&smb_StartedLock);
10024 if (powerStateSuspended)
10025 afsi_log("smb_RestartListeners called while suspended");
10027 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10028 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10029 if (smb_NetbiosInit(1))
10030 smb_StartListeners(1);
10031 } else if (smb_LanAdapterChangeDetected) {
10032 smb_LanAdapterChange(1);
10036 lock_ReleaseMutex(&smb_StartedLock);
10039 void smb_StopListener(NCB *ncbp, int lana, int wait)
10043 memset(ncbp, 0, sizeof(*ncbp));
10044 ncbp->ncb_command = NCBDELNAME;
10045 ncbp->ncb_lana_num = lana;
10046 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10047 code = Netbios(ncbp);
10049 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10050 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10052 /* and then reset the LANA; this will cause the listener threads to exit */
10053 ncbp->ncb_command = NCBRESET;
10054 ncbp->ncb_callname[0] = 100;
10055 ncbp->ncb_callname[2] = 100;
10056 ncbp->ncb_lana_num = lana;
10057 code = Netbios(ncbp);
10059 code = ncbp->ncb_retcode;
10061 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10063 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10067 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10070 void smb_StopListeners(int locked)
10076 lock_ObtainMutex(&smb_StartedLock);
10078 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10080 lock_ReleaseMutex(&smb_StartedLock);
10084 afsi_log("smb_StopListeners");
10085 smb_ListenerState = SMB_LISTENER_STOPPED;
10086 cm_VolStatus_Network_Stopped(cm_NetbiosName
10092 ncbp = smb_GetNCB();
10094 /* Unregister the SMB name */
10095 for (l = 0; l < lana_list.length; l++) {
10096 lana = lana_list.lana[l];
10098 if (lana != LANA_INVALID) {
10099 smb_StopListener(ncbp, lana, TRUE);
10101 /* mark the adapter invalid */
10102 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10106 /* force a re-evaluation of the network adapters */
10107 lana_list.length = 0;
10108 smb_LANadapter = LANA_INVALID;
10111 lock_ReleaseMutex(&smb_StartedLock);
10114 void smb_Init(osi_log_t *logp, int useV3,
10124 EVENT_HANDLE retHandle;
10125 char eventName[MAX_PATH];
10126 int startListeners = 0;
10128 smb_TlsRequestSlot = TlsAlloc();
10130 smb_MBfunc = aMBfunc;
10134 /* Initialize smb_localZero */
10135 myTime.tm_isdst = -1; /* compute whether on DST or not */
10136 myTime.tm_year = 70;
10138 myTime.tm_mday = 1;
10139 myTime.tm_hour = 0;
10142 smb_localZero = mktime(&myTime);
10144 #ifndef USE_NUMERIC_TIME_CONV
10145 /* Initialize kludge-GMT */
10146 smb_CalculateNowTZ();
10147 #endif /* USE_NUMERIC_TIME_CONV */
10148 #ifdef AFS_FREELANCE_CLIENT
10149 /* Make sure the root.afs volume has the correct time */
10150 cm_noteLocalMountPointChange();
10153 /* initialize the remote debugging log */
10156 /* and the global lock */
10157 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10158 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10160 /* Raw I/O data structures */
10161 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10163 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10164 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10166 /* 4 Raw I/O buffers */
10167 smb_RawBufs = calloc(65536,1);
10168 *((char **)smb_RawBufs) = NULL;
10169 for (i=0; i<3; i++) {
10170 char *rawBuf = calloc(65536,1);
10171 *((char **)rawBuf) = smb_RawBufs;
10172 smb_RawBufs = rawBuf;
10175 /* global free lists */
10176 smb_ncbFreeListp = NULL;
10177 smb_packetFreeListp = NULL;
10179 lock_ObtainMutex(&smb_StartedLock);
10180 startListeners = smb_NetbiosInit(1);
10182 /* Initialize listener and server structures */
10184 memset(dead_sessions, 0, sizeof(dead_sessions));
10185 sprintf(eventName, "SessionEvents[0]");
10186 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10187 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10188 afsi_log("Event Object Already Exists: %s", eventName);
10190 smb_NumServerThreads = nThreads;
10191 sprintf(eventName, "NCBavails[0]");
10192 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10193 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10194 afsi_log("Event Object Already Exists: %s", eventName);
10195 sprintf(eventName, "NCBevents[0]");
10196 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10197 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10198 afsi_log("Event Object Already Exists: %s", eventName);
10199 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10200 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10201 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10202 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10203 afsi_log("Event Object Already Exists: %s", eventName);
10204 for (i = 0; i < smb_NumServerThreads; i++) {
10205 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10206 NCBreturns[i][0] = retHandle;
10209 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10210 for (i = 0; i < smb_NumServerThreads; i++) {
10211 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10212 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10213 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10214 afsi_log("Event Object Already Exists: %s", eventName);
10215 InitNCBslot((int)(i+1));
10217 numNCBs = smb_NumServerThreads + 1;
10219 /* Initialize dispatch table */
10220 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10221 /* Prepare the table for unknown operations */
10222 for(i=0; i<= SMB_NOPCODES; i++) {
10223 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10225 /* Fill in the ones we do know */
10226 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10227 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10228 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10229 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10230 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10231 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10232 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10233 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10234 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10235 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10236 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10237 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10238 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10239 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10240 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10241 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10242 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10243 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10244 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10245 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10246 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10247 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10248 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10249 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10250 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10251 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10252 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10253 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10254 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10255 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10256 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10257 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10258 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10259 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10260 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10261 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10262 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10263 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10264 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10265 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10266 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10267 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10268 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10269 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10270 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10271 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10272 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10273 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10274 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10275 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10276 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10277 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10278 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10279 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10280 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10281 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10282 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10283 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10284 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10285 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10286 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10287 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10288 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10289 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10290 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10291 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10292 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10293 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10294 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10295 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10296 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10297 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10298 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10299 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10301 /* setup tran 2 dispatch table */
10302 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10303 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10304 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10305 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10306 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10307 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10308 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10309 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10310 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10311 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10312 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10313 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10314 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10315 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10316 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10317 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10318 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10319 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10321 /* setup the rap dispatch table */
10322 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10323 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10324 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10325 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10326 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10330 /* if we are doing SMB authentication we have register outselves as a logon process */
10331 if (smb_authType != SMB_AUTH_NONE) {
10332 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10333 LSA_STRING afsProcessName;
10334 LSA_OPERATIONAL_MODE dummy; /*junk*/
10336 afsProcessName.Buffer = "OpenAFSClientDaemon";
10337 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10338 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10340 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10342 if (nts == STATUS_SUCCESS) {
10343 LSA_STRING packageName;
10344 /* we are registered. Find out the security package id */
10345 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10346 packageName.Length = (USHORT)strlen(packageName.Buffer);
10347 packageName.MaximumLength = packageName.Length + 1;
10348 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10349 if (nts == STATUS_SUCCESS) {
10351 * This code forces Windows to authenticate against the Logon Cache
10352 * first instead of attempting to authenticate against the Domain
10353 * Controller. When the Windows logon cache is enabled this improves
10354 * performance by removing the network access and works around a bug
10355 * seen at sites which are using a MIT Kerberos principal to login
10356 * to machines joined to a non-root domain in a multi-domain forest.
10357 * MsV1_0SetProcessOption was added in Windows XP.
10359 PVOID pResponse = NULL;
10360 ULONG cbResponse = 0;
10361 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10363 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10364 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10365 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10366 OptionsRequest.DisableOptions = FALSE;
10368 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10371 sizeof(OptionsRequest),
10377 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10378 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10381 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10383 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10384 afsi_log("MsV1_0SetProcessOption success");
10386 /* END - code from Larry */
10388 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10389 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10390 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10392 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10394 /* something went wrong. We report the error and revert back to no authentication
10395 because we can't perform any auth requests without a successful lsa handle
10396 or sec package id. */
10397 afsi_log("Reverting to NO SMB AUTH");
10398 smb_authType = SMB_AUTH_NONE;
10401 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10403 /* something went wrong. We report the error and revert back to no authentication
10404 because we can't perform any auth requests without a successful lsa handle
10405 or sec package id. */
10406 afsi_log("Reverting to NO SMB AUTH");
10407 smb_authType = SMB_AUTH_NONE;
10411 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10412 * time prevents the failure of authentication when logged into Windows with an
10413 * external Kerberos principal mapped to a local account.
10415 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10416 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10417 * then the only option is NTLMSSP anyway; so just fallback.
10422 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10423 if (secBlobLength == 0) {
10424 smb_authType = SMB_AUTH_NTLM;
10425 afsi_log("Reverting to SMB AUTH NTLM");
10434 /* Now get ourselves a domain name. */
10435 /* For now we are using the local computer name as the domain name.
10436 * It is actually the domain for local logins, and we are acting as
10437 * a local SMB server.
10439 bufsize = lengthof(smb_ServerDomainName) - 1;
10440 GetComputerNameW(smb_ServerDomainName, &bufsize);
10441 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10442 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10445 /* Start listeners, waiters, servers, and daemons */
10446 if (startListeners)
10447 smb_StartListeners(1);
10449 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10450 NULL, 0, &lpid, "smb_ClientWaiter");
10451 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10452 thrd_CloseHandle(phandle);
10454 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10455 NULL, 0, &lpid, "smb_ServerWaiter");
10456 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10457 thrd_CloseHandle(phandle);
10459 for (i=0; i<smb_NumServerThreads; i++) {
10460 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10461 (void *) i, 0, &lpid, "smb_Server");
10462 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10463 thrd_CloseHandle(phandle);
10466 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10467 NULL, 0, &lpid, "smb_Daemon");
10468 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10469 thrd_CloseHandle(phandle);
10471 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10472 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10473 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10474 thrd_CloseHandle(phandle);
10476 lock_ReleaseMutex(&smb_StartedLock);
10480 void smb_Shutdown(void)
10487 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10489 /* setup the NCB system */
10490 ncbp = smb_GetNCB();
10492 /* Block new sessions by setting shutdown flag */
10493 smbShutdownFlag = 1;
10495 /* Hang up all sessions */
10496 memset((char *)ncbp, 0, sizeof(NCB));
10497 for (i = 1; i < numSessions; i++)
10499 if (dead_sessions[i])
10502 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10503 ncbp->ncb_command = NCBHANGUP;
10504 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10505 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10506 code = Netbios(ncbp);
10507 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10508 if (code == 0) code = ncbp->ncb_retcode;
10510 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10511 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10515 /* Trigger the shutdown of all SMB threads */
10516 for (i = 0; i < smb_NumServerThreads; i++)
10517 thrd_SetEvent(NCBreturns[i][0]);
10519 thrd_SetEvent(NCBevents[0]);
10520 thrd_SetEvent(SessionEvents[0]);
10521 thrd_SetEvent(NCBavails[0]);
10523 for (i = 0;i < smb_NumServerThreads; i++) {
10524 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10525 if (code == WAIT_OBJECT_0) {
10528 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10529 thrd_SetEvent(NCBreturns[i--][0]);
10533 /* Delete Netbios name */
10534 memset((char *)ncbp, 0, sizeof(NCB));
10535 for (i = 0; i < lana_list.length; i++) {
10536 if (lana_list.lana[i] == LANA_INVALID) continue;
10537 ncbp->ncb_command = NCBDELNAME;
10538 ncbp->ncb_lana_num = lana_list.lana[i];
10539 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10540 code = Netbios(ncbp);
10542 code = ncbp->ncb_retcode;
10544 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10545 ncbp->ncb_lana_num, code);
10550 /* Release the reference counts held by the VCs */
10551 lock_ObtainWrite(&smb_rctLock);
10552 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10557 if (vcp->magic != SMB_VC_MAGIC)
10558 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10559 __FILE__, __LINE__);
10561 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10563 if (fidp->scp != NULL) {
10566 lock_ReleaseWrite(&smb_rctLock);
10567 lock_ObtainMutex(&fidp->mx);
10568 if (fidp->scp != NULL) {
10571 lock_ObtainWrite(&scp->rw);
10572 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10573 lock_ReleaseWrite(&scp->rw);
10574 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10575 cm_ReleaseSCache(scp);
10577 lock_ReleaseMutex(&fidp->mx);
10578 lock_ObtainWrite(&smb_rctLock);
10582 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10584 smb_ReleaseVCNoLock(tidp->vcp);
10586 cm_user_t *userp = tidp->userp;
10587 tidp->userp = NULL;
10588 cm_ReleaseUser(userp);
10592 lock_ReleaseWrite(&smb_rctLock);
10594 TlsFree(smb_TlsRequestSlot);
10597 /* Get the UNC \\<servername>\<sharename> prefix. */
10598 char *smb_GetSharename()
10603 /* Make sure we have been properly initialized. */
10604 if (smb_localNamep == NULL)
10607 /* Allocate space for \\<servername>\<sharename>, plus the
10610 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10611 name = malloc(len);
10612 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10618 void smb_LogPacket(smb_packet_t *packet)
10622 unsigned length, paramlen, datalen, i, j;
10624 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10626 if (!packet) return;
10628 osi_Log0(smb_logp, "*** SMB packet dump ***");
10630 smbp = (smb_t *) packet->data;
10631 vp = (BYTE *) packet->data;
10633 paramlen = smbp->wct * 2;
10634 datalen = *((WORD *) (smbp->vdata + paramlen));
10635 length = sizeof(*smbp) + paramlen + 1 + datalen;
10637 for (i=0;i < length; i+=16)
10639 memset( buf, ' ', 80 );
10642 itoa( i, buf, 16 );
10644 buf[strlen(buf)] = ' ';
10646 cp = (BYTE*) buf + 7;
10648 for (j=0;j < 16 && (i+j)<length; j++)
10650 *(cp++) = hex[vp[i+j] >> 4];
10651 *(cp++) = hex[vp[i+j] & 0xf];
10661 for (j=0;j < 16 && (i+j)<length;j++)
10663 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10674 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10677 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10679 #endif /* LOG_PACKET */
10682 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10688 smb_username_t *unp;
10689 smb_waitingLockRequest_t *wlrp;
10692 lock_ObtainRead(&smb_rctLock);
10694 sprintf(output, "begin dumping smb_username_t\r\n");
10695 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10696 for (unp = usernamesp; unp; unp=unp->nextp)
10698 cm_ucell_t *ucellp;
10700 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10701 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10702 unp->name ? unp->name : _C("NULL"),
10703 unp->machine ? unp->machine : _C("NULL"));
10704 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10706 sprintf(output, " begin dumping cm_ucell_t\r\n");
10707 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10709 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10710 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",
10711 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10712 ucellp->expirationTime, ucellp->gen,
10714 ucellp->cellp->name);
10715 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10718 sprintf(output, " done dumping cm_ucell_t\r\n");
10719 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10722 sprintf(output, "done dumping smb_username_t\r\n");
10723 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10726 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10727 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10730 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10731 smb_waitingLock_t *lockp;
10733 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10734 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10735 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10737 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10738 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10739 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10740 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10741 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10742 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10744 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10745 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10748 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10749 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10751 sprintf(output, "begin dumping smb_vc_t\r\n");
10752 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10754 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10760 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10761 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10762 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10764 sprintf(output, " begin dumping smb_user_t\r\n");
10765 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10766 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10767 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10768 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10769 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10771 sprintf(output, " done dumping smb_user_t\r\n");
10772 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10774 sprintf(output, " begin dumping smb_tid_t\r\n");
10775 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10776 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10777 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",
10778 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10779 tidp->pathname ? tidp->pathname : _C("NULL"));
10780 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10782 sprintf(output, " done dumping smb_tid_t\r\n");
10783 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10785 sprintf(output, " begin dumping smb_fid_t\r\n");
10786 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10788 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10790 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",
10791 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10792 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10793 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10794 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10797 sprintf(output, " done dumping smb_fid_t\r\n");
10798 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10801 sprintf(output, "done dumping smb_vc_t\r\n");
10802 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10804 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10805 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10807 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10813 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10814 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10815 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10817 sprintf(output, " begin dumping smb_user_t\r\n");
10818 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10819 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10820 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10821 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10822 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10824 sprintf(output, " done dumping smb_user_t\r\n");
10825 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10827 sprintf(output, " begin dumping smb_tid_t\r\n");
10828 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10829 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10830 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",
10831 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10832 tidp->pathname ? tidp->pathname : _C("NULL"));
10833 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10835 sprintf(output, " done dumping smb_tid_t\r\n");
10836 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10838 sprintf(output, " begin dumping smb_fid_t\r\n");
10839 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10841 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10843 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",
10844 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10845 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10846 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10847 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10850 sprintf(output, " done dumping smb_fid_t\r\n");
10851 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10854 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10855 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10858 lock_ReleaseRead(&smb_rctLock);
10862 long smb_IsNetworkStarted(void)
10865 lock_ObtainWrite(&smb_globalLock);
10866 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10867 lock_ReleaseWrite(&smb_globalLock);